Browse Source

Merge minor into default

Alex Szpakowski 7 years ago
parent
commit
4399e7cfad
100 changed files with 21261 additions and 1204 deletions
  1. 311 82
      CMakeLists.txt
  2. 139 6
      changes.txt
  3. 12 3
      extra/appveyor/appveyor.yml
  4. BIN
      extra/windows/love.rc
  5. 246 7
      license.txt
  6. 22 20
      platform/unix/automagic
  7. 56 59
      platform/unix/configure.ac
  8. 1 1
      platform/unix/debian/copyright
  9. 77 0
      platform/unix/deps.m4
  10. 3 2
      platform/unix/exclude
  11. 0 38
      platform/unix/gen-makefile
  12. 60 64
      platform/unix/genmodules
  13. 26 1
      platform/xcode/Images.xcassets/iOS AppIcon.appiconset/Contents.json
  14. 1 1
      platform/xcode/ios/love-ios.plist
  15. 642 245
      platform/xcode/liblove.xcodeproj/project.pbxproj
  16. 80 1
      platform/xcode/love.xcodeproj/project.pbxproj
  17. 5 0
      platform/xcode/love.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
  18. 1 1
      platform/xcode/macosx/liblove-macosx.plist
  19. 4 2
      platform/xcode/macosx/love-macosx.plist
  20. 39 7
      src/common/Color.h
  21. 29 0
      src/common/Data.cpp
  22. 7 1
      src/common/Data.h
  23. 1 1
      src/common/EnumMap.h
  24. 1 1
      src/common/Exception.cpp
  25. 1 1
      src/common/Exception.h
  26. 230 41
      src/common/Matrix.cpp
  27. 103 22
      src/common/Matrix.h
  28. 1 1
      src/common/Memoizer.cpp
  29. 1 1
      src/common/Memoizer.h
  30. 10 1
      src/common/Module.cpp
  31. 6 2
      src/common/Module.h
  32. 3 1
      src/common/Object.cpp
  33. 4 1
      src/common/Object.h
  34. 55 0
      src/common/Optional.h
  35. 1 1
      src/common/Reference.cpp
  36. 1 1
      src/common/Reference.h
  37. 29 0
      src/common/Stream.cpp
  38. 2 0
      src/common/Stream.h
  39. 25 0
      src/common/StringMap.cpp
  40. 22 1
      src/common/StringMap.h
  41. 56 52
      src/common/Variant.cpp
  42. 7 6
      src/common/Variant.h
  43. 1 1
      src/common/Vector.cpp
  44. 212 131
      src/common/Vector.h
  45. 1 1
      src/common/android.cpp
  46. 1 1
      src/common/android.h
  47. 112 19
      src/common/b64.cpp
  48. 18 4
      src/common/b64.h
  49. 34 29
      src/common/config.h
  50. 3 1
      src/common/delay.cpp
  51. 1 1
      src/common/delay.h
  52. 187 0
      src/common/deprecation.cpp
  53. 81 0
      src/common/deprecation.h
  54. 156 0
      src/common/halffloat.cpp
  55. 38 0
      src/common/halffloat.h
  56. 1 1
      src/common/int.h
  57. 1 1
      src/common/ios.h
  58. 1 1
      src/common/ios.mm
  59. 1 1
      src/common/macosx.h
  60. 1 1
      src/common/macosx.mm
  61. 9 5
      src/common/math.h
  62. 70 0
      src/common/memory.cpp
  63. 38 0
      src/common/memory.h
  64. 179 0
      src/common/pixelformat.cpp
  65. 138 0
      src/common/pixelformat.h
  66. 192 36
      src/common/runtime.cpp
  67. 112 26
      src/common/runtime.h
  68. 42 105
      src/common/types.cpp
  69. 40 103
      src/common/types.h
  70. 1 1
      src/common/utf8.cpp
  71. 1 1
      src/common/utf8.h
  72. 6 6
      src/common/version.h
  73. 14 16
      src/libraries/ddsparse/ddsinfo.h
  74. 14 16
      src/libraries/ddsparse/ddsparse.cpp
  75. 14 16
      src/libraries/ddsparse/ddsparse.h
  76. 1 4
      src/libraries/enet/enet.cpp
  77. 1 1
      src/libraries/enet/lua-enet.h
  78. 155 0
      src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp
  79. 49 0
      src/libraries/glslang/OGLCompilersDLL/InitializeDll.h
  80. 76 0
      src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp
  81. 91 0
      src/libraries/glslang/glslang/GenericCodeGen/Link.cpp
  82. 382 0
      src/libraries/glslang/glslang/Include/BaseTypes.h
  83. 266 0
      src/libraries/glslang/glslang/Include/Common.h
  84. 625 0
      src/libraries/glslang/glslang/Include/ConstantUnion.h
  85. 144 0
      src/libraries/glslang/glslang/Include/InfoSink.h
  86. 47 0
      src/libraries/glslang/glslang/Include/InitializeGlobals.h
  87. 324 0
      src/libraries/glslang/glslang/Include/PoolAlloc.h
  88. 140 0
      src/libraries/glslang/glslang/Include/ResourceLimits.h
  89. 173 0
      src/libraries/glslang/glslang/Include/ShHandle.h
  90. 1915 0
      src/libraries/glslang/glslang/Include/Types.h
  91. 320 0
      src/libraries/glslang/glslang/Include/arrays.h
  92. 1406 0
      src/libraries/glslang/glslang/Include/intermediate.h
  93. 6 0
      src/libraries/glslang/glslang/Include/revision.h
  94. 1029 0
      src/libraries/glslang/glslang/MachineIndependent/Constant.cpp
  95. 113 0
      src/libraries/glslang/glslang/MachineIndependent/InfoSink.cpp
  96. 6207 0
      src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp
  97. 112 0
      src/libraries/glslang/glslang/MachineIndependent/Initialize.h
  98. 302 0
      src/libraries/glslang/glslang/MachineIndependent/IntermTraverse.cpp
  99. 3199 0
      src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp
  100. 138 0
      src/libraries/glslang/glslang/MachineIndependent/LiveTraverser.h

+ 311 - 82
CMakeLists.txt

@@ -1,5 +1,5 @@
 #
 #
-# Copyright (c) 2006-2016 LOVE Development Team
+# Copyright (c) 2006-2017 LOVE Development Team
 #
 #
 # This software is provided 'as-is', without any express or implied
 # This software is provided 'as-is', without any express or implied
 # warranty.  In no event will the authors be held liable for any damages
 # warranty.  In no event will the authors be held liable for any damages
@@ -255,27 +255,41 @@ endfunction()
 set(LOVE_SRC_COMMON
 set(LOVE_SRC_COMMON
 	src/common/b64.cpp
 	src/common/b64.cpp
 	src/common/b64.h
 	src/common/b64.h
+	src/common/Color.h
 	src/common/config.h
 	src/common/config.h
+	src/common/Data.cpp
 	src/common/Data.h
 	src/common/Data.h
 	src/common/delay.cpp
 	src/common/delay.cpp
 	src/common/delay.h
 	src/common/delay.h
+	src/common/deprecation.cpp
+	src/common/deprecation.h
 	src/common/EnumMap.h
 	src/common/EnumMap.h
 	src/common/Exception.cpp
 	src/common/Exception.cpp
 	src/common/Exception.h
 	src/common/Exception.h
+	src/common/halffloat.cpp
+	src/common/halffloat.h
 	src/common/int.h
 	src/common/int.h
 	src/common/math.h
 	src/common/math.h
 	src/common/Matrix.cpp
 	src/common/Matrix.cpp
 	src/common/Matrix.h
 	src/common/Matrix.h
 	src/common/Memoizer.cpp
 	src/common/Memoizer.cpp
 	src/common/Memoizer.h
 	src/common/Memoizer.h
+	src/common/memory.cpp
+	src/common/memory.h
 	src/common/Module.cpp
 	src/common/Module.cpp
 	src/common/Module.h
 	src/common/Module.h
 	src/common/Object.cpp
 	src/common/Object.cpp
 	src/common/Object.h
 	src/common/Object.h
+	src/common/Optional.h
+	src/common/pixelformat.cpp
+	src/common/pixelformat.h
 	src/common/Reference.cpp
 	src/common/Reference.cpp
 	src/common/Reference.h
 	src/common/Reference.h
 	src/common/runtime.cpp
 	src/common/runtime.cpp
 	src/common/runtime.h
 	src/common/runtime.h
+	src/common/Stream.cpp
+	src/common/Stream.h
+	src/common/StringMap.cpp
 	src/common/StringMap.h
 	src/common/StringMap.h
 	src/common/types.cpp
 	src/common/types.cpp
 	src/common/types.h
 	src/common/types.h
@@ -286,8 +300,6 @@ set(LOVE_SRC_COMMON
 	#src/common/Vector.cpp # Vector.cpp is empty.
 	#src/common/Vector.cpp # Vector.cpp is empty.
 	src/common/Vector.h
 	src/common/Vector.h
 	src/common/version.h
 	src/common/version.h
-	src/common/wrap_Data.cpp
-	src/common/wrap_Data.h
 )
 )
 
 
 if (APPLE)
 if (APPLE)
@@ -307,10 +319,18 @@ set(LOVE_SRC_MODULE_AUDIO_ROOT
 	src/modules/audio/Audio.h
 	src/modules/audio/Audio.h
 	src/modules/audio/Source.cpp
 	src/modules/audio/Source.cpp
 	src/modules/audio/Source.h
 	src/modules/audio/Source.h
+	src/modules/audio/RecordingDevice.cpp
+	src/modules/audio/RecordingDevice.h
+	src/modules/audio/Filter.cpp
+	src/modules/audio/Filter.h
+	src/modules/audio/Effect.cpp
+	src/modules/audio/Effect.h
 	src/modules/audio/wrap_Audio.cpp
 	src/modules/audio/wrap_Audio.cpp
 	src/modules/audio/wrap_Audio.h
 	src/modules/audio/wrap_Audio.h
 	src/modules/audio/wrap_Source.cpp
 	src/modules/audio/wrap_Source.cpp
 	src/modules/audio/wrap_Source.h
 	src/modules/audio/wrap_Source.h
+	src/modules/audio/wrap_RecordingDevice.cpp
+	src/modules/audio/wrap_RecordingDevice.h
 )
 )
 
 
 set(LOVE_SRC_MODULE_AUDIO_NULL
 set(LOVE_SRC_MODULE_AUDIO_NULL
@@ -318,6 +338,8 @@ set(LOVE_SRC_MODULE_AUDIO_NULL
 	src/modules/audio/null/Audio.h
 	src/modules/audio/null/Audio.h
 	src/modules/audio/null/Source.cpp
 	src/modules/audio/null/Source.cpp
 	src/modules/audio/null/Source.h
 	src/modules/audio/null/Source.h
+	src/modules/audio/null/RecordingDevice.cpp
+	src/modules/audio/null/RecordingDevice.h
 )
 )
 
 
 set(LOVE_SRC_MODULE_AUDIO_OPENAL
 set(LOVE_SRC_MODULE_AUDIO_OPENAL
@@ -327,6 +349,12 @@ set(LOVE_SRC_MODULE_AUDIO_OPENAL
 	src/modules/audio/openal/Pool.h
 	src/modules/audio/openal/Pool.h
 	src/modules/audio/openal/Source.cpp
 	src/modules/audio/openal/Source.cpp
 	src/modules/audio/openal/Source.h
 	src/modules/audio/openal/Source.h
+	src/modules/audio/openal/RecordingDevice.cpp
+	src/modules/audio/openal/RecordingDevice.h
+	src/modules/audio/openal/Filter.cpp
+	src/modules/audio/openal/Filter.h
+	src/modules/audio/openal/Effect.cpp
+	src/modules/audio/openal/Effect.h
 )
 )
 
 
 set(LOVE_SRC_MODULE_AUDIO
 set(LOVE_SRC_MODULE_AUDIO
@@ -339,6 +367,37 @@ source_group("modules\\audio" FILES ${LOVE_SRC_MODULE_AUDIO_ROOT})
 source_group("modules\\audio\\null" FILES ${LOVE_SRC_MODULE_AUDIO_NULL})
 source_group("modules\\audio\\null" FILES ${LOVE_SRC_MODULE_AUDIO_NULL})
 source_group("modules\\audio\\openal" FILES ${LOVE_SRC_MODULE_AUDIO_OPENAL})
 source_group("modules\\audio\\openal" FILES ${LOVE_SRC_MODULE_AUDIO_OPENAL})
 
 
+#
+# love.data
+#
+
+set(LOVE_SRC_MODULE_DATA
+	src/modules/data/ByteData.cpp
+	src/modules/data/ByteData.h
+	src/modules/data/CompressedData.cpp
+	src/modules/data/CompressedData.h
+	src/modules/data/Compressor.cpp
+	src/modules/data/Compressor.h
+	src/modules/data/DataModule.cpp
+	src/modules/data/DataModule.h
+	src/modules/data/DataView.cpp
+	src/modules/data/DataView.h
+	src/modules/data/HashFunction.cpp
+	src/modules/data/HashFunction.h
+	src/modules/data/wrap_ByteData.cpp
+	src/modules/data/wrap_ByteData.h
+	src/modules/data/wrap_CompressedData.cpp
+	src/modules/data/wrap_CompressedData.h
+	src/modules/data/wrap_Data.cpp
+	src/modules/data/wrap_Data.h
+	src/modules/data/wrap_DataModule.cpp
+	src/modules/data/wrap_DataModule.h
+	src/modules/data/wrap_DataView.cpp
+	src/modules/data/wrap_DataView.h
+)
+
+source_group("modules\\data" FILES ${LOVE_SRC_MODULE_DATA})
+
 #
 #
 # love.event
 # love.event
 #
 #
@@ -446,71 +505,94 @@ source_group("modules\\font\\freetype" FILES ${LOVE_SRC_MODULE_FONT_FREETYPE})
 #
 #
 
 
 set(LOVE_SRC_MODULE_GRAPHICS_ROOT
 set(LOVE_SRC_MODULE_GRAPHICS_ROOT
-	src/modules/graphics/Color.h
+	src/modules/graphics/Buffer.cpp
+	src/modules/graphics/Buffer.h
+	src/modules/graphics/Canvas.cpp
+	src/modules/graphics/Canvas.h
+	src/modules/graphics/depthstencil.cpp
+	src/modules/graphics/depthstencil.h
+	src/modules/graphics/Deprecations.cpp
+	src/modules/graphics/Deprecations.h
+	src/modules/graphics/Drawable.cpp
 	src/modules/graphics/Drawable.h
 	src/modules/graphics/Drawable.h
+	src/modules/graphics/Font.cpp
+	src/modules/graphics/Font.h
 	src/modules/graphics/Graphics.cpp
 	src/modules/graphics/Graphics.cpp
 	src/modules/graphics/Graphics.h
 	src/modules/graphics/Graphics.h
+	src/modules/graphics/Image.cpp
+	src/modules/graphics/Image.h
+	src/modules/graphics/Mesh.cpp
+	src/modules/graphics/Mesh.h
 	src/modules/graphics/ParticleSystem.cpp
 	src/modules/graphics/ParticleSystem.cpp
 	src/modules/graphics/ParticleSystem.h
 	src/modules/graphics/ParticleSystem.h
+	src/modules/graphics/Polyline.cpp
+	src/modules/graphics/Polyline.h
 	src/modules/graphics/Quad.cpp
 	src/modules/graphics/Quad.cpp
 	src/modules/graphics/Quad.h
 	src/modules/graphics/Quad.h
+	src/modules/graphics/Resource.h
+	src/modules/graphics/Shader.cpp
+	src/modules/graphics/Shader.h
+	src/modules/graphics/ShaderStage.cpp
+	src/modules/graphics/ShaderStage.h
+	src/modules/graphics/SpriteBatch.cpp
+	src/modules/graphics/SpriteBatch.h
+	src/modules/graphics/StreamBuffer.cpp
+	src/modules/graphics/StreamBuffer.h
+	src/modules/graphics/Text.cpp
+	src/modules/graphics/Text.h
 	src/modules/graphics/Texture.cpp
 	src/modules/graphics/Texture.cpp
 	src/modules/graphics/Texture.h
 	src/modules/graphics/Texture.h
+	src/modules/graphics/vertex.cpp
+	src/modules/graphics/vertex.h
+	src/modules/graphics/Video.cpp
+	src/modules/graphics/Video.h
 	src/modules/graphics/Volatile.cpp
 	src/modules/graphics/Volatile.cpp
 	src/modules/graphics/Volatile.h
 	src/modules/graphics/Volatile.h
+	src/modules/graphics/wrap_Canvas.cpp
+	src/modules/graphics/wrap_Canvas.h
+	src/modules/graphics/wrap_Font.cpp
+	src/modules/graphics/wrap_Font.h
+	src/modules/graphics/wrap_Graphics.cpp
+	src/modules/graphics/wrap_Graphics.h
+	src/modules/graphics/wrap_Image.cpp
+	src/modules/graphics/wrap_Image.h
+	src/modules/graphics/wrap_Mesh.cpp
+	src/modules/graphics/wrap_Mesh.h
+	src/modules/graphics/wrap_ParticleSystem.cpp
+	src/modules/graphics/wrap_ParticleSystem.h
 	src/modules/graphics/wrap_Quad.cpp
 	src/modules/graphics/wrap_Quad.cpp
 	src/modules/graphics/wrap_Quad.h
 	src/modules/graphics/wrap_Quad.h
+	src/modules/graphics/wrap_Shader.cpp
+	src/modules/graphics/wrap_Shader.h
+	src/modules/graphics/wrap_SpriteBatch.cpp
+	src/modules/graphics/wrap_SpriteBatch.h
 	src/modules/graphics/wrap_Texture.cpp
 	src/modules/graphics/wrap_Texture.cpp
 	src/modules/graphics/wrap_Texture.h
 	src/modules/graphics/wrap_Texture.h
+	src/modules/graphics/wrap_Text.cpp
+	src/modules/graphics/wrap_Text.h
+	src/modules/graphics/wrap_Video.cpp
+	src/modules/graphics/wrap_Video.h
 )
 )
 
 
 set(LOVE_SRC_MODULE_GRAPHICS_OPENGL
 set(LOVE_SRC_MODULE_GRAPHICS_OPENGL
+	src/modules/graphics/opengl/Buffer.cpp
+	src/modules/graphics/opengl/Buffer.h
 	src/modules/graphics/opengl/Canvas.cpp
 	src/modules/graphics/opengl/Canvas.cpp
 	src/modules/graphics/opengl/Canvas.h
 	src/modules/graphics/opengl/Canvas.h
-	src/modules/graphics/opengl/Font.cpp
-	src/modules/graphics/opengl/Font.h
-	src/modules/graphics/opengl/GLBuffer.cpp
-	src/modules/graphics/opengl/GLBuffer.h
+	src/modules/graphics/opengl/FenceSync.cpp
+	src/modules/graphics/opengl/FenceSync.h
 	src/modules/graphics/opengl/Graphics.cpp
 	src/modules/graphics/opengl/Graphics.cpp
 	src/modules/graphics/opengl/Graphics.h
 	src/modules/graphics/opengl/Graphics.h
 	src/modules/graphics/opengl/Image.cpp
 	src/modules/graphics/opengl/Image.cpp
 	src/modules/graphics/opengl/Image.h
 	src/modules/graphics/opengl/Image.h
-	src/modules/graphics/opengl/Mesh.cpp
-	src/modules/graphics/opengl/Mesh.h
 	src/modules/graphics/opengl/OpenGL.cpp
 	src/modules/graphics/opengl/OpenGL.cpp
 	src/modules/graphics/opengl/OpenGL.h
 	src/modules/graphics/opengl/OpenGL.h
-	src/modules/graphics/opengl/ParticleSystem.cpp
-	src/modules/graphics/opengl/ParticleSystem.h
-	src/modules/graphics/opengl/Polyline.cpp
-	src/modules/graphics/opengl/Polyline.h
 	src/modules/graphics/opengl/Shader.cpp
 	src/modules/graphics/opengl/Shader.cpp
 	src/modules/graphics/opengl/Shader.h
 	src/modules/graphics/opengl/Shader.h
-	src/modules/graphics/opengl/SpriteBatch.cpp
-	src/modules/graphics/opengl/SpriteBatch.h
-	src/modules/graphics/opengl/Text.cpp
-	src/modules/graphics/opengl/Text.h
-	src/modules/graphics/opengl/Video.cpp
-	src/modules/graphics/opengl/Video.h
-	src/modules/graphics/opengl/wrap_Canvas.cpp
-	src/modules/graphics/opengl/wrap_Canvas.h
-	src/modules/graphics/opengl/wrap_Font.cpp
-	src/modules/graphics/opengl/wrap_Font.h
-	src/modules/graphics/opengl/wrap_Graphics.cpp
-	src/modules/graphics/opengl/wrap_Graphics.h
-	src/modules/graphics/opengl/wrap_Image.cpp
-	src/modules/graphics/opengl/wrap_Image.h
-	src/modules/graphics/opengl/wrap_Mesh.cpp
-	src/modules/graphics/opengl/wrap_Mesh.h
-	src/modules/graphics/opengl/wrap_ParticleSystem.cpp
-	src/modules/graphics/opengl/wrap_ParticleSystem.h
-	src/modules/graphics/opengl/wrap_Shader.cpp
-	src/modules/graphics/opengl/wrap_Shader.h
-	src/modules/graphics/opengl/wrap_SpriteBatch.cpp
-	src/modules/graphics/opengl/wrap_SpriteBatch.h
-	src/modules/graphics/opengl/wrap_Text.cpp
-	src/modules/graphics/opengl/wrap_Text.h
-	src/modules/graphics/opengl/wrap_Video.cpp
-	src/modules/graphics/opengl/wrap_Video.h
+	src/modules/graphics/opengl/ShaderStage.cpp
+	src/modules/graphics/opengl/ShaderStage.h
+	src/modules/graphics/opengl/StreamBuffer.cpp
+	src/modules/graphics/opengl/StreamBuffer.h
 )
 )
 
 
 set(LOVE_SRC_MODULE_GRAPHICS
 set(LOVE_SRC_MODULE_GRAPHICS
@@ -528,9 +610,16 @@ source_group("modules\\graphics\\opengl" FILES ${LOVE_SRC_MODULE_GRAPHICS_OPENGL
 set(LOVE_SRC_MODULE_IMAGE_ROOT
 set(LOVE_SRC_MODULE_IMAGE_ROOT
 	src/modules/image/CompressedImageData.cpp
 	src/modules/image/CompressedImageData.cpp
 	src/modules/image/CompressedImageData.h
 	src/modules/image/CompressedImageData.h
+	src/modules/image/CompressedSlice.cpp
+	src/modules/image/CompressedSlice.h
+	src/modules/image/FormatHandler.cpp
+	src/modules/image/FormatHandler.h
+	src/modules/image/Image.cpp
 	src/modules/image/Image.h
 	src/modules/image/Image.h
 	src/modules/image/ImageData.cpp
 	src/modules/image/ImageData.cpp
 	src/modules/image/ImageData.h
 	src/modules/image/ImageData.h
+	src/modules/image/ImageDataBase.cpp
+	src/modules/image/ImageDataBase.h
 	src/modules/image/wrap_CompressedImageData.cpp
 	src/modules/image/wrap_CompressedImageData.cpp
 	src/modules/image/wrap_CompressedImageData.h
 	src/modules/image/wrap_CompressedImageData.h
 	src/modules/image/wrap_Image.cpp
 	src/modules/image/wrap_Image.cpp
@@ -542,17 +631,10 @@ set(LOVE_SRC_MODULE_IMAGE_ROOT
 set(LOVE_SRC_MODULE_IMAGE_MAGPIE
 set(LOVE_SRC_MODULE_IMAGE_MAGPIE
 	src/modules/image/magpie/ASTCHandler.cpp
 	src/modules/image/magpie/ASTCHandler.cpp
 	src/modules/image/magpie/ASTCHandler.h
 	src/modules/image/magpie/ASTCHandler.h
-	src/modules/image/magpie/CompressedImageData.cpp
-	src/modules/image/magpie/CompressedImageData.h
-	src/modules/image/magpie/CompressedFormatHandler.h
 	src/modules/image/magpie/ddsHandler.cpp
 	src/modules/image/magpie/ddsHandler.cpp
 	src/modules/image/magpie/ddsHandler.h
 	src/modules/image/magpie/ddsHandler.h
-	src/modules/image/magpie/FormatHandler.cpp
-	src/modules/image/magpie/FormatHandler.h
-	src/modules/image/magpie/Image.cpp
-	src/modules/image/magpie/Image.h
-	src/modules/image/magpie/ImageData.cpp
-	src/modules/image/magpie/ImageData.h
+	src/modules/image/magpie/EXRHandler.cpp
+	src/modules/image/magpie/EXRHandler.h
 	src/modules/image/magpie/KTXHandler.cpp
 	src/modules/image/magpie/KTXHandler.cpp
 	src/modules/image/magpie/KTXHandler.h
 	src/modules/image/magpie/KTXHandler.h
 	src/modules/image/magpie/PKMHandler.cpp
 	src/modules/image/magpie/PKMHandler.cpp
@@ -633,22 +715,20 @@ source_group("modules\\keyboard\\sdl" FILES ${LOVE_SRC_MODULE_KEYBOARD_SDL})
 set(LOVE_SRC_MODULE_MATH
 set(LOVE_SRC_MODULE_MATH
 	src/modules/math/BezierCurve.cpp
 	src/modules/math/BezierCurve.cpp
 	src/modules/math/BezierCurve.h
 	src/modules/math/BezierCurve.h
-	src/modules/math/CompressedData.cpp
-	src/modules/math/CompressedData.h
-	src/modules/math/Compressor.cpp
-	src/modules/math/Compressor.h
 	src/modules/math/MathModule.cpp
 	src/modules/math/MathModule.cpp
 	src/modules/math/MathModule.h
 	src/modules/math/MathModule.h
 	src/modules/math/RandomGenerator.cpp
 	src/modules/math/RandomGenerator.cpp
 	src/modules/math/RandomGenerator.h
 	src/modules/math/RandomGenerator.h
+	src/modules/math/Transform.cpp
+	src/modules/math/Transform.h
 	src/modules/math/wrap_BezierCurve.cpp
 	src/modules/math/wrap_BezierCurve.cpp
 	src/modules/math/wrap_BezierCurve.h
 	src/modules/math/wrap_BezierCurve.h
-	src/modules/math/wrap_CompressedData.cpp
-	src/modules/math/wrap_CompressedData.h
 	src/modules/math/wrap_Math.cpp
 	src/modules/math/wrap_Math.cpp
 	src/modules/math/wrap_Math.h
 	src/modules/math/wrap_Math.h
 	src/modules/math/wrap_RandomGenerator.cpp
 	src/modules/math/wrap_RandomGenerator.cpp
 	src/modules/math/wrap_RandomGenerator.h
 	src/modules/math/wrap_RandomGenerator.h
+	src/modules/math/wrap_Transform.cpp
+	src/modules/math/wrap_Transform.h
 )
 )
 
 
 source_group("modules\\math" FILES ${LOVE_SRC_MODULE_MATH})
 source_group("modules\\math" FILES ${LOVE_SRC_MODULE_MATH})
@@ -809,6 +889,7 @@ source_group("modules\\physics\\box2d" FILES ${LOVE_SRC_MODULE_PHYSICS_BOX2D})
 #
 #
 
 
 set(LOVE_SRC_MODULE_SOUND_ROOT
 set(LOVE_SRC_MODULE_SOUND_ROOT
+	src/modules/sound/Decoder.cpp
 	src/modules/sound/Decoder.h
 	src/modules/sound/Decoder.h
 	src/modules/sound/Sound.cpp
 	src/modules/sound/Sound.cpp
 	src/modules/sound/Sound.h
 	src/modules/sound/Sound.h
@@ -823,8 +904,6 @@ set(LOVE_SRC_MODULE_SOUND_ROOT
 )
 )
 
 
 set(LOVE_SRC_MODULE_SOUND_LULLABY
 set(LOVE_SRC_MODULE_SOUND_LULLABY
-	src/modules/sound/lullaby/Decoder.cpp
-	src/modules/sound/lullaby/Decoder.h
 	src/modules/sound/lullaby/FLACDecoder.cpp
 	src/modules/sound/lullaby/FLACDecoder.cpp
 	src/modules/sound/lullaby/FLACDecoder.h
 	src/modules/sound/lullaby/FLACDecoder.h
 	src/modules/sound/lullaby/GmeDecoder.cpp
 	src/modules/sound/lullaby/GmeDecoder.cpp
@@ -920,25 +999,14 @@ source_group("modules\\thread\\sdl" FILES ${LOVE_SRC_MODULE_THREAD_SDL})
 # love.timer
 # love.timer
 #
 #
 
 
-set(LOVE_SRC_MODULE_TIMER_ROOT
+set(LOVE_SRC_MODULE_TIMER
 	src/modules/timer/Timer.cpp
 	src/modules/timer/Timer.cpp
 	src/modules/timer/Timer.h
 	src/modules/timer/Timer.h
 	src/modules/timer/wrap_Timer.cpp
 	src/modules/timer/wrap_Timer.cpp
 	src/modules/timer/wrap_Timer.h
 	src/modules/timer/wrap_Timer.h
 )
 )
 
 
-set(LOVE_SRC_MODULE_TIMER_SDL
-	src/modules/timer/sdl/Timer.cpp
-	src/modules/timer/sdl/Timer.h
-)
-
-set(LOVE_SRC_MODULE_TIMER
-	${LOVE_SRC_MODULE_TIMER_ROOT}
-	${LOVE_SRC_MODULE_TIMER_SDL}
-)
-
-source_group("modules\\timer" FILES ${LOVE_SRC_MODULE_TIMER_ROOT})
-source_group("modules\\timer\\sdl" FILES ${LOVE_SRC_MODULE_TIMER_SDL})
+source_group("modules\\timer" FILES ${LOVE_SRC_MODULE_TIMER})
 
 
 #
 #
 # love.touch
 # love.touch
@@ -980,8 +1048,10 @@ set(LOVE_SRC_MODULE_VIDEO_ROOT
 set(LOVE_SRC_MODULE_VIDEO_THEORA
 set(LOVE_SRC_MODULE_VIDEO_THEORA
 	src/modules/video/theora/Video.cpp
 	src/modules/video/theora/Video.cpp
 	src/modules/video/theora/Video.h
 	src/modules/video/theora/Video.h
-	src/modules/video/theora/VideoStream.cpp
-	src/modules/video/theora/VideoStream.h
+	src/modules/video/theora/OggDemuxer.cpp
+	src/modules/video/theora/OggDemuxer.h
+	src/modules/video/theora/TheoraVideoStream.cpp
+	src/modules/video/theora/TheoraVideoStream.h
 )
 )
 
 
 set(LOVE_SRC_MODULE_VIDEO
 set(LOVE_SRC_MODULE_VIDEO
@@ -1220,6 +1290,121 @@ set(LOVE_SRC_3P_GLAD
 
 
 add_library(love_3p_glad ${LOVE_SRC_3P_GLAD})
 add_library(love_3p_glad ${LOVE_SRC_3P_GLAD})
 
 
+#
+# glslang
+#
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_GENERICCODEGEN
+	src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp
+	src/libraries/glslang/glslang/GenericCodeGen/Link.cpp
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_INCLUDE
+	src/libraries/glslang/glslang/Include/arrays.h
+	src/libraries/glslang/glslang/Include/BaseTypes.h
+	src/libraries/glslang/glslang/Include/Common.h
+	src/libraries/glslang/glslang/Include/ConstantUnion.h
+	src/libraries/glslang/glslang/Include/InfoSink.h
+	src/libraries/glslang/glslang/Include/InitializeGlobals.h
+	src/libraries/glslang/glslang/Include/intermediate.h
+	src/libraries/glslang/glslang/Include/PoolAlloc.h
+	src/libraries/glslang/glslang/Include/ResourceLimits.h
+	src/libraries/glslang/glslang/Include/revision.h
+	src/libraries/glslang/glslang/Include/ShHandle.h
+	src/libraries/glslang/glslang/Include/Types.h
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT_PREPROCESSOR
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp
+	src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT_PREPROCESSOR}
+	src/libraries/glslang/glslang/MachineIndependent/Constant.cpp
+	src/libraries/glslang/glslang/MachineIndependent/gl_types.h
+	src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp
+	src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h
+	src/libraries/glslang/glslang/MachineIndependent/InfoSink.cpp
+	src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp
+	src/libraries/glslang/glslang/MachineIndependent/Initialize.h
+	src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp
+	src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp
+	src/libraries/glslang/glslang/MachineIndependent/IntermTraverse.cpp
+	src/libraries/glslang/glslang/MachineIndependent/iomapper.cpp
+	src/libraries/glslang/glslang/MachineIndependent/iomapper.h
+	src/libraries/glslang/glslang/MachineIndependent/limits.cpp
+	src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp
+	src/libraries/glslang/glslang/MachineIndependent/LiveTraverser.h
+	src/libraries/glslang/glslang/MachineIndependent/localintermediate.h
+	src/libraries/glslang/glslang/MachineIndependent/parseConst.cpp
+	src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp
+	src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp
+	src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h
+	src/libraries/glslang/glslang/MachineIndependent/parseVersions.h
+	src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp
+	src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp
+	src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.h
+	src/libraries/glslang/glslang/MachineIndependent/reflection.cpp
+	src/libraries/glslang/glslang/MachineIndependent/reflection.h
+	src/libraries/glslang/glslang/MachineIndependent/RemoveTree.cpp
+	src/libraries/glslang/glslang/MachineIndependent/RemoveTree.h
+	src/libraries/glslang/glslang/MachineIndependent/Scan.cpp
+	src/libraries/glslang/glslang/MachineIndependent/Scan.h
+	src/libraries/glslang/glslang/MachineIndependent/ScanContext.h
+	src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp
+	src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp
+	src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h
+	src/libraries/glslang/glslang/MachineIndependent/Versions.cpp
+	src/libraries/glslang/glslang/MachineIndependent/Versions.h
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT
+	src/libraries/glslang/glslang/OSDependent/osinclude.h
+)
+
+if(MSVC)
+	set(LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT
+		${LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT}
+		src/libraries/glslang/glslang/OSDependent/Windows/main.cpp
+		src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp
+	)
+else()
+	set(LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT
+		${LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT}
+		src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp
+	)
+endif()
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG_PUBLIC
+	src/libraries/glslang/glslang/Public/ShaderLang.h
+)
+
+set(LOVE_SRC_3P_GLSLANG_GLSLANG
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_GENERICCODEGEN}
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_INCLUDE}
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT}
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT}
+	${LOVE_SRC_3P_GLSLANG_GLSLANG_PUBLIC}
+)
+
+set(LOVE_SRC_3P_GLSLANG_OGLCOMPILERSDLL
+	src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp
+	src/libraries/glslang/OGLCompilersDLL/InitializeDll.h
+)
+
+set(LOVE_SRC_3P_GLSLANG
+	${LOVE_SRC_3P_GLSLANG_GLSLANG}
+	${LOVE_SRC_3P_GLSLANG_OGLCOMPILERSDLL}
+)
+
+add_library(love_3p_glslang ${LOVE_SRC_3P_GLSLANG})
+
 #
 #
 # LodePNG
 # LodePNG
 #
 #
@@ -1245,23 +1430,27 @@ set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET
 	src/libraries/luasocket/libluasocket/auxiliar.h
 	src/libraries/luasocket/libluasocket/auxiliar.h
 	src/libraries/luasocket/libluasocket/buffer.c
 	src/libraries/luasocket/libluasocket/buffer.c
 	src/libraries/luasocket/libluasocket/buffer.h
 	src/libraries/luasocket/libluasocket/buffer.h
+	src/libraries/luasocket/libluasocket/compat.c
+	src/libraries/luasocket/libluasocket/compat.h
 	src/libraries/luasocket/libluasocket/except.c
 	src/libraries/luasocket/libluasocket/except.c
 	src/libraries/luasocket/libluasocket/except.h
 	src/libraries/luasocket/libluasocket/except.h
 	src/libraries/luasocket/libluasocket/ftp.lua.h
 	src/libraries/luasocket/libluasocket/ftp.lua.h
+	src/libraries/luasocket/libluasocket/headers.lua.h
 	src/libraries/luasocket/libluasocket/http.lua.h
 	src/libraries/luasocket/libluasocket/http.lua.h
 	src/libraries/luasocket/libluasocket/inet.c
 	src/libraries/luasocket/libluasocket/inet.c
 	src/libraries/luasocket/libluasocket/inet.h
 	src/libraries/luasocket/libluasocket/inet.h
 	src/libraries/luasocket/libluasocket/io.c
 	src/libraries/luasocket/libluasocket/io.c
 	src/libraries/luasocket/libluasocket/io.h
 	src/libraries/luasocket/libluasocket/io.h
 	src/libraries/luasocket/libluasocket/ltn12.lua.h
 	src/libraries/luasocket/libluasocket/ltn12.lua.h
-	src/libraries/luasocket/libluasocket/lua.h
 	src/libraries/luasocket/libluasocket/luasocket.c
 	src/libraries/luasocket/libluasocket/luasocket.c
 	src/libraries/luasocket/libluasocket/luasocket.h
 	src/libraries/luasocket/libluasocket/luasocket.h
+	src/libraries/luasocket/libluasocket/mbox.lua.h
 	src/libraries/luasocket/libluasocket/mime.c
 	src/libraries/luasocket/libluasocket/mime.c
 	src/libraries/luasocket/libluasocket/mime.h
 	src/libraries/luasocket/libluasocket/mime.h
 	src/libraries/luasocket/libluasocket/mime.lua.h
 	src/libraries/luasocket/libluasocket/mime.lua.h
 	src/libraries/luasocket/libluasocket/options.c
 	src/libraries/luasocket/libluasocket/options.c
 	src/libraries/luasocket/libluasocket/options.h
 	src/libraries/luasocket/libluasocket/options.h
+	src/libraries/luasocket/libluasocket/pierror.h
 	src/libraries/luasocket/libluasocket/select.c
 	src/libraries/luasocket/libluasocket/select.c
 	src/libraries/luasocket/libluasocket/select.h
 	src/libraries/luasocket/libluasocket/select.h
 	src/libraries/luasocket/libluasocket/smtp.lua.h
 	src/libraries/luasocket/libluasocket/smtp.lua.h
@@ -1277,15 +1466,29 @@ set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET
 	src/libraries/luasocket/libluasocket/url.lua.h
 	src/libraries/luasocket/libluasocket/url.lua.h
 )
 )
 
 
+set(LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET)
+
 if(MSVC)
 if(MSVC)
 	set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET
 	set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET
 		${LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET}
 		${LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET}
 		src/libraries/luasocket/libluasocket/wsocket.c
 		src/libraries/luasocket/libluasocket/wsocket.c
 		src/libraries/luasocket/libluasocket/wsocket.h
 		src/libraries/luasocket/libluasocket/wsocket.h
 	)
 	)
+
+	set(LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET
+		${LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET}
+		ws2_32.lib
+	)
 else()
 else()
 	set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET
 	set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET
 		${LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET}
 		${LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET}
+		src/libraries/luasocket/libluasocket/serial.c
+		src/libraries/luasocket/libluasocket/unix.c
+		src/libraries/luasocket/libluasocket/unix.h
+		src/libraries/luasocket/libluasocket/unixtcp.c
+		src/libraries/luasocket/libluasocket/unixtcp.h
+		src/libraries/luasocket/libluasocket/unixudp.c
+		src/libraries/luasocket/libluasocket/unixudp.h
 		src/libraries/luasocket/libluasocket/usocket.c
 		src/libraries/luasocket/libluasocket/usocket.c
 		src/libraries/luasocket/libluasocket/usocket.h
 		src/libraries/luasocket/libluasocket/usocket.h
 	)
 	)
@@ -1297,20 +1500,22 @@ set(LOVE_SRC_3P_LUASOCKET
 )
 )
 
 
 add_library(love_3p_luasocket ${LOVE_SRC_3P_LUASOCKET})
 add_library(love_3p_luasocket ${LOVE_SRC_3P_LUASOCKET})
-target_link_libraries(love_3p_luasocket ${LOVE_LUA_LIBRARY})
+target_link_libraries(love_3p_luasocket ${LOVE_LUA_LIBRARY} ${LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET})
 
 
 #
 #
-# Lua 5.3's UTF-8 library
+# APIs from Lua 5.3
 #
 #
 
 
-set(LOVE_SRC_3P_LUAUTF8
-	src/libraries/luautf8/lprefix.h
-	src/libraries/luautf8/lutf8lib.c
-	src/libraries/luautf8/lutf8lib.h
+set(LOVE_SRC_3P_LUA53
+	src/libraries/lua53/lprefix.h
+	src/libraries/lua53/lstrlib.c
+	src/libraries/lua53/lstrlib.h
+	src/libraries/lua53/lutf8lib.c
+	src/libraries/lua53/lutf8lib.h
 )
 )
 
 
-add_library(love_3p_luautf8 ${LOVE_SRC_3P_LUAUTF8})
-target_link_libraries(love_3p_luautf8 ${LOVE_LUA_LIBRARY})
+add_library(love_3p_lua53 ${LOVE_SRC_3P_LUA53})
+target_link_libraries(love_3p_lua53 ${LOVE_LUA_LIBRARY})
 
 
 #
 #
 # lz4
 # lz4
@@ -1348,6 +1553,16 @@ set(LOVE_SRC_3P_STB
 
 
 # stb_image has no implementation files of its own.
 # stb_image has no implementation files of its own.
 
 
+#
+# tiny exr
+#
+
+set(LOVE_SRC_3P_TINEXR
+	src/libraries/tinyexr/tinyexr.h
+)
+
+# tinyexr has no implementation files of its own.
+
 #
 #
 # utf8
 # utf8
 #
 #
@@ -1385,17 +1600,30 @@ set(LOVE_SRC_3P_WUFF
 
 
 add_library(love_3p_wuff ${LOVE_SRC_3P_WUFF})
 add_library(love_3p_wuff ${LOVE_SRC_3P_WUFF})
 
 
+#
+# xxHash
+#
+
+set(LOVE_SRC_3P_XXHASH
+	src/libraries/xxHash/xxhash.c
+	src/libraries/xxHash/xxhash.h
+)
+
+add_library(love_3p_xxhash ${LOVE_SRC_3P_XXHASH})
+
 set(LOVE_3P
 set(LOVE_3P
 	love_3p_box2d
 	love_3p_box2d
 	love_3p_ddsparse
 	love_3p_ddsparse
 	love_3p_enet
 	love_3p_enet
 	love_3p_glad
 	love_3p_glad
+	love_3p_glslang
 	love_3p_lodepng
 	love_3p_lodepng
 	love_3p_luasocket
 	love_3p_luasocket
-	love_3p_luautf8
+	love_3p_lua53
 	love_3p_lz4
 	love_3p_lz4
 	love_3p_noise1234
 	love_3p_noise1234
 	love_3p_wuff
 	love_3p_wuff
+	love_3p_xxhash
 )
 )
 
 
 love_disable_warnings(love_3p_box2d love_3p_enet love_3p_luasocket)
 love_disable_warnings(love_3p_box2d love_3p_enet love_3p_luasocket)
@@ -1407,6 +1635,7 @@ set(LOVE_LIB_SRC
 	${LOVE_SRC_COMMON}
 	${LOVE_SRC_COMMON}
 	# Modules
 	# Modules
 	${LOVE_SRC_MODULE_AUDIO}
 	${LOVE_SRC_MODULE_AUDIO}
+	${LOVE_SRC_MODULE_DATA}
 	${LOVE_SRC_MODULE_EVENT}
 	${LOVE_SRC_MODULE_EVENT}
 	${LOVE_SRC_MODULE_FILESYSTEM}
 	${LOVE_SRC_MODULE_FILESYSTEM}
 	${LOVE_SRC_MODULE_FONT}
 	${LOVE_SRC_MODULE_FONT}

+ 139 - 6
changes.txt

@@ -1,20 +1,153 @@
-LOVE 0.10.3 [Super Toast]
--------------------------
+LOVE 0.11.0 []
+--------------
 
 
 Released: N/A
 Released: N/A
 
 
+  * Added Object:release.
+  * Added Data:clone.
+  * Added queueable audio sources.
+  * Added audio input support.
+  * Added Source filters: low gain, high gain and band pass.
+  * Added audio effect APIs (reverb, echo, etc.)
+  * Added variants of SoundData:getSample/setSample which take a channel parameter.
+  * Added variants of all table-with-fields-returning get* functions, the new variants take an existing table to fill in.
+  * Added a variant to World:update, which accepts the number of iterations to run. The defaults are now 8 and 3.
   * Added RopeJoint:setMaxLength.
   * Added RopeJoint:setMaxLength.
-
+  * Added a click count argument to love.mousepressed and love.mousereleased.
+  * Added love.filesystem.get/setCRequirePath, and use that to find c libraries for require.
+  * Added Channel:hasRead, which checks if a message has been read. Takes an id, which Channel:push will now return.
+  * Added variants of Channel:demand and Channel:supply which take a timeout argument.
+  * Added love.data module. It includes hex/base64 encoding functions, MD5 and SHA hashing, string packing, and more.
+  * Added Transform objects to love.math.
+  * Added support for different ImageData formats, including RGBA8 (the default), RGBA16, RGBA16F, and RGBA32F.
+  * Added the ability to load Radiance HDR, OpenEXR, and 16 bit PNG images.
+  * Added love.graphics.getImageFormats (replaces love.graphics.getCompressedImageFormats).
+  * Added the ability to specify a per-object pixel density scale factor when creating Images, Canvases, Fonts, and Videos. Affects drawing.
+  * Added Texture:getPixelWidth/Height and love.graphics.getPixelWidth/Height.
+  * Added Texture:getPixelDensity, love.graphics.getPixelDensity, and Font:getPixelDensity.
+  * Added Array, Cubemap, and Volume texture types and corresponding Image and Canvas APIs.
+  * Added love.graphics.getTextureTypes, returns a table with fields indicating support for each texture type.
+  * Added mipmapping support to Canvases, including both auto-generated mipmaps and manually rendering to a specific mipmap level.
+  * Added 'stencil8', 'depth24stencil8', 'depth32fstencil8', 'depth16', 'depth24', and 'depth32f' pixel formats for Canvases.
+  * Added optional 'readable' boolean field to the table passed into love.graphics.newCanvas.
+  * Added optional 'depthstencil' field to the table passed into love.graphics.setCanvas, for using a depth/stencil Canvas.
+  * Added optional 'depth' and 'stencil' boolean fields to the table passed into setCanvas, for enabling depth and stencil buffers if 'depthstencil' isn't used.
+  * Added shadow sampler support for Canvases.
+  * Added love.graphics.setDepthMode for using the depth buffer for depth testing/writes. Depth values of rendered objects can only be set via shaders.
+  * Added love.graphics.setMeshCullMode, for culling back- or front-facing triangles when drawing a Mesh.
+  * Added love.graphics.setFrontFaceWinding.
+  * Added variant of love.graphics.getCanvasFormats which takes a 'readable' boolean.
+  * Added love.graphics.drawLayer and SpriteBatch:add/setLayer for easily drawing layers of Array Textures.
+  * Added variants of love.graphics.print and printf which take a Font argument.
+  * Added variants of love.graphics.clear to control how the active depth and stencil buffers are cleared.
+  * Added love.graphics.getStackDepth.
+  * Added love.graphics.flushBatch for manually flushing automatically batched draws.
+  * Added SpriteBatch:setDrawRange.
+  * Added per-shader opt in support for the GLSL 3.30 and GLSL ES 3.00 shading languages.
+  * Added 'void effect()' pixel shader entry point.
+  * Added love.graphics.validateShader.
+  * Added Shader:hasUniform.
+  * Added support for non-square shader uniform matrices on desktop platforms and on mobile GLSL 3.
+  * Added Shader:send(matrixname, is_column_major, matrix, ...) which specifies how to interpret the matrix table arguments.
+  * Added Shader:send variants which accept a Data object.
+  * Added 'borderellipse' and 'borderrectangle' ParticleSystem distributions.
+  * Added ParticleSystem:set/getAreaSpreadAngle and set/getAreaSpreadIsRelativeDirection.
+  * Added love.graphics.captureScreenshot (replaces love.graphics.newScreenshot).
+  * Added 'glsl3', 'instancing', 'fullnpot','pixelshaderhighp', and 'shaderderivatives' graphics features.
+  * Added 'anisotropy' graphics limit.
+  * Added Mesh instancing support via love.graphics.drawInstanced and Mesh:attachAttribute.
+  * Added a Mesh:attachAttribute variant that takes a different target attribute name.
+  * Added Mesh:detachAttribute.
+  * Added a variant of Mesh:setVertexMap which accepts a Data object.
+  * Added love.window.updateMode.
+  * Added love.window.isMinimized.
+  * Added love.window.restore.
+  * Added the ability to prevent love from creating a stencil buffer for the window.
+  * Added cycle detection to Variant's table serialization, cycles now cause an error, rather than a stack overflow.
+  * Added love.graphics.newShader File and FileData variants.
+  * Added a default love.threaderror callback, which raises the error in the main thread.
+  * Added checks for invalid constants passed to love.keyboard.isDown/isScancodeDown.
+  * Added deprecation warnings, on by default for non-fused games.
+  * Added love.filesystem.getInfo.
+  * Added 'drawcallsbatched' to love.graphics.getStats.
+
+  * Changed all color values to be in the range 0-1, rather than 0-255.
+  * Changed high-dpi functionality to require much less code (often none at all) for graphics to appear at the correct sizes and positions.
+  * Changed love.graphics.print and friends to ignore carriage returns.
+  * Changed the 'multiply' blend mode to error if not used with the 'premultiplied' blend alpha mode, since the formula only works with that anyway.
+  * Changed some love.graphics, love.window, and love.event APIs to cause an error if a Canvas is active.
+  * Changed stenciling functionality with a Canvas active to require stencil=true (or a custom stencil-formatted Canvas) to be set in setCanvas.
+  * Changed Mesh:setDrawRange to take 'start' and 'count' parameters instead of 'min' and 'max'.
+  * Changed the 'vsync' field of love.window.setMode and t.window in love.conf. It's now an integer with 0 disabling vsync.
+  * Changed the audio playback APIs drastically.
+  * Changed enet to no longer set the 'enet' global, again matching luasocket.
+  * Changed Source seeking behaviour, all kinds of Sources now behave similarly when seeking past the boundaries.
+  * Changed love.timer.step, it now returns dt.
+  * Changed love.run and love.errhand to return a function for their main loop, which gets called until love quits.
+
+  * Fixed error in default error handler when the error message contains non UTF-8 bytes.
+  * Fixed a memory leak when sending love objects to threads which never load that object's module.
+  * Fixed os.execute always returning -1 in Linux.
+  * Fixed the default reference angle for WeldJoint, PrismaticJoint, and RevoluteJoint.
+  * Fixed Fixture:getShape to reuse the existing internal Fixture-owned shape.
+  * Fixed MouseJoint:setFrequency to error instead of crashing if a frequency of 0 is set.
+  * Fixed love.system.set/getClipboardText to error instead of crashing, when a window hasn't been created.
+  * Fixed Joystick:getGamepadMapping to work with xinput controllers.
+  * Fixed love.joystick.setGamepadMapping's replacement code.
+  * Fixed baseline calculation when rendering text.
+  * Fixed VaryingTexCoords and love_ScreenSize in shaders to be 'highp' in OpenGL ES, when supported.
+  * Fixed ParticleSystem:setParticleLifetime to error if a negative value is given.
   * Fixed Shader:send and Shader:sendColor ignoring the last argument for an array.
   * Fixed Shader:send and Shader:sendColor ignoring the last argument for an array.
   * Fixed a crash when love.graphics.pop is called after a love.window.setMode while the transformation stack was not empty.
   * Fixed a crash when love.graphics.pop is called after a love.window.setMode while the transformation stack was not empty.
+  * Fixed love.window.isMaximized.
+  * Fixed video playback to work with a wider range of Ogg Theora files.
+  * Fixed video seeking to be faster.
   * Fixed BezierCurves to error instead of hanging in some situations.
   * Fixed BezierCurves to error instead of hanging in some situations.
   * Fixed compilation of luasocket with newer luajit 2.1.0 beta versions.
   * Fixed compilation of luasocket with newer luajit 2.1.0 beta versions.
 
 
-  * Improved command line argument handling.
-  * Improved seeking support, especially for short video files.
-
+  * Improved performance when drawing textures, shapes, lines, and points by automatically batching their draw calls together when possible.
+  * Improved performance of Shader:send when the Shader is not active.
+  * Improved performance of love.math.randomNormal when LuaJIT's JIT compiler is enabled.
+  * Improved performance of love.filesystem.lines and File:lines, especially when reading from a file inside a zip/.love.
+
+  * Renamed love.window.getPixelScale to love.window.getDPIScale.
+  * Renamed love.mouse.hasCursor to love.mouse.isCursorSupported.
+  * Renamed love.errhand to love.errorhandler.
+  * Renamed Source/SoundData/Decoder:getChannels to getChannelCount.
+  * Renamed PrismaticJoint/RevoluteJoint:hasLimitsEnabled to areLimitsEnabled.
+  * Renamed love.audio.getSourceCount to love.audio.getActiveSourceCount.
+  * Renamed love.math.compress/decompress to love.data.compress/decompress, and updated the argument order.
+  * Renamed all get[Object]List functions to get[Object]s.
+
+  * Removed the default source type for love.audio.newSource.
+  * Removed variant of love.filesystem.newFileData which takes base64 data, use love.math.decode instead.
+  * Removed the no-argument variant of Text:set, use Text:clear instead.
+  * Removed love.graphics.getCompressedImageFormats, use love.graphics.getImageFormats instead.
+  * Removed the 'void effects(...)' pixel shader entry point. Use the new 'void effect()' instead.
+  * Removed Shader:getExternVariable, use Shader:hasUniform instead.
+  * Removed love.graphics.newScreenshot, use love.graphics.captureScreenshot instead.
+  * Removed deprecated enet function host:socket_get_address.
+  * Removed functions deprecated in LÖVE 0.10.2:
+    * Removed Shader:sendInt, Shader:sendBoolean, Shader:sentFloat, Shader:sendMatrix, and Shader:sendTexture (use Shader:send instead).
+    * Removed love.window.isCreated (use love.window.isOpen instead).
+
+  * Updated and improved command line argument handling.
+  * Updated invalid enum value error messages to show a list of the valid enum values.
+  * Updated Source:seek to work if the Source isn't playing.
+  * Updated love.event.poll to stop allocating memory unnecessarily.
+  * Updated love.math.random to have improved numeric distribution.
+  * Updated love.graphics to support Core Profile OpenGL 3.3+ when available.
+  * Updated shaders to always expose derivative functions (dFdx, dFdy, fwidth) when available in OpenGL ES.
+  * Updated shaders to allow using VERTEX and PIXEL in shader code.
+  * Updated love.graphics.circle/ellipse/arc/rectangle to take transformation scale into account when determining the number of segments to use.
+  * Updated Font glyph generation to improve antialiasing.
+  * Updated Canvas:newImageData to return an ImageData with a format that matches the Canvas' as closely as possible.
+  * Updated love.graphics.newImage to treat file names ending with "@2x", "@3x", etc. as a pixel density scale factor if none is explicitly supplied.
+  * Updated the error message when bad values are given to love.graphics.line.
+  * Updated the maximum love.graphics transformation/state stack depth from 64 to 128.
   * Updated the default error handler to allow copying the error to the clipboard when the user decides to do so.
   * Updated the default error handler to allow copying the error to the clipboard when the user decides to do so.
   * Updated love.filesystem.setRequirePath to support multiple template '?' characters in each path.
   * Updated love.filesystem.setRequirePath to support multiple template '?' characters in each path.
+  * Updated luasocket to version 3.0rc1.
 
 
 LOVE 0.10.2 [Super Toast]
 LOVE 0.10.2 [Super Toast]
 -------------------------
 -------------------------

+ 12 - 3
extra/appveyor/appveyor.yml

@@ -1,12 +1,21 @@
-version: 0.10.2.{build}
+version: 0.11.0.{build}
 
 
 image: Visual Studio 2013
 image: Visual Studio 2013
 
 
 shallow_clone: true
 shallow_clone: true
 
 
+environment:
+  matrix:
+    - PLATFORM: x86
+      VCVARSALL_PLATFORM: x86
+      GENERATOR: "Visual Studio 12"
+    - PLATFORM: x64
+      VCVARSALL_PLATFORM: x86_amd64
+      GENERATOR: "Visual Studio 12 Win64"
+
 init:
 init:
 # Make VS 2013 command line tools available
 # Make VS 2013 command line tools available
-- call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %platform%
+- call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %VCVARSALL_PLATFORM%
 
 
 install:
 install:
 # We need to install NSIS to create the packaged installer executable.
 # We need to install NSIS to create the packaged installer executable.
@@ -26,7 +35,7 @@ install:
 - move love libs\love
 - move love libs\love
 
 
 before_build:
 before_build:
-- cmake -G "Visual Studio 12" -H. -Bbuild
+- cmake -G "%GENERATOR%" -H. -Bbuild
 
 
 build_script:
 build_script:
 - cmake --build build --target PACKAGE --config Release
 - cmake --build build --target PACKAGE --config Release

BIN
extra/windows/love.rc


+ 246 - 7
license.txt

@@ -1,6 +1,6 @@
 This software uses LOVE:
 This software uses LOVE:
 
 
-LOVE is Copyright (c) 2006-2016 LOVE Development Team
+LOVE is Copyright (c) 2006-2017 LOVE Development Team
 
 
 This software is provided 'as-is', without any express or implied
 This software is provided 'as-is', without any express or implied
 warranty. In no event will the authors be held liable for any damages
 warranty. In no event will the authors be held liable for any damages
@@ -23,9 +23,9 @@ distribution.
 
 
 ---------
 ---------
 
 
-This software uses LuaJIT:
+This software uses ENet:
 
 
-LuaJIT is Copyright (c) 2005-2015 Mike Pall
+Copyright (c) 2002-2016 Lee Salzman
 
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 of this software and associated documentation files (the "Software"), to deal
@@ -47,9 +47,97 @@ THE SOFTWARE.
 
 
 ---------
 ---------
 
 
-This software uses ENet:
+This software uses GLAD:
+
+ The MIT License (MIT)
+ 
+ Copyright (c) 2013 David Herberth, modified by Alex Szpakowski
+ 
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
+ this software and associated documentation files (the "Software"), to deal in
+ the Software without restriction, including without limitation the rights to
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ the Software, and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------
+
+This software uses glslang:
+
+Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+Copyright (C) 2013-2016 LunarG, Inc.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+   Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following
+   disclaimer in the documentation and/or other materials provided
+   with the distribution.
+
+   Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+---------
+
+This software uses portions of Kepler Project's lua-compat-5.3:
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Kepler Project.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
 
 
-Copyright (c) 2002-2014 Lee Salzman
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------
+
+This software uses lua-enet:
+
+Copyright (C) 2011 by Leaf Corcoran
 
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 of this software and associated documentation files (the "Software"), to deal
@@ -71,9 +159,9 @@ THE SOFTWARE.
 
 
 ---------
 ---------
 
 
-This software uses lua-enet:
+This software uses LuaJIT:
 
 
-Copyright (C) 2011 by Leaf Corcoran
+LuaJIT is Copyright (c) 2005-2016 Mike Pall
 
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 of this software and associated documentation files (the "Software"), to deal
@@ -95,6 +183,121 @@ THE SOFTWARE.
 
 
 ---------
 ---------
 
 
+This software uses Lua's UTF-8 module:
+
+Copyright (C) 1994-2015 Lua.org, PUC-Rio, 2015 LOVE Development Team.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------
+
+This software uses luasocket:
+
+LuaSocket 3.0 license
+Copyright (C) 2004-2013 Diego Nehab
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+---------
+
+This software uses LZ4:
+
+LZ4 - Fast LZ compression algorithm
+Copyright (C) 2011-2015, Yann Collet.
+
+BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You can contact the author at :
+- LZ4 source repository : https://github.com/Cyan4973/lz4
+- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+
+---------
+
+This software uses TinyEXR:
+
+Copyright (c) 2014 - 2016, Syoyo Fujita
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the <organization> nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+---------
+
 This software uses UTF8-CPP:
 This software uses UTF8-CPP:
 
 
 Copyright 2006 Nemanja Trifunovic
 Copyright 2006 Nemanja Trifunovic
@@ -123,12 +326,48 @@ DEALINGS IN THE SOFTWARE.
 
 
 ---------
 ---------
 
 
+This software uses xxHash:
+
+xxHash - Extremely Fast Hash algorithm
+Copyright (C) 2012-2016, Yann Collet.
+
+BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You can contact the author at :
+- xxHash source repository : https://github.com/Cyan4973/xxHash
+
+---------
+
 This software uses the following LGPL libraries on Windows, Mac OS X, Linux,
 This software uses the following LGPL libraries on Windows, Mac OS X, Linux,
 and Android:
 and Android:
 
 
  - libmpg123
  - libmpg123
      Website: http://www.mpg123.de/
      Website: http://www.mpg123.de/
      Source download: http://sourceforge.net/projects/mpg123/files/latest/download
      Source download: http://sourceforge.net/projects/mpg123/files/latest/download
+
  - OpenAL Soft
  - OpenAL Soft
      Website: http://kcat.strangesoft.net/openal.html
      Website: http://kcat.strangesoft.net/openal.html
      Source download: http://kcat.strangesoft.net/openal.html#download
      Source download: http://kcat.strangesoft.net/openal.html#download

+ 22 - 20
platform/unix/automagic

@@ -26,42 +26,44 @@ AUTOMAKE=${AUTOMAKE:-$(which automake)}
 [[ -x ${ACLOCAL} ]]    || die "Could not find aclocal. Install automake."
 [[ -x ${ACLOCAL} ]]    || die "Could not find aclocal. Install automake."
 [[ -x ${AUTOMAKE} ]]   || die "Could not find automake."
 [[ -x ${AUTOMAKE} ]]   || die "Could not find automake."
 
 
+print_errors() {
+	local output
+	output="$("$@" 2>&1)" && return 0
+	printf "%s\n" "$output"
+	return 1
+}
+
 automagic() {
 automagic() {
-	log "Copying files..." >&2
+	log "Copying files..."
 	cp platform/unix/configure.ac .
 	cp platform/unix/configure.ac .
 	cp platform/unix/Makefile.am .
 	cp platform/unix/Makefile.am .
 
 
-	log "Running genmodules..." >&2
-	if ! bash platform/unix/genmodules "$1"; then
+	log "Running genmodules..."
+	if ! print_errors bash platform/unix/genmodules "$1"; then
 		echo "You should be doing this from the root directory of the project."
 		echo "You should be doing this from the root directory of the project."
 		exit 1
 		exit 1
 	fi
 	fi
 
 
-	log "Running autoheader..." >&2
-	${AUTOHEADER} 2>&1 || return 1 # Gimmie config.h.in
+	log "Running autoheader..."
+	print_errors ${AUTOHEADER} || return 1 # Gimmie config.h.in
 
 
-	log "Running libtoolize..." >&2
-	${LIBTOOLIZE} --force 2>&1 || return 1
+	log "Running libtoolize..."
+	print_errors ${LIBTOOLIZE} --force || return 1
 
 
-	log "Running aclocal..." >&2
-	${ACLOCAL} 2>&1 || return 1
+	log "Running aclocal..."
+	print_errors ${ACLOCAL} || return 1
 
 
-	log "Running autoconf..." >&2
-	${AUTOCONF} 2>&1 || return 1
+	log "Running autoconf..."
+	print_errors ${AUTOCONF} || return 1
 
 
-	log "Running automake..." >&2
-	${AUTOMAKE} -a 2>&1 || return 1
+	log "Running automake..."
+	print_errors ${AUTOMAKE} -a || return 1
 }
 }
 
 
-if [[ $1 == "-d" ]]; then
-	shift 1
-	automagic "$@" 2>&1
-else
-	(automagic "$@" > /dev/null) 2>&1
-fi
+automagic "$@"
+
 if [[ $? -eq 1 ]]; then
 if [[ $? -eq 1 ]]; then
 	log "Failed, sadface."
 	log "Failed, sadface."
-	log "You can make this script more verbose running it in debug mode (-d)"
 	log "This is generally a configuration error (I'm looking at you aclocal)"
 	log "This is generally a configuration error (I'm looking at you aclocal)"
 	exit 1
 	exit 1
 else
 else

+ 56 - 59
platform/unix/configure.ac

@@ -1,4 +1,4 @@
-AC_INIT([love], [HEAD])
+AC_INIT([love], [0.11.0])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_AUX_DIR([platform/unix])
 AC_CONFIG_AUX_DIR([platform/unix])
 AC_CONFIG_MACRO_DIR([platform/unix/m4])
 AC_CONFIG_MACRO_DIR([platform/unix/m4])
@@ -19,6 +19,7 @@ AC_LANG([C++])
 
 
 dnl Workaround for old aclocal versions
 dnl Workaround for old aclocal versions
 m4_include([platform/unix/cpp11.m4])
 m4_include([platform/unix/cpp11.m4])
+m4_include([platform/unix/deps.m4])
 
 
 includes=
 includes=
 
 
@@ -44,70 +45,68 @@ AS_VAR_IF([enable_stbi_sse2_override], [no], [], #else
 
 
 # --with-lua and --with-luaversion
 # --with-lua and --with-luaversion
 AC_ARG_WITH([lua], [AS_HELP_STRING([--with-lua], [Select the lua implementation])],
 AC_ARG_WITH([lua], [AS_HELP_STRING([--with-lua], [Select the lua implementation])],
-			[], [with_lua=luajit])
+	[], [with_lua=luajit])
 AC_ARG_WITH([luaversion], [AS_HELP_STRING([--with-luaversion], [Select the lua version])],
 AC_ARG_WITH([luaversion], [AS_HELP_STRING([--with-luaversion], [Select the lua version])],
-			[], [with_luaversion=5.1])
+	[], [with_luaversion=5.1])
 
 
-# pkg-config libraries
-AM_PATH_SDL2([], [], [LOVE_MSG_ERROR([SDL 2])])
 with_clean_luaversion=`printf ${with_luaversion} | sed 's/\.//g'`
 with_clean_luaversion=`printf ${with_luaversion} | sed 's/\.//g'`
-PKG_CHECK_MODULES([lua], [${with_lua}${with_luaversion}], [lua_found=yes],
-	[PKG_CHECK_MODULES([lua], [${with_lua}${with_clean_luaversion}], [lua_found=yes],
-	[PKG_CHECK_MODULES([lua], [${with_lua}], [lua_found=yes], [lua_found=no])])])
-PKG_CHECK_MODULES([freetype2], [freetype2], [], [LOVE_MSG_ERROR([FreeType2])])
-PKG_CHECK_MODULES([openal], [openal], [], [LOVE_MSG_ERROR([OpenAL])])
-PKG_CHECK_MODULES([libmodplug], [libmodplug], [], [LOVE_MSG_ERROR([libmodplug])])
-PKG_CHECK_MODULES([vorbisfile], [vorbisfile], [], [LOVE_MSG_ERROR([libvorbis and libvorbisfile])])
-PKG_CHECK_MODULES([zlib], [zlib], [], [LOVE_MSG_ERROR([zlib])])
-PKG_CHECK_MODULES([theora], [theoradec], [], [LOVE_MSG_ERROR([libtheora])])
-
-# Other libraries
-AC_SEARCH_LIBS([sqrt], [m], [], [LOVE_MSG_ERROR([the C math library])])
-AC_SEARCH_LIBS([PHYSFS_init], [physfs], [], [LOVE_MSG_ERROR([PhysicsFS])])
-
-# Lua, treated seperately because of --with-lua
-AS_VAR_IF([lua_found], [yes],
-		  #if
-		  [
-		   luaheaders_found=yes
-		   AC_MSG_CHECKING([for library containing lua_call])
-		   AC_MSG_RESULT([${lua_LIBS}])],
-		  #else
-		  [
-		   AC_MSG_WARN([Could not find pkg-config definition for ${with_lua}${with_luaversion} or ${with_lua}${with_clean_luaversion}${with_lua}, falling back to manual detection])
-		   AC_SEARCH_LIBS([lua_call], ["${with_lua}${with_luaversion}" "${with_lua}"], [],
-						  [LOVE_MSG_ERROR([$with_lua])])
-		   luaheaders_found=no
-		   AC_CHECK_HEADER(["${with_lua}${with_luaversion}/lua.h"], [luaheaders_found=yes includes="$includes -I/usr/include/${with_lua}${with_luaversion}"], [])
-		   AC_CHECK_HEADER(["${with_lua}/lua.h"], [luaheaders_found=yes includes="$includes -I/usr/include/${with_lua}"], [])])
-AS_VAR_IF([luaheaders_found], [yes], [], #else
-		  [
-		   AC_MSG_WARN([Could not locate lua headers for ${with_lua}${with_luaversion} or ${with_lua}, you probably need to specify them with CPPFLAGS])])
-
-# mpg123, treated seperately because it can be disabled (default on)
-# also not pkg-config because of the FILE_OFFSET_BITS.. bit
+
+# Generated sources for enabling/disabling modules
+m4_include([configure-modules-pre.ac])
+
+# Other features that can be enabled/disabled
 AC_ARG_ENABLE([mpg123], AC_HELP_STRING([--disable-mpg123], [Disable mp3 support, for patent-free builds]), [], [enable_mpg123=yes])
 AC_ARG_ENABLE([mpg123], AC_HELP_STRING([--disable-mpg123], [Disable mp3 support, for patent-free builds]), [], [enable_mpg123=yes])
+AC_ARG_ENABLE([gme], AC_HELP_STRING([--enable-gme], [Enable GME support, for more chiptuney goodness]), [], [enable_gme=no])
+
+# Dependencies we always use
+ACLOVE_DEP_LUA
+ACLOVE_DEP_SDL2
+ACLOVE_DEP_LIBM
+ACLOVE_DEP_ZLIB
+
+# Conditional dependencies
+AS_VAR_IF([enable_module_audio], [yes], [ACLOVE_DEP_OPENAL], [])
+AS_VAR_IF([enable_module_filesystem], [yes], [ACLOVE_DEP_PHYSFS], [])
+AS_VAR_IF([enable_module_font], [yes], [ACLOVE_DEP_FREETYPE2], [])
+AS_VAR_IF([enable_module_sound], [yes], [
+	ACLOVE_DEP_LIBMODPLUG
+	ACLOVE_DEP_VORBISFILE
+], [enable_mpg123=no])
+AS_VAR_IF([enable_module_video], [yes], [ACLOVE_DEP_THEORA], [])
+AS_VAR_IF([enable_gme], [yes], [ACLOVE_DEP_GME], [])
 AS_VAR_IF([enable_mpg123], [no],
 AS_VAR_IF([enable_mpg123], [no],
 	  AC_DEFINE([LOVE_NOMPG123], [], [Build without mpg123]),
 	  AC_DEFINE([LOVE_NOMPG123], [], [Build without mpg123]),
-	  # else
-	  AC_SEARCH_LIBS([mpg123_open_feed], [mpg123], [],
-					 [LOVE_MSG_ERROR([libmpg123])])
-	  AC_SEARCH_LIBS([mpg123_seek_64], [mpg123],
-					 AC_SUBST([FILE_OFFSET],[-D_FILE_OFFSET_BITS=64]),
-					 AC_SUBST([FILE_OFFSET],[])))
-
-# GME, treated seperately because it can be enabled (default off)
-AC_ARG_ENABLE([gme], AC_HELP_STRING([--enable-gme], [Enable GME support, for more chiptuney goodness]), [], [enable_gme=no])
-AS_VAR_IF([enable_gme], [yes],
-	  AC_SEARCH_LIBS([gme_open_data], [gme], [], [LOVE_MSG_ERROR([gme])])
-	  AC_DEFINE([LOVE_SUPPORT_GME], [], [Enable gme])
-	  AC_CHECK_HEADER([gme/gme.h], [includes="$includes -I/usr/include/gme"], []))
+	  [ACLOVE_DEP_MPG123])
+
+# Add flags for optional libraries
+AC_ARG_ENABLE([library-enet], [  --disable-library-enet    Turn off library enet], [], [enable_library_enet=yes])
+AC_ARG_ENABLE([library-luasocket], [  --disable-library-luasocket    Turn off library luasocket], [], [enable_library_luasocket=yes])
+AC_ARG_ENABLE([library-lua53], [  --disable-library-lua53    Turn off library lua53 (lua 5.3 backports, required by love.data)], [], [enable_library_lua53=yes])
+
+# Select the libraries we need to build, based on the selected modules
+AS_VAR_IF([enable_module_physics], [yes], [enable_library_Box2D=yes], [enable_library_Box2D=no])
+AS_VAR_IF([enable_module_image], [yes], [enable_library_ddsparse=yes], [enable_library_ddsparse=no])
+AS_VAR_IF([enable_module_graphics], [yes], [enable_library_glad=yes], [enable_library_glad=no])
+AS_VAR_IF([enable_module_graphics], [yes], [enable_library_glslang=yes], [enable_library_glslang=no])
+AS_VAR_IF([enable_module_image], [yes], [enable_library_lodepng=yes], [enable_library_lodepng=no])
+AS_VAR_IF([enable_module_data], [yes], [enable_library_lua53=yes], [])
+AS_VAR_IF([enable_module_math], [yes], [enable_library_lz4=yes], [enable_library_lz4=no])
+AS_VAR_IF([enable_module_math], [yes], [enable_library_noise1234=yes], [enable_library_noise1234=no])
+AS_VAR_IF([enable_module_image], [yes], [enable_library_stb=yes], [enable_library_stb=no])
+AS_VAR_IF([enable_module_image], [yes], [enable_library_tinyexr=yes], [enable_library_tinyexr=no])
+AS_VAR_IF([enable_module_sound], [yes], [enable_library_Wuff=yes], [enable_library_Wuff=no])
+AS_VAR_IF([enable_module_graphics], [yes], [enable_library_xxHash=yes], [enable_library_xxHash=no])
+
+# Utf8 is required by both graphics and font, so enable if either is enabled
+enable_library_utf8=no
+AS_VAR_IF([enable_module_graphics], [yes], [enable_library_utf8=yes], [])
+AS_VAR_IF([enable_module_font], [yes], [enable_library_utf8=yes], [])
 
 
 # libenet check for socklen_t
 # libenet check for socklen_t
-AC_CHECK_TYPE([socklen_t], [AC_DEFINE([HAS_SOCKLEN_T], [1], [Define if socklen_t exists.] )], , 
-              #include <sys/types.h>
-              #include <sys/socket.h>
-)
+ACLOVE_SOCKLEN_T
+
+# Generated sources for enabling/disabling modules
+m4_include([configure-modules-post.ac])
 
 
 # Optionally build the executable (default on)
 # Optionally build the executable (default on)
 AC_ARG_ENABLE([exe],
 AC_ARG_ENABLE([exe],
@@ -128,8 +127,6 @@ AS_VAR_IF([LUA_EXECUTABLE], [:],
 # Set our includes as automake variable
 # Set our includes as automake variable
 AC_SUBST([LOVE_INCLUDES], ["$includes"])
 AC_SUBST([LOVE_INCLUDES], ["$includes"])
 
 
-m4_include([configure-modules.ac])
-
 AC_CONFIG_FILES([
 AC_CONFIG_FILES([
 	Makefile
 	Makefile
 	src/Makefile
 	src/Makefile

+ 1 - 1
platform/unix/debian/copyright

@@ -4,7 +4,7 @@ Upstream-Contact: Bart van Strien <[email protected]>
 Source: http://www.love2d.org/
 Source: http://www.love2d.org/
 
 
 Files: *
 Files: *
-Copyright: 2006-2015 LOVE Development Team
+Copyright: 2006-2017 LOVE Development Team
 License: zlib
 License: zlib
  This software is provided 'as-is', without any express or implied
  This software is provided 'as-is', without any express or implied
  warranty. In no event will the authors be held liable for any damages
  warranty. In no event will the authors be held liable for any damages

+ 77 - 0
platform/unix/deps.m4

@@ -0,0 +1,77 @@
+AC_DEFUN([ACLOVE_DEP_FREETYPE2], [
+	PKG_CHECK_MODULES([freetype2], [freetype2], [], [LOVE_MSG_ERROR([FreeType2])])])
+
+AC_DEFUN([ACLOVE_DEP_OPENAL], [
+	PKG_CHECK_MODULES([openal], [openal], [], [LOVE_MSG_ERROR([OpenAL])])])
+
+AC_DEFUN([ACLOVE_DEP_LIBMODPLUG], [
+	PKG_CHECK_MODULES([libmodplug], [libmodplug], [], [LOVE_MSG_ERROR([libmodplug])])])
+
+AC_DEFUN([ACLOVE_DEP_VORBISFILE], [
+	PKG_CHECK_MODULES([vorbisfile], [vorbisfile], [], [LOVE_MSG_ERROR([libvorbis and libvorbisfile])])])
+
+AC_DEFUN([ACLOVE_DEP_ZLIB], [
+	PKG_CHECK_MODULES([zlib], [zlib], [], [LOVE_MSG_ERROR([zlib])])])
+
+AC_DEFUN([ACLOVE_DEP_THEORA], [
+	PKG_CHECK_MODULES([theora], [theoradec], [], [LOVE_MSG_ERROR([libtheora])])])
+
+AC_DEFUN([ACLOVE_DEP_LIBM], [
+	AC_SEARCH_LIBS([sqrt], [m], [], [LOVE_MSG_ERROR([the C math library])])])
+
+AC_DEFUN([ACLOVE_DEP_PHYSFS], [
+	AC_SEARCH_LIBS([PHYSFS_init], [physfs], [], [LOVE_MSG_ERROR([PhysicsFS])])])
+
+AC_DEFUN([ACLOVE_DEP_SDL2], [
+	AM_PATH_SDL2([], [], [LOVE_MSG_ERROR([SDL 2])])])
+
+# does not use pkg-config because of the FILE_OFFSET_BITS.. bit
+AC_DEFUN([ACLOVE_DEP_MPG123], [
+	AC_SEARCH_LIBS([mpg123_open_feed], [mpg123], [],
+		[LOVE_MSG_ERROR([libmpg123])])
+	AC_SEARCH_LIBS([mpg123_seek_64], [mpg123],
+		AC_SUBST([FILE_OFFSET],[-D_FILE_OFFSET_BITS=64]),
+		AC_SUBST([FILE_OFFSET],[]))])
+
+AC_DEFUN([ACLOVE_DEP_GME], [
+	AC_SEARCH_LIBS([gme_open_data], [gme], [], [LOVE_MSG_ERROR([gme])])
+	AC_DEFINE([LOVE_SUPPORT_GME], [], [Enable gme])
+	AC_CHECK_HEADER([gme/gme.h], [includes="$includes -I/usr/include/gme"], [])])
+
+# For enet
+AC_DEFUN([ACLOVE_SOCKLEN_T], [
+	AC_CHECK_TYPE([socklen_t], [AC_DEFINE([HAS_SOCKLEN_T], [1], [Define if socklen_t exists.] )], ,
+		#include <sys/types.h>
+		#include <sys/socket.h>
+	)])
+
+# The lua detection is quite annoying because of distro differences and our version selection code
+AC_DEFUN([ACLOVE_DEP_LUA_PKGCONFIG], [
+	PKG_CHECK_MODULES([lua], [${with_lua}${with_luaversion}], [aclove_lua_found=yes],
+		[PKG_CHECK_MODULES([lua], [${with_lua}${with_clean_luaversion}], [aclove_lua_found=yes],
+			[PKG_CHECK_MODULES([lua], [${with_lua}], [aclove_lua_found=yes], [])])])
+
+	AS_VAR_IF([aclove_lua_found], [yes],
+		[
+			aclove_luaheaders_found=yes
+			AC_MSG_CHECKING([for library containing lua_call])
+			AC_MSG_RESULT([${lua_LIBS}])
+		], [])])
+
+AC_DEFUN([ACLOVE_DEP_LUA_FALLBACK], [
+	AC_MSG_WARN([Could not find pkg-config definition for ${with_lua}${with_luaversion} or ${with_lua}${with_clean_luaversion}${with_lua}, falling back to manual detection])
+	AC_SEARCH_LIBS([lua_call], ["${with_lua}${with_luaversion}" "${with_lua}"], [aclove_lua_found=yes],
+		[LOVE_MSG_ERROR([$with_lua])])
+
+	AC_CHECK_HEADER(["${with_lua}${with_luaversion}/lua.h"], [aclove_luaheaders_found=yes includes="$includes -I/usr/include/${with_lua}${with_luaversion}"], [])
+	AC_CHECK_HEADER(["${with_lua}/lua.h"], [aclove_luaheaders_found=yes includes="$includes -I/usr/include/${with_lua}"], [])])
+
+# First, try pkg-config, then fall back to manual detection if not available.
+AC_DEFUN([ACLOVE_DEP_LUA], [ dnl Requires with-lua and with-luaversion
+	aclove_lua_found=no
+	aclove_luaheaders_found=no
+
+	ACLOVE_DEP_LUA_PKGCONFIG
+	AS_VAR_IF([aclove_lua_found], [no], [ACLOVE_DEP_LUA_FALLBACK], [])
+	AS_VAR_IF([aclove_luaheaders_found], [no],
+		[AC_MSG_WARN([Could not locate lua headers for ${with_lua}${with_luaversion} or ${with_lua}, you probably need to specify them with CPPFLAGS])], [])])

+ 3 - 2
platform/unix/exclude

@@ -1,5 +1,6 @@
-\./libraries/luasocket/libluasocket/wsocket\.*
-\./modules/sound/lullaby/FLACDecoder\.*
+\./libraries/luasocket/libluasocket/wsocket.*
+\./modules/sound/lullaby/FLACDecoder\..*
 \./love\.cpp
 \./love\.cpp
 \./modules/sound/lullaby/Mpg123Decoder\.cpp
 \./modules/sound/lullaby/Mpg123Decoder\.cpp
 \./modules/sound/lullaby/Mpg123Decoder\.h
 \./modules/sound/lullaby/Mpg123Decoder\.h
+\./libraries/glslang/glslang/OSDependent/Windows

+ 0 - 38
platform/unix/gen-makefile

@@ -1,38 +0,0 @@
-#!/bin/bash
-echo Generating src/Makefile.am ...
-inc_current='$(srcdir)'
-inc_modules="$inc_current/modules"
-inc_libraries="$inc_current/libraries"
-
-cat > src/Makefile.am << EOF
-AM_CPPFLAGS = -I$inc_current -I$inc_modules -I$inc_libraries -I$inc_libraries/enet/libenet/include \$(LOVE_INCLUDES) \$(FILE_OFFSET)
-AM_CXXFLAGS = \$(SDL_CFLAGS)
-AUTOMAKE_OPTIONS = subdir-objects
-SUBDIRS =
-
-if LOVE_BUILD_EXE
-# LÖVE executable
-bin_PROGRAMS = love
-#love_LDFLAGS =
-love_LDADD = liblove.la
-love_SOURCES = love.cpp
-endif
-
-# Compile scripts
-#scripts/%.lua.h: scripts/%.lua
-#	cd scripts; \
-#	lua auto.lua \$*
-#TODO: Figure out how to only do this on gnu make, and detect which lua
-#      executable to run
-
-# libLÖVE
-lib_LTLIBRARIES = liblove.la
-liblove_la_LDFLAGS = -module -export-dynamic \$(LDFLAGS) \$(SDL_LIBS)
-EOF
-
-platform/unix/genmodules >> src/Makefile.am
-
-printf "\n" >> src/Makefile.am
-
-cd ..
-echo "src/Makefile.am is updated! ^.^"

+ 60 - 64
platform/unix/genmodules

@@ -3,20 +3,15 @@
 love_suffix="$1"
 love_suffix="$1"
 love_amsuffix="$(echo "$love_suffix" | sed 's/\-/_/g' | sed 's/\./_/g')"
 love_amsuffix="$(echo "$love_suffix" | sed 's/\-/_/g' | sed 's/\./_/g')"
 
 
-flags=""
+flags=()
 upper()
 upper()
 {
 {
 	echo "$@" | tr '[:lower:]' '[:upper:]'
 	echo "$@" | tr '[:lower:]' '[:upper:]'
 }
 }
 
 
-implfind()
-{
-	find "$1" -maxdepth 1 -type d -exec basename '{}' \; | grep -v "^\." | tail -n +2
-}
-
 sourcefind()
 sourcefind()
 {
 {
-	find "$1" $2 -type f \( -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.lch" \) | awk "{print \"./$prefix\"\$0\" \\\\\"}" | grep -v -f"$LOVEROOT/platform/unix/exclude"
+	find "$1" $2 -type f \( -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.lch" -o -iname "*.lua" \) | awk "{print \"./$prefix\"\$0\" \\\\\"}" | grep -v -f"$LOVEROOT/platform/unix/exclude" | sort
 }
 }
 
 
 handlemodule()
 handlemodule()
@@ -26,82 +21,90 @@ handlemodule()
 	printf "$DEFINENAME"
 	printf "$DEFINENAME"
 }
 }
 
 
-handleimpl()
-{
-	module="$1"
-	implementation="$2"
-	name="$3"
-
-	printf "if $name\n"
-	FILES="$(sourcefind "$module/$implementation" | sed "s/^/    /")"
-	if [[ "x$FILES" != "x" ]]; then
-		printf "liblove${love_amsuffix}_la_SOURCES += \\\\\n"
-		printf "${FILES:0:${#FILES}-2}\n"
-	fi
-	printf "endif\n\n"
-}
-
 genmodules()
 genmodules()
 {
 {
 	LOVEROOT="$(pwd)"
 	LOVEROOT="$(pwd)"
-	cd src
+	cd ./src
 
 
 	printf "liblove${love_amsuffix}_la_SOURCES = \\\\\n"
 	printf "liblove${love_amsuffix}_la_SOURCES = \\\\\n"
 	sourcefind "common" | sed "s/^/    /"
 	sourcefind "common" | sed "s/^/    /"
 	FILES="$(sourcefind "scripts" | sed "s/^/    /")"
 	FILES="$(sourcefind "scripts" | sed "s/^/    /")"
 	printf "${FILES:0:${#FILES}-2}\n\n"
 	printf "${FILES:0:${#FILES}-2}\n\n"
 
 
-	cd modules
+	local -a modulelist=()
+	local -a liblist=()
+
+	cd ./modules
 	prefix="modules/"
 	prefix="modules/"
 	for module in *; do
 	for module in *; do
-		NAME=$(handlemodule "$module")
-		flags="$flags module-$module"
+		flags+=("module-$module")
 
 
-		printf "if $NAME\n"
-
-		for implementation in $(implfind "$module"); do
-			flags="$flags implementation-$module-$implementation"
-			handleimpl "$module" "$implementation" "LOVE_IMPLEMENTATION_$(upper "$module")_$(upper "$implementation")"
-		done
-
-		FILES="$(sourcefind "$module" "-maxdepth 1" | sed "s/^/    /")"
+		FILES="$(sourcefind "$module" | sed "s/^/    /")"
 		if [[ "x$FILES" != "x" ]]; then
 		if [[ "x$FILES" != "x" ]]; then
-			printf "liblove${love_amsuffix}_la_SOURCES += \\\\\n"
-			printf "${FILES:0:${#FILES}-2}\n"
+			printf "liblove_module_$module = \\\\\n"
+			printf "${FILES:0:${#FILES}-2}\n\n"
+			modulelist+=("$module")
 		fi
 		fi
 
 
-		printf "endif\n\n"
+		if [[ "$module" = "sound" ]]; then
+			printf "if !LOVE_NOMPG123\n"
+			printf "liblove_module_$module += \\\\\n"
+			printf "\t./modules/sound/lullaby/Mpg123Decoder.cpp \\\\\n"
+			printf "\t./modules/sound/lullaby/Mpg123Decoder.h\n"
+			printf "endif\n\n"
+		fi
 	done
 	done
 
 
 	cd ../libraries
 	cd ../libraries
 	prefix="libraries/"
 	prefix="libraries/"
 	for library in *; do
 	for library in *; do
-		NAME="LOVE_LIBRARY_$(upper "$library")"
-		flags="$flags library-$library"
+		flags+=("library-$library")
 		FILES="$(sourcefind "$library" | sed "s/^/    /")"
 		FILES="$(sourcefind "$library" | sed "s/^/    /")"
 
 
 		if [[ ${#FILES} -gt 2 ]]; then
 		if [[ ${#FILES} -gt 2 ]]; then
-			printf "if $NAME\n"
-			printf "liblove${love_amsuffix}_la_SOURCES += \\\\\n"
-			printf "${FILES:0:${#FILES}-2}\nendif\n\n"
+			printf "liblove_library_$library = \\\\\n"
+			printf "${FILES:0:${#FILES}-2}\n\n"
+			liblist+=("$library")
 		fi
 		fi
 	done
 	done
+
+	for module in "${modulelist[@]}"; do
+		NAME=$(handlemodule "$module")
+		printf "if $NAME\n"
+		printf "liblove${love_amsuffix}_la_SOURCES += \$(liblove_module_$module)\n"
+		printf "endif\n\n"
+	done
+
+	for library in "${liblist[@]}"; do
+		NAME="LOVE_LIBRARY_$(upper "$library")"
+		printf "if $NAME\n"
+		printf "liblove${love_amsuffix}_la_SOURCES += \$(liblove_library_$library)\n"
+		printf "endif\n\n"
+	done
+
 	cd ../..
 	cd ../..
 }
 }
 
 
 genflags()
 genflags()
 {
 {
-	for flag in $flags; do
-		prettyflag="$(echo "$flag" | sed 's/-/ love./' | sed 's/-/./g')"
-		varflag="enable_$(echo "$flag" | sed 's/^[^-]*-//' | sed 's/[^a-zA-Z0-9]/_/')"
-		defineflag="LOVE_ENABLE_$(upper $(echo $flag | sed 's/^[^-]*-//' | sed 's/-/_/g'))"
+	printf > configure-modules-pre.ac
+	printf > configure-modules-post.ac
+	for flag in "${flags[@]}"; do
+		prettyflag="$(echo "$flag" | sed -e 's/-/ love./' -e 's/-/./g')"
+		varflag="enable_$(echo "$flag" | sed -e 's/[^a-zA-Z0-9]/_/')"
+		defineflag="LOVE_ENABLE_$(upper $(echo $flag | sed -e 's/^[^-]*-//' -e 's/-/_/g'))"
 		amflag="$(upper $(echo love-$flag | sed 's/-/_/g'))"
 		amflag="$(upper $(echo love-$flag | sed 's/-/_/g'))"
-		printf "AC_ARG_ENABLE([$flag], [  --disable-$flag    Turn off $prettyflag], [], [$varflag=true])\n"
-		printf "AH_TEMPLATE([$defineflag], [])\n"
-		printf "if test x\"\$$varflag\" = xtrue; then\n"
-		printf "    AC_DEFINE([$defineflag], [])\n"
-		printf "fi\n"
-		printf "AM_CONDITIONAL([$amflag], [test x\$$varflag = xtrue])\n\n"
+
+		# Don't generate an --enable rule for libraries
+		if [[ "$(echo $flag | sed -e '/^library-/d')" != "" ]]; then
+			printf "AC_ARG_ENABLE([$flag], [  --disable-$flag    Turn off $prettyflag], [], [$varflag=yes])\n" >> configure-modules-pre.ac
+		fi
+
+		printf "AH_TEMPLATE([$defineflag], [])\n" >> configure-modules-post.ac
+		printf "if test x\"\$$varflag\" = xyes; then\n" >> configure-modules-post.ac
+		printf "    AC_DEFINE([$defineflag], [])\n" >> configure-modules-post.ac
+		printf "fi\n" >> configure-modules-post.ac
+		printf "AM_CONDITIONAL([$amflag], [test x\$$varflag = xyes])\n\n" >> configure-modules-post.ac
 	done
 	done
 }
 }
 
 
@@ -137,33 +140,26 @@ endif
 
 
 # Compile scripts
 # Compile scripts
 .lua.lua.h:
 .lua.lua.h:
-	cd scripts; \
+	cd ./scripts; \
 	\$(LUA_EXECUTABLE) auto.lua \$<
 	\$(LUA_EXECUTABLE) auto.lua \$<
 
 
 # libLÖVE
 # libLÖVE
 lib_LTLIBRARIES = liblove${love_suffix}.la
 lib_LTLIBRARIES = liblove${love_suffix}.la
-liblove${love_amsuffix}_la_LDFLAGS = -module -export-dynamic \$(LDFLAGS)
+liblove${love_amsuffix}_la_LDFLAGS = -module -export-dynamic \$(LDFLAGS) -release \$(PACKAGE_VERSION)
 liblove${love_amsuffix}_la_LIBADD = \
 liblove${love_amsuffix}_la_LIBADD = \
 	\$(SDL_LIBS) \$(freetype2_LIBS) \$(lua_LIBS)\
 	\$(SDL_LIBS) \$(freetype2_LIBS) \$(lua_LIBS)\
 	\$(openal_LIBS) \$(zlib_LIBS) \$(libmodplug_LIBS)\
 	\$(openal_LIBS) \$(zlib_LIBS) \$(libmodplug_LIBS)\
 	\$(vorbisfile_LIBS) \$(theora_LIBS)
 	\$(vorbisfile_LIBS) \$(theora_LIBS)
+
 EOF
 EOF
 
 
 genmodules >> src/Makefile.am
 genmodules >> src/Makefile.am
 
 
-cat >> src/Makefile.am << EOF
-if !LOVE_NOMPG123
-liblove${love_amsuffix}_la_SOURCES += \\
-    ./modules/sound/lullaby/Mpg123Decoder.cpp \\
-    ./modules/sound/lullaby/Mpg123Decoder.h
-endif
-EOF
-
 echo "src/Makefile.am is updated! ^.^"
 echo "src/Makefile.am is updated! ^.^"
 
 
 echo "Generating configure-modules.ac"
 echo "Generating configure-modules.ac"
-genflags > configure-modules.ac
-cat >> configure-modules.ac << EOF
+genflags
+cat >> configure-modules-post.ac << EOF
 AC_SUBST([LOVE_SUFFIX], [${love_suffix}])
 AC_SUBST([LOVE_SUFFIX], [${love_suffix}])
 EOF
 EOF
 echo "configure-modules.ac is updated! ^.^"
 echo "configure-modules.ac is updated! ^.^"

+ 26 - 1
platform/xcode/Images.xcassets/iOS AppIcon.appiconset/Contents.json

@@ -1,5 +1,15 @@
 {
 {
   "images" : [
   "images" : [
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "3x"
+    },
     {
     {
       "size" : "29x29",
       "size" : "29x29",
       "idiom" : "iphone",
       "idiom" : "iphone",
@@ -54,6 +64,16 @@
       "filename" : "[email protected]",
       "filename" : "[email protected]",
       "scale" : "3x"
       "scale" : "3x"
     },
     },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
     {
     {
       "size" : "29x29",
       "size" : "29x29",
       "idiom" : "ipad",
       "idiom" : "ipad",
@@ -119,10 +139,15 @@
       "idiom" : "ipad",
       "idiom" : "ipad",
       "filename" : "[email protected]",
       "filename" : "[email protected]",
       "scale" : "2x"
       "scale" : "2x"
+    },
+    {
+      "idiom" : "ios-marketing",
+      "size" : "1024x1024",
+      "scale" : "1x"
     }
     }
   ],
   ],
   "info" : {
   "info" : {
     "version" : 1,
     "version" : 1,
     "author" : "xcode"
     "author" : "xcode"
   }
   }
-}
+}

+ 1 - 1
platform/xcode/ios/love-ios.plist

@@ -40,7 +40,7 @@
 	<key>CFBundlePackageType</key>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
 	<key>CFBundleShortVersionString</key>
-	<string>0.10.2</string>
+	<string>0.11.0</string>
 	<key>CFBundleSignature</key>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<string>????</string>
 	<key>CFBundleVersion</key>
 	<key>CFBundleVersion</key>

File diff suppressed because it is too large
+ 642 - 245
platform/xcode/liblove.xcodeproj/project.pbxproj


+ 80 - 1
platform/xcode/love.xcodeproj/project.pbxproj

@@ -22,6 +22,7 @@
 		FA08F69616C766E000F007B5 /* love.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; };
 		FA08F69616C766E000F007B5 /* love.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; };
 		FA08F69716C766E700F007B5 /* love.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
 		FA08F69716C766E700F007B5 /* love.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
 		FA0B7F301A95AC7D000E1D17 /* love.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A93E6A3410420AC0007D418B /* love.cpp */; };
 		FA0B7F301A95AC7D000E1D17 /* love.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A93E6A3410420AC0007D418B /* love.cpp */; };
+		FA15DFB41F9B8D9E0042AB22 /* libbz2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = FA15DFB31F9B8D9E0042AB22 /* libbz2.tbd */; };
 		FA27B3CB1B498696008A9DCE /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA27B3CA1B498696008A9DCE /* Theora.framework */; };
 		FA27B3CB1B498696008A9DCE /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA27B3CA1B498696008A9DCE /* Theora.framework */; };
 		FA5933751C6D625B000EC779 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FA5D249A1A96CF4300C6FC8F /* Images.xcassets */; };
 		FA5933751C6D625B000EC779 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FA5D249A1A96CF4300C6FC8F /* Images.xcassets */; };
 		FA5D24821A96CA1800C6FC8F /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA5D24811A96CA1800C6FC8F /* OpenAL.framework */; };
 		FA5D24821A96CA1800C6FC8F /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA5D24811A96CA1800C6FC8F /* OpenAL.framework */; };
@@ -115,6 +116,7 @@
 		FA0797981BF480A200034B7C /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; };
 		FA0797981BF480A200034B7C /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; };
 		FA08F69116C765A200F007B5 /* love.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		FA08F69116C765A200F007B5 /* love.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		FA0B7F061A95AAF3000E1D17 /* love.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = love.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		FA0B7F061A95AAF3000E1D17 /* love.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = love.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		FA15DFB31F9B8D9E0042AB22 /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.sdk/usr/lib/libbz2.tbd; sourceTree = DEVELOPER_DIR; };
 		FA27B3CA1B498696008A9DCE /* Theora.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Theora.framework; path = /Library/Frameworks/Theora.framework; sourceTree = "<absolute>"; };
 		FA27B3CA1B498696008A9DCE /* Theora.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Theora.framework; path = /Library/Frameworks/Theora.framework; sourceTree = "<absolute>"; };
 		FA577A9316C7217800860150 /* liblove.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = liblove.xcodeproj; sourceTree = "<group>"; };
 		FA577A9316C7217800860150 /* liblove.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = liblove.xcodeproj; sourceTree = "<group>"; };
 		FA5D24811A96CA1800C6FC8F /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
 		FA5D24811A96CA1800C6FC8F /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
@@ -151,6 +153,7 @@
 			isa = PBXFrameworksBuildPhase;
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
+				FA15DFB41F9B8D9E0042AB22 /* libbz2.tbd in Frameworks */,
 				CE73F8001EEB64150052DAB3 /* AVFoundation.framework in Frameworks */,
 				CE73F8001EEB64150052DAB3 /* AVFoundation.framework in Frameworks */,
 				FA5D24D11A96E73300C6FC8F /* liblove.a in Frameworks */,
 				FA5D24D11A96E73300C6FC8F /* liblove.a in Frameworks */,
 				FA5D24C21A96D78000C6FC8F /* Foundation.framework in Frameworks */,
 				FA5D24C21A96D78000C6FC8F /* Foundation.framework in Frameworks */,
@@ -172,6 +175,7 @@
 		1058C7A0FEA54F0111CA2CBB /* Frameworks */ = {
 		1058C7A0FEA54F0111CA2CBB /* Frameworks */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				FA15DFB31F9B8D9E0042AB22 /* libbz2.tbd */,
 				CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */,
 				CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */,
 				FA5D24801A96C97900C6FC8F /* ios */,
 				FA5D24801A96C97900C6FC8F /* ios */,
 				FA0B7EEC1A959249000E1D17 /* macosx */,
 				FA0B7EEC1A959249000E1D17 /* macosx */,
@@ -322,7 +326,7 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			isa = PBXProject;
 			attributes = {
 			attributes = {
-				LastUpgradeCheck = 0700;
+				LastUpgradeCheck = 0920;
 				TargetAttributes = {
 				TargetAttributes = {
 					FA0B7F051A95AAF3000E1D17 = {
 					FA0B7F051A95AAF3000E1D17 = {
 						CreatedOnToolsVersion = 6.1.1;
 						CreatedOnToolsVersion = 6.1.1;
@@ -434,6 +438,7 @@
 				COMBINE_HIDPI_IMAGES = YES;
 				COMBINE_HIDPI_IMAGES = YES;
 				FRAMEWORK_SEARCH_PATHS = (
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks",
 					/Library/Frameworks,
 					/Library/Frameworks,
 					"\"$(SRCROOT)/build/Release\"",
 					"\"$(SRCROOT)/build/Release\"",
 					"\"$(SRCROOT)/build/Debug\"",
 					"\"$(SRCROOT)/build/Debug\"",
@@ -443,6 +448,8 @@
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				HEADER_SEARCH_PATHS = (
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
+					"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
 					/Library/Frameworks/Lua.framework/Headers,
 					/Library/Frameworks/Lua.framework/Headers,
 					/Library/Frameworks/SDL2.framework/Headers,
 					/Library/Frameworks/SDL2.framework/Headers,
 				);
 				);
@@ -462,6 +469,7 @@
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				FRAMEWORK_SEARCH_PATHS = (
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks",
 					/Library/Frameworks,
 					/Library/Frameworks,
 					"\"$(SRCROOT)/build/Release\"",
 					"\"$(SRCROOT)/build/Release\"",
 					"\"$(SRCROOT)/build/Debug\"",
 					"\"$(SRCROOT)/build/Debug\"",
@@ -469,6 +477,8 @@
 				);
 				);
 				HEADER_SEARCH_PATHS = (
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
+					"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
 					/Library/Frameworks/Lua.framework/Headers,
 					/Library/Frameworks/Lua.framework/Headers,
 					/Library/Frameworks/SDL2.framework/Headers,
 					/Library/Frameworks/SDL2.framework/Headers,
 				);
 				);
@@ -484,16 +494,35 @@
 			isa = XCBuildConfiguration;
 			isa = XCBuildConfiguration;
 			buildSettings = {
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
 				ENABLE_TESTABILITY = YES;
 				FRAMEWORK_SEARCH_PATHS = "";
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES;
 				GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = LOVE_APPLE_USE_FRAMEWORKS;
 				GCC_PREPROCESSOR_DEFINITIONS = LOVE_APPLE_USE_FRAMEWORKS;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
 				GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
 				GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
 				GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
@@ -508,6 +537,9 @@
 				GCC_WARN_SHADOW = NO;
 				GCC_WARN_SHADOW = NO;
 				GCC_WARN_SIGN_COMPARE = YES;
 				GCC_WARN_SIGN_COMPARE = YES;
 				GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
 				GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				HEADER_SEARCH_PATHS = (
 				HEADER_SEARCH_PATHS = (
 					"\"$(SRCROOT)/../../src\"",
 					"\"$(SRCROOT)/../../src\"",
@@ -539,16 +571,35 @@
 			isa = XCBuildConfiguration;
 			isa = XCBuildConfiguration;
 			buildSettings = {
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				DEPLOYMENT_POSTPROCESSING = NO;
 				DEPLOYMENT_POSTPROCESSING = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				FRAMEWORK_SEARCH_PATHS = "";
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_INPUT_FILETYPE = automatic;
 				GCC_INPUT_FILETYPE = automatic;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 3;
 				GCC_OPTIMIZATION_LEVEL = 3;
 				GCC_PREPROCESSOR_DEFINITIONS = LOVE_APPLE_USE_FRAMEWORKS;
 				GCC_PREPROCESSOR_DEFINITIONS = LOVE_APPLE_USE_FRAMEWORKS;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
 				GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
 				GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
 				GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
@@ -563,6 +614,9 @@
 				GCC_WARN_SHADOW = NO;
 				GCC_WARN_SHADOW = NO;
 				GCC_WARN_SIGN_COMPARE = YES;
 				GCC_WARN_SIGN_COMPARE = YES;
 				GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
 				GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_PARAMETER = NO;
 				GCC_WARN_UNUSED_PARAMETER = NO;
 				GCC_WARN_UNUSED_VALUE = NO;
 				GCC_WARN_UNUSED_VALUE = NO;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
@@ -734,16 +788,35 @@
 			isa = XCBuildConfiguration;
 			isa = XCBuildConfiguration;
 			buildSettings = {
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				DEPLOYMENT_POSTPROCESSING = NO;
 				DEPLOYMENT_POSTPROCESSING = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				FRAMEWORK_SEARCH_PATHS = "";
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_INPUT_FILETYPE = automatic;
 				GCC_INPUT_FILETYPE = automatic;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 3;
 				GCC_OPTIMIZATION_LEVEL = 3;
 				GCC_PREPROCESSOR_DEFINITIONS = LOVE_APPLE_USE_FRAMEWORKS;
 				GCC_PREPROCESSOR_DEFINITIONS = LOVE_APPLE_USE_FRAMEWORKS;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
 				GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
 				GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
 				GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
@@ -758,6 +831,9 @@
 				GCC_WARN_SHADOW = NO;
 				GCC_WARN_SHADOW = NO;
 				GCC_WARN_SIGN_COMPARE = YES;
 				GCC_WARN_SIGN_COMPARE = YES;
 				GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
 				GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_PARAMETER = NO;
 				GCC_WARN_UNUSED_PARAMETER = NO;
 				GCC_WARN_UNUSED_VALUE = NO;
 				GCC_WARN_UNUSED_VALUE = NO;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
@@ -797,6 +873,7 @@
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				FRAMEWORK_SEARCH_PATHS = (
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks",
 					/Library/Frameworks,
 					/Library/Frameworks,
 					"\"$(SRCROOT)/build/Release\"",
 					"\"$(SRCROOT)/build/Release\"",
 					"\"$(SRCROOT)/build/Debug\"",
 					"\"$(SRCROOT)/build/Debug\"",
@@ -804,6 +881,8 @@
 				);
 				);
 				HEADER_SEARCH_PATHS = (
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
+					"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
 					/Library/Frameworks/Lua.framework/Headers,
 					/Library/Frameworks/Lua.framework/Headers,
 					/Library/Frameworks/SDL2.framework/Headers,
 					/Library/Frameworks/SDL2.framework/Headers,
 				);
 				);

+ 5 - 0
platform/xcode/love.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict/>
+</plist>

+ 1 - 1
platform/xcode/macosx/liblove-macosx.plist

@@ -17,7 +17,7 @@
 	<key>CFBundlePackageType</key>
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
 	<key>CFBundleShortVersionString</key>
-	<string>0.10.1</string>
+	<string>0.11.0</string>
 	<key>CFBundleSignature</key>
 	<key>CFBundleSignature</key>
 	<string>LoVe</string>
 	<string>LoVe</string>
 	<key>NSPrincipalClass</key>
 	<key>NSPrincipalClass</key>

+ 4 - 2
platform/xcode/macosx/love-macosx.plist

@@ -62,7 +62,7 @@
 	<key>CFBundlePackageType</key>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
 	<key>CFBundleShortVersionString</key>
-	<string>0.10.2</string>
+	<string>0.11.0</string>
 	<key>CFBundleSignature</key>
 	<key>CFBundleSignature</key>
 	<string>LoVe</string>
 	<string>LoVe</string>
 	<key>LSApplicationCategoryType</key>
 	<key>LSApplicationCategoryType</key>
@@ -70,9 +70,11 @@
 	<key>NSHighResolutionCapable</key>
 	<key>NSHighResolutionCapable</key>
 	<true/>
 	<true/>
 	<key>NSHumanReadableCopyright</key>
 	<key>NSHumanReadableCopyright</key>
-	<string>© 2006-2016 LÖVE Development Team</string>
+	<string>© 2006-2017 LÖVE Development Team</string>
 	<key>NSPrincipalClass</key>
 	<key>NSPrincipalClass</key>
 	<string>NSApplication</string>
 	<string>NSApplication</string>
+	<key>NSSupportsAutomaticGraphicsSwitching</key>
+	<false/>
 	<key>UTExportedTypeDeclarations</key>
 	<key>UTExportedTypeDeclarations</key>
 	<array>
 	<array>
 		<dict>
 		<dict>

+ 39 - 7
src/modules/graphics/Color.h → src/common/Color.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2011 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -18,13 +18,11 @@
  * 3. This notice may not be removed or altered from any source distribution.
  * 3. This notice may not be removed or altered from any source distribution.
  **/
  **/
 
 
-#ifndef LOVE_GRAPHICS_COLOR_H
-#define LOVE_GRAPHICS_COLOR_H
+#ifndef LOVE_COLOR_H
+#define LOVE_COLOR_H
 
 
 namespace love
 namespace love
 {
 {
-namespace graphics
-{
 
 
 template <typename T>
 template <typename T>
 struct ColorT
 struct ColorT
@@ -48,6 +46,7 @@ struct ColorT
 	bool operator!=(const ColorT<T> &other) const;
 	bool operator!=(const ColorT<T> &other) const;
 
 
 	ColorT<T> operator+=(const ColorT<T> &other);
 	ColorT<T> operator+=(const ColorT<T> &other);
+	ColorT<T> operator*=(const ColorT<T> &other);
 	ColorT<T> operator*=(T s);
 	ColorT<T> operator*=(T s);
 	ColorT<T> operator/=(T s);
 	ColorT<T> operator/=(T s);
 };
 };
@@ -74,6 +73,16 @@ ColorT<T> ColorT<T>::operator+=(const ColorT<T> &other)
 	return *this;
 	return *this;
 }
 }
 
 
+template <typename T>
+ColorT<T> ColorT<T>::operator*=(const ColorT<T> &other)
+{
+	r *= other.r;
+	g *= other.g;
+	b *= other.b;
+	a *= other.a;
+	return *this;
+}
+
 template <typename T>
 template <typename T>
 ColorT<T> ColorT<T>::operator*=(T s)
 ColorT<T> ColorT<T>::operator*=(T s)
 {
 {
@@ -101,6 +110,17 @@ ColorT<T> operator+(const ColorT<T> &a, const ColorT<T> &b)
 	return tmp += b;
 	return tmp += b;
 }
 }
 
 
+template <typename T>
+ColorT<T> operator*(const ColorT<T> &a, const ColorT<T> &b)
+{
+	ColorT<T> res;
+	res.r = a.r * b.r;
+	res.g = a.g * b.g;
+	res.b = a.b * b.b;
+	res.a = a.a * b.a;
+	return res;
+}
+
 template <typename T>
 template <typename T>
 ColorT<T> operator*(const ColorT<T> &a, T s)
 ColorT<T> operator*(const ColorT<T> &a, T s)
 {
 {
@@ -118,7 +138,19 @@ ColorT<T> operator/(const ColorT<T> &a, T s)
 typedef ColorT<unsigned char> Color;
 typedef ColorT<unsigned char> Color;
 typedef ColorT<float> Colorf;
 typedef ColorT<float> Colorf;
 
 
-} // graphics
+inline Color toColor(Colorf cf)
+{
+	return Color((unsigned char) (cf.r * 255.0f),
+	             (unsigned char) (cf.g * 255.0f),
+	             (unsigned char) (cf.b * 255.0f),
+	             (unsigned char) (cf.a * 255.0f));
+}
+
+inline Colorf toColorf(Color c)
+{
+	return Colorf(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f, c.a / 255.0f);
+}
+
 } // love
 } // love
 
 
-#endif // LOVE_GRAPHICS_COLOR_H
+#endif // LOVE_COLOR_H

+ 29 - 0
src/common/Data.cpp

@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+// LOVE
+#include "Data.h"
+
+namespace love
+{
+
+love::Type Data::type("Data", &Object::type);
+
+} // love

+ 7 - 1
src/common/Data.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -38,11 +38,17 @@ class Data : public Object
 {
 {
 public:
 public:
 
 
+	static love::Type type;
+
 	/**
 	/**
 	 * Destructor.
 	 * Destructor.
 	 **/
 	 **/
 	virtual ~Data() {}
 	virtual ~Data() {}
 
 
+	/**
+	 * Creates a duplicate of Data derived class instance.
+	 **/
+	virtual Data *clone() const = 0;
 	/**
 	/**
 	 * Gets a pointer to the data. This pointer will obviously not
 	 * Gets a pointer to the data. This pointer will obviously not
 	 * be valid if the Data object is destroyed.
 	 * be valid if the Data object is destroyed.

+ 1 - 1
src/common/EnumMap.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/Exception.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/Exception.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 230 - 41
src/common/Matrix.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -19,14 +19,87 @@
  **/
  **/
 
 
 #include "Matrix.h"
 #include "Matrix.h"
+#include "common/config.h"
 
 
 // STD
 // STD
 #include <cstring> // memcpy
 #include <cstring> // memcpy
 #include <cmath>
 #include <cmath>
 
 
+#if defined(LOVE_SIMD_SSE)
+#include <xmmintrin.h>
+#endif
+
 namespace love
 namespace love
 {
 {
 
 
+//                 | e0 e4 e8  e12 |
+//                 | e1 e5 e9  e13 |
+//                 | e2 e6 e10 e14 |
+//                 | e3 e7 e11 e15 |
+// | e0 e4 e8  e12 |
+// | e1 e5 e9  e13 |
+// | e2 e6 e10 e14 |
+// | e3 e7 e11 e15 |
+
+void Matrix4::multiply(const Matrix4 &a, const Matrix4 &b, float t[16])
+{
+	// NOTE: in my testing with ARM NEON instructions (on an iPhone 6 with arm64)
+	// it performed slightly worse than the regular add/multiply code. Further
+	// investigation would be useful.
+#if defined(LOVE_SIMD_SSE)
+
+	// We can't guarantee 16-bit alignment (e.g. for heap-allocated Matrix4
+	// objects) so we use unaligned loads and stores.
+	__m128 col1 = _mm_loadu_ps(&a.e[0]);
+	__m128 col2 = _mm_loadu_ps(&a.e[4]);
+	__m128 col3 = _mm_loadu_ps(&a.e[8]);
+	__m128 col4 = _mm_loadu_ps(&a.e[12]);
+
+	for (int i = 0; i < 4; i++)
+	{
+		__m128 brod1 = _mm_set1_ps(b.e[4*i + 0]);
+		__m128 brod2 = _mm_set1_ps(b.e[4*i + 1]);
+		__m128 brod3 = _mm_set1_ps(b.e[4*i + 2]);
+		__m128 brod4 = _mm_set1_ps(b.e[4*i + 3]);
+
+		__m128 col = _mm_add_ps(
+			_mm_add_ps(_mm_mul_ps(brod1, col1), _mm_mul_ps(brod2, col2)),
+			_mm_add_ps(_mm_mul_ps(brod3, col3), _mm_mul_ps(brod4, col4))
+		);
+
+		_mm_storeu_ps(&t[4*i], col);
+	}
+
+#else
+
+	t[0]  = (a.e[0]*b.e[0])  + (a.e[4]*b.e[1])  + (a.e[8]*b.e[2])  + (a.e[12]*b.e[3]);
+	t[4]  = (a.e[0]*b.e[4])  + (a.e[4]*b.e[5])  + (a.e[8]*b.e[6])  + (a.e[12]*b.e[7]);
+	t[8]  = (a.e[0]*b.e[8])  + (a.e[4]*b.e[9])  + (a.e[8]*b.e[10]) + (a.e[12]*b.e[11]);
+	t[12] = (a.e[0]*b.e[12]) + (a.e[4]*b.e[13]) + (a.e[8]*b.e[14]) + (a.e[12]*b.e[15]);
+
+	t[1]  = (a.e[1]*b.e[0])  + (a.e[5]*b.e[1])  + (a.e[9]*b.e[2])  + (a.e[13]*b.e[3]);
+	t[5]  = (a.e[1]*b.e[4])  + (a.e[5]*b.e[5])  + (a.e[9]*b.e[6])  + (a.e[13]*b.e[7]);
+	t[9]  = (a.e[1]*b.e[8])  + (a.e[5]*b.e[9])  + (a.e[9]*b.e[10]) + (a.e[13]*b.e[11]);
+	t[13] = (a.e[1]*b.e[12]) + (a.e[5]*b.e[13]) + (a.e[9]*b.e[14]) + (a.e[13]*b.e[15]);
+
+	t[2]  = (a.e[2]*b.e[0])  + (a.e[6]*b.e[1])  + (a.e[10]*b.e[2])  + (a.e[14]*b.e[3]);
+	t[6]  = (a.e[2]*b.e[4])  + (a.e[6]*b.e[5])  + (a.e[10]*b.e[6])  + (a.e[14]*b.e[7]);
+	t[10] = (a.e[2]*b.e[8])  + (a.e[6]*b.e[9])  + (a.e[10]*b.e[10]) + (a.e[14]*b.e[11]);
+	t[14] = (a.e[2]*b.e[12]) + (a.e[6]*b.e[13]) + (a.e[10]*b.e[14]) + (a.e[14]*b.e[15]);
+
+	t[3]  = (a.e[3]*b.e[0])  + (a.e[7]*b.e[1])  + (a.e[11]*b.e[2])  + (a.e[15]*b.e[3]);
+	t[7]  = (a.e[3]*b.e[4])  + (a.e[7]*b.e[5])  + (a.e[11]*b.e[6])  + (a.e[15]*b.e[7]);
+	t[11] = (a.e[3]*b.e[8])  + (a.e[7]*b.e[9])  + (a.e[11]*b.e[10]) + (a.e[15]*b.e[11]);
+	t[15] = (a.e[3]*b.e[12]) + (a.e[7]*b.e[13]) + (a.e[11]*b.e[14]) + (a.e[15]*b.e[15]);
+
+#endif
+}
+
+void Matrix4::multiply(const Matrix4 &a, const Matrix4 &b, Matrix4 &t)
+{
+	multiply(a, b, t.e);
+}
+
 // | e0 e4 e8  e12 |
 // | e0 e4 e8  e12 |
 // | e1 e5 e9  e13 |
 // | e1 e5 e9  e13 |
 // | e2 e6 e10 e14 |
 // | e2 e6 e10 e14 |
@@ -36,61 +109,38 @@ Matrix4::Matrix4()
 {
 {
 	setIdentity();
 	setIdentity();
 }
 }
+
+
+Matrix4::Matrix4(const float elements[16])
+{
+	memcpy(e, elements, sizeof(float) * 16);
+}
 	
 	
 Matrix4::Matrix4(float t00, float t10, float t01, float t11, float x, float y)
 Matrix4::Matrix4(float t00, float t10, float t01, float t11, float x, float y)
 {
 {
 	setRawTransformation(t00, t10, t01, t11, x, y);
 	setRawTransformation(t00, t10, t01, t11, x, y);
 }
 }
 
 
-Matrix4::Matrix4(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
+Matrix4::Matrix4(const Matrix4 &a, const Matrix4 &b)
 {
 {
-	setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
+	multiply(a, b, e);
 }
 }
 
 
-Matrix4::~Matrix4()
+Matrix4::Matrix4(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
 {
 {
+	setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
 }
 }
 
 
-//                 | e0 e4 e8  e12 |
-//                 | e1 e5 e9  e13 |
-//                 | e2 e6 e10 e14 |
-//                 | e3 e7 e11 e15 |
-// | e0 e4 e8  e12 |
-// | e1 e5 e9  e13 |
-// | e2 e6 e10 e14 |
-// | e3 e7 e11 e15 |
-
 Matrix4 Matrix4::operator * (const Matrix4 &m) const
 Matrix4 Matrix4::operator * (const Matrix4 &m) const
 {
 {
-	Matrix4 t;
-
-	t.e[0] = (e[0]*m.e[0]) + (e[4]*m.e[1]) + (e[8]*m.e[2]) + (e[12]*m.e[3]);
-	t.e[4] = (e[0]*m.e[4]) + (e[4]*m.e[5]) + (e[8]*m.e[6]) + (e[12]*m.e[7]);
-	t.e[8] = (e[0]*m.e[8]) + (e[4]*m.e[9]) + (e[8]*m.e[10]) + (e[12]*m.e[11]);
-	t.e[12] = (e[0]*m.e[12]) + (e[4]*m.e[13]) + (e[8]*m.e[14]) + (e[12]*m.e[15]);
-
-	t.e[1] = (e[1]*m.e[0]) + (e[5]*m.e[1]) + (e[9]*m.e[2]) + (e[13]*m.e[3]);
-	t.e[5] = (e[1]*m.e[4]) + (e[5]*m.e[5]) + (e[9]*m.e[6]) + (e[13]*m.e[7]);
-	t.e[9] = (e[1]*m.e[8]) + (e[5]*m.e[9]) + (e[9]*m.e[10]) + (e[13]*m.e[11]);
-	t.e[13] = (e[1]*m.e[12]) + (e[5]*m.e[13]) + (e[9]*m.e[14]) + (e[13]*m.e[15]);
-
-	t.e[2] = (e[2]*m.e[0]) + (e[6]*m.e[1]) + (e[10]*m.e[2]) + (e[14]*m.e[3]);
-	t.e[6] = (e[2]*m.e[4]) + (e[6]*m.e[5]) + (e[10]*m.e[6]) + (e[14]*m.e[7]);
-	t.e[10] = (e[2]*m.e[8]) + (e[6]*m.e[9]) + (e[10]*m.e[10]) + (e[14]*m.e[11]);
-	t.e[14] = (e[2]*m.e[12]) + (e[6]*m.e[13]) + (e[10]*m.e[14]) + (e[14]*m.e[15]);
-
-	t.e[3] = (e[3]*m.e[0]) + (e[7]*m.e[1]) + (e[11]*m.e[2]) + (e[15]*m.e[3]);
-	t.e[7] = (e[3]*m.e[4]) + (e[7]*m.e[5]) + (e[11]*m.e[6]) + (e[15]*m.e[7]);
-	t.e[11] = (e[3]*m.e[8]) + (e[7]*m.e[9]) + (e[11]*m.e[10]) + (e[15]*m.e[11]);
-	t.e[15] = (e[3]*m.e[12]) + (e[7]*m.e[13]) + (e[11]*m.e[14]) + (e[15]*m.e[15]);
-
-	return t;
+	return Matrix4(*this, m);
 }
 }
 
 
 void Matrix4::operator *= (const Matrix4 &m)
 void Matrix4::operator *= (const Matrix4 &m)
 {
 {
-	Matrix4 t = (*this) * m;
-	memcpy(this->e, t.e, sizeof(float)*16);
+	float t[16];
+	multiply(*this, m, t);
+	memcpy(this->e, t, sizeof(float)*16);
 }
 }
 
 
 const float *Matrix4::getElements() const
 const float *Matrix4::getElements() const
@@ -101,7 +151,7 @@ const float *Matrix4::getElements() const
 void Matrix4::setIdentity()
 void Matrix4::setIdentity()
 {
 {
 	memset(e, 0, sizeof(float)*16);
 	memset(e, 0, sizeof(float)*16);
-	e[0] = e[5] = e[10] = e[15] = 1;
+	e[15] = e[10] = e[5] = e[0] = 1;
 }
 }
 
 
 void Matrix4::setTranslation(float x, float y)
 void Matrix4::setTranslation(float x, float y)
@@ -134,6 +184,12 @@ void Matrix4::setShear(float kx, float ky)
 	e[1] = ky;
 	e[1] = ky;
 	e[4] = kx;
 	e[4] = kx;
 }
 }
+
+void Matrix4::getApproximateScale(float &sx, float &sy) const
+{
+	sx = sqrtf(e[0] * e[0] + e[4] * e[4]);
+	sy = sqrtf(e[1] * e[1] + e[5] * e[5]);
+}
 	
 	
 void Matrix4::setRawTransformation(float t00, float t10, float t01, float t11, float x, float y)
 void Matrix4::setRawTransformation(float t00, float t10, float t01, float t11, float x, float y)
 {
 {
@@ -194,16 +250,149 @@ void Matrix4::shear(float kx, float ky)
 	this->operator *=(t);
 	this->operator *=(t);
 }
 }
 
 
-Matrix4 Matrix4::ortho(float left, float right, float bottom, float top)
+bool Matrix4::isAffine2DTransform() const
+{
+	return fabsf(e[2] + e[3] + e[6] + e[7] + e[8] + e[9] + e[11] + e[14]) < 0.00001f
+		&& fabsf(e[10] + e[15] - 2.0f) < 0.00001f;
+}
+
+Matrix4 Matrix4::inverse() const
+{
+	Matrix4 inv;
+
+	inv.e[0] = e[5]  * e[10] * e[15] -
+	           e[5]  * e[11] * e[14] -
+	           e[9]  * e[6]  * e[15] +
+	           e[9]  * e[7]  * e[14] +
+	           e[13] * e[6]  * e[11] -
+	           e[13] * e[7]  * e[10];
+
+	inv.e[4] = -e[4]  * e[10] * e[15] +
+	            e[4]  * e[11] * e[14] +
+	            e[8]  * e[6]  * e[15] -
+	            e[8]  * e[7]  * e[14] -
+	            e[12] * e[6]  * e[11] +
+	            e[12] * e[7]  * e[10];
+
+	inv.e[8] = e[4]  * e[9]  * e[15] -
+	           e[4]  * e[11] * e[13] -
+	           e[8]  * e[5]  * e[15] +
+	           e[8]  * e[7]  * e[13] +
+	           e[12] * e[5]  * e[11] -
+	           e[12] * e[7]  * e[9];
+
+	inv.e[12] = -e[4]  * e[9]  * e[14] +
+	             e[4]  * e[10] * e[13] +
+	             e[8]  * e[5]  * e[14] -
+	             e[8]  * e[6]  * e[13] -
+	             e[12] * e[5]  * e[10] +
+	             e[12] * e[6]  * e[9];
+
+	inv.e[1] = -e[1]  * e[10] * e[15] +
+	            e[1]  * e[11] * e[14] +
+	            e[9]  * e[2]  * e[15] -
+	            e[9]  * e[3]  * e[14] -
+	            e[13] * e[2]  * e[11] +
+	            e[13] * e[3]  * e[10];
+
+	inv.e[5] = e[0]  * e[10] * e[15] -
+	           e[0]  * e[11] * e[14] -
+	           e[8]  * e[2]  * e[15] +
+	           e[8]  * e[3]  * e[14] +
+	           e[12] * e[2]  * e[11] -
+	           e[12] * e[3]  * e[10];
+
+	inv.e[9] = -e[0]  * e[9]  * e[15] +
+	            e[0]  * e[11] * e[13] +
+	            e[8]  * e[1]  * e[15] -
+	            e[8]  * e[3]  * e[13] -
+	            e[12] * e[1]  * e[11] +
+	            e[12] * e[3]  * e[9];
+
+	inv.e[13] = e[0]  * e[9]  * e[14] -
+	            e[0]  * e[10] * e[13] -
+	            e[8]  * e[1]  * e[14] +
+	            e[8]  * e[2]  * e[13] +
+	            e[12] * e[1]  * e[10] -
+	            e[12] * e[2]  * e[9];
+
+	inv.e[2] = e[1]  * e[6] * e[15] -
+	           e[1]  * e[7] * e[14] -
+	           e[5]  * e[2] * e[15] +
+	           e[5]  * e[3] * e[14] +
+	           e[13] * e[2] * e[7] -
+	           e[13] * e[3] * e[6];
+
+	inv.e[6] = -e[0]  * e[6] * e[15] +
+	            e[0]  * e[7] * e[14] +
+	            e[4]  * e[2] * e[15] -
+	            e[4]  * e[3] * e[14] -
+	            e[12] * e[2] * e[7] +
+	            e[12] * e[3] * e[6];
+
+	inv.e[10] = e[0]  * e[5] * e[15] -
+	            e[0]  * e[7] * e[13] -
+	            e[4]  * e[1] * e[15] +
+	            e[4]  * e[3] * e[13] +
+	            e[12] * e[1] * e[7] -
+	            e[12] * e[3] * e[5];
+
+	inv.e[14] = -e[0]  * e[5] * e[14] +
+	             e[0]  * e[6] * e[13] +
+	             e[4]  * e[1] * e[14] -
+	             e[4]  * e[2] * e[13] -
+	             e[12] * e[1] * e[6] +
+	             e[12] * e[2] * e[5];
+
+	inv.e[3] = -e[1] * e[6] * e[11] +
+	            e[1] * e[7] * e[10] +
+	            e[5] * e[2] * e[11] -
+	            e[5] * e[3] * e[10] -
+	            e[9] * e[2] * e[7] +
+	            e[9] * e[3] * e[6];
+
+	inv.e[7] = e[0] * e[6] * e[11] -
+	           e[0] * e[7] * e[10] -
+	           e[4] * e[2] * e[11] +
+	           e[4] * e[3] * e[10] +
+	           e[8] * e[2] * e[7] -
+	           e[8] * e[3] * e[6];
+
+	inv.e[11] = -e[0] * e[5] * e[11] +
+	             e[0] * e[7] * e[9] +
+	             e[4] * e[1] * e[11] -
+	             e[4] * e[3] * e[9] -
+	             e[8] * e[1] * e[7] +
+	             e[8] * e[3] * e[5];
+
+	inv.e[15] = e[0] * e[5] * e[10] -
+	            e[0] * e[6] * e[9] -
+	            e[4] * e[1] * e[10] +
+	            e[4] * e[2] * e[9] +
+	            e[8] * e[1] * e[6] -
+	            e[8] * e[2] * e[5];
+
+	float det = e[0] * inv.e[0] + e[1] * inv.e[4] + e[2] * inv.e[8] + e[3] * inv.e[12];
+
+	float invdet = 1.0f / det;
+
+	for (int i = 0; i < 16; i++)
+		inv.e[i] *= invdet;
+
+	return inv;
+}
+
+Matrix4 Matrix4::ortho(float left, float right, float bottom, float top, float near, float far)
 {
 {
 	Matrix4 m;
 	Matrix4 m;
 
 
 	m.e[0] = 2.0f / (right - left);
 	m.e[0] = 2.0f / (right - left);
 	m.e[5] = 2.0f / (top - bottom);
 	m.e[5] = 2.0f / (top - bottom);
-	m.e[10] = -1.0;
+	m.e[10] = -2.0f / (far - near);
 
 
 	m.e[12] = -(right + left) / (right - left);
 	m.e[12] = -(right + left) / (right - left);
 	m.e[13] = -(top + bottom) / (top - bottom);
 	m.e[13] = -(top + bottom) / (top - bottom);
+	m.e[14] = -(far + near) / (far - near);
 
 
 	return m;
 	return m;
 }
 }

+ 103 - 22
src/common/Matrix.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -34,8 +34,14 @@ namespace love
  **/
  **/
 class Matrix4
 class Matrix4
 {
 {
+private:
+
+	static void multiply(const Matrix4 &a, const Matrix4 &b, float t[16]);
+
 public:
 public:
 
 
+	static void multiply(const Matrix4 &a, const Matrix4 &b, Matrix4 &result);
+
 	/**
 	/**
 	 * Creates a new identity matrix.
 	 * Creates a new identity matrix.
 	 **/
 	 **/
@@ -47,14 +53,21 @@ public:
 	Matrix4(float t00, float t10, float t01, float t11, float x, float y);
 	Matrix4(float t00, float t10, float t01, float t11, float x, float y);
 
 
 	/**
 	/**
-	 * Creates a new matrix set to a transformation.
+	 * Creates a new matrix from the specified elements. Be sure to pass
+	 * exactly 16 elements in!
 	 **/
 	 **/
-	Matrix4(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
+	Matrix4(const float elements[16]);
 
 
 	/**
 	/**
-	 * Destructor.
+	 * Creates a new matrix from the result of multiplying the two specified
+	 * matrices.
 	 **/
 	 **/
-	~Matrix4();
+	Matrix4(const Matrix4 &a, const Matrix4 &b);
+
+	/**
+	 * Creates a new matrix set to a transformation.
+	 **/
+	Matrix4(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
 
 
 	/**
 	/**
 	 * Multiplies this Matrix with another Matrix, changing neither.
 	 * Multiplies this Matrix with another Matrix, changing neither.
@@ -106,6 +119,12 @@ public:
 	 * @param ky Shear along y-axis.
 	 * @param ky Shear along y-axis.
 	 **/
 	 **/
 	void setShear(float kx, float ky);
 	void setShear(float kx, float ky);
+
+	/**
+	 * Calculates the scale factors for a 2D affine transform. The output values
+	 * are absolute (not signed).
+	 **/
+	void getApproximateScale(float &sx, float &sy) const;
 	
 	
 	/**
 	/**
 	 * Sets a transformation's values directly. Useful if you want to modify them inplace,
 	 * Sets a transformation's values directly. Useful if you want to modify them inplace,
@@ -166,21 +185,42 @@ public:
 	void shear(float kx, float ky);
 	void shear(float kx, float ky);
 
 
 	/**
 	/**
-	 * Transforms an array of vertices by this Matrix. The sources and
-	 * destination arrays may be the same.
-	 *
-	 * @param dst Storage for the transformed vertices.
-	 * @param src The source vertices.
-	 * @param size The number of vertices.
+	 * Transforms an array of 2-component vertices by this Matrix. The source
+	 * and destination arrays may be the same.
 	 **/
 	 **/
-	template <typename V>
-	void transform(V *dst, const V *src, int size) const;
+	template <typename Vdst, typename Vsrc>
+	void transformXY(Vdst *dst, const Vsrc *src, int size) const;
 
 
 	/**
 	/**
-	 * Creates a new orthographic projection matrix with depth in the range of
-	 * [-1, 1].
+	 * Transforms an array of 2-component vertices by this Matrix, and stores
+	 * them in an array of 3-component vertices.
 	 **/
 	 **/
-	static Matrix4 ortho(float left, float right, float bottom, float top);
+	template <typename Vdst, typename Vsrc>
+	void transformXY0(Vdst *dst, const Vsrc *src, int size) const;
+
+	/**
+	 * Transforms an array of 3-component vertices by this Matrix. The source
+	 * and destination arrays may be the same.
+	 **/
+	template <typename Vdst, typename Vsrc>
+	void transformXYZ(Vdst *dst, const Vsrc *src, int size) const;
+
+	/**
+	 * Gets whether this matrix is an affine 2D transform (if the only non-
+	 * identity elements are the upper-left 2x2 and 2 translation values in the
+	 * 4th column).
+	 **/
+	bool isAffine2DTransform() const;
+
+	/**
+	 * Computes and returns the inverse of the matrix.
+	 **/
+	Matrix4 inverse() const;
+
+	/**
+	 * Creates a new orthographic projection matrix.
+	 **/
+	static Matrix4 ortho(float left, float right, float bottom, float top, float near, float far);
 
 
 private:
 private:
 
 
@@ -249,8 +289,8 @@ public:
 	/**
 	/**
 	 * Transforms an array of vertices by this matrix.
 	 * Transforms an array of vertices by this matrix.
 	 **/
 	 **/
-	template <typename V>
-	void transform(V *dst, const V *src, int size) const;
+	template <typename Vdst, typename Vsrc>
+	void transformXY(Vdst *dst, const Vsrc *src, int size) const;
 
 
 private:
 private:
 
 
@@ -272,8 +312,8 @@ private:
 // | e2 e6 e10 e14 |
 // | e2 e6 e10 e14 |
 // | e3 e7 e11 e15 |
 // | e3 e7 e11 e15 |
 
 
-template <typename V>
-void Matrix4::transform(V *dst, const V *src, int size) const
+template <typename Vdst, typename Vsrc>
+void Matrix4::transformXY(Vdst *dst, const Vsrc *src, int size) const
 {
 {
 	for (int i = 0; i < size; i++)
 	for (int i = 0; i < size; i++)
 	{
 	{
@@ -286,14 +326,55 @@ void Matrix4::transform(V *dst, const V *src, int size) const
 	}
 	}
 }
 }
 
 
+template <typename Vdst, typename Vsrc>
+void Matrix4::transformXY0(Vdst *dst, const Vsrc *src, int size) const
+{
+	for (int i = 0; i < size; i++)
+	{
+		// Store in temp variables in case src = dst
+		float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (0) + (e[12]);
+		float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (0) + (e[13]);
+		float z = (e[2]*src[i].x) + (e[6]*src[i].y) + (0) + (e[14]);
+
+		dst[i].x = x;
+		dst[i].y = y;
+		dst[i].z = z;
+	}
+}
+
+//                 | x |
+//                 | y |
+//                 | z |
+//                 | 1 |
+// | e0 e4 e8  e12 |
+// | e1 e5 e9  e13 |
+// | e2 e6 e10 e14 |
+// | e3 e7 e11 e15 |
+
+template <typename Vdst, typename Vsrc>
+void Matrix4::transformXYZ(Vdst *dst, const Vsrc *src, int size) const
+{
+	for (int i = 0; i < size; i++)
+	{
+		// Store in temp variables in case src = dst
+		float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (e[ 8]*src[i].z) + (e[12]);
+		float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (e[ 9]*src[i].z) + (e[13]);
+		float z = (e[2]*src[i].x) + (e[6]*src[i].y) + (e[10]*src[i].z) + (e[14]);
+
+		dst[i].x = x;
+		dst[i].y = y;
+		dst[i].z = z;
+	}
+}
+
 //            | x |
 //            | x |
 //            | y |
 //            | y |
 //            | 1 |
 //            | 1 |
 // | e0 e3 e6 |
 // | e0 e3 e6 |
 // | e1 e4 e7 |
 // | e1 e4 e7 |
 // | e2 e5 e8 |
 // | e2 e5 e8 |
-template <typename V>
-void Matrix3::transform(V *dst, const V *src, int size) const
+template <typename Vdst, typename Vsrc>
+void Matrix3::transformXY(Vdst *dst, const Vsrc *src, int size) const
 {
 {
 	for (int i = 0; i < size; i++)
 	for (int i = 0; i < size; i++)
 	{
 	{

+ 1 - 1
src/common/Memoizer.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/Memoizer.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 10 - 1
src/common/Module.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -21,6 +21,7 @@
 // LOVE
 // LOVE
 #include "Module.h"
 #include "Module.h"
 #include "Exception.h"
 #include "Exception.h"
+#include "deprecation.h"
 
 
 // std
 // std
 #include <map>
 #include <map>
@@ -58,8 +59,14 @@ namespace
 namespace love
 namespace love
 {
 {
 
 
+love::Type Module::type("Module", &Object::type);
 Module *Module::instances[] = {};
 Module *Module::instances[] = {};
 
 
+Module::Module()
+{
+	initDeprecation();
+}
+
 Module::~Module()
 Module::~Module()
 {
 {
 	ModuleRegistry &registry = registryInstance();
 	ModuleRegistry &registry = registryInstance();
@@ -82,6 +89,8 @@ Module::~Module()
 	}
 	}
 
 
 	freeEmptyRegistry();
 	freeEmptyRegistry();
+
+	deinitDeprecation();
 }
 }
 
 
 void Module::registerInstance(Module *instance)
 void Module::registerInstance(Module *instance)

+ 6 - 2
src/common/Module.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -34,9 +34,12 @@ class Module : public Object
 {
 {
 public:
 public:
 
 
+	static love::Type type;
+
 	enum ModuleType
 	enum ModuleType
 	{
 	{
 		M_AUDIO,
 		M_AUDIO,
+		M_DATA,
 		M_EVENT,
 		M_EVENT,
 		M_FILESYSTEM,
 		M_FILESYSTEM,
 		M_FONT,
 		M_FONT,
@@ -52,11 +55,12 @@ public:
 		M_THREAD,
 		M_THREAD,
 		M_TIMER,
 		M_TIMER,
 		M_TOUCH,
 		M_TOUCH,
-		M_WINDOW,
 		M_VIDEO,
 		M_VIDEO,
+		M_WINDOW,
 		M_MAX_ENUM
 		M_MAX_ENUM
 	};
 	};
 
 
+	Module();
 	virtual ~Module();
 	virtual ~Module();
 
 
     /**
     /**

+ 3 - 1
src/common/Object.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -24,6 +24,8 @@
 namespace love
 namespace love
 {
 {
 
 
+love::Type Object::type("Object", nullptr);
+
 Object::Object()
 Object::Object()
 	: count(1)
 	: count(1)
 {
 {

+ 4 - 1
src/common/Object.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -22,6 +22,7 @@
 #define LOVE_OBJECT_H
 #define LOVE_OBJECT_H
 
 
 #include <atomic>
 #include <atomic>
+#include "types.h"
 
 
 namespace love
 namespace love
 {
 {
@@ -38,6 +39,8 @@ class Object
 {
 {
 public:
 public:
 
 
+	static love::Type type;
+
 	/**
 	/**
 	 * Constructor. Sets reference count to one.
 	 * Constructor. Sets reference count to one.
 	 **/
 	 **/

+ 55 - 0
src/common/Optional.h

@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#pragma once
+
+namespace love
+{
+
+// Currently only meant for simple and small types.
+template <typename T>
+struct Optional
+{
+	bool hasValue;
+	T value;
+
+	Optional()
+		: hasValue(false)
+		, value(T())
+	{}
+
+	Optional(T val)
+		: hasValue(true)
+		, value(val)
+	{}
+
+	void set(T val)
+	{
+		hasValue = true;
+		value = val;
+	}
+};
+
+typedef Optional<bool> OptionalBool;
+typedef Optional<float> OptionalFloat;
+typedef Optional<double> OptionalDouble;
+typedef Optional<int> OptionalInt;
+
+} // love

+ 1 - 1
src/common/Reference.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/Reference.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 29 - 0
src/common/Stream.cpp

@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2006-2015 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+// LOVE
+#include "Stream.h"
+
+namespace love
+{
+
+love::Type Stream::type("Stream", &Object::type);
+
+} // love

+ 2 - 0
src/common/Stream.h

@@ -31,6 +31,8 @@ namespace love
 class Stream : public Object
 class Stream : public Object
 {
 {
 public:
 public:
+	static love::Type type;
+
 	virtual ~Stream() {}
 	virtual ~Stream() {}
 
 
 	// getData and getSize are assumed to talk about
 	// getData and getSize are assumed to talk about

+ 25 - 0
src/common/StringMap.cpp

@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "StringMap.h"
+
+// See the header
+template class std::vector<std::string>;
+template decltype(std::vector<std::string>().emplace_back("")) std::vector<std::string>::emplace_back<const char *const&>(const char *const&);

+ 22 - 1
src/common/StringMap.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -23,6 +23,15 @@
 
 
 #include "Exception.h"
 #include "Exception.h"
 
 
+#include <string>
+#include <vector>
+
+// As StringMap instantiates std::vector<std::string> for instances that use
+// getNames(), we end up with multiple copies in the object files. This
+// declaration means we only emit it once (in StringMap.cpp).
+extern template class std::vector<std::string>;
+extern template decltype(std::vector<std::string>().emplace_back("")) std::vector<std::string>::emplace_back<const char *const&>(const char *const&);
+
 namespace love
 namespace love
 {
 {
 
 
@@ -145,6 +154,18 @@ public:
 		return hash;
 		return hash;
 	}
 	}
 
 
+	std::vector<std::string> getNames() const
+	{
+		std::vector<std::string> names;
+		names.reserve(SIZE);
+
+		for (unsigned int i = 0; i < SIZE; ++i)
+			if (reverse[i] != nullptr)
+				names.emplace_back(reverse[i]);
+
+		return names;
+	}
+
 private:
 private:
 
 
 	struct Record
 	struct Record

+ 56 - 52
src/common/Variant.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -18,25 +18,27 @@
  * 3. This notice may not be removed or altered from any source distribution.
  * 3. This notice may not be removed or altered from any source distribution.
  **/
  **/
 
 
+#include <memory>
+
 #include "Variant.h"
 #include "Variant.h"
 #include "common/StringMap.h"
 #include "common/StringMap.h"
 
 
 namespace love
 namespace love
 {
 {
 
 
-static love::Type extractudatatype(lua_State *L, int idx)
+static Proxy *tryextractproxy(lua_State *L, int idx)
 {
 {
 	Proxy *u = (Proxy *)lua_touserdata(L, idx);
 	Proxy *u = (Proxy *)lua_touserdata(L, idx);
 
 
-	if (u == nullptr || u->type <= INVALID_ID || u->type >= TYPE_MAX_ENUM)
-		return INVALID_ID;
+	if (u == nullptr || u->type == nullptr)
+		return nullptr;
 
 
 	// We could get rid of the dynamic_cast for more performance, but it would
 	// We could get rid of the dynamic_cast for more performance, but it would
 	// be less safe...
 	// be less safe...
 	if (dynamic_cast<Object *>(u->object) != nullptr)
 	if (dynamic_cast<Object *>(u->object) != nullptr)
-		return u->type;
+		return u;
 
 
-	return INVALID_ID;
+	return nullptr;
 }
 }
 
 
 Variant::Variant()
 Variant::Variant()
@@ -71,24 +73,20 @@ Variant::Variant(const char *string, size_t len)
 	}
 	}
 }
 }
 
 
-Variant::Variant(void *userdata)
+Variant::Variant(void *lightuserdata)
 	: type(LUSERDATA)
 	: type(LUSERDATA)
 {
 {
-	data.userdata = userdata;
+	data.userdata = lightuserdata;
 }
 }
 
 
-Variant::Variant(love::Type udatatype, void *userdata)
-	: type(FUSERDATA)
-	, udatatype(udatatype)
+Variant::Variant(love::Type *lovetype, love::Object *object)
+	: type(LOVEOBJECT)
 {
 {
-	if (udatatype != INVALID_ID)
-	{
-		Proxy *p = (Proxy *) userdata;
-		data.userdata = p->object;
-		p->object->retain();
-	}
-	else
-		data.userdata = userdata;
+	data.objectproxy.type = lovetype;
+	data.objectproxy.object = object;
+
+	if (data.objectproxy.object != nullptr)
+		data.objectproxy.object->retain();
 }
 }
 
 
 // Variant gets ownership of the vector.
 // Variant gets ownership of the vector.
@@ -100,20 +98,18 @@ Variant::Variant(std::vector<std::pair<Variant, Variant>> *table)
 
 
 Variant::Variant(const Variant &v)
 Variant::Variant(const Variant &v)
 	: type(v.type)
 	: type(v.type)
-	, udatatype(v.udatatype)
 	, data(v.data)
 	, data(v.data)
 {
 {
 	if (type == STRING)
 	if (type == STRING)
 		data.string->retain();
 		data.string->retain();
-	else if (type == FUSERDATA)
-		((love::Object *) data.userdata)->retain();
+	else if (type == LOVEOBJECT && data.objectproxy.object != nullptr)
+		data.objectproxy.object->retain();
 	else if (type == TABLE)
 	else if (type == TABLE)
 		data.table->retain();
 		data.table->retain();
 }
 }
 
 
 Variant::Variant(Variant &&v)
 Variant::Variant(Variant &&v)
 	: type(std::move(v.type))
 	: type(std::move(v.type))
-	, udatatype(std::move(v.udatatype))
 	, data(std::move(v.data))
 	, data(std::move(v.data))
 {
 {
 	v.type = NIL;
 	v.type = NIL;
@@ -121,49 +117,41 @@ Variant::Variant(Variant &&v)
 
 
 Variant::~Variant()
 Variant::~Variant()
 {
 {
-	switch (type)
-	{
-	case STRING:
+	if (type == STRING)
 		data.string->release();
 		data.string->release();
-		break;
-	case FUSERDATA:
-		((love::Object *) data.userdata)->release();
-		break;
-	case TABLE:
+	else if (type == LOVEOBJECT && data.objectproxy.object != nullptr)
+		data.objectproxy.object->release();
+	else if (type == TABLE)
 		data.table->release();
 		data.table->release();
-		break;
-	default:
-		break;
-	}
 }
 }
 
 
 Variant &Variant::operator = (const Variant &v)
 Variant &Variant::operator = (const Variant &v)
 {
 {
 	if (v.type == STRING)
 	if (v.type == STRING)
 		v.data.string->retain();
 		v.data.string->retain();
-	else if (v.type == FUSERDATA)
-		((love::Object *) v.data.userdata)->retain();
+	else if (v.type == LOVEOBJECT && v.data.objectproxy.object != nullptr)
+		v.data.objectproxy.object->retain();
 	else if (v.type == TABLE)
 	else if (v.type == TABLE)
 		v.data.table->retain();
 		v.data.table->retain();
 
 
 	if (type == STRING)
 	if (type == STRING)
 		data.string->release();
 		data.string->release();
-	else if (type == FUSERDATA)
-		((love::Object *) v.data.userdata)->release();
+	else if (type == LOVEOBJECT && data.objectproxy.object != nullptr)
+		data.objectproxy.object->release();
 	else if (type == TABLE)
 	else if (type == TABLE)
 		data.table->release();
 		data.table->release();
 
 
 	type = v.type;
 	type = v.type;
 	data = v.data;
 	data = v.data;
-	udatatype = v.udatatype;
 
 
 	return *this;
 	return *this;
 }
 }
 
 
-Variant Variant::fromLua(lua_State *L, int n, bool allowTables)
+Variant Variant::fromLua(lua_State *L, int n, std::set<const void*> *tableSet)
 {
 {
 	size_t len;
 	size_t len;
 	const char *str;
 	const char *str;
+	Proxy *p = nullptr;
 
 
 	if (n < 0) // Fix the stack position, we might modify it later
 	if (n < 0) // Fix the stack position, we might modify it later
 		n += lua_gettop(L) + 1;
 		n += lua_gettop(L) + 1;
@@ -180,15 +168,34 @@ Variant Variant::fromLua(lua_State *L, int n, bool allowTables)
 	case LUA_TLIGHTUSERDATA:
 	case LUA_TLIGHTUSERDATA:
 		return Variant(lua_touserdata(L, n));
 		return Variant(lua_touserdata(L, n));
 	case LUA_TUSERDATA:
 	case LUA_TUSERDATA:
-		return Variant(extractudatatype(L, n), lua_touserdata(L, n));
+		p = tryextractproxy(L, n);
+		if (p != nullptr)
+			return Variant(p->type, p->object);
+		else
+		{
+			luax_typerror(L, n, "love type");
+			return Variant();
+		}
 	case LUA_TNIL:
 	case LUA_TNIL:
 		return Variant();
 		return Variant();
 	case LUA_TTABLE:
 	case LUA_TTABLE:
-		if (allowTables)
 		{
 		{
 			bool success = true;
 			bool success = true;
+			std::unique_ptr<std::set<const void*>> tableSetPtr;
 			std::vector<std::pair<Variant, Variant>> *table = new std::vector<std::pair<Variant, Variant>>();
 			std::vector<std::pair<Variant, Variant>> *table = new std::vector<std::pair<Variant, Variant>>();
 
 
+			// If we had no tables argument, allocate one now, and store it in our unique_ptr
+			if (tableSet == nullptr)
+				tableSetPtr.reset(tableSet = new std::set<const void*>);
+
+			// Now make sure this table wasn't already serialised
+			const void *tablePointer = lua_topointer(L, n);
+			{
+				auto result = tableSet->insert(tablePointer);
+				if (!result.second) // insertion failed
+					throw love::Exception("Cycle detected in table");
+			}
+
 			size_t len = luax_objlen(L, -1);
 			size_t len = luax_objlen(L, -1);
 			if (len > 0)
 			if (len > 0)
 				table->reserve(len);
 				table->reserve(len);
@@ -197,7 +204,7 @@ Variant Variant::fromLua(lua_State *L, int n, bool allowTables)
 
 
 			while (lua_next(L, n))
 			while (lua_next(L, n))
 			{
 			{
-				table->emplace_back(fromLua(L, -2), fromLua(L, -1));
+				table->emplace_back(fromLua(L, -2, tableSet), fromLua(L, -1, tableSet));
 				lua_pop(L, 1);
 				lua_pop(L, 1);
 
 
 				const auto &p = table->back();
 				const auto &p = table->back();
@@ -208,6 +215,9 @@ Variant Variant::fromLua(lua_State *L, int n, bool allowTables)
 				}
 				}
 			}
 			}
 
 
+			// And remove the table from the set again
+			tableSet->erase(tablePointer);
+
 			if (success)
 			if (success)
 				return Variant(table);
 				return Variant(table);
 			else
 			else
@@ -240,14 +250,8 @@ void Variant::toLua(lua_State *L) const
 	case LUSERDATA:
 	case LUSERDATA:
 		lua_pushlightuserdata(L, data.userdata);
 		lua_pushlightuserdata(L, data.userdata);
 		break;
 		break;
-	case FUSERDATA:
-		if (udatatype != INVALID_ID)
-			luax_pushtype(L, udatatype, (love::Object *) data.userdata);
-		else
-			lua_pushlightuserdata(L, data.userdata);
-		// I know this is not the same
-		// sadly, however, it's the most
-		// I can do (at the moment).
+	case LOVEOBJECT:
+		luax_pushtype(L, *data.objectproxy.type, data.objectproxy.object);
 		break;
 		break;
 	case TABLE:
 	case TABLE:
 	{
 	{

+ 7 - 6
src/common/Variant.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -27,6 +27,7 @@
 
 
 #include <cstring>
 #include <cstring>
 #include <vector>
 #include <vector>
+#include <set>
 
 
 namespace love
 namespace love
 {
 {
@@ -43,7 +44,7 @@ public:
 		STRING,
 		STRING,
 		SMALLSTRING,
 		SMALLSTRING,
 		LUSERDATA,
 		LUSERDATA,
-		FUSERDATA,
+		LOVEOBJECT,
 		NIL,
 		NIL,
 		TABLE
 		TABLE
 	};
 	};
@@ -52,8 +53,8 @@ public:
 	Variant(bool boolean);
 	Variant(bool boolean);
 	Variant(double number);
 	Variant(double number);
 	Variant(const char *string, size_t len);
 	Variant(const char *string, size_t len);
-	Variant(void *userdata);
-	Variant(love::Type udatatype, void *userdata);
+	Variant(void *lightuserdata);
+	Variant(love::Type *type, love::Object *object);
 	Variant(std::vector<std::pair<Variant, Variant>> *table);
 	Variant(std::vector<std::pair<Variant, Variant>> *table);
 	Variant(const Variant &v);
 	Variant(const Variant &v);
 	Variant(Variant &&v);
 	Variant(Variant &&v);
@@ -63,7 +64,7 @@ public:
 
 
 	Type getType() const { return type; }
 	Type getType() const { return type; }
 
 
-	static Variant fromLua(lua_State *L, int n, bool allowTables = true);
+	static Variant fromLua(lua_State *L, int n, std::set<const void*> *tableSet = nullptr);
 	void toLua(lua_State *L) const;
 	void toLua(lua_State *L) const;
 
 
 private:
 private:
@@ -101,7 +102,6 @@ private:
 	static const int MAX_SMALL_STRING_LENGTH = 15;
 	static const int MAX_SMALL_STRING_LENGTH = 15;
 
 
 	Type type;
 	Type type;
-	love::Type udatatype;
 
 
 	union Data
 	union Data
 	{
 	{
@@ -109,6 +109,7 @@ private:
 		double number;
 		double number;
 		SharedString *string;
 		SharedString *string;
 		void *userdata;
 		void *userdata;
+		Proxy objectproxy;
 		SharedTable *table;
 		SharedTable *table;
 		struct
 		struct
 		{
 		{

+ 1 - 1
src/common/Vector.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 212 - 131
src/common/Vector.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -24,45 +24,26 @@
 // STD
 // STD
 #include <cmath>
 #include <cmath>
 
 
-// LOVE
-#include "Matrix.h"
-
 namespace love
 namespace love
 {
 {
 
 
-/**
- * 2D Vector class.
- *
- * @author Anders Ruud
- * @date 2006-05-13
- **/
-class Vector
+struct Vector2
 {
 {
-public:
-
-	// The components.
 	float x, y;
 	float x, y;
 
 
-	/**
-	 * Creates a new (1,1) Vector.
-	 **/
-	Vector();
+	Vector2()
+		: x(0.0f), y(0.0f)
+	{}
 
 
-	/**
-	 * Creates a new Vector.
-	 * @param x The x position/dimension.
-	 * @param y The y position/dimension.
-	 **/
-	Vector(float x, float y);
+	Vector2(float x, float y)
+		: x(x), y(y)
+	{}
 
 
 	/**
 	/**
 	 * Gets the length of the Vector.
 	 * Gets the length of the Vector.
-	 * @return The length of the Vector.
-	 *
-	 * This method requires sqrtf() and should be used
-	 * carefully.
 	 **/
 	 **/
 	float getLength() const;
 	float getLength() const;
+	float getLengthSquare() const;
 
 
 	/**
 	/**
 	 * Normalizes the Vector.
 	 * Normalizes the Vector.
@@ -76,7 +57,7 @@ public:
 	 * To get the true (normalized) normal, use v.getNormal(1.0f / v.getLength())
 	 * To get the true (normalized) normal, use v.getNormal(1.0f / v.getLength())
 	 * @return A normal to the Vector.
 	 * @return A normal to the Vector.
 	 **/
 	 **/
-	Vector getNormal() const;
+	Vector2 getNormal() const;
 
 
 	/**
 	/**
 	 * Gets a vector perpendicular to the Vector.
 	 * Gets a vector perpendicular to the Vector.
@@ -84,125 +65,177 @@ public:
 	 * @param scale factor to apply.
 	 * @param scale factor to apply.
 	 * @return A normal to the Vector.
 	 * @return A normal to the Vector.
 	 **/
 	 **/
-	Vector getNormal(float scale) const;
+	Vector2 getNormal(float scale) const;
+
+	static inline float dot(const Vector2 &a, const Vector2 &b);
+	static inline float cross(const Vector2 &a, const Vector2 &b);
 
 
 	/**
 	/**
 	 * Adds a Vector to this Vector.
 	 * Adds a Vector to this Vector.
-	 * @param v The Vector we want to add to this Vector.
-	 * @return The resulting Vector.
 	 **/
 	 **/
-	Vector operator + (const Vector &v) const;
+	Vector2 operator + (const Vector2 &v) const;
 
 
 	/**
 	/**
-	 * Substracts a Vector to this Vector.
-	 * @param v The Vector we want to subtract to this Vector.
-	 * @return The resulting Vector.
+	 * Substracts a Vector from this Vector.
 	 **/
 	 **/
-	Vector operator - (const Vector &v) const;
+	Vector2 operator - (const Vector2 &v) const;
 
 
 	/**
 	/**
-	 * Resizes a Vector by a scalar.
-	 * @param s The scalar with which to resize the Vector.
-	 * @return The resulting Vector.
+	 * Component-wise multiplies the Vector by a scalar.
 	 **/
 	 **/
-	Vector operator * (float s) const;
+	Vector2 operator * (float s) const;
 
 
 	/**
 	/**
-	 * Resizes a Vector by a scalar.
-	 * @param s The scalar with which to resize the Vector.
-	 * @return The resulting Vector.
+	 * Component-wise divides the Vector by a scalar.
 	 **/
 	 **/
-	Vector operator / (float s) const;
+	Vector2 operator / (float s) const;
 
 
 	/**
 	/**
-	 * Reverses the Vector.
-	 * @return The reversed Vector.
+	 * Component-wise negates the Vector.
 	 **/
 	 **/
-	Vector operator - () const;
+	Vector2 operator - () const;
 
 
 	/**
 	/**
 	 * Adds a Vector to this Vector, and also saves changes in the first Vector.
 	 * Adds a Vector to this Vector, and also saves changes in the first Vector.
-	 * @param v The Vector we want to add to this Vector.
 	 **/
 	 **/
-	void operator += (const Vector &v);
+	void operator += (const Vector2 &v);
 
 
 	/**
 	/**
 	 * Subtracts a Vector to this Vector, and also saves changes in the first Vector.
 	 * Subtracts a Vector to this Vector, and also saves changes in the first Vector.
-	 * @param v The Vector we want to subtract to this Vector.
 	 **/
 	 **/
-	void operator -= (const Vector &v);
+	void operator -= (const Vector2 &v);
 
 
 	/**
 	/**
 	 * Resizes the Vector, and also saves changes in the first Vector.
 	 * Resizes the Vector, and also saves changes in the first Vector.
-	 * @param s The scalar by which we want to resize the Vector.
 	 **/
 	 **/
 	void operator *= (float s);
 	void operator *= (float s);
 
 
 	/**
 	/**
 	 * Resizes the Vector, and also saves changes in the first Vector.
 	 * Resizes the Vector, and also saves changes in the first Vector.
-	 * @param s The scalar by which we want to resize the Vector.
 	 **/
 	 **/
 	void operator /= (float s);
 	void operator /= (float s);
 
 
+	bool operator == (const Vector2 &v) const;
+	bool operator != (const Vector2 &v) const;
+
+}; // Vector2
+
+
+struct Vector3
+{
+	float x, y, z;
+
+	Vector3()
+		: x(0.0f), y(0.0f), z(0.0f)
+	{}
+
+	Vector3(float x, float y, float z)
+		: x(x), y(y), z(z)
+	{}
+
+	Vector3(const Vector2 &v)
+		: x(v.x), y(v.y), z(0.0f)
+	{}
+
+	/**
+	 * Gets the length of the Vector.
+	 **/
+	float getLength() const;
+	float getLengthSquare() const;
+
+	/**
+	 * Normalizes the Vector.
+	 * @param length Desired length of the vector.
+	 * @return The old length of the Vector.
+	 **/
+	float normalize(float length = 1.0);
+
+	static inline float dot(const Vector3 &a, const Vector3 &b);
+	static inline Vector3 cross(const Vector3 &a, const Vector3 &b);
+
+	/**
+	 * Adds a Vector to this Vector.
+	 **/
+	Vector3 operator + (const Vector3 &v) const;
+
+	/**
+	 * Substracts a Vector from this Vector.
+	 **/
+	Vector3 operator - (const Vector3 &v) const;
+
 	/**
 	/**
-	 * Calculates the dot product of two Vectors.
-	 * @return The dot product of the two Vectors.
+	 * Component-wise multiplies the Vector by a scalar.
 	 **/
 	 **/
-	float operator * (const Vector &v) const;
+	Vector3 operator * (float s) const;
 
 
 	/**
 	/**
-	 * Calculates the cross product of two Vectors.
-	 * @return The cross product of the two Vectors.
+	 * Component-wise divides the Vector by a scalar.
 	 **/
 	 **/
-	float operator ^ (const Vector &v) const;
+	Vector3 operator / (float s) const;
 
 
-	bool operator == (const Vector &v) const;
+	/**
+	 * Component-wise negates the Vector.
+	 **/
+	Vector3 operator - () const;
 
 
-	bool operator < (const Vector &v) const;
 	/**
 	/**
-	 * Gets the x value of the Vector.
-	 * @return The x value of the Vector.
+	 * Adds a Vector to this Vector, and also saves changes in the first Vector.
 	 **/
 	 **/
-	float getX() const;
+	void operator += (const Vector3 &v);
 
 
 	/**
 	/**
-	 * Gets the x value of the Vector.
-	 * @return The x value of the Vector.
+	 * Subtracts a Vector to this Vector, and also saves changes in the first Vector.
 	 **/
 	 **/
-	float getY() const;
+	void operator -= (const Vector3 &v);
 
 
 	/**
 	/**
-	 * Sets the x value of the Vector.
-	 * @param x The x value of the Vector.
+	 * Resizes the Vector, and also saves changes in the first Vector.
 	 **/
 	 **/
-	void setX(float x);
+	void operator *= (float s);
 
 
 	/**
 	/**
-	 * Sets the x value of the Vector.
-	 * @param y The x value of the Vector.
+	 * Resizes the Vector, and also saves changes in the first Vector.
 	 **/
 	 **/
-	void setY(float y);
+	void operator /= (float s);
+
+	bool operator == (const Vector3 &v) const;
+	bool operator != (const Vector3 &v) const;
+
+}; // Vector3
 
 
-};
 
 
-inline float Vector::getLength() const
+inline float Vector2::getLength() const
 {
 {
 	return sqrtf(x*x + y*y);
 	return sqrtf(x*x + y*y);
 }
 }
 
 
-inline Vector Vector::getNormal() const
+inline float Vector2::getLengthSquare() const
 {
 {
-	return Vector(-y, x);
+	return x*x + y*y;
 }
 }
 
 
-inline Vector Vector::getNormal(float scale) const
+inline Vector2 Vector2::getNormal() const
 {
 {
-	return Vector(-y * scale, x * scale);
+	return Vector2(-y, x);
 }
 }
 
 
-inline float Vector::normalize(float length)
+inline Vector2 Vector2::getNormal(float scale) const
 {
 {
+	return Vector2(-y * scale, x * scale);
+}
+
+inline float Vector2::dot(const Vector2 &a, const Vector2 &b)
+{
+	return a.x * b.x + a.y * b.y;
+}
+
+inline float Vector2::cross(const Vector2 &a, const Vector2 &b)
+{
+	return a.x * b.y - a.y * b.x;
+}
 
 
+inline float Vector2::normalize(float length)
+{
 	float length_current = getLength();
 	float length_current = getLength();
 
 
 	if (length_current > 0)
 	if (length_current > 0)
@@ -211,113 +244,161 @@ inline float Vector::normalize(float length)
 	return length_current;
 	return length_current;
 }
 }
 
 
-/**
- * Inline methods must have body in header.
- **/
+inline Vector2 Vector2::operator + (const Vector2 &v) const
+{
+	return Vector2(x + v.x, y + v.y);
+}
 
 
-inline Vector::Vector()
-	: x(0.0f)
-	, y(0.0f)
+inline Vector2 Vector2::operator - (const Vector2 &v) const
 {
 {
+	return Vector2(x - v.x, y - v.y);
 }
 }
 
 
-inline Vector::Vector(float x, float y)
-	: x(x)
-	, y(y)
+inline Vector2 Vector2::operator * (float s) const
 {
 {
+	return Vector2(x*s, y*s);
 }
 }
 
 
-inline Vector Vector::operator + (const Vector &v) const
+inline Vector2 Vector2::operator / (float s) const
 {
 {
-	return Vector(x + v.x, y + v.y);
+	float invs = 1.0f / s;
+	return Vector2(x*invs, y*invs);
 }
 }
 
 
-inline Vector Vector::operator - (const Vector &v) const
+inline Vector2 Vector2::operator - () const
 {
 {
-	return Vector(x - v.getX(), y - v.getY());
+	return Vector2(-x, -y);
 }
 }
 
 
-inline Vector Vector::operator * (float s) const
+inline void Vector2::operator += (const Vector2 &v)
 {
 {
-	return Vector(x*s, y*s);
+	x += v.x;
+	y += v.y;
 }
 }
 
 
-inline Vector Vector::operator / (float s) const
+inline void Vector2::operator -= (const Vector2 &v)
 {
 {
-	return Vector(x/s, y/s);
+	x -= v.x;
+	y -= v.y;
 }
 }
 
 
-inline Vector Vector::operator - () const
+inline void Vector2::operator *= (float s)
 {
 {
-	return Vector(-x, -y);
+	x *= s;
+	y *= s;
 }
 }
 
 
-inline void Vector::operator += (const Vector &v)
+inline void Vector2::operator /= (float s)
 {
 {
-	x += v.getX();
-	y += v.getY();
+	float invs = 1.0f / s;
+	x *= invs;
+	y *= invs;
 }
 }
 
 
-inline void Vector::operator -= (const Vector &v)
+inline bool Vector2::operator == (const Vector2 &v) const
 {
 {
-	x -= v.getX();
-	y -= v.getY();
+	return x == v.x && y == v.y;
 }
 }
 
 
-inline void Vector::operator *= (float s)
+inline bool Vector2::operator != (const Vector2 &v) const
 {
 {
-	x *= s;
-	y *= s;
+	return x != v.x || y != v.y;
 }
 }
 
 
-inline void Vector::operator /= (float s)
+
+inline float Vector3::getLength() const
 {
 {
-	x /= s;
-	y /= s;
+	return sqrtf(x*x + y*y + z*z);
 }
 }
 
 
-inline float Vector::operator * (const Vector &v) const
+inline float Vector3::getLengthSquare() const
 {
 {
-	return x * v.getX() + y * v.getY();
+	return x*x + y*y + z*z;
 }
 }
 
 
-inline float Vector::operator ^ (const Vector &v) const
+inline float Vector3::dot(const Vector3 &a, const Vector3 &b)
 {
 {
-	return x * v.getY() - y * v.getX();
+	return a.x * b.x + a.y * b.y + a.z * b.z;
 }
 }
 
 
-inline bool Vector::operator == (const Vector &v) const
+inline Vector3 Vector3::cross(const Vector3 &a, const Vector3 &b)
 {
 {
-	return getLength() == v.getLength();
+	return Vector3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
 }
 }
 
 
-inline bool Vector::operator < (const Vector &v) const
+inline float Vector3::normalize(float length)
 {
 {
-	return getLength() < v.getLength();
+	float length_current = getLength();
+
+	if (length_current > 0)
+		(*this) *= length / length_current;
+
+	return length_current;
 }
 }
 
 
-/**
- * Accessor methods
- **/
+inline Vector3 Vector3::operator + (const Vector3 &v) const
+{
+	return Vector3(x + v.x, y + v.y, z + v.z);
+}
+
+inline Vector3 Vector3::operator - (const Vector3 &v) const
+{
+	return Vector3(x - v.x, y - v.y, z - v.z);
+}
+
+inline Vector3 Vector3::operator * (float s) const
+{
+	return Vector3(x*s, y*s, z*s);
+}
+
+inline Vector3 Vector3::operator / (float s) const
+{
+	float invs = 1.0f / s;
+	return Vector3(x*invs, y*invs, z*invs);
+}
 
 
-inline float Vector::getX() const
+inline Vector3 Vector3::operator - () const
 {
 {
-	return x;
+	return Vector3(-x, -y, -z);
+}
+
+inline void Vector3::operator += (const Vector3 &v)
+{
+	x += v.x;
+	y += v.y;
+	z += v.z;
+}
+
+inline void Vector3::operator -= (const Vector3 &v)
+{
+	x -= v.x;
+	y -= v.y;
+	z -= v.z;
+}
+
+inline void Vector3::operator *= (float s)
+{
+	x *= s;
+	y *= s;
+	z *= s;
 }
 }
 
 
-inline float Vector::getY() const
+inline void Vector3::operator /= (float s)
 {
 {
-	return y;
+	float invs = 1.0f / s;
+	x *= invs;
+	y *= invs;
+	z *= invs;
 }
 }
 
 
-inline void Vector::setX(float x)
+inline bool Vector3::operator == (const Vector3 &v) const
 {
 {
-	this->x = x;
+	return x == v.x && y == v.y && z == v.z;
 }
 }
 
 
-inline void Vector::setY(float y)
+inline bool Vector3::operator != (const Vector3 &v) const
 {
 {
-	this->y = y;
+	return x != v.x || y != v.y || z != v.z;
 }
 }
 
 
 } //love
 } //love

+ 1 - 1
src/common/android.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/android.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 112 - 19
src/common/b64.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -19,12 +19,98 @@
  **/
  **/
 
 
 #include "b64.h"
 #include "b64.h"
+#include "Exception.h"
+
+#include <limits>
+#include <stdio.h>
 
 
 namespace love
 namespace love
 {
 {
 
 
+// Translation table as described in RFC1113
+static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+// Translation table to decode (created by Bob Trower)
 static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
 static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
 
 
+/**
+ * encode 3 8-bit binary bytes as 4 '6-bit' characters
+ **/
+static void b64_encode_block(char in[3], char out[4], int len)
+{
+	out[0] = (char) cb64[(int)(in[0] >> 2)];
+	out[1] = (char) cb64[(int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4))];
+	out[2] = (char) (len > 1 ? cb64[(int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6))] : '=');
+	out[3] = (char) (len > 2 ? cb64[(int)(in[2] & 0x3f)] : '=');
+}
+
+char *b64_encode(const char *src, size_t srclen, size_t linelen, size_t &dstlen)
+{
+	if (linelen == 0)
+		linelen = std::numeric_limits<size_t>::max();
+
+	size_t blocksout = 0;
+	size_t srcpos = 0;
+
+	size_t adjustment = (srclen % 3) ? (3 - (srclen % 3)) : 0;
+	size_t paddedlen = ((srclen + adjustment) / 3) * 4;
+
+	dstlen = paddedlen + paddedlen / linelen;
+
+	if (dstlen == 0)
+		return nullptr;
+
+	char *dst = nullptr;
+	try
+	{
+		dst = new char[dstlen + 1];
+	}
+	catch (std::exception &)
+	{
+		throw love::Exception("Out of memory.");
+	}
+
+	size_t dstpos = 0;
+
+	while (srcpos < srclen)
+	{
+		char in[3]  = {0};
+		char out[4] = {0};
+
+		int len = 0;
+
+		for (int i = 0; i < 3; i++)
+		{
+			if (srcpos >= srclen)
+				break;
+
+			in[i] = src[srcpos++];
+			len++;
+		}
+
+		if (len > 0)
+		{
+			b64_encode_block(in, out, len);
+
+			for (int i = 0; i < 4 && dstpos < dstlen; i++, dstpos++)
+				dst[dstpos] = out[i];
+
+			blocksout++;
+		}
+
+		if (blocksout >= linelen / 4 || srcpos >= srclen)
+		{
+			if (blocksout > 0 && dstpos < dstlen)
+				dst[dstpos++] = '\n';
+
+			blocksout = 0;
+		}
+	}
+
+	dst[dstpos] = '\0';
+	return dst;
+}
+
 static void b64_decode_block(char in[4], char out[3])
 static void b64_decode_block(char in[4], char out[3])
 {
 {
 	out[0] = (char)(in[0] << 2 | in[1] >> 4);
 	out[0] = (char)(in[0] << 2 | in[1] >> 4);
@@ -32,36 +118,44 @@ static void b64_decode_block(char in[4], char out[3])
 	out[2] = (char)(((in[2] << 6) & 0xc0) | in[3]);
 	out[2] = (char)(((in[2] << 6) & 0xc0) | in[3]);
 }
 }
 
 
-char *b64_decode(const char *src, int slen, int &size)
+char *b64_decode(const char *src, size_t srclen, size_t &size)
 {
 {
-	// Actual output may be smaller due to padding and/or whitespace in the
-	// base64-encoded string.
-	int max_size = (slen / 4) * 3;
+	size_t paddedsize = (srclen / 4) * 3;
+
+	char *dst = nullptr;
+	try
+	{
+		dst = new char[paddedsize];
+	}
+	catch (std::exception &)
+	{
+		throw love::Exception("Out of memory.");
+	}
 
 
-	char *dst = new char[max_size];
 	char *d = dst;
 	char *d = dst;
 
 
-	char in[4] = {0}, out[3], v;
-	int i, len, pos = 0;
+	char in[4]  = {0};
+	char out[3] = {0};
+	size_t i, len, srcpos = 0;
 
 
-	while (pos <= slen)
+	while (srcpos <= srclen)
 	{
 	{
-		for (len = 0, i = 0; i < 4 && pos <= slen; i++)
+		for (len = 0, i = 0; i < 4 && srcpos <= srclen; i++)
 		{
 		{
-			v = 0;
+			char v = 0;
 
 
-			while (pos <= slen && v == 0)
+			while (srcpos <= srclen && v == 0)
 			{
 			{
-				v = src[pos++];
+				v = src[srcpos++];
 				v = (char)((v < 43 || v > 122) ? 0 : cd64[v - 43]);
 				v = (char)((v < 43 || v > 122) ? 0 : cd64[v - 43]);
-				if (v)
+				if (v != 0)
 					v = (char)((v == '$') ? 0 : v - 61);
 					v = (char)((v == '$') ? 0 : v - 61);
 			}
 			}
 
 
-			if (pos <= slen)
+			if (srcpos <= srclen)
 			{
 			{
 				len++;
 				len++;
-				if (v)
+				if (v != 0)
 					in[i] = (char)(v - 1);
 					in[i] = (char)(v - 1);
 			}
 			}
 			else
 			else
@@ -72,12 +166,11 @@ char *b64_decode(const char *src, int slen, int &size)
 		{
 		{
 			b64_decode_block(in, out);
 			b64_decode_block(in, out);
 			for (i = 0; i < len - 1; i++)
 			for (i = 0; i < len - 1; i++)
-				*(d++) = out[i];
+				 *(d++) = out[i];
 		}
 		}
 	}
 	}
 
 
-	size = int(d - dst);
-
+	size = (size_t)(ptrdiff_t) (d - dst);
 	return dst;
 	return dst;
 }
 }
 
 

+ 18 - 4
src/common/b64.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -20,21 +20,35 @@
 
 
 #include "config.h"
 #include "config.h"
 
 
+#include <stddef.h>
+
 #ifndef LOVE_B64_H
 #ifndef LOVE_B64_H
 #define LOVE_B64_H
 #define LOVE_B64_H
 
 
 namespace love
 namespace love
 {
 {
 
 
+/**
+ * Base64-encode data.
+ *
+ * @param src The data to encode.
+ * @param srclen The size in bytes of the data.
+ * @param linelen The maximum length of each line in the encoded string.
+ *        0 indicates no maximum length.
+ * @param dstlen The length of the encoded string is stored here.
+ * @return A string containing the base64-encoded data (allocated with new[]).
+ */
+char *b64_encode(const char *src, size_t srclen, size_t linelen, size_t &dstlen);
+
 /**
 /**
  * Decode base64 encoded data.
  * Decode base64 encoded data.
  *
  *
  * @param src The string containing the base64 data.
  * @param src The string containing the base64 data.
- * @param slen The length of the string.
- * @param size The size of the binary data is stored here.
+ * @param srclen The length of the string.
+ * @param dstlen The size of the binary data is stored here.
  * @return A chunk of memory containing the binary data (allocated with new[]).
  * @return A chunk of memory containing the binary data (allocated with new[]).
  */
  */
-char *b64_decode(const char *src, int slen, int &size);
+char *b64_decode(const char *src, size_t srclen, size_t &dstlen);
 
 
 } // love
 } // love
 
 

+ 34 - 29
src/common/config.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -26,7 +26,7 @@
 #	define LOVE_WINDOWS 1
 #	define LOVE_WINDOWS 1
 	// If _USING_V110_SDK71_ is defined it means we are using the xp toolset.
 	// If _USING_V110_SDK71_ is defined it means we are using the xp toolset.
 #	if defined(_MSC_VER) && (_MSC_VER >= 1700) && !_USING_V110_SDK71_
 #	if defined(_MSC_VER) && (_MSC_VER >= 1700) && !_USING_V110_SDK71_
-#	include <winapifamily.h>
+#		include <winapifamily.h>
 #		if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
 #		if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
 #			define LOVE_WINDOWS_UWP 1
 #			define LOVE_WINDOWS_UWP 1
 #			define LOVE_NO_MODPLUG 1
 #			define LOVE_NO_MODPLUG 1
@@ -60,6 +60,22 @@
 #	define LOVE_LITTLE_ENDIAN 1
 #	define LOVE_LITTLE_ENDIAN 1
 #endif
 #endif
 
 
+// SSE instructions.
+#if defined(__SSE__)
+#	define LOVE_SIMD_SSE
+#elif defined(_MSC_VER)
+#	if defined(_M_AMD64) || defined(_M_X64)
+#		define LOVE_SIMD_SSE
+#	elif _M_IX86_FP
+#		define LOVE_SIMD_SSE
+#	endif
+#endif
+
+// NEON instructions.
+#if defined(__ARM_NEON)
+#	define LOVE_SIMD_NEON
+#endif
+
 // Warnings.
 // Warnings.
 #ifndef _CRT_SECURE_NO_WARNINGS
 #ifndef _CRT_SECURE_NO_WARNINGS
 #	define _CRT_SECURE_NO_WARNINGS
 #	define _CRT_SECURE_NO_WARNINGS
@@ -70,6 +86,16 @@
 #	define LOVE_UNUSED(x) (void)sizeof(x)
 #	define LOVE_UNUSED(x) (void)sizeof(x)
 #endif
 #endif
 
 
+
+// Warn on unused return values
+#ifdef __GNUC__
+#	define LOVE_WARN_UNUSED __attribute__((warn_unused_result))
+#elif _MSC_VER
+#	define LOVE_WARN_UNUSED _Check_return_
+#else
+#	define LOVE_WARN_UNUSED
+#endif
+
 #ifndef LOVE_BUILD
 #ifndef LOVE_BUILD
 #	define LOVE_BUILD
 #	define LOVE_BUILD
 #	define LOVE_BUILD_STANDALONE
 #	define LOVE_BUILD_STANDALONE
@@ -111,51 +137,30 @@
 #		define LOVE_LITTLE_ENDIAN 1
 #		define LOVE_LITTLE_ENDIAN 1
 #	endif
 #	endif
 #else
 #else
+#	define LOVE_ENABLE_LOVE
 #	define LOVE_ENABLE_AUDIO
 #	define LOVE_ENABLE_AUDIO
-#	define LOVE_ENABLE_AUDIO_NULL
-#	define LOVE_ENABLE_AUDIO_OPENAL
-#	define LOVE_ENABLE_BOX2D
-#	define LOVE_ENABLE_DDSPARSE
-#	define LOVE_ENABLE_ENET
+#	define LOVE_ENABLE_DATA
 #	define LOVE_ENABLE_EVENT
 #	define LOVE_ENABLE_EVENT
-#	define LOVE_ENABLE_EVENT_SDL
 #	define LOVE_ENABLE_FILESYSTEM
 #	define LOVE_ENABLE_FILESYSTEM
-#	define LOVE_ENABLE_FILESYSTEM_PHYSFS
 #	define LOVE_ENABLE_FONT
 #	define LOVE_ENABLE_FONT
-#	define LOVE_ENABLE_FONT_FREETYPE
 #	define LOVE_ENABLE_GRAPHICS
 #	define LOVE_ENABLE_GRAPHICS
-#	define LOVE_ENABLE_GRAPHICS_OPENGL
 #	define LOVE_ENABLE_IMAGE
 #	define LOVE_ENABLE_IMAGE
-#	define LOVE_ENABLE_IMAGE_MAGPIE
 #	define LOVE_ENABLE_JOYSTICK
 #	define LOVE_ENABLE_JOYSTICK
-#	define LOVE_ENABLE_JOYSTICK_SDL
 #	define LOVE_ENABLE_KEYBOARD
 #	define LOVE_ENABLE_KEYBOARD
-#	define LOVE_ENABLE_KEYBOARD_SDL
-#	define LOVE_ENABLE_LOVE
-#	define LOVE_ENABLE_LUASOCKET
-#	define LOVE_ENABLE_LUAUTF8
 #	define LOVE_ENABLE_MATH
 #	define LOVE_ENABLE_MATH
 #	define LOVE_ENABLE_MOUSE
 #	define LOVE_ENABLE_MOUSE
-#	define LOVE_ENABLE_MOUSE_SDL
-#	define LOVE_ENABLE_NOISE1234
 #	define LOVE_ENABLE_PHYSICS
 #	define LOVE_ENABLE_PHYSICS
-#	define LOVE_ENABLE_PHYSICS_BOX2D
 #	define LOVE_ENABLE_SOUND
 #	define LOVE_ENABLE_SOUND
-#	define LOVE_ENABLE_SOUND_LULLABY
 #	define LOVE_ENABLE_SYSTEM
 #	define LOVE_ENABLE_SYSTEM
-#	define LOVE_ENABLE_SYSTEM_SDL
 #	define LOVE_ENABLE_THREAD
 #	define LOVE_ENABLE_THREAD
-#	define LOVE_ENABLE_THREAD_SDL
 #	define LOVE_ENABLE_TIMER
 #	define LOVE_ENABLE_TIMER
-#	define LOVE_ENABLE_TIMER_SDL
 #	define LOVE_ENABLE_TOUCH
 #	define LOVE_ENABLE_TOUCH
-#	define LOVE_ENABLE_TOUCH_SDL
-#	define LOVE_ENABLE_UTF8
 #	define LOVE_ENABLE_VIDEO
 #	define LOVE_ENABLE_VIDEO
-#	define LOVE_ENABLE_VIDEO_THEORA
 #	define LOVE_ENABLE_WINDOW
 #	define LOVE_ENABLE_WINDOW
-#	define LOVE_ENABLE_WINDOW_SDL
-#	define LOVE_ENABLE_WUFF
+
+#	define LOVE_ENABLE_ENET
+#	define LOVE_ENABLE_LUASOCKET
+#	define LOVE_ENABLE_LUA53
 #endif
 #endif
 
 
 // Check we have a sane configuration
 // Check we have a sane configuration

+ 3 - 1
src/common/delay.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -27,6 +27,8 @@ namespace love
 
 
 void sleep(unsigned int ms)
 void sleep(unsigned int ms)
 {
 {
+	// We don't need to initialize the SDL timer subsystem for SDL_Delay to
+	// function - and doing so causes SDL to create a worker thread.
 	SDL_Delay(ms);
 	SDL_Delay(ms);
 }
 }
 
 

+ 1 - 1
src/common/delay.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 187 - 0
src/common/deprecation.cpp

@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "common/config.h"
+#include "deprecation.h"
+#include "thread/threads.h"
+
+#include <atomic>
+#include <map>
+
+namespace love
+{
+
+static std::map<std::string, DeprecationInfo> *deprecated = nullptr;
+static std::vector<const DeprecationInfo *> *deprecatedList = nullptr;
+
+static std::atomic<int> initCount;
+
+static thread::Mutex *mutex = nullptr;
+static bool outputEnabled = false;
+
+void initDeprecation()
+{
+	if (initCount.fetch_add(1) == 0)
+	{
+		mutex = thread::newMutex();
+
+		// These are heap-allocated because we want to clear them on deinit,
+		// and deinit may be called when the program is shutting down in the
+		// middle of static variable cleanup (eg in the Math module destructor).
+		// Calling std::map::clear() in that case was causing segfaults.
+		deprecated = new std::map<std::string, DeprecationInfo>();
+		deprecatedList = new std::vector<const DeprecationInfo *>();
+	}
+}
+
+void deinitDeprecation()
+{
+	if (initCount.fetch_sub(1) == 1)
+	{
+		delete deprecated;
+		delete deprecatedList;
+		delete mutex;
+
+		deprecated = nullptr;
+		deprecatedList = nullptr;
+		mutex = nullptr;
+	}
+}
+
+static void printDeprecationNotice(const DeprecationInfo &info)
+{
+	std::string notice = getDeprecationNotice(info, true);
+	printf("LOVE - Warning: %s\n", notice.c_str());
+}
+
+void setDeprecationOutputEnabled(bool enable)
+{
+	if (enable == outputEnabled)
+		return;
+
+	outputEnabled = enable;
+
+	if (enable)
+	{
+		GetDeprecated deprecated;
+
+		for (const DeprecationInfo *info : deprecated.all)
+		{
+			if (info->uses == 1)
+				printDeprecationNotice(*info);
+		}
+	}
+}
+
+bool isDeprecationOutputEnabled()
+{
+	return outputEnabled;
+}
+
+std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere)
+{
+	std::string notice;
+
+	if (usewhere)
+		notice += info.where;
+
+	notice += "Using deprecated ";
+
+	if (info.apiType == API_FUNCTION)
+		notice += "function ";
+	else if (info.apiType == API_METHOD)
+		notice += "method ";
+	else if (info.apiType == API_FIELD)
+		notice += "field ";
+	else if (info.apiType == API_CONSTANT)
+		notice += "constant ";
+	else
+		notice += "API ";
+
+	notice += info.name;
+
+	if (info.type == DEPRECATED_REPLACED && !info.replacement.empty())
+		notice += " (replaced by " + info.replacement + ")";
+	else if (info.type == DEPRECATED_RENAMED && !info.replacement.empty())
+		notice += " (renamed to " + info.replacement + ")";
+
+	return notice;
+}
+
+GetDeprecated::GetDeprecated()
+	: all(*deprecatedList)
+{
+	if (mutex != nullptr)
+		mutex->lock();
+}
+
+GetDeprecated::~GetDeprecated()
+{
+	if (mutex != nullptr)
+		mutex->unlock();
+}
+
+MarkDeprecated::MarkDeprecated(const char *name, APIType api)
+	: MarkDeprecated(name, api, DEPRECATED_NO_REPLACEMENT, nullptr)
+{
+}
+
+MarkDeprecated::MarkDeprecated(const char *name, APIType api, DeprecationType type, const char *replacement)
+	: info(nullptr)
+{
+	if (mutex != nullptr)
+		mutex->lock();
+
+	auto it = deprecated->find(name);
+
+	if (it != deprecated->end())
+	{
+		it->second.uses++;
+		info = &it->second;
+	}
+	else
+	{
+		DeprecationInfo newinfo = {};
+
+		newinfo.type = type;
+		newinfo.apiType = api;
+		newinfo.uses = 1;
+		newinfo.name = name;
+
+		if (replacement != nullptr)
+			newinfo.replacement = replacement;
+
+		auto inserted = deprecated->insert(std::make_pair(newinfo.name, newinfo));
+
+		info = &inserted.first->second;
+		deprecatedList->push_back(info);
+	}
+}
+
+MarkDeprecated::~MarkDeprecated()
+{
+	if (outputEnabled && info != nullptr && info->uses == 1)
+		printDeprecationNotice(*info);
+
+	if (mutex != nullptr)
+		mutex->unlock();
+}
+
+} // love

+ 81 - 0
src/common/deprecation.h

@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#pragma once
+
+#include "int.h"
+
+#include <string>
+#include <vector>
+
+namespace love
+{
+
+enum APIType
+{
+	API_FUNCTION,
+	API_METHOD,
+	API_FIELD,
+	API_CONSTANT,
+};
+
+enum DeprecationType
+{
+	DEPRECATED_NO_REPLACEMENT,
+	DEPRECATED_REPLACED,
+	DEPRECATED_RENAMED,
+};
+
+struct DeprecationInfo
+{
+	DeprecationType type;
+	APIType apiType;
+	int64 uses;
+	std::string name;
+	std::string replacement;
+	std::string where;
+};
+
+void initDeprecation();
+void deinitDeprecation();
+
+void setDeprecationOutputEnabled(bool enable);
+bool isDeprecationOutputEnabled();
+
+std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere);
+
+struct GetDeprecated
+{
+	GetDeprecated();
+	~GetDeprecated();
+
+	const std::vector<const DeprecationInfo *> &all;
+};
+
+struct MarkDeprecated
+{
+	MarkDeprecated(const char *name, APIType api);
+	MarkDeprecated(const char *name, APIType api, DeprecationType type, const char *replacement);
+	~MarkDeprecated();
+
+	DeprecationInfo *info;
+};
+
+} // love

+ 156 - 0
src/common/halffloat.cpp

@@ -0,0 +1,156 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "halffloat.h"
+
+namespace love
+{
+
+// Code from ftp://www.fox-toolkit.org/pub/fasthalffloatconversion.pdf
+
+static bool initialized = false;
+
+// tables for half -> float conversions
+static uint32 mantissatable[2048];
+static uint16 offsettable[64];
+static uint32 exponenttable[64];
+
+// tables for float -> half conversions
+static uint16 basetable[512];
+static uint8 shifttable[512];
+
+
+static uint32 convertMantissa(uint32 i)
+{
+	uint32 m = i << 13; // Zero pad mantissa bits
+	uint32 e = 0; // Zero exponent
+
+	while (!(m & 0x00800000)) // While not normalized
+	{
+		e -= 0x00800000; // Decrement exponent (1<<23)
+		m <<= 1; // Shift mantissa
+	}
+
+	m &= ~(0x00800000); // Clear leading 1 bit
+	e += 0x38800000; // Adjust bias ((127-14)<<23)
+
+	return m | e; // Return combined number
+}
+
+void halfInit()
+{
+	if (initialized)
+		return;
+
+	initialized = true;
+
+
+	// tables for half -> float conversions.
+
+	mantissatable[0] = 0;
+
+	for (uint32 i = 1; i < 1024; i++)
+		mantissatable[i] = convertMantissa(i);
+
+	for (uint32 i = 1024; i < 2048; i++)
+		mantissatable[i] = 0x38000000 + ((i - 1024) << 13);
+
+	exponenttable[0] = 0;
+	exponenttable[32] = 0x80000000;
+
+	for (uint32 i = 0; i < 31; i++)
+		exponenttable[i] = i << 23;
+
+	for (uint32 i = 33; i < 63; i++)
+		exponenttable[i] = 0x80000000 + ((i - 32) << 23);
+
+	exponenttable[31] = 0x47800000;
+	exponenttable[63] = 0xC7800000;
+
+	for (int i = 0; i < 64; i++)
+	{
+		if (i == 0 || i == 32)
+			offsettable[i] = 0;
+		else
+			offsettable[i] = 1024;
+	}
+
+
+	// tables for float -> half conversions.
+
+	for (uint32 i = 0; i < 256; i++)
+	{
+		int e = (int) i - 127;
+
+		if (e < -24) // Very small numbers map to zero
+		{
+			basetable[i | 0x000] = 0x0000;
+			basetable[i | 0x100] = 0x8000;
+			shifttable[i | 0x000] = 24;
+			shifttable[i | 0x100] = 24;
+		}
+		else if (e < -14) // Small numbers map to denorms
+		{
+			basetable[i | 0x000] = (0x0400 >> (-e - 14));
+			basetable[i | 0x100] = (0x0400 >> (-e - 14)) | 0x8000;
+			shifttable[i | 0x000] = -e - 1;
+			shifttable[i | 0x100] = -e - 1;
+		}
+		else if (e <= 15) // Normal numbers just lose precision
+		{
+			basetable[i | 0x000] = ((e + 15) << 10);
+			basetable[i | 0x100] = ((e + 15) << 10) | 0x8000;
+			shifttable[i | 0x000] = 13;
+			shifttable[i | 0x100] = 13;
+		}
+		else if (e < 128) // Large numbers map to Infinity
+		{
+			basetable[i | 0x000] = 0x7C00;
+			basetable[i | 0x100] = 0xFC00;
+			shifttable[i | 0x000] = 24;
+			shifttable[i | 0x100] = 24;
+		}
+		else // Infinity and NaN's stay Infinity and NaN's
+		{
+			basetable[i | 0x000] = 0x7C00;
+			basetable[i | 0x100] = 0xFC00;
+			shifttable[i | 0x000] = 13;
+			shifttable[i | 0x100] = 13;
+		}
+	}
+}
+
+float halfToFloat(half h)
+{
+	union { float f; uint32 i; } conv;
+
+	conv.i = mantissatable[offsettable[h >> 10] + (h & 0x3FF)] + exponenttable[h >> 10];
+	return conv.f;
+}
+
+half floatToHalf(float f)
+{
+	union { float f; uint32 i; } conv;
+	conv.f = f;
+
+	return basetable[(conv.i >> 23) & 0x1FF] + ((conv.i & 0x007FFFFF) >> shifttable[(conv.i >> 23) & 0x1FF]);
+}
+
+} // love

+ 38 - 0
src/common/halffloat.h

@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_HALF_FLOAT_H
+#define LOVE_HALF_FLOAT_H
+
+#include "int.h"
+
+namespace love
+{
+
+typedef uint16 half;
+
+void halfInit();
+
+float halfToFloat(half h);
+half floatToHalf(float f);
+
+} // love
+
+#endif // LOVE_HALF_FLOAT_H

+ 1 - 1
src/common/int.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/ios.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/ios.mm

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/macosx.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/macosx.mm

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 9 - 5
src/common/math.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -61,11 +61,15 @@
 namespace love
 namespace love
 {
 {
 
 
-struct Vertex
+struct Rect
 {
 {
-	float x, y;
-	float s, t;
-	unsigned char r, g, b, a;
+	int x, y;
+	int w, h;
+
+	bool operator == (const Rect &rhs) const
+	{
+		return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
+	}
 };
 };
 
 
 inline int nextP2(int x)
 inline int nextP2(int x)

+ 70 - 0
src/common/memory.cpp

@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "config.h"
+#include "memory.h"
+
+#include <stdlib.h>
+
+#ifdef LOVE_WINDOWS
+#include <malloc.h>
+#else
+#include <unistd.h> // Assume POSIX support.
+#endif
+
+namespace love
+{
+
+bool alignedMalloc(void **mem, size_t size, size_t alignment)
+{
+#ifdef LOVE_WINDOWS
+	*mem = _aligned_malloc(size, alignment);
+	return *mem != nullptr;
+#else
+	return posix_memalign(mem, alignment, size) == 0;
+#endif
+}
+
+void alignedFree(void *mem)
+{
+#ifdef LOVE_WINDOWS
+	_aligned_free(mem);
+#else
+	free(mem);
+#endif
+}
+
+size_t getPageSize()
+{
+#ifdef LOVE_WINDOWS
+	// TODO: Do an actual query.
+	return 4096;
+#else
+	static const long size = sysconf(_SC_PAGESIZE);
+	return size > 0 ? (size_t) size : 4096;
+#endif
+}
+
+size_t alignUp(size_t size, size_t alignment)
+{
+	return (size + alignment - 1) & (~(alignment - 1));
+}
+
+} // love

+ 38 - 0
src/common/memory.h

@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#pragma once
+
+#include <stddef.h>
+
+namespace love
+{
+
+bool alignedMalloc(void **mem, size_t size, size_t alignment);
+void alignedFree(void *mem);
+
+size_t getPageSize();
+
+/**
+ * 'alignment' must be a power of two.
+ **/
+size_t alignUp(size_t size, size_t alignment);
+
+} // love

+ 179 - 0
src/common/pixelformat.cpp

@@ -0,0 +1,179 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "pixelformat.h"
+#include "StringMap.h"
+
+namespace love
+{
+
+static StringMap<PixelFormat, PIXELFORMAT_MAX_ENUM>::Entry formatEntries[] =
+{
+    { "unknown", PIXELFORMAT_UNKNOWN },
+
+	{ "normal",  PIXELFORMAT_NORMAL  },
+	{ "hdr",     PIXELFORMAT_HDR     },
+
+	{ "r8",      PIXELFORMAT_R8      },
+	{ "rg8",     PIXELFORMAT_RG8     },
+	{ "rgba8",   PIXELFORMAT_RGBA8   },
+	{ "srgba8",  PIXELFORMAT_sRGBA8  },
+	{ "r16",     PIXELFORMAT_R16     },
+	{ "rg16",    PIXELFORMAT_RG16    },
+	{ "rgba16",  PIXELFORMAT_RGBA16  },
+	{ "r16f",    PIXELFORMAT_R16F    },
+	{ "rg16f",   PIXELFORMAT_RG16F   },
+	{ "rgba16f", PIXELFORMAT_RGBA16F },
+	{ "r32f",    PIXELFORMAT_R32F    },
+	{ "rg32f",   PIXELFORMAT_RG32F   },
+	{ "rgba32f", PIXELFORMAT_RGBA32F },
+
+	{ "la8",     PIXELFORMAT_LA8     },
+
+	{ "rgba4",    PIXELFORMAT_RGBA4    },
+	{ "rgb5a1",   PIXELFORMAT_RGB5A1   },
+	{ "rgb565",   PIXELFORMAT_RGB565   },
+	{ "rgb10a2",  PIXELFORMAT_RGB10A2  },
+	{ "rg11b10f", PIXELFORMAT_RG11B10F },
+
+	{ "stencil8",         PIXELFORMAT_STENCIL8          },
+	{ "depth16",          PIXELFORMAT_DEPTH16           },
+	{ "depth24",          PIXELFORMAT_DEPTH24           },
+	{ "depth32f",         PIXELFORMAT_DEPTH32F          },
+	{ "depth24stencil8",  PIXELFORMAT_DEPTH24_STENCIL8  },
+	{ "depth32fstencil8", PIXELFORMAT_DEPTH32F_STENCIL8 },
+	
+	{ "DXT1",      PIXELFORMAT_DXT1       },
+	{ "DXT3",      PIXELFORMAT_DXT3       },
+	{ "DXT5",      PIXELFORMAT_DXT5       },
+	{ "BC4",       PIXELFORMAT_BC4        },
+	{ "BC4s",      PIXELFORMAT_BC4s       },
+	{ "BC5",       PIXELFORMAT_BC5        },
+	{ "BC5s",      PIXELFORMAT_BC5s       },
+	{ "BC6h",      PIXELFORMAT_BC6H       },
+	{ "BC6hs",     PIXELFORMAT_BC6Hs      },
+	{ "BC7",       PIXELFORMAT_BC7        },
+	{ "PVR1rgb2",  PIXELFORMAT_PVR1_RGB2  },
+	{ "PVR1rgb4",  PIXELFORMAT_PVR1_RGB4  },
+	{ "PVR1rgba2", PIXELFORMAT_PVR1_RGBA2 },
+	{ "PVR1rgba4", PIXELFORMAT_PVR1_RGBA4 },
+	{ "ETC1",      PIXELFORMAT_ETC1       },
+	{ "ETC2rgb",   PIXELFORMAT_ETC2_RGB   },
+	{ "ETC2rgba",  PIXELFORMAT_ETC2_RGBA  },
+	{ "ETC2rgba1", PIXELFORMAT_ETC2_RGBA1 },
+	{ "EACr",      PIXELFORMAT_EAC_R      },
+	{ "EACrs",     PIXELFORMAT_EAC_Rs     },
+	{ "EACrg",     PIXELFORMAT_EAC_RG     },
+	{ "EACrgs",    PIXELFORMAT_EAC_RGs    },
+	{ "ASTC4x4",   PIXELFORMAT_ASTC_4x4   },
+	{ "ASTC5x4",   PIXELFORMAT_ASTC_5x4   },
+	{ "ASTC5x5",   PIXELFORMAT_ASTC_5x5   },
+	{ "ASTC6x5",   PIXELFORMAT_ASTC_6x5   },
+	{ "ASTC6x6",   PIXELFORMAT_ASTC_6x6   },
+	{ "ASTC8x5",   PIXELFORMAT_ASTC_8x5   },
+	{ "ASTC8x6",   PIXELFORMAT_ASTC_8x6   },
+	{ "ASTC8x8",   PIXELFORMAT_ASTC_8x8   },
+	{ "ASTC10x5",  PIXELFORMAT_ASTC_10x5  },
+	{ "ASTC10x6",  PIXELFORMAT_ASTC_10x6  },
+	{ "ASTC10x8",  PIXELFORMAT_ASTC_10x8  },
+	{ "ASTC10x10", PIXELFORMAT_ASTC_10x10 },
+	{ "ASTC12x10", PIXELFORMAT_ASTC_12x10 },
+	{ "ASTC12x12", PIXELFORMAT_ASTC_12x12 },
+};
+
+static_assert(sizeof(formatEntries) / sizeof(formatEntries[0]) == (size_t) PIXELFORMAT_MAX_ENUM, "pixel format string map is missing entries!");
+
+static StringMap<PixelFormat, PIXELFORMAT_MAX_ENUM> formats(formatEntries, sizeof(formatEntries));
+
+bool getConstant(const char *in, PixelFormat &out)
+{
+	return formats.find(in, out);
+}
+
+bool getConstant(PixelFormat in, const char *&out)
+{
+	return formats.find(in, out);
+}
+
+bool isPixelFormatCompressed(PixelFormat format)
+{
+	// I'm lazy
+	int iformat = (int) format;
+	return iformat >= (int) PIXELFORMAT_DXT1 && iformat < (int) PIXELFORMAT_MAX_ENUM;
+}
+
+bool isPixelFormatDepthStencil(PixelFormat format)
+{
+	int iformat = (int) format;
+	return iformat >= (int) PIXELFORMAT_STENCIL8 && iformat <= (int) PIXELFORMAT_DEPTH32F_STENCIL8;
+}
+
+bool isPixelFormatDepth(PixelFormat format)
+{
+	int iformat = (int) format;
+	return iformat >= (int) PIXELFORMAT_DEPTH16 && iformat <= (int) PIXELFORMAT_DEPTH32F_STENCIL8;
+}
+
+bool isPixelFormatStencil(PixelFormat format)
+{
+	return format == PIXELFORMAT_STENCIL8 || format == PIXELFORMAT_DEPTH24_STENCIL8 || format == PIXELFORMAT_DEPTH32F_STENCIL8;
+}
+
+size_t getPixelFormatSize(PixelFormat format)
+{
+	switch (format)
+	{
+	case PIXELFORMAT_R8:
+	case PIXELFORMAT_STENCIL8:
+		return 1;
+	case PIXELFORMAT_RG8:
+	case PIXELFORMAT_R16:
+	case PIXELFORMAT_R16F:
+	case PIXELFORMAT_LA8:
+	case PIXELFORMAT_RGBA4:
+	case PIXELFORMAT_RGB5A1:
+	case PIXELFORMAT_RGB565:
+	case PIXELFORMAT_DEPTH16:
+		return 2;
+	case PIXELFORMAT_RGBA8:
+	case PIXELFORMAT_sRGBA8:
+	case PIXELFORMAT_RG16:
+	case PIXELFORMAT_RG16F:
+	case PIXELFORMAT_R32F:
+	case PIXELFORMAT_RGB10A2:
+	case PIXELFORMAT_RG11B10F:
+	case PIXELFORMAT_DEPTH24:
+	case PIXELFORMAT_DEPTH32F:
+	case PIXELFORMAT_DEPTH24_STENCIL8:
+		return 4;
+	case PIXELFORMAT_RGBA16:
+	case PIXELFORMAT_RGBA16F:
+	case PIXELFORMAT_RG32F:
+	case PIXELFORMAT_DEPTH32F_STENCIL8:
+		return 8;
+	case PIXELFORMAT_RGBA32F:
+		return 16;
+	default:
+		// TODO: compressed formats
+		return 0;
+	}
+}
+
+} // love

+ 138 - 0
src/common/pixelformat.h

@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#pragma once
+
+#include "stddef.h"
+
+namespace love
+{
+
+enum PixelFormat
+{
+    PIXELFORMAT_UNKNOWN,
+
+	// these are converted to an actual format by love
+	PIXELFORMAT_NORMAL,
+	PIXELFORMAT_HDR,
+
+	// "regular" formats
+	PIXELFORMAT_R8,
+	PIXELFORMAT_RG8,
+	PIXELFORMAT_RGBA8,
+	PIXELFORMAT_sRGBA8,
+	PIXELFORMAT_R16,
+	PIXELFORMAT_RG16,
+	PIXELFORMAT_RGBA16,
+	PIXELFORMAT_R16F,
+	PIXELFORMAT_RG16F,
+	PIXELFORMAT_RGBA16F,
+	PIXELFORMAT_R32F,
+	PIXELFORMAT_RG32F,
+	PIXELFORMAT_RGBA32F,
+
+	PIXELFORMAT_LA8, // Same as RG8, but accessed as (L, L, L, A)
+
+	// packed formats
+	PIXELFORMAT_RGBA4,
+	PIXELFORMAT_RGB5A1,
+	PIXELFORMAT_RGB565,
+	PIXELFORMAT_RGB10A2,
+	PIXELFORMAT_RG11B10F,
+
+	// depth/stencil formats
+	PIXELFORMAT_STENCIL8,
+	PIXELFORMAT_DEPTH16,
+	PIXELFORMAT_DEPTH24,
+	PIXELFORMAT_DEPTH32F,
+	PIXELFORMAT_DEPTH24_STENCIL8,
+	PIXELFORMAT_DEPTH32F_STENCIL8,
+
+	// compressed formats
+	PIXELFORMAT_DXT1,
+	PIXELFORMAT_DXT3,
+	PIXELFORMAT_DXT5,
+	PIXELFORMAT_BC4,
+	PIXELFORMAT_BC4s,
+	PIXELFORMAT_BC5,
+	PIXELFORMAT_BC5s,
+	PIXELFORMAT_BC6H,
+	PIXELFORMAT_BC6Hs,
+	PIXELFORMAT_BC7,
+	PIXELFORMAT_PVR1_RGB2,
+	PIXELFORMAT_PVR1_RGB4,
+	PIXELFORMAT_PVR1_RGBA2,
+	PIXELFORMAT_PVR1_RGBA4,
+	PIXELFORMAT_ETC1,
+	PIXELFORMAT_ETC2_RGB,
+	PIXELFORMAT_ETC2_RGBA,
+	PIXELFORMAT_ETC2_RGBA1,
+	PIXELFORMAT_EAC_R,
+	PIXELFORMAT_EAC_Rs,
+	PIXELFORMAT_EAC_RG,
+	PIXELFORMAT_EAC_RGs,
+	PIXELFORMAT_ASTC_4x4,
+	PIXELFORMAT_ASTC_5x4,
+	PIXELFORMAT_ASTC_5x5,
+	PIXELFORMAT_ASTC_6x5,
+	PIXELFORMAT_ASTC_6x6,
+	PIXELFORMAT_ASTC_8x5,
+	PIXELFORMAT_ASTC_8x6,
+	PIXELFORMAT_ASTC_8x8,
+	PIXELFORMAT_ASTC_10x5,
+	PIXELFORMAT_ASTC_10x6,
+	PIXELFORMAT_ASTC_10x8,
+	PIXELFORMAT_ASTC_10x10,
+	PIXELFORMAT_ASTC_12x10,
+	PIXELFORMAT_ASTC_12x12,
+
+	PIXELFORMAT_MAX_ENUM
+};
+
+bool getConstant(PixelFormat in, const char *&out);
+bool getConstant(const char *in, PixelFormat &out);
+
+/**
+ * Gets whether the specified pixel format is a compressed type.
+ **/
+bool isPixelFormatCompressed(PixelFormat format);
+
+/**
+ * Gets whether the specified pixel format is a depth or stencil type.
+ **/
+bool isPixelFormatDepthStencil(PixelFormat format);
+
+/**
+ * Gets whether the specified pixel format is a depth type.
+ **/
+bool isPixelFormatDepth(PixelFormat format);
+
+/**
+ * Gets whether the specified pixel format is a stencil type.
+ **/
+bool isPixelFormatStencil(PixelFormat format);
+
+/**
+ * Gets the size in bytes of the specified pixel format.
+ * NOTE: Currently returns 0 for compressed formats.
+ **/
+size_t getPixelFormatSize(PixelFormat format);
+
+} // love

+ 192 - 36
src/common/runtime.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -31,6 +31,7 @@
 #include <algorithm>
 #include <algorithm>
 #include <iostream>
 #include <iostream>
 #include <cstdio>
 #include <cstdio>
+#include <sstream>
 
 
 namespace love
 namespace love
 {
 {
@@ -42,7 +43,11 @@ namespace love
 static int w__gc(lua_State *L)
 static int w__gc(lua_State *L)
 {
 {
 	Proxy *p = (Proxy *) lua_touserdata(L, 1);
 	Proxy *p = (Proxy *) lua_touserdata(L, 1);
-	p->object->release();
+	if (p->object != nullptr)
+	{
+		p->object->release();
+		p->object = nullptr;
+	}
 	return 0;
 	return 0;
 }
 }
 
 
@@ -63,8 +68,11 @@ static int w__type(lua_State *L)
 static int w__typeOf(lua_State *L)
 static int w__typeOf(lua_State *L)
 {
 {
 	Proxy *p = (Proxy *)lua_touserdata(L, 1);
 	Proxy *p = (Proxy *)lua_touserdata(L, 1);
-	Type t = luax_type(L, 2);
-	luax_pushboolean(L, typeFlags[p->type][t]);
+	Type *t = luax_type(L, 2);
+	if (!t)
+		luax_pushboolean(L, false);
+	else
+		luax_pushboolean(L, p->type->isa(*t));
 	return 1;
 	return 1;
 }
 }
 
 
@@ -72,7 +80,35 @@ static int w__eq(lua_State *L)
 {
 {
 	Proxy *p1 = (Proxy *)lua_touserdata(L, 1);
 	Proxy *p1 = (Proxy *)lua_touserdata(L, 1);
 	Proxy *p2 = (Proxy *)lua_touserdata(L, 2);
 	Proxy *p2 = (Proxy *)lua_touserdata(L, 2);
-	luax_pushboolean(L, p1->object == p2->object);
+	luax_pushboolean(L, p1->object == p2->object && p1->object != nullptr);
+	return 1;
+}
+
+static int w__release(lua_State *L)
+{
+	Proxy *p = (Proxy *) lua_touserdata(L, 1);
+	Object *object = p->object;
+
+	if (object != nullptr)
+	{
+		p->object = nullptr;
+		object->release();
+
+		// Fetch the registry table of instantiated objects.
+		luax_getregistry(L, REGISTRY_OBJECTS);
+
+		if (lua_istable(L, -1))
+		{
+			// loveobjects[object] = nil
+			lua_pushlightuserdata(L, object);
+			lua_pushnil(L);
+			lua_settable(L, -3);
+		}
+
+		lua_pop(L, 1);
+	}
+
+	luax_pushboolean(L, object != nullptr);
 	return 1;
 	return 1;
 }
 }
 
 
@@ -95,11 +131,53 @@ void luax_printstack(lua_State *L)
 		std::cout << i << " - " << luaL_typename(L, i) << std::endl;
 		std::cout << i << " - " << luaL_typename(L, i) << std::endl;
 }
 }
 
 
+int luax_traceback(lua_State *L)
+{
+	if (!lua_isstring(L, 1))  // 'message' not a string?
+		return 1; // keep it intact
+
+	lua_getglobal(L, "debug");
+	if (!lua_istable(L, -1))
+	{
+		lua_pop(L, 1);
+		return 1;
+	}
+
+	lua_getfield(L, -1, "traceback");
+	if (!lua_isfunction(L, -1))
+	{
+		lua_pop(L, 2);
+		return 1;
+	}
+
+	lua_pushvalue(L, 1); // pass error message
+	lua_pushinteger(L, 2); // skip this function and traceback
+	lua_call(L, 2, 1); // call debug.traceback
+	return 1;
+}
+
+bool luax_isarrayoftables(lua_State *L, int idx)
+{
+	if (!lua_istable(L, idx))
+		return false;
+
+	lua_rawgeti(L, idx, 1);
+	bool tableoftables = lua_istable(L, -1);
+	lua_pop(L, 1);
+	return tableoftables;
+}
+
 bool luax_toboolean(lua_State *L, int idx)
 bool luax_toboolean(lua_State *L, int idx)
 {
 {
 	return (lua_toboolean(L, idx) != 0);
 	return (lua_toboolean(L, idx) != 0);
 }
 }
 
 
+bool luax_checkboolean(lua_State *L, int idx)
+{
+	luaL_checktype(L, idx, LUA_TBOOLEAN);
+	return luax_toboolean(L, idx);
+}
+
 void luax_pushboolean(lua_State *L, bool b)
 void luax_pushboolean(lua_State *L, bool b)
 {
 {
 	lua_pushboolean(L, b ? 1 : 0);
 	lua_pushboolean(L, b ? 1 : 0);
@@ -159,6 +237,37 @@ int luax_intflag(lua_State *L, int table_index, const char *key, int defaultValu
 	return retval;
 	return retval;
 }
 }
 
 
+double luax_numberflag(lua_State *L, int table_index, const char *key, double defaultValue)
+{
+	lua_getfield(L, table_index, key);
+
+	int retval;
+	if (!lua_isnumber(L, -1))
+		retval = defaultValue;
+	else
+		retval = lua_tonumber(L, -1);
+
+	lua_pop(L, 1);
+	return retval;
+}
+
+int luax_checkintflag(lua_State *L, int table_index, const char *key)
+{
+	lua_getfield(L, table_index, key);
+
+	int retval;
+	if (!lua_isnumber(L, -1))
+	{
+		std::string err = "expected integer field " + std::string(key) + " in table";
+		return luaL_argerror(L, table_index, err.c_str());
+	}
+	else
+		retval = (int) luaL_checkinteger(L, -1);
+	lua_pop(L, 1);
+
+	return retval;
+}
+
 int luax_assert_argc(lua_State *L, int min)
 int luax_assert_argc(lua_State *L, int min)
 {
 {
 	int argc = lua_gettop(L);
 	int argc = lua_gettop(L);
@@ -216,7 +325,7 @@ int luax_require(lua_State *L, const char *name)
 
 
 int luax_register_module(lua_State *L, const WrappedModule &m)
 int luax_register_module(lua_State *L, const WrappedModule &m)
 {
 {
-	love::addTypeName(m.type, m.name);
+	m.type->init();
 
 
 	// Put a reference to the C++ module in Lua.
 	// Put a reference to the C++ module in Lua.
 	luax_insistregistry(L, REGISTRY_MODULES);
 	luax_insistregistry(L, REGISTRY_MODULES);
@@ -272,9 +381,9 @@ int luax_preload(lua_State *L, lua_CFunction f, const char *name)
 	return 0;
 	return 0;
 }
 }
 
 
-int luax_register_type(lua_State *L, love::Type type, const char *name, ...)
+int luax_register_type(lua_State *L, love::Type *type, ...)
 {
 {
-	love::addTypeName(type, name);
+	type->init();
 
 
 	// Get the place for storing and re-using instantiated love types.
 	// Get the place for storing and re-using instantiated love types.
 	luax_getregistry(L, REGISTRY_OBJECTS);
 	luax_getregistry(L, REGISTRY_OBJECTS);
@@ -301,7 +410,7 @@ int luax_register_type(lua_State *L, love::Type type, const char *name, ...)
 	else
 	else
 		lua_pop(L, 1);
 		lua_pop(L, 1);
 
 
-	luaL_newmetatable(L, name);
+	luaL_newmetatable(L, type->getName());
 
 
 	// m.__index = m
 	// m.__index = m
 	lua_pushvalue(L, -1);
 	lua_pushvalue(L, -1);
@@ -316,12 +425,12 @@ int luax_register_type(lua_State *L, love::Type type, const char *name, ...)
 	lua_setfield(L, -2, "__eq");
 	lua_setfield(L, -2, "__eq");
 
 
 	// Add tostring function.
 	// Add tostring function.
-	lua_pushstring(L, name);
+	lua_pushstring(L, type->getName());
 	lua_pushcclosure(L, w__tostring, 1);
 	lua_pushcclosure(L, w__tostring, 1);
 	lua_setfield(L, -2, "__tostring");
 	lua_setfield(L, -2, "__tostring");
 
 
 	// Add type
 	// Add type
-	lua_pushstring(L, name);
+	lua_pushstring(L, type->getName());
 	lua_pushcclosure(L, w__type, 1);
 	lua_pushcclosure(L, w__type, 1);
 	lua_setfield(L, -2, "type");
 	lua_setfield(L, -2, "type");
 
 
@@ -329,8 +438,12 @@ int luax_register_type(lua_State *L, love::Type type, const char *name, ...)
 	lua_pushcfunction(L, w__typeOf);
 	lua_pushcfunction(L, w__typeOf);
 	lua_setfield(L, -2, "typeOf");
 	lua_setfield(L, -2, "typeOf");
 
 
+	// Add release
+	lua_pushcfunction(L, w__release);
+	lua_setfield(L, -2, "release");
+
 	va_list fs;
 	va_list fs;
-	va_start(fs, name);
+	va_start(fs, type);
 	for (const luaL_Reg *f = va_arg(fs, const luaL_Reg *); f; f = va_arg(fs, const luaL_Reg *))
 	for (const luaL_Reg *f = va_arg(fs, const luaL_Reg *); f; f = va_arg(fs, const luaL_Reg *))
 		luax_setfuncs(L, f);
 		luax_setfuncs(L, f);
 	va_end(fs);
 	va_end(fs);
@@ -339,13 +452,10 @@ int luax_register_type(lua_State *L, love::Type type, const char *name, ...)
 	return 0;
 	return 0;
 }
 }
 
 
-void luax_gettypemetatable(lua_State *L, love::Type type)
+void luax_gettypemetatable(lua_State *L, love::Type &type)
 {
 {
-	const char *name = nullptr;
-	if (getTypeName(type, name))
-		lua_getfield(L, LUA_REGISTRYINDEX, name);
-	else
-		lua_pushnil(L);
+	const char *name = type.getName();
+	lua_getfield(L, LUA_REGISTRYINDEX, name);
 }
 }
 
 
 int luax_table_insert(lua_State *L, int tindex, int vindex, int pos)
 int luax_table_insert(lua_State *L, int tindex, int vindex, int pos)
@@ -401,23 +511,34 @@ int luax_register_searcher(lua_State *L, lua_CFunction f, int pos)
 	return 0;
 	return 0;
 }
 }
 
 
-void luax_rawnewtype(lua_State *L, love::Type type, love::Object *object)
+void luax_rawnewtype(lua_State *L, love::Type &type, love::Object *object)
 {
 {
 	Proxy *u = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
 	Proxy *u = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
 
 
 	object->retain();
 	object->retain();
 
 
 	u->object = object;
 	u->object = object;
-	u->type = type;
-
-	const char *name = "Invalid";
-	getTypeName(type, name);
+	u->type = &type;
 
 
+	const char *name = type.getName();
 	luaL_newmetatable(L, name);
 	luaL_newmetatable(L, name);
+
+	lua_getfield(L, -1, "__gc");
+	bool has_gc = !lua_isnoneornil(L, -1);
+	lua_pop(L, 1);
+
+	// Make sure mt.__gc exists, so Lua states which don't have the object's
+	// module loaded will still clean the object up when it's collected.
+	if (!has_gc)
+	{
+		lua_pushcfunction(L, w__gc);
+		lua_setfield(L, -2, "__gc");
+	}
+
 	lua_setmetatable(L, -2);
 	lua_setmetatable(L, -2);
 }
 }
 
 
-void luax_pushtype(lua_State *L, love::Type type, love::Object *object)
+void luax_pushtype(lua_State *L, love::Type &type, love::Object *object)
 {
 {
 	if (object == nullptr)
 	if (object == nullptr)
 	{
 	{
@@ -459,15 +580,15 @@ void luax_pushtype(lua_State *L, love::Type type, love::Object *object)
 	// Keep the Proxy userdata on the stack.
 	// Keep the Proxy userdata on the stack.
 }
 }
 
 
-bool luax_istype(lua_State *L, int idx, love::Type type)
+bool luax_istype(lua_State *L, int idx, love::Type &type)
 {
 {
 	if (lua_type(L, idx) != LUA_TUSERDATA)
 	if (lua_type(L, idx) != LUA_TUSERDATA)
 		return false;
 		return false;
 
 
 	Proxy *p = (Proxy *) lua_touserdata(L, idx);
 	Proxy *p = (Proxy *) lua_touserdata(L, idx);
 
 
-	if (p->type > INVALID_ID && p->type < TYPE_MAX_ENUM)
-		return typeFlags[p->type][type];
+	if (p->type != nullptr)
+		return p->type->isa(type);
 	else
 	else
 		return false;
 		return false;
 }
 }
@@ -666,10 +787,29 @@ lua_State *luax_getpinnedthread(lua_State *L)
 	return thread;
 	return thread;
 }
 }
 
 
+void luax_markdeprecated(lua_State *L, const char *name, APIType api)
+{
+	luax_markdeprecated(L, name, api, DEPRECATED_NO_REPLACEMENT, nullptr);
+}
+
+void luax_markdeprecated(lua_State *L, const char *name, APIType api, DeprecationType type, const char *replacement)
+{
+	MarkDeprecated deprecated(name, api, type, replacement);
+
+	if (deprecated.info != nullptr && deprecated.info->uses == 1)
+	{
+		luaL_where(L, 1);
+		const char *where = lua_tostring(L, -1);
+		if (where != nullptr)
+			deprecated.info->where = where;
+		lua_pop(L, 1);
+	}
+}
+
 extern "C" int luax_typerror(lua_State *L, int narg, const char *tname)
 extern "C" int luax_typerror(lua_State *L, int narg, const char *tname)
 {
 {
 	int argtype = lua_type(L, narg);
 	int argtype = lua_type(L, narg);
-	const char *argtname = 0;
+	const char *argtname = nullptr;
 
 
 	// We want to use the love type name for userdata, if possible.
 	// We want to use the love type name for userdata, if possible.
 	if (argtype == LUA_TUSERDATA && luaL_getmetafield(L, narg, "type") != 0)
 	if (argtype == LUA_TUSERDATA && luaL_getmetafield(L, narg, "type") != 0)
@@ -681,19 +821,37 @@ extern "C" int luax_typerror(lua_State *L, int narg, const char *tname)
 
 
 			// Non-love userdata might have a type metamethod which doesn't
 			// Non-love userdata might have a type metamethod which doesn't
 			// describe its type properly, so we only use it for love types.
 			// describe its type properly, so we only use it for love types.
-			love::Type t;
-			if (!love::getTypeName(argtname, t))
-				argtname = 0;
+			if (!Type::byName(argtname))
+				argtname = nullptr;
 		}
 		}
 	}
 	}
 
 
-	if (argtname == 0)
+	if (argtname == nullptr)
 		argtname = lua_typename(L, argtype);
 		argtname = lua_typename(L, argtype);
 
 
 	const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, argtname);
 	const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, argtname);
 	return luaL_argerror(L, narg, msg);
 	return luaL_argerror(L, narg, msg);
 }
 }
 
 
+int luax_enumerror(lua_State *L, const char *enumName, const char *value)
+{
+	return luaL_error(L, "Invalid %s: %s", enumName, value);
+}
+
+int luax_enumerror(lua_State *L, const char *enumName, const std::vector<std::string> &values, const char *value)
+{
+	std::stringstream valueStream;
+	bool first = true;
+	for (auto value : values)
+	{
+		valueStream << (first ? "'" : ", '") << value << "'";
+		first = false;
+	}
+
+	std::string valueString = valueStream.str();
+	return luaL_error(L, "Invalid %s '%s', expected one of: %s", enumName, value, valueString.c_str());
+}
+
 size_t luax_objlen(lua_State *L, int ndx)
 size_t luax_objlen(lua_State *L, int ndx)
 {
 {
 #if LUA_VERSION_NUM == 501
 #if LUA_VERSION_NUM == 501
@@ -716,11 +874,9 @@ void luax_register(lua_State *L, const char *name, const luaL_Reg *l)
 	}
 	}
 }
 }
 
 
-Type luax_type(lua_State *L, int idx)
+Type *luax_type(lua_State *L, int idx)
 {
 {
-	Type t = INVALID_ID;
-	getTypeName(luaL_checkstring(L, idx), t);
-	return t;
+	return Type::byName(luaL_checkstring(L, idx));
 }
 }
 
 
 } // love
 } // love

+ 112 - 26
src/common/runtime.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -22,7 +22,9 @@
 #define LOVE_RUNTIME_H
 #define LOVE_RUNTIME_H
 
 
 // LOVE
 // LOVE
+#include "config.h"
 #include "types.h"
 #include "types.h"
+#include "deprecation.h"
 
 
 // Lua
 // Lua
 extern "C" {
 extern "C" {
@@ -34,6 +36,7 @@ extern "C" {
 
 
 // C++
 // C++
 #include <exception>
 #include <exception>
+#include <algorithm>
 
 
 namespace love
 namespace love
 {
 {
@@ -43,6 +46,9 @@ class Object;
 class Module;
 class Module;
 class Reference;
 class Reference;
 
 
+template<typename T>
+class StrongRef;
+
 /**
 /**
  * Registries represent special tables which can be accessed with
  * Registries represent special tables which can be accessed with
  * luax_insistregistry and luax_getregistry.
  * luax_insistregistry and luax_getregistry.
@@ -62,7 +68,7 @@ enum Registry
 struct Proxy
 struct Proxy
 {
 {
 	// Holds type information (see types.h).
 	// Holds type information (see types.h).
-	Type type;
+	love::Type *type;
 
 
 	// Pointer to the actual object.
 	// Pointer to the actual object.
 	Object *object;
 	Object *object;
@@ -80,7 +86,7 @@ struct WrappedModule
 	const char *name;
 	const char *name;
 
 
 	// The type of this module.
 	// The type of this module.
-	love::Type type;
+	love::Type *type;
 
 
 	// The functions of the module (last element {0,0}).
 	// The functions of the module (last element {0,0}).
 	const luaL_Reg *functions;
 	const luaL_Reg *functions;
@@ -103,6 +109,16 @@ Reference *luax_refif(lua_State *L, int type);
  **/
  **/
 void luax_printstack(lua_State *L);
 void luax_printstack(lua_State *L);
 
 
+/**
+ * Traceback function for use with lua_pcall. Calls debug.traceback.
+ **/
+int luax_traceback(lua_State *L);
+
+/**
+ * Gets whether the value at idx is an array of tables.
+ **/
+bool luax_isarrayoftables(lua_State *L, int idx);
+
 /**
 /**
  * Converts the value at idx to a bool. It follow the same rules
  * Converts the value at idx to a bool. It follow the same rules
  * as lua_toboolean, but returns a bool instead of an int.
  * as lua_toboolean, but returns a bool instead of an int.
@@ -112,6 +128,12 @@ void luax_printstack(lua_State *L);
  **/
  **/
 bool luax_toboolean(lua_State *L, int idx);
 bool luax_toboolean(lua_State *L, int idx);
 
 
+/**
+ * Returns the boolean value at idx. Causes a Lua error if the value is not
+ * a boolean.
+ **/
+bool luax_checkboolean(lua_State *L, int idx);
+
 /**
 /**
  * Pushes a bool onto the stack. It's the same as lua_pushboolean,
  * Pushes a bool onto the stack. It's the same as lua_pushboolean,
  * but with bool instead of int.
  * but with bool instead of int.
@@ -158,6 +180,9 @@ void luax_pushstring(lua_State *L, const std::string &str);
 
 
 bool luax_boolflag(lua_State *L, int table_index, const char *key, bool defaultValue);
 bool luax_boolflag(lua_State *L, int table_index, const char *key, bool defaultValue);
 int luax_intflag(lua_State *L, int table_index, const char *key, int defaultValue);
 int luax_intflag(lua_State *L, int table_index, const char *key, int defaultValue);
+double luax_numberflag(lua_State *L, int table_index, const char *key, double defaultValue);
+
+int luax_checkintflag(lua_State *L, int table_index, const char *key);
 
 
 /**
 /**
  * Convert the value at the specified index to an Lua number, and then
  * Convert the value at the specified index to an Lua number, and then
@@ -181,6 +206,16 @@ inline float luax_checkfloat(lua_State *L, int idx)
 	return static_cast<float>(luaL_checknumber(L, idx));
 	return static_cast<float>(luaL_checknumber(L, idx));
 }
 }
 
 
+inline lua_Number luax_checknumberclamped01(lua_State *L, int idx)
+{
+	return std::min(std::max(luaL_checknumber(L, idx), 0.0), 1.0);
+}
+
+inline lua_Number luax_optnumberclamped01(lua_State *L, int idx, double def)
+{
+	return std::min(std::max(luaL_optnumber(L, idx, def), 0.0), 1.0);
+}
+
 /**
 /**
  * Require at least 'min' number of items on the stack.
  * Require at least 'min' number of items on the stack.
  * @param L The Lua state.
  * @param L The Lua state.
@@ -246,16 +281,17 @@ int luax_preload(lua_State *L, lua_CFunction f, const char *name);
 
 
 /**
 /**
  * Register a new type.
  * Register a new type.
+ * NOTE: The type is passed by pointer instead of reference because calling va_start
+ * on a reference is undefined behaviour.
  * @param type The type.
  * @param type The type.
- * @param name The type's human-readable name
  * @param ... The list of lists of member functions for the type. (of type luaL_Reg*)
  * @param ... The list of lists of member functions for the type. (of type luaL_Reg*)
  **/
  **/
-int luax_register_type(lua_State *L, love::Type type, const char *name, ...);
+int luax_register_type(lua_State *L, love::Type *type, ...);
 
 
 /**
 /**
  * Pushes the metatable of the specified type onto the stack.
  * Pushes the metatable of the specified type onto the stack.
 **/
 **/
-void luax_gettypemetatable(lua_State *L, love::Type type);
+void luax_gettypemetatable(lua_State *L, love::Type &type);
 
 
 /**
 /**
  * Do a table.insert from C
  * Do a table.insert from C
@@ -283,7 +319,19 @@ int luax_register_searcher(lua_State *L, lua_CFunction f, int pos = -1);
  * @param type The type information of the object.
  * @param type The type information of the object.
  * @param object The pointer to the actual object.
  * @param object The pointer to the actual object.
  **/
  **/
-void luax_pushtype(lua_State *L, const love::Type type, love::Object *object);
+void luax_pushtype(lua_State *L, love::Type &type, love::Object *object);
+
+template <typename T>
+void luax_pushtype(lua_State *L, T *object)
+{
+	luax_pushtype(L, T::type, object);
+}
+
+template <typename T>
+void luax_pushtype(lua_State *L, StrongRef<T> &object)
+{
+	luax_pushtype(L, T::type, object);
+}
 
 
 /**
 /**
  * Creates a new Lua representation of the given object *without* checking if it
  * Creates a new Lua representation of the given object *without* checking if it
@@ -296,7 +344,7 @@ void luax_pushtype(lua_State *L, const love::Type type, love::Object *object);
  * @param type The type information of the object.
  * @param type The type information of the object.
  * @param object The pointer to the actual object.
  * @param object The pointer to the actual object.
  **/
  **/
-void luax_rawnewtype(lua_State *L, love::Type type, love::Object *object);
+void luax_rawnewtype(lua_State *L, love::Type &type, love::Object *object);
 
 
 /**
 /**
  * Checks whether the value at idx is a certain type.
  * Checks whether the value at idx is a certain type.
@@ -305,7 +353,7 @@ void luax_rawnewtype(lua_State *L, love::Type type, love::Object *object);
  * @param type The type to check for.
  * @param type The type to check for.
  * @return True if the value is Proxy of the specified type, false otherwise.
  * @return True if the value is Proxy of the specified type, false otherwise.
  **/
  **/
-bool luax_istype(lua_State *L, int idx, love::Type type);
+bool luax_istype(lua_State *L, int idx, love::Type &type);
 
 
 /**
 /**
  * Gets the function love.module.function and puts it on top of the stack (alone). If the
  * Gets the function love.module.function and puts it on top of the stack (alone). If the
@@ -412,10 +460,20 @@ lua_State *luax_insistpinnedthread(lua_State *L);
  **/
  **/
 lua_State *luax_getpinnedthread(lua_State *L);
 lua_State *luax_getpinnedthread(lua_State *L);
 
 
+/**
+ * Mark a function as deprecated. Should only be called inside wrapper function
+ * code.
+ **/
+void luax_markdeprecated(lua_State *L, const char *name, APIType api);
+void luax_markdeprecated(lua_State *L, const char *name, APIType api, DeprecationType type, const char *replacement);
+
 extern "C" { // Also called from luasocket
 extern "C" { // Also called from luasocket
 	int luax_typerror(lua_State *L, int narg, const char *tname);
 	int luax_typerror(lua_State *L, int narg, const char *tname);
 }
 }
 
 
+int luax_enumerror(lua_State *L, const char *enumName, const char *value);
+int luax_enumerror(lua_State *L, const char *enumName, const std::vector<std::string> &values, const char *value);
+
 /**
 /**
  * Calls luax_objlen/lua_rawlen depending on version
  * Calls luax_objlen/lua_rawlen depending on version
  **/
  **/
@@ -434,32 +492,38 @@ extern "C" { // Called by enet and luasocket
  * @param type The type bit.
  * @param type The type bit.
  **/
  **/
 template <typename T>
 template <typename T>
-T *luax_checktype(lua_State *L, int idx, love::Type type)
+T *luax_checktype(lua_State *L, int idx, const love::Type &type)
 {
 {
 	if (lua_type(L, idx) != LUA_TUSERDATA)
 	if (lua_type(L, idx) != LUA_TUSERDATA)
 	{
 	{
-		const char *name = "Invalid";
-		getTypeName(type, name);
+		const char *name = type.getName();
 		luax_typerror(L, idx, name);
 		luax_typerror(L, idx, name);
 	}
 	}
 
 
 	Proxy *u = (Proxy *)lua_touserdata(L, idx);
 	Proxy *u = (Proxy *)lua_touserdata(L, idx);
 
 
-	if (u->type <= INVALID_ID || u->type >= TYPE_MAX_ENUM || !typeFlags[u->type][type])
+	if (u->type == nullptr || !u->type->isa(type))
 	{
 	{
-		const char *name = "Invalid";
-		getTypeName(type, name);
+		const char *name = type.getName();
 		luax_typerror(L, idx, name);
 		luax_typerror(L, idx, name);
 	}
 	}
 
 
+	if (u->object == nullptr)
+		luaL_error(L, "Cannot use object after it has been released.");
+
 	return (T *)u->object;
 	return (T *)u->object;
 }
 }
 
 
 template <typename T>
 template <typename T>
-T *luax_getmodule(lua_State *L, love::Type type)
+T *luax_checktype(lua_State *L, int idx)
 {
 {
-	const char *name = "Invalid";
-	getTypeName(type, name);
+	return luax_checktype<T>(L, idx, T::type);
+}
+
+template <typename T>
+T *luax_getmodule(lua_State *L, const love::Type &type)
+{
+	const char *name = type.getName();
 
 
 	luax_insistregistry(L, REGISTRY_MODULES);
 	luax_insistregistry(L, REGISTRY_MODULES);
 	lua_getfield(L, -1, name);
 	lua_getfield(L, -1, name);
@@ -469,7 +533,7 @@ T *luax_getmodule(lua_State *L, love::Type type)
 
 
 	Proxy *u = (Proxy *)lua_touserdata(L, -1);
 	Proxy *u = (Proxy *)lua_touserdata(L, -1);
 
 
-	if (u->type <= INVALID_ID || u->type >= TYPE_MAX_ENUM || !typeFlags[u->type][type])
+	if (u->type == nullptr || !u->type->isa(type))
 		luaL_error(L, "Incorrect module %s", name);
 		luaL_error(L, "Incorrect module %s", name);
 
 
 	lua_pop(L, 2);
 	lua_pop(L, 2);
@@ -478,10 +542,15 @@ T *luax_getmodule(lua_State *L, love::Type type)
 }
 }
 
 
 template <typename T>
 template <typename T>
-T *luax_optmodule(lua_State *L, love::Type type)
+T *luax_getmodule(lua_State *L)
+{
+	return luax_getmodule<T>(L, T::type);
+}
+
+template <typename T>
+T *luax_optmodule(lua_State *L, const love::Type &type)
 {
 {
-	const char *name = "Invalid";
-	getTypeName(type, name);
+	const char *name = type.getName();
 
 
 	luax_insistregistry(L, REGISTRY_MODULES);
 	luax_insistregistry(L, REGISTRY_MODULES);
 	lua_getfield(L, -1, name);
 	lua_getfield(L, -1, name);
@@ -494,7 +563,7 @@ T *luax_optmodule(lua_State *L, love::Type type)
 
 
 	Proxy *u = (Proxy *)lua_touserdata(L, -1);
 	Proxy *u = (Proxy *)lua_touserdata(L, -1);
 
 
-	if (!typeFlags[u->type][type])
+	if (!u->type->isa(type))
 		luaL_error(L, "Incorrect module %s", name);
 		luaL_error(L, "Incorrect module %s", name);
 
 
 	lua_pop(L, 2);
 	lua_pop(L, 2);
@@ -502,6 +571,12 @@ T *luax_optmodule(lua_State *L, love::Type type)
 	return (T *) u->object;
 	return (T *) u->object;
 }
 }
 
 
+template <typename T>
+T *luax_optmodule(lua_State *L)
+{
+	return luax_optmodule<T>(L, T::type);
+}
+
 /**
 /**
  * Converts the value at idx to the specified type without checking that
  * Converts the value at idx to the specified type without checking that
  * this conversion is valid. If the type has been previously verified with
  * this conversion is valid. If the type has been previously verified with
@@ -511,12 +586,23 @@ T *luax_optmodule(lua_State *L, love::Type type)
  * @param type The type of the object.
  * @param type The type of the object.
  **/
  **/
 template <typename T>
 template <typename T>
-T *luax_totype(lua_State *L, int idx, love::Type /*type*/)
+T *luax_totype(lua_State *L, int idx, const love::Type& /*type*/)
+{
+	T *o = (T *)(((Proxy *)lua_touserdata(L, idx))->object);
+
+	if (o == nullptr)
+		luaL_error(L, "Cannot use object after it has been released.");
+
+	return o;
+}
+
+template <typename T>
+T *luax_totype(lua_State *L, int idx)
 {
 {
-	return (T *)(((Proxy *)lua_touserdata(L, idx))->object);
+	return luax_totype<T>(L, idx, T::type);
 }
 }
 
 
-Type luax_type(lua_State *L, int idx);
+Type *luax_type(lua_State *L, int idx);
 
 
 /**
 /**
  * Converts any exceptions thrown by the passed lambda function into a Lua error.
  * Converts any exceptions thrown by the passed lambda function into a Lua error.

+ 42 - 105
src/common/types.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -18,126 +18,63 @@
  * 3. This notice may not be removed or altered from any source distribution.
  * 3. This notice may not be removed or altered from any source distribution.
  **/
  **/
 
 
+// STL
+#include <unordered_map>
+
 #include "types.h"
 #include "types.h"
-#include "StringMap.h"
 
 
 namespace love
 namespace love
 {
 {
 
 
-static const TypeBits *createTypeFlags()
-{
-	static TypeBits b[TYPE_MAX_ENUM];
-	TypeBits one = TypeBits(1);
-
-	b[INVALID_ID] = one << INVALID_ID;
-
-	b[OBJECT_ID] = one << OBJECT_ID;
-	b[DATA_ID] = (one << DATA_ID) | b[OBJECT_ID];
-	b[MODULE_ID] = (one << MODULE_ID) | b[OBJECT_ID];
-	b[STREAM_ID] = (one << STREAM_ID) | b[OBJECT_ID];
-
-	// Filesystem.
-	b[FILESYSTEM_FILE_ID] = (one << FILESYSTEM_FILE_ID) | b[OBJECT_ID];
-	b[FILESYSTEM_DROPPED_FILE_ID] = (one << FILESYSTEM_DROPPED_FILE_ID) | b[FILESYSTEM_FILE_ID];
-	b[FILESYSTEM_FILE_DATA_ID] = (one << FILESYSTEM_FILE_DATA_ID) | b[DATA_ID];
-
-	b[FONT_GLYPH_DATA_ID] = (one << FONT_GLYPH_DATA_ID) | b[DATA_ID];
-	b[FONT_RASTERIZER_ID] = (one << FONT_RASTERIZER_ID) | b[OBJECT_ID];
-
-	// Graphics.
-	b[GRAPHICS_DRAWABLE_ID] = (one << GRAPHICS_DRAWABLE_ID) | b[OBJECT_ID];
-	b[GRAPHICS_TEXTURE_ID] = (one << GRAPHICS_TEXTURE_ID) | b[GRAPHICS_DRAWABLE_ID];
-	b[GRAPHICS_IMAGE_ID] = (one << GRAPHICS_IMAGE_ID) | b[GRAPHICS_TEXTURE_ID];
-	b[GRAPHICS_QUAD_ID] = (one << GRAPHICS_QUAD_ID) | b[OBJECT_ID];
-	b[GRAPHICS_FONT_ID] = (one << GRAPHICS_FONT_ID) | b[OBJECT_ID];
-	b[GRAPHICS_PARTICLE_SYSTEM_ID] = (one << GRAPHICS_PARTICLE_SYSTEM_ID) | b[GRAPHICS_DRAWABLE_ID];
-	b[GRAPHICS_SPRITE_BATCH_ID] = (one << GRAPHICS_SPRITE_BATCH_ID) | b[GRAPHICS_DRAWABLE_ID];
-	b[GRAPHICS_CANVAS_ID] = (one << GRAPHICS_CANVAS_ID) | b[GRAPHICS_TEXTURE_ID];
-	b[GRAPHICS_SHADER_ID] = (one << GRAPHICS_SHADER_ID) | b[OBJECT_ID];
-	b[GRAPHICS_MESH_ID] = (one << GRAPHICS_MESH_ID) | b[GRAPHICS_DRAWABLE_ID];
-	b[GRAPHICS_TEXT_ID] = (one << GRAPHICS_TEXT_ID) | b[GRAPHICS_DRAWABLE_ID];
-	b[GRAPHICS_VIDEO_ID] = (one << GRAPHICS_VIDEO_ID) | b[GRAPHICS_DRAWABLE_ID];
-
-	// Image.
-	b[IMAGE_IMAGE_DATA_ID] = (one << IMAGE_IMAGE_DATA_ID) | b[DATA_ID];
-	b[IMAGE_COMPRESSED_IMAGE_DATA_ID] = (one << IMAGE_COMPRESSED_IMAGE_DATA_ID) | b[DATA_ID];
-
-	// Joystick.
-	b[JOYSTICK_JOYSTICK_ID] = (one << JOYSTICK_JOYSTICK_ID) | b[OBJECT_ID];
-
-	// Math.
-	b[MATH_RANDOM_GENERATOR_ID] = (one << MATH_RANDOM_GENERATOR_ID) | b[OBJECT_ID];
-	b[MATH_BEZIER_CURVE_ID] = (one << MATH_BEZIER_CURVE_ID) | b[OBJECT_ID];
-	b[MATH_COMPRESSED_DATA_ID] = (one <<MATH_COMPRESSED_DATA_ID) | b[DATA_ID];
-
-	// Audio.
-	b[AUDIO_SOURCE_ID] = (one << AUDIO_SOURCE_ID) | b[OBJECT_ID];
+static std::unordered_map<std::string, Type*> types;
 
 
-	// Sound.
-	b[SOUND_SOUND_DATA_ID] = (one << SOUND_SOUND_DATA_ID) | b[DATA_ID];
-	b[SOUND_DECODER_ID] = one << SOUND_DECODER_ID;
-
-	// Mouse.
-	b[MOUSE_CURSOR_ID] = (one << MOUSE_CURSOR_ID) | b[OBJECT_ID];
-
-	// Physics.
-	b[PHYSICS_WORLD_ID] = (one << PHYSICS_WORLD_ID) | b[OBJECT_ID];
-	b[PHYSICS_CONTACT_ID] = (one << PHYSICS_CONTACT_ID) | b[OBJECT_ID];
-	b[PHYSICS_BODY_ID] = (one << PHYSICS_BODY_ID) | b[OBJECT_ID];
-	b[PHYSICS_FIXTURE_ID] = (one << PHYSICS_FIXTURE_ID) | b[OBJECT_ID];
-	b[PHYSICS_SHAPE_ID] = (one << PHYSICS_SHAPE_ID) | b[OBJECT_ID];
-	b[PHYSICS_CIRCLE_SHAPE_ID] = (one << PHYSICS_CIRCLE_SHAPE_ID) | b[PHYSICS_SHAPE_ID];
-	b[PHYSICS_POLYGON_SHAPE_ID] = (one << PHYSICS_POLYGON_SHAPE_ID) | b[PHYSICS_SHAPE_ID];
-	b[PHYSICS_EDGE_SHAPE_ID] = (one << PHYSICS_EDGE_SHAPE_ID) | b[PHYSICS_SHAPE_ID];
-	b[PHYSICS_CHAIN_SHAPE_ID] = (one << PHYSICS_CHAIN_SHAPE_ID) | b[PHYSICS_SHAPE_ID];
-	b[PHYSICS_JOINT_ID] = (one << PHYSICS_JOINT_ID) | b[OBJECT_ID];
-	b[PHYSICS_MOUSE_JOINT_ID] = (one << PHYSICS_MOUSE_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_DISTANCE_JOINT_ID] = (one << PHYSICS_DISTANCE_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_PRISMATIC_JOINT_ID] = (one << PHYSICS_PRISMATIC_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_REVOLUTE_JOINT_ID] = (one << PHYSICS_REVOLUTE_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_PULLEY_JOINT_ID] = (one << PHYSICS_PULLEY_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_GEAR_JOINT_ID] = (one << PHYSICS_GEAR_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_FRICTION_JOINT_ID] = (one << PHYSICS_FRICTION_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_WELD_JOINT_ID] = (one << PHYSICS_WELD_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_ROPE_JOINT_ID] = (one << PHYSICS_ROPE_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_WHEEL_JOINT_ID] = (one << PHYSICS_WHEEL_JOINT_ID) | b[PHYSICS_JOINT_ID];
-	b[PHYSICS_MOTOR_JOINT_ID] = (one << PHYSICS_MOTOR_JOINT_ID) | b[PHYSICS_JOINT_ID];
-
-	// Thread.
-	b[THREAD_THREAD_ID] = (one << THREAD_THREAD_ID) | b[OBJECT_ID];
-	b[THREAD_CHANNEL_ID] = (one << THREAD_CHANNEL_ID) | b[OBJECT_ID];
-
-	// Video
-	b[VIDEO_VIDEO_STREAM_ID] = (one << VIDEO_VIDEO_STREAM_ID) | b[STREAM_ID];
-
-	// Modules.
-	b[MODULE_FILESYSTEM_ID] = (one << MODULE_FILESYSTEM_ID) | b[MODULE_ID];
-	b[MODULE_GRAPHICS_ID] = (one << MODULE_GRAPHICS_ID) | b[MODULE_ID];
-	b[MODULE_IMAGE_ID] = (one << MODULE_IMAGE_ID) | b[MODULE_ID];
-	b[MODULE_SOUND_ID] = (one << MODULE_SOUND_ID) | b[MODULE_ID];
-
-	return b;
+Type::Type(const char *name, Type *parent)
+	: name(name)
+	, parent(parent)
+	, id(0)
+	, inited(false)
+{
 }
 }
 
 
-const TypeBits *typeFlags = createTypeFlags();
-
-static StringMap<Type, TYPE_MAX_ENUM> types(nullptr, 0);
+void Type::init()
+{
+	static uint32 nextId = 1;
+
+	// Make sure we don't init twice, that would be bad
+	if (inited)
+		return;
+
+	// Note: we add it here, not in the constructor, because some Types can get initialized before the map!
+	types[name] = this;
+	id = nextId++;
+	bits[id] = true;
+	inited = true;
+
+	if (!parent)
+		return;
+	if (!parent->inited)
+		parent->init();
+	bits |= parent->bits;
+}
 
 
-void addTypeName(Type type, const char *name)
+uint32 Type::getId()
 {
 {
-	const char *n;
-	if (!types.find(type, n))
-		types.add(name, type);
+	if (!inited)
+		init();
+	return id;
 }
 }
 
 
-bool getTypeName(const char *in, love::Type &out)
+const char *Type::getName() const
 {
 {
-	return types.find(in, out);
+	return name;
 }
 }
 
 
-bool getTypeName(love::Type in, const char *&out)
+Type *Type::byName(const char *name)
 {
 {
-	return types.find(in, out);
+	auto pos = types.find(name);
+	if (pos == types.end())
+		return nullptr;
+	return pos->second;
 }
 }
 
 
 } // love
 } // love

+ 40 - 103
src/common/types.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -21,117 +21,54 @@
 #ifndef LOVE_TYPES_H
 #ifndef LOVE_TYPES_H
 #define LOVE_TYPES_H
 #define LOVE_TYPES_H
 
 
+#include "int.h"
+
 // STD
 // STD
 #include <bitset>
 #include <bitset>
+#include <vector>
 
 
 namespace love
 namespace love
 {
 {
 
 
-enum Type
+class Type
 {
 {
-	INVALID_ID = 0,
-	// Cross-module types.
-	OBJECT_ID,
-	DATA_ID,
-	MODULE_ID,
-	STREAM_ID,
-
-	// Filesystem.
-	FILESYSTEM_FILE_ID,
-	FILESYSTEM_DROPPED_FILE_ID,
-	FILESYSTEM_FILE_DATA_ID,
-
-	// Font
-	FONT_GLYPH_DATA_ID,
-	FONT_RASTERIZER_ID,
-
-	// Graphics
-	GRAPHICS_DRAWABLE_ID,
-	GRAPHICS_TEXTURE_ID,
-	GRAPHICS_IMAGE_ID,
-	GRAPHICS_QUAD_ID,
-	GRAPHICS_FONT_ID,
-	GRAPHICS_PARTICLE_SYSTEM_ID,
-	GRAPHICS_SPRITE_BATCH_ID,
-	GRAPHICS_CANVAS_ID,
-	GRAPHICS_SHADER_ID,
-	GRAPHICS_MESH_ID,
-	GRAPHICS_TEXT_ID,
-	GRAPHICS_VIDEO_ID,
-
-	// Image
-	IMAGE_IMAGE_DATA_ID,
-	IMAGE_COMPRESSED_IMAGE_DATA_ID,
-
-	// Joystick
-	JOYSTICK_JOYSTICK_ID,
-
-	// Math
-	MATH_RANDOM_GENERATOR_ID,
-	MATH_BEZIER_CURVE_ID,
-	MATH_COMPRESSED_DATA_ID,
-
-	// Audio
-	AUDIO_SOURCE_ID,
-
-	// Sound
-	SOUND_SOUND_DATA_ID,
-	SOUND_DECODER_ID,
-
-	// Mouse
-	MOUSE_CURSOR_ID,
-
-	// Physics
-	PHYSICS_WORLD_ID,
-	PHYSICS_CONTACT_ID,
-	PHYSICS_BODY_ID,
-	PHYSICS_FIXTURE_ID,
-	PHYSICS_SHAPE_ID,
-	PHYSICS_CIRCLE_SHAPE_ID,
-	PHYSICS_POLYGON_SHAPE_ID,
-	PHYSICS_EDGE_SHAPE_ID,
-	PHYSICS_CHAIN_SHAPE_ID,
-	PHYSICS_JOINT_ID,
-	PHYSICS_MOUSE_JOINT_ID,
-	PHYSICS_DISTANCE_JOINT_ID,
-	PHYSICS_PRISMATIC_JOINT_ID,
-	PHYSICS_REVOLUTE_JOINT_ID,
-	PHYSICS_PULLEY_JOINT_ID,
-	PHYSICS_GEAR_JOINT_ID,
-	PHYSICS_FRICTION_JOINT_ID,
-	PHYSICS_WELD_JOINT_ID,
-	PHYSICS_ROPE_JOINT_ID,
-	PHYSICS_WHEEL_JOINT_ID,
-	PHYSICS_MOTOR_JOINT_ID,
-
-	// Thread
-	THREAD_THREAD_ID,
-	THREAD_CHANNEL_ID,
-
-	// Video
-	VIDEO_VIDEO_STREAM_ID,
-
-	// The modules themselves. Only add abstracted modules here.
-	MODULE_FILESYSTEM_ID,
-	MODULE_GRAPHICS_ID,
-	MODULE_IMAGE_ID,
-	MODULE_SOUND_ID,
-
-	// Count the number of bits needed.
-	TYPE_MAX_ENUM
+public:
+	static const uint32 MAX_TYPES = 128;
+
+	Type(const char *name, Type *parent);
+	Type(const Type&) = delete;
+
+	static Type *byName(const char *name);
+
+	void init();
+	uint32 getId();
+	const char *getName() const;
+
+	bool isa(const uint32 &other)
+	{
+		if (!inited)
+			init();
+		return bits[other];
+	}
+
+	bool isa(const Type &other)
+	{
+		if (!inited)
+			init();
+		// Note that if this type implements the other
+		// calling init above will also have inited
+		// the other.
+		return bits[other.id];
+	}
+
+private:
+	const char * const name;
+	Type * const parent;
+	uint32 id;
+	bool inited;
+	std::bitset<MAX_TYPES> bits;
 };
 };
 
 
-typedef std::bitset<TYPE_MAX_ENUM> TypeBits;
-
-/**
- * Array of length TYPE_MAX_ENUM containing the flags for each love Type.
- **/
-extern const TypeBits *typeFlags;
-
-void addTypeName(Type type, const char *name);
-bool getTypeName(const char *in, Type &out);
-bool getTypeName(Type in, const char *&out);
-
 } // love
 } // love
 
 
 #endif // LOVE_TYPES_H
 #endif // LOVE_TYPES_H

+ 1 - 1
src/common/utf8.cpp

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
src/common/utf8.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages

+ 6 - 6
src/common/version.h

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2006-2016 LOVE Development Team
+ * Copyright (c) 2006-2017 LOVE Development Team
  *
  *
  * This software is provided 'as-is', without any express or implied
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
  * warranty.  In no event will the authors be held liable for any damages
@@ -25,13 +25,13 @@ namespace love
 {
 {
 
 
 // Version stuff.
 // Version stuff.
-#define LOVE_VERSION_STRING "0.10.2"
+#define LOVE_VERSION_STRING "0.11.0"
 static const int VERSION_MAJOR = 0;
 static const int VERSION_MAJOR = 0;
-static const int VERSION_MINOR = 10;
-static const int VERSION_REV = 2;
+static const int VERSION_MINOR = 11;
+static const int VERSION_REV = 0;
 static const char *VERSION = LOVE_VERSION_STRING;
 static const char *VERSION = LOVE_VERSION_STRING;
-static const char *VERSION_COMPATIBILITY[] =  { VERSION, "0.10.1", "0.10.0", 0 };
-static const char *VERSION_CODENAME = "Super Toast";
+static const char *VERSION_COMPATIBILITY[] =  { VERSION, 0 };
+static const char *VERSION_CODENAME = "";
 
 
 } // love
 } // love
 
 

+ 14 - 16
src/libraries/ddsparse/ddsinfo.h

@@ -1,25 +1,23 @@
 /**
 /**
  * Simple DDS data parser for compressed 2D textures.
  * Simple DDS data parser for compressed 2D textures.
  *
  *
- * Copyright (c) 2013 Alexander Szpakowski.
+ * Copyright (c) 2013-2017 Alex Szpakowski
  *
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
  *
  *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
  *
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
  *
  *
  *
  *
  * Enums and structs copied from Microsoft.
  * Enums and structs copied from Microsoft.

+ 14 - 16
src/libraries/ddsparse/ddsparse.cpp

@@ -1,25 +1,23 @@
 /**
 /**
  * Simple DDS data parser for compressed 2D textures.
  * Simple DDS data parser for compressed 2D textures.
  *
  *
- * Copyright (c) 2013 Alexander Szpakowski.
+ * Copyright (c) 2013-2017 Alex Szpakowski
  *
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
  *
  *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
  *
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
  **/
  **/
 
 
 #include "ddsparse.h"
 #include "ddsparse.h"

+ 14 - 16
src/libraries/ddsparse/ddsparse.h

@@ -1,25 +1,23 @@
 /**
 /**
  * Simple DDS data parser for compressed 2D textures.
  * Simple DDS data parser for compressed 2D textures.
  *
  *
- * Copyright (c) 2013 Alexander Szpakowski.
+ * Copyright (c) 2013-2017 Alex Szpakowski
  *
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
  *
  *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
  *
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
  **/
  **/
 
 
 #ifndef DDS_PARSE_H
 #ifndef DDS_PARSE_H

+ 1 - 4
src/libraries/enet/enet.cpp

@@ -734,9 +734,6 @@ static const struct luaL_Reg enet_host_funcs [] = {
 	// Since ENetSocket isn't part of enet-lua, we should try to keep
 	// Since ENetSocket isn't part of enet-lua, we should try to keep
 	// naming conventions the same as the rest of the lib.
 	// naming conventions the same as the rest of the lib.
 	{"get_socket_address", host_get_socket_address},
 	{"get_socket_address", host_get_socket_address},
-	// TODO: Remove the line below in future versions, it's for backward
-	// compatibility only.
-	{"socket_get_address", host_get_socket_address},
 	// We need this function to free up our ports when needed!
 	// We need this function to free up our ports when needed!
 	{"destroy", host_gc},
 	{"destroy", host_gc},
 
 
@@ -803,7 +800,7 @@ int luaopen_enet(lua_State *l) {
 
 
 	lua_setfield(l, LUA_REGISTRYINDEX, "enet_peers");
 	lua_setfield(l, LUA_REGISTRYINDEX, "enet_peers");
 
 
-	luax_register(l, "enet", enet_funcs);
+	luax_register(l, nullptr, enet_funcs);
 
 
 	// return the enet table created with luaL_register
 	// return the enet table created with luaL_register
 	return 1;
 	return 1;

+ 1 - 1
src/libraries/enet/lua-enet.h

@@ -1,5 +1,5 @@
 /**
 /**
-* Copyright (c) 2006-2016 LOVE Development Team
+* Copyright (c) 2006-2017 LOVE Development Team
 * 
 * 
 * This software is provided 'as-is', without any express or implied
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * warranty.  In no event will the authors be held liable for any damages

+ 155 - 0
src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp

@@ -0,0 +1,155 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#define SH_EXPORTING
+
+#include <cassert>
+
+#include "InitializeDll.h"
+#include "../glslang/Include/InitializeGlobals.h"
+
+#include "../glslang/Public/ShaderLang.h"
+
+namespace glslang {
+
+OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
+
+bool InitProcess()
+{
+    glslang::GetGlobalLock();
+
+    if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) {
+        //
+        // Function is re-entrant.
+        //
+
+        glslang::ReleaseGlobalLock();
+        return true;
+    }
+
+    ThreadInitializeIndex = OS_AllocTLSIndex();
+
+    if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
+        assert(0 && "InitProcess(): Failed to allocate TLS area for init flag");
+
+        glslang::ReleaseGlobalLock();
+        return false;
+    }
+
+    if (! InitializePoolIndex()) {
+        assert(0 && "InitProcess(): Failed to initialize global pool");
+
+        glslang::ReleaseGlobalLock();
+        return false;
+    }
+
+    if (! InitThread()) {
+        assert(0 && "InitProcess(): Failed to initialize thread");
+
+        glslang::ReleaseGlobalLock();
+        return false;
+    }
+
+    glslang::ReleaseGlobalLock();
+    return true;
+}
+
+
+bool InitThread()
+{
+    //
+    // This function is re-entrant
+    //
+    if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
+        assert(0 && "InitThread(): Process hasn't been initalised.");
+        return false;
+    }
+
+    if (OS_GetTLSValue(ThreadInitializeIndex) != 0)
+        return true;
+
+    InitializeMemoryPools();
+
+    if (! OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) {
+        assert(0 && "InitThread(): Unable to set init flag.");
+        return false;
+    }
+
+    return true;
+}
+
+
+bool DetachThread()
+{
+    bool success = true;
+
+    if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
+        return true;
+
+    //
+    // Function is re-entrant and this thread may not have been initialized.
+    //
+    if (OS_GetTLSValue(ThreadInitializeIndex) != 0) {
+        if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) {
+            assert(0 && "DetachThread(): Unable to clear init flag.");
+            success = false;
+        }
+
+        FreeGlobalPools();
+
+    }
+
+    return success;
+}
+
+bool DetachProcess()
+{
+    bool success = true;
+
+    if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
+        return true;
+
+    ShFinalize();
+
+    success = DetachThread();
+
+    FreePoolIndex();
+
+    OS_FreeTLSIndex(ThreadInitializeIndex);
+    ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
+
+    return success;
+}
+
+} // end namespace glslang

+ 49 - 0
src/libraries/glslang/OGLCompilersDLL/InitializeDll.h

@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+#ifndef __INITIALIZEDLL_H
+#define __INITIALIZEDLL_H
+
+#include "../glslang/OSDependent/osinclude.h"
+
+namespace glslang {
+
+bool InitProcess();
+bool InitThread();
+bool DetachThread();
+bool DetachProcess();
+
+} // end namespace glslang
+
+#endif // __INITIALIZEDLL_H
+

+ 76 - 0
src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp

@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/Common.h"
+#include "../Include/ShHandle.h"
+#include "../MachineIndependent/Versions.h"
+
+//
+// Here is where real machine specific high-level data would be defined.
+//
+class TGenericCompiler : public TCompiler {
+public:
+    TGenericCompiler(EShLanguage l, int dOptions) : TCompiler(l, infoSink), debugOptions(dOptions) { }
+    virtual bool compile(TIntermNode* root, int version = 0, EProfile profile = ENoProfile);
+    TInfoSink infoSink;
+    int debugOptions;
+};
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code.  It returns
+// a subclass of TCompiler.
+//
+TCompiler* ConstructCompiler(EShLanguage language, int debugOptions)
+{
+    return new TGenericCompiler(language, debugOptions);
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+    delete compiler;
+}
+
+//
+//  Generate code from the given parse tree
+//
+bool TGenericCompiler::compile(TIntermNode* /*root*/, int /*version*/, EProfile /*profile*/)
+{
+    haveValidObjectCode = true;
+
+    return haveValidObjectCode;
+}

+ 91 - 0
src/libraries/glslang/glslang/GenericCodeGen/Link.cpp

@@ -0,0 +1,91 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// The top level algorithms for linking multiple
+// shaders together.
+//
+#include "../Include/Common.h"
+#include "../Include/ShHandle.h"
+
+//
+// Actual link object, derived from the shader handle base classes.
+//
+class TGenericLinker : public TLinker {
+public:
+    TGenericLinker(EShExecutable e, int dOptions) : TLinker(e, infoSink), debugOptions(dOptions) { }
+    bool link(TCompilerList&, TUniformMap*) { return true; }
+    void getAttributeBindings(ShBindingTable const **) const { }
+    TInfoSink infoSink;
+    int debugOptions;
+};
+
+//
+// The internal view of a uniform/float object exchanged with the driver.
+//
+class TUniformLinkedMap : public TUniformMap {
+public:
+    TUniformLinkedMap() { }
+    virtual int getLocation(const char*) { return 0; }
+};
+
+TShHandleBase* ConstructLinker(EShExecutable executable, int debugOptions)
+{
+    return new TGenericLinker(executable, debugOptions);
+}
+
+void DeleteLinker(TShHandleBase* linker)
+{
+    delete linker;
+}
+
+TUniformMap* ConstructUniformMap()
+{
+    return new TUniformLinkedMap();
+}
+
+void DeleteUniformMap(TUniformMap* map)
+{
+    delete map;
+}
+
+TShHandleBase* ConstructBindings()
+{
+    return 0;
+}
+
+void DeleteBindingList(TShHandleBase* bindingList)
+{
+    delete bindingList;
+}

+ 382 - 0
src/libraries/glslang/glslang/Include/BaseTypes.h

@@ -0,0 +1,382 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _BASICTYPES_INCLUDED_
+#define _BASICTYPES_INCLUDED_
+
+namespace glslang {
+
+//
+// Basic type.  Arrays, vectors, sampler details, etc., are orthogonal to this.
+//
+enum TBasicType {
+    EbtVoid,
+    EbtFloat,
+    EbtDouble,
+#ifdef AMD_EXTENSIONS
+    EbtFloat16,
+#endif
+    EbtInt,
+    EbtUint,
+    EbtInt64,
+    EbtUint64,
+#ifdef AMD_EXTENSIONS
+    EbtInt16,
+    EbtUint16,
+#endif
+    EbtBool,
+    EbtAtomicUint,
+    EbtSampler,
+    EbtStruct,
+    EbtBlock,
+
+    // HLSL types that live only temporarily.
+    EbtString,
+
+    EbtNumTypes
+};
+
+//
+// Storage qualifiers.  Should align with different kinds of storage or
+// resource or GLSL storage qualifier.  Expansion is deprecated.
+//
+// N.B.: You probably DON'T want to add anything here, but rather just add it
+// to the built-in variables.  See the comment above TBuiltInVariable.
+//
+// A new built-in variable will normally be an existing qualifier, like 'in', 'out', etc.
+// DO NOT follow the design pattern of, say EvqInstanceId, etc.
+//
+enum TStorageQualifier {
+    EvqTemporary,     // For temporaries (within a function), read/write
+    EvqGlobal,        // For globals read/write
+    EvqConst,         // User-defined constant values, will be semantically constant and constant folded
+    EvqVaryingIn,     // pipeline input, read only, also supercategory for all built-ins not included in this enum (see TBuiltInVariable)
+    EvqVaryingOut,    // pipeline output, read/write, also supercategory for all built-ins not included in this enum (see TBuiltInVariable)
+    EvqUniform,       // read only, shared with app
+    EvqBuffer,        // read/write, shared with app
+    EvqShared,        // compute shader's read/write 'shared' qualifier
+
+    // parameters
+    EvqIn,            // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter
+    EvqOut,           // also, for 'out' in the grammar before we know if it's a pipeline output or an 'out' parameter
+    EvqInOut,
+    EvqConstReadOnly, // input; also other read-only types having neither a constant value nor constant-value semantics
+
+    // built-ins read by vertex shader
+    EvqVertexId,
+    EvqInstanceId,
+
+    // built-ins written by vertex shader
+    EvqPosition,
+    EvqPointSize,
+    EvqClipVertex,
+
+    // built-ins read by fragment shader
+    EvqFace,
+    EvqFragCoord,
+    EvqPointCoord,
+
+    // built-ins written by fragment shader
+    EvqFragColor,
+    EvqFragDepth,
+
+    // end of list
+    EvqLast
+};
+
+//
+// Subcategories of the TStorageQualifier, simply to give a direct mapping
+// between built-in variable names and an numerical value (the enum).
+//
+// For backward compatibility, there is some redundancy between the
+// TStorageQualifier and these.  Existing members should both be maintained accurately.
+// However, any new built-in variable (and any existing non-redundant one)
+// must follow the pattern that the specific built-in is here, and only its
+// general qualifier is in TStorageQualifier.
+//
+// Something like gl_Position, which is sometimes 'in' and sometimes 'out'
+// shows up as two different built-in variables in a single stage, but
+// only has a single enum in TBuiltInVariable, so both the
+// TStorageQualifier and the TBuitinVariable are needed to distinguish
+// between them.
+//
+enum TBuiltInVariable {
+    EbvNone,
+    EbvNumWorkGroups,
+    EbvWorkGroupSize,
+    EbvWorkGroupId,
+    EbvLocalInvocationId,
+    EbvGlobalInvocationId,
+    EbvLocalInvocationIndex,
+    EbvSubGroupSize,
+    EbvSubGroupInvocation,
+    EbvSubGroupEqMask,
+    EbvSubGroupGeMask,
+    EbvSubGroupGtMask,
+    EbvSubGroupLeMask,
+    EbvSubGroupLtMask,
+    EbvVertexId,
+    EbvInstanceId,
+    EbvVertexIndex,
+    EbvInstanceIndex,
+    EbvBaseVertex,
+    EbvBaseInstance,
+    EbvDrawId,
+    EbvPosition,
+    EbvPointSize,
+    EbvClipVertex,
+    EbvClipDistance,
+    EbvCullDistance,
+    EbvNormal,
+    EbvVertex,
+    EbvMultiTexCoord0,
+    EbvMultiTexCoord1,
+    EbvMultiTexCoord2,
+    EbvMultiTexCoord3,
+    EbvMultiTexCoord4,
+    EbvMultiTexCoord5,
+    EbvMultiTexCoord6,
+    EbvMultiTexCoord7,
+    EbvFrontColor,
+    EbvBackColor,
+    EbvFrontSecondaryColor,
+    EbvBackSecondaryColor,
+    EbvTexCoord,
+    EbvFogFragCoord,
+    EbvInvocationId,
+    EbvPrimitiveId,
+    EbvLayer,
+    EbvViewportIndex,
+    EbvPatchVertices,
+    EbvTessLevelOuter,
+    EbvTessLevelInner,
+    EbvBoundingBox,
+    EbvTessCoord,
+    EbvColor,
+    EbvSecondaryColor,
+    EbvFace,
+    EbvFragCoord,
+    EbvPointCoord,
+    EbvFragColor,
+    EbvFragData,
+    EbvFragDepth,
+    EbvSampleId,
+    EbvSamplePosition,
+    EbvSampleMask,
+    EbvHelperInvocation,
+#ifdef AMD_EXTENSIONS
+    EbvBaryCoordNoPersp,
+    EbvBaryCoordNoPerspCentroid,
+    EbvBaryCoordNoPerspSample,
+    EbvBaryCoordSmooth,
+    EbvBaryCoordSmoothCentroid,
+    EbvBaryCoordSmoothSample,
+    EbvBaryCoordPullModel,
+#endif
+
+    EbvViewIndex,
+    EbvDeviceIndex,
+
+#ifdef NV_EXTENSIONS
+    EbvViewportMaskNV,
+    EbvSecondaryPositionNV,
+    EbvSecondaryViewportMaskNV,
+    EbvPositionPerViewNV,
+    EbvViewportMaskPerViewNV,
+#endif 
+
+    // HLSL built-ins that live only temporarily, until they get remapped
+    // to one of the above.
+    EbvFragDepthGreater,
+    EbvFragDepthLesser,
+    EbvStencilRef,
+    EbvGsOutputStream,
+    EbvOutputPatch,
+    EbvInputPatch,
+
+    // structbuffer types
+    EbvAppendConsume, // no need to differentiate append and consume
+    EbvRWStructuredBuffer,
+    EbvStructuredBuffer,
+    EbvByteAddressBuffer,
+    EbvRWByteAddressBuffer,
+
+    EbvLast
+};
+
+// These will show up in error messages
+__inline const char* GetStorageQualifierString(TStorageQualifier q)
+{
+    switch (q) {
+    case EvqTemporary:      return "temp";           break;
+    case EvqGlobal:         return "global";         break;
+    case EvqConst:          return "const";          break;
+    case EvqConstReadOnly:  return "const (read only)"; break;
+    case EvqVaryingIn:      return "in";             break;
+    case EvqVaryingOut:     return "out";            break;
+    case EvqUniform:        return "uniform";        break;
+    case EvqBuffer:         return "buffer";         break;
+    case EvqShared:         return "shared";         break;
+    case EvqIn:             return "in";             break;
+    case EvqOut:            return "out";            break;
+    case EvqInOut:          return "inout";          break;
+    case EvqVertexId:       return "gl_VertexId";    break;
+    case EvqInstanceId:     return "gl_InstanceId";  break;
+    case EvqPosition:       return "gl_Position";    break;
+    case EvqPointSize:      return "gl_PointSize";   break;
+    case EvqClipVertex:     return "gl_ClipVertex";  break;
+    case EvqFace:           return "gl_FrontFacing"; break;
+    case EvqFragCoord:      return "gl_FragCoord";   break;
+    case EvqPointCoord:     return "gl_PointCoord";  break;
+    case EvqFragColor:      return "fragColor";      break;
+    case EvqFragDepth:      return "gl_FragDepth";   break;
+    default:                return "unknown qualifier";
+    }
+}
+
+__inline const char* GetBuiltInVariableString(TBuiltInVariable v)
+{
+    switch (v) {
+    case EbvNone:                 return "";
+    case EbvNumWorkGroups:        return "NumWorkGroups";
+    case EbvWorkGroupSize:        return "WorkGroupSize";
+    case EbvWorkGroupId:          return "WorkGroupID";
+    case EbvLocalInvocationId:    return "LocalInvocationID";
+    case EbvGlobalInvocationId:   return "GlobalInvocationID";
+    case EbvLocalInvocationIndex: return "LocalInvocationIndex";
+    case EbvSubGroupSize:         return "SubGroupSize";
+    case EbvSubGroupInvocation:   return "SubGroupInvocation";
+    case EbvSubGroupEqMask:       return "SubGroupEqMask";
+    case EbvSubGroupGeMask:       return "SubGroupGeMask";
+    case EbvSubGroupGtMask:       return "SubGroupGtMask";
+    case EbvSubGroupLeMask:       return "SubGroupLeMask";
+    case EbvSubGroupLtMask:       return "SubGroupLtMask";
+    case EbvVertexId:             return "VertexId";
+    case EbvInstanceId:           return "InstanceId";
+    case EbvVertexIndex:          return "VertexIndex";
+    case EbvInstanceIndex:        return "InstanceIndex";
+    case EbvBaseVertex:           return "BaseVertex";
+    case EbvBaseInstance:         return "BaseInstance";
+    case EbvDrawId:               return "DrawId";
+    case EbvPosition:             return "Position";
+    case EbvPointSize:            return "PointSize";
+    case EbvClipVertex:           return "ClipVertex";
+    case EbvClipDistance:         return "ClipDistance";
+    case EbvCullDistance:         return "CullDistance";
+    case EbvNormal:               return "Normal";
+    case EbvVertex:               return "Vertex";
+    case EbvMultiTexCoord0:       return "MultiTexCoord0";
+    case EbvMultiTexCoord1:       return "MultiTexCoord1";
+    case EbvMultiTexCoord2:       return "MultiTexCoord2";
+    case EbvMultiTexCoord3:       return "MultiTexCoord3";
+    case EbvMultiTexCoord4:       return "MultiTexCoord4";
+    case EbvMultiTexCoord5:       return "MultiTexCoord5";
+    case EbvMultiTexCoord6:       return "MultiTexCoord6";
+    case EbvMultiTexCoord7:       return "MultiTexCoord7";
+    case EbvFrontColor:           return "FrontColor";
+    case EbvBackColor:            return "BackColor";
+    case EbvFrontSecondaryColor:  return "FrontSecondaryColor";
+    case EbvBackSecondaryColor:   return "BackSecondaryColor";
+    case EbvTexCoord:             return "TexCoord";
+    case EbvFogFragCoord:         return "FogFragCoord";
+    case EbvInvocationId:         return "InvocationID";
+    case EbvPrimitiveId:          return "PrimitiveID";
+    case EbvLayer:                return "Layer";
+    case EbvViewportIndex:        return "ViewportIndex";
+    case EbvPatchVertices:        return "PatchVertices";
+    case EbvTessLevelOuter:       return "TessLevelOuter";
+    case EbvTessLevelInner:       return "TessLevelInner";
+    case EbvBoundingBox:          return "BoundingBox";
+    case EbvTessCoord:            return "TessCoord";
+    case EbvColor:                return "Color";
+    case EbvSecondaryColor:       return "SecondaryColor";
+    case EbvFace:                 return "Face";
+    case EbvFragCoord:            return "FragCoord";
+    case EbvPointCoord:           return "PointCoord";
+    case EbvFragColor:            return "FragColor";
+    case EbvFragData:             return "FragData";
+    case EbvFragDepth:            return "FragDepth";
+    case EbvSampleId:             return "SampleId";
+    case EbvSamplePosition:       return "SamplePosition";
+    case EbvSampleMask:           return "SampleMaskIn";
+    case EbvHelperInvocation:     return "HelperInvocation";
+#ifdef AMD_EXTENSIONS
+    case EbvBaryCoordNoPersp:           return "BaryCoordNoPersp";
+    case EbvBaryCoordNoPerspCentroid:   return "BaryCoordNoPerspCentroid";
+    case EbvBaryCoordNoPerspSample:     return "BaryCoordNoPerspSample";
+    case EbvBaryCoordSmooth:            return "BaryCoordSmooth";
+    case EbvBaryCoordSmoothCentroid:    return "BaryCoordSmoothCentroid";
+    case EbvBaryCoordSmoothSample:      return "BaryCoordSmoothSample";
+    case EbvBaryCoordPullModel:         return "BaryCoordPullModel";
+#endif
+
+    case EbvViewIndex:                  return "ViewIndex";
+    case EbvDeviceIndex:                return "DeviceIndex";
+
+#ifdef NV_EXTENSIONS
+    case EbvViewportMaskNV:             return "ViewportMaskNV";
+    case EbvSecondaryPositionNV:        return "SecondaryPositionNV";
+    case EbvSecondaryViewportMaskNV:    return "SecondaryViewportMaskNV";
+    case EbvPositionPerViewNV:          return "PositionPerViewNV";
+    case EbvViewportMaskPerViewNV:      return "ViewportMaskPerViewNV";
+#endif 
+    default:                      return "unknown built-in variable";
+    }
+}
+
+// In this enum, order matters; users can assume higher precision is a bigger value
+// and EpqNone is 0.
+enum TPrecisionQualifier {
+    EpqNone = 0,
+    EpqLow,
+    EpqMedium,
+    EpqHigh
+};
+
+__inline const char* GetPrecisionQualifierString(TPrecisionQualifier p)
+{
+    switch(p) {
+    case EpqNone:   return "";        break;
+    case EpqLow:    return "lowp";    break;
+    case EpqMedium: return "mediump"; break;
+    case EpqHigh:   return "highp";   break;
+    default:        return "unknown precision qualifier";
+    }
+}
+
+} // end namespace glslang
+
+#endif // _BASICTYPES_INCLUDED_

+ 266 - 0
src/libraries/glslang/glslang/Include/Common.h

@@ -0,0 +1,266 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _COMMON_INCLUDED_
+#define _COMMON_INCLUDED_
+
+#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) || defined MINGW_HAS_SECURE_API
+    #include <basetsd.h>
+    #define snprintf sprintf_s
+    #define safe_vsprintf(buf,max,format,args) vsnprintf_s((buf), (max), (max), (format), (args))
+#elif defined (solaris)
+    #define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args))
+    #include <sys/int_types.h>
+    #define UINT_PTR uintptr_t
+#else
+    #define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args))
+    #include <stdint.h>
+    #define UINT_PTR uintptr_t
+#endif
+
+#if defined(__ANDROID__) || _MSC_VER < 1700
+#include <sstream>
+namespace std {
+template<typename T>
+std::string to_string(const T& val) {
+  std::ostringstream os;
+  os << val;
+  return os.str();
+}
+}
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1700
+inline long long int strtoll (const char* str, char** endptr, int base)
+{
+  return _strtoi64(str, endptr, base);
+}
+inline unsigned long long int strtoull (const char* str, char** endptr, int base)
+{
+  return _strtoui64(str, endptr, base);
+}
+inline long long int atoll (const char* str)
+{
+  return strtoll(str, NULL, 10);
+}
+#endif
+
+/* windows only pragma */
+#ifdef _MSC_VER
+    #pragma warning(disable : 4786) // Don't warn about too long identifiers
+    #pragma warning(disable : 4514) // unused inline method
+    #pragma warning(disable : 4201) // nameless union
+#endif
+
+#include <set>
+#include <unordered_set>
+#include <vector>
+#include <map>
+#include <unordered_map>
+#include <list>
+#include <algorithm>
+#include <string>
+#include <cstdio>
+#include <cassert>
+
+#include "PoolAlloc.h"
+
+//
+// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
+//
+#define POOL_ALLOCATOR_NEW_DELETE(A)                                  \
+    void* operator new(size_t s) { return (A).allocate(s); }          \
+    void* operator new(size_t, void *_Where) { return (_Where); }     \
+    void operator delete(void*) { }                                   \
+    void operator delete(void *, void *) { }                          \
+    void* operator new[](size_t s) { return (A).allocate(s); }        \
+    void* operator new[](size_t, void *_Where) { return (_Where); }   \
+    void operator delete[](void*) { }                                 \
+    void operator delete[](void *, void *) { }
+
+namespace glslang {
+
+    //
+    // Pool version of string.
+    //
+    typedef pool_allocator<char> TStringAllocator;
+    typedef std::basic_string <char, std::char_traits<char>, TStringAllocator> TString;
+
+} // end namespace glslang
+
+// Repackage the std::hash for use by unordered map/set with a TString key.
+namespace std {
+
+    template<> struct hash<glslang::TString> {
+        std::size_t operator()(const glslang::TString& s) const
+        {
+            const unsigned _FNV_offset_basis = 2166136261U;
+            const unsigned _FNV_prime = 16777619U;
+            unsigned _Val = _FNV_offset_basis;
+            size_t _Count = s.size();
+            const char* _First = s.c_str();
+            for (size_t _Next = 0; _Next < _Count; ++_Next)
+            {
+                _Val ^= (unsigned)_First[_Next];
+                _Val *= _FNV_prime;
+            }
+
+            return _Val;
+        }
+    };
+}
+
+namespace glslang {
+
+inline TString* NewPoolTString(const char* s)
+{
+    void* memory = GetThreadPoolAllocator().allocate(sizeof(TString));
+    return new(memory) TString(s);
+}
+
+template<class T> inline T* NewPoolObject(T)
+{
+    return new(GetThreadPoolAllocator().allocate(sizeof(T))) T;
+}
+
+template<class T> inline T* NewPoolObject(T, int instances)
+{
+    return new(GetThreadPoolAllocator().allocate(instances * sizeof(T))) T[instances];
+}
+
+//
+// Pool allocator versions of vectors, lists, and maps
+//
+template <class T> class TVector : public std::vector<T, pool_allocator<T> > {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    typedef typename std::vector<T, pool_allocator<T> >::size_type size_type;
+    TVector() : std::vector<T, pool_allocator<T> >() {}
+    TVector(const pool_allocator<T>& a) : std::vector<T, pool_allocator<T> >(a) {}
+    TVector(size_type i) : std::vector<T, pool_allocator<T> >(i) {}
+    TVector(size_type i, const T& val) : std::vector<T, pool_allocator<T> >(i, val) {}
+};
+
+template <class T> class TList  : public std::list<T, pool_allocator<T> > {
+};
+
+template <class K, class D, class CMP = std::less<K> >
+class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<K const, D> > > {
+};
+
+template <class K, class D, class HASH = std::hash<K>, class PRED = std::equal_to<K> >
+class TUnorderedMap : public std::unordered_map<K, D, HASH, PRED, pool_allocator<std::pair<K const, D> > > {
+};
+
+//
+// Persistent string memory.  Should only be used for strings that survive
+// across compiles/links.
+//
+typedef std::basic_string<char> TPersistString;
+
+//
+// templatized min and max functions.
+//
+template <class T> T Min(const T a, const T b) { return a < b ? a : b; }
+template <class T> T Max(const T a, const T b) { return a > b ? a : b; }
+
+//
+// Create a TString object from an integer.
+//
+#if defined _MSC_VER || defined MINGW_HAS_SECURE_API
+inline const TString String(const int i, const int base = 10)
+{
+    char text[16];     // 32 bit ints are at most 10 digits in base 10
+    _itoa_s(i, text, sizeof(text), base);
+    return text;
+}
+#else
+inline const TString String(const int i, const int /*base*/ = 10)
+{
+    char text[16];     // 32 bit ints are at most 10 digits in base 10
+
+    // we assume base 10 for all cases
+    snprintf(text, sizeof(text), "%d", i);
+
+    return text;
+}
+#endif
+
+struct TSourceLoc {
+    void init() { name = nullptr; string = 0; line = 0; column = 0; }
+    // Returns the name if it exists. Otherwise, returns the string number.
+    std::string getStringNameOrNum(bool quoteStringName = true) const
+    {
+        if (name != nullptr)
+            return quoteStringName ? ("\"" + std::string(name) + "\"") : name;
+        return std::to_string((long long)string);
+    }
+    const char* name; // descriptive name for this string
+    int string;
+    int line;
+    int column;
+};
+
+typedef TMap<TString, TString> TPragmaTable;
+
+const int MaxTokenLength = 1024;
+
+template <class T> bool IsPow2(T powerOf2)
+{
+    if (powerOf2 <= 0)
+        return false;
+
+    return (powerOf2 & (powerOf2 - 1)) == 0;
+}
+
+// Round number up to a multiple of the given powerOf2, which is not
+// a power, just a number that must be a power of 2.
+template <class T> void RoundToPow2(T& number, int powerOf2)
+{
+    assert(IsPow2(powerOf2));
+    number = (number + powerOf2 - 1) & ~(powerOf2 - 1);
+}
+
+template <class T> bool IsMultipleOfPow2(T number, int powerOf2)
+{
+    assert(IsPow2(powerOf2));
+    return ! (number & (powerOf2 - 1));
+}
+
+} // end namespace glslang
+
+#endif // _COMMON_INCLUDED_

+ 625 - 0
src/libraries/glslang/glslang/Include/ConstantUnion.h

@@ -0,0 +1,625 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _CONSTANT_UNION_INCLUDED_
+#define _CONSTANT_UNION_INCLUDED_
+
+namespace glslang {
+
+class TConstUnion {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    TConstUnion() : iConst(0), type(EbtInt) { }
+
+    void setIConst(int i)
+    {
+        iConst = i;
+        type = EbtInt;
+    }
+
+    void setUConst(unsigned int u)
+    {
+        uConst = u;
+        type = EbtUint;
+    }
+
+    void setI64Const(long long i64)
+    {
+        i64Const = i64;
+        type = EbtInt64;
+    }
+
+    void setU64Const(unsigned long long u64)
+    {
+        u64Const = u64;
+        type = EbtUint64;
+    }
+
+    void setDConst(double d)
+    {
+        dConst = d;
+        type = EbtDouble;
+    }
+
+    void setBConst(bool b)
+    {
+        bConst = b;
+        type = EbtBool;
+    }
+
+    void setSConst(const TString* s)
+    {
+        sConst = s;
+        type = EbtString;
+    }
+
+    int                getIConst() const   { return iConst; }
+    unsigned int       getUConst() const   { return uConst; }
+    long long          getI64Const() const { return i64Const; }
+    unsigned long long getU64Const() const { return u64Const; }
+    double             getDConst() const   { return dConst; }
+    bool               getBConst() const   { return bConst; }
+    const TString*     getSConst() const   { return sConst; }
+
+    bool operator==(const int i) const
+    {
+        if (i == iConst)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const unsigned int u) const
+    {
+        if (u == uConst)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const long long i64) const
+    {
+        if (i64 == i64Const)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const unsigned long long u64) const
+    {
+        if (u64 == u64Const)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const double d) const
+    {
+        if (d == dConst)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const bool b) const
+    {
+        if (b == bConst)
+            return true;
+
+        return false;
+    }
+
+    bool operator==(const TConstUnion& constant) const
+    {
+        if (constant.type != type)
+            return false;
+
+        switch (type) {
+        case EbtInt:
+            if (constant.iConst == iConst)
+                return true;
+
+            break;
+        case EbtUint:
+            if (constant.uConst == uConst)
+                return true;
+
+            break;
+        case EbtInt64:
+            if (constant.i64Const == i64Const)
+                return true;
+
+            break;
+        case EbtUint64:
+            if (constant.u64Const == u64Const)
+                return true;
+
+            break;
+        case EbtDouble:
+            if (constant.dConst == dConst)
+                return true;
+
+            break;
+        case EbtBool:
+            if (constant.bConst == bConst)
+                return true;
+
+            break;
+        default:
+            assert(false && "Default missing");
+        }
+
+        return false;
+    }
+
+    bool operator!=(const int i) const
+    {
+        return !operator==(i);
+    }
+
+    bool operator!=(const unsigned int u) const
+    {
+        return !operator==(u);
+    }
+
+    bool operator!=(const long long i) const
+    {
+        return !operator==(i);
+    }
+
+    bool operator!=(const unsigned long long u) const
+    {
+        return !operator==(u);
+    }
+
+    bool operator!=(const float f) const
+    {
+        return !operator==(f);
+    }
+
+    bool operator!=(const bool b) const
+    {
+        return !operator==(b);
+    }
+
+    bool operator!=(const TConstUnion& constant) const
+    {
+        return !operator==(constant);
+    }
+
+    bool operator>(const TConstUnion& constant) const
+    {
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:
+            if (iConst > constant.iConst)
+                return true;
+
+            return false;
+        case EbtUint:
+            if (uConst > constant.uConst)
+                return true;
+
+            return false;
+        case EbtInt64:
+            if (i64Const > constant.i64Const)
+                return true;
+
+            return false;
+        case EbtUint64:
+            if (u64Const > constant.u64Const)
+                return true;
+
+            return false;
+        case EbtDouble:
+            if (dConst > constant.dConst)
+                return true;
+
+            return false;
+        default:
+            assert(false && "Default missing");
+            return false;
+        }
+    }
+
+    bool operator<(const TConstUnion& constant) const
+    {
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:
+            if (iConst < constant.iConst)
+                return true;
+
+            return false;
+        case EbtUint:
+            if (uConst < constant.uConst)
+                return true;
+
+            return false;
+        case EbtInt64:
+            if (i64Const < constant.i64Const)
+                return true;
+
+            return false;
+        case EbtUint64:
+            if (u64Const < constant.u64Const)
+                return true;
+
+            return false;
+        case EbtDouble:
+            if (dConst < constant.dConst)
+                return true;
+
+            return false;
+        default:
+            assert(false && "Default missing");
+            return false;
+        }
+    }
+
+    TConstUnion operator+(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
+        case EbtInt64: returnValue.setI64Const(i64Const + constant.i64Const); break;
+        case EbtUint: returnValue.setUConst(uConst + constant.uConst); break;
+        case EbtUint64: returnValue.setU64Const(u64Const + constant.u64Const); break;
+        case EbtDouble: returnValue.setDConst(dConst + constant.dConst); break;
+        default: assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator-(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
+        case EbtInt64: returnValue.setI64Const(i64Const - constant.i64Const); break;
+        case EbtUint: returnValue.setUConst(uConst - constant.uConst); break;
+        case EbtUint64: returnValue.setU64Const(u64Const - constant.u64Const); break;
+        case EbtDouble: returnValue.setDConst(dConst - constant.dConst); break;
+        default: assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator*(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
+        case EbtInt64: returnValue.setI64Const(i64Const * constant.i64Const); break;
+        case EbtUint: returnValue.setUConst(uConst * constant.uConst); break;
+        case EbtUint64: returnValue.setU64Const(u64Const * constant.u64Const); break;
+        case EbtDouble: returnValue.setDConst(dConst * constant.dConst); break;
+        default: assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator%(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
+        case EbtInt64: returnValue.setI64Const(i64Const % constant.i64Const); break;
+        case EbtUint: returnValue.setUConst(uConst % constant.uConst); break;
+        case EbtUint64: returnValue.setU64Const(u64Const % constant.u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator>>(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        switch (type) {
+        case EbtInt:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setIConst(iConst >> constant.iConst);   break;
+            case EbtUint:   returnValue.setIConst(iConst >> constant.uConst);   break;
+            case EbtInt64:  returnValue.setIConst(iConst >> constant.i64Const); break;
+            case EbtUint64: returnValue.setIConst(iConst >> constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtUint:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setUConst(uConst >> constant.iConst);   break;
+            case EbtUint:   returnValue.setUConst(uConst >> constant.uConst);   break;
+            case EbtInt64:  returnValue.setUConst(uConst >> constant.i64Const); break;
+            case EbtUint64: returnValue.setUConst(uConst >> constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+         case EbtInt64:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setI64Const(i64Const >> constant.iConst);   break;
+            case EbtUint:   returnValue.setI64Const(i64Const >> constant.uConst);   break;
+            case EbtInt64:  returnValue.setI64Const(i64Const >> constant.i64Const); break;
+            case EbtUint64: returnValue.setI64Const(i64Const >> constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtUint64:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setU64Const(u64Const >> constant.iConst);   break;
+            case EbtUint:   returnValue.setU64Const(u64Const >> constant.uConst);   break;
+            case EbtInt64:  returnValue.setU64Const(u64Const >> constant.i64Const); break;
+            case EbtUint64: returnValue.setU64Const(u64Const >> constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator<<(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        switch (type) {
+        case EbtInt:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setIConst(iConst << constant.iConst);   break;
+            case EbtUint:   returnValue.setIConst(iConst << constant.uConst);   break;
+            case EbtInt64:  returnValue.setIConst(iConst << constant.i64Const); break;
+            case EbtUint64: returnValue.setIConst(iConst << constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtUint:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setUConst(uConst << constant.iConst);   break;
+            case EbtUint:   returnValue.setUConst(uConst << constant.uConst);   break;
+            case EbtInt64:  returnValue.setUConst(uConst << constant.i64Const); break;
+            case EbtUint64: returnValue.setUConst(uConst << constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtInt64:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setI64Const(i64Const << constant.iConst);   break;
+            case EbtUint:   returnValue.setI64Const(i64Const << constant.uConst);   break;
+            case EbtInt64:  returnValue.setI64Const(i64Const << constant.i64Const); break;
+            case EbtUint64: returnValue.setI64Const(i64Const << constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        case EbtUint64:
+            switch (constant.type) {
+            case EbtInt:    returnValue.setU64Const(u64Const << constant.iConst);   break;
+            case EbtUint:   returnValue.setU64Const(u64Const << constant.uConst);   break;
+            case EbtInt64:  returnValue.setU64Const(u64Const << constant.i64Const); break;
+            case EbtUint64: returnValue.setU64Const(u64Const << constant.u64Const); break;
+            default:       assert(false && "Default missing");
+            }
+            break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator&(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:  returnValue.setIConst(iConst & constant.iConst); break;
+        case EbtUint: returnValue.setUConst(uConst & constant.uConst); break;
+        case EbtInt64:  returnValue.setI64Const(i64Const & constant.i64Const); break;
+        case EbtUint64: returnValue.setU64Const(u64Const & constant.u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator|(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:  returnValue.setIConst(iConst | constant.iConst); break;
+        case EbtUint: returnValue.setUConst(uConst | constant.uConst); break;
+        case EbtInt64:  returnValue.setI64Const(i64Const | constant.i64Const); break;
+        case EbtUint64: returnValue.setU64Const(u64Const | constant.u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator^(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtInt:  returnValue.setIConst(iConst ^ constant.iConst); break;
+        case EbtUint: returnValue.setUConst(uConst ^ constant.uConst); break;
+        case EbtInt64:  returnValue.setI64Const(i64Const ^ constant.i64Const); break;
+        case EbtUint64: returnValue.setU64Const(u64Const ^ constant.u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator~() const
+    {
+        TConstUnion returnValue;
+        switch (type) {
+        case EbtInt:  returnValue.setIConst(~iConst); break;
+        case EbtUint: returnValue.setUConst(~uConst); break;
+        case EbtInt64:  returnValue.setI64Const(~i64Const); break;
+        case EbtUint64: returnValue.setU64Const(~u64Const); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator&&(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TConstUnion operator||(const TConstUnion& constant) const
+    {
+        TConstUnion returnValue;
+        assert(type == constant.type);
+        switch (type) {
+        case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
+        default:     assert(false && "Default missing");
+        }
+
+        return returnValue;
+    }
+
+    TBasicType getType() const { return type; }
+
+private:
+    union  {
+        int                iConst;      // used for ivec, scalar ints
+        unsigned int       uConst;      // used for uvec, scalar uints
+        long long          i64Const;    // used for i64vec, scalar int64s
+        unsigned long long u64Const;    // used for u64vec, scalar uint64s
+        bool               bConst;      // used for bvec, scalar bools
+        double             dConst;      // used for vec, dvec, mat, dmat, scalar floats and doubles
+        const TString*     sConst;      // string constant
+    };
+
+    TBasicType type;
+};
+
+// Encapsulate having a pointer to an array of TConstUnion,
+// which only needs to be allocated if its size is going to be
+// bigger than 0.
+//
+// One convenience is being able to use [] to go inside the array, instead
+// of C++ assuming it as an array of pointers to vectors.
+//
+// General usage is that the size is known up front, and it is
+// created once with the proper size.
+//
+class TConstUnionArray {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    TConstUnionArray() : unionArray(nullptr) { }
+    virtual ~TConstUnionArray() { }
+
+    explicit TConstUnionArray(int size)
+    {
+        if (size == 0)
+            unionArray = nullptr;
+        else
+            unionArray =  new TConstUnionVector(size);
+    }
+    TConstUnionArray(const TConstUnionArray& a) : unionArray(a.unionArray) { }
+    TConstUnionArray(const TConstUnionArray& a, int start, int size)
+    {
+        unionArray = new TConstUnionVector(size);
+        for (int i = 0; i < size; ++i)
+            (*unionArray)[i] = a[start + i];
+    }
+
+    // Use this constructor for a smear operation
+    TConstUnionArray(int size, const TConstUnion& val)
+    {
+        unionArray = new TConstUnionVector(size, val);
+    }
+
+    int size() const { return unionArray ? (int)unionArray->size() : 0; }
+    TConstUnion& operator[](size_t index) { return (*unionArray)[index]; }
+    const TConstUnion& operator[](size_t index) const { return (*unionArray)[index]; }
+    bool operator==(const TConstUnionArray& rhs) const
+    {
+        // this includes the case that both are unallocated
+        if (unionArray == rhs.unionArray)
+            return true;
+
+        if (! unionArray || ! rhs.unionArray)
+            return false;
+
+        if (! unionArray || ! rhs.unionArray)
+            return false;
+
+        return *unionArray == *rhs.unionArray;
+    }
+    bool operator!=(const TConstUnionArray& rhs) const { return ! operator==(rhs); }
+
+    double dot(const TConstUnionArray& rhs)
+    {
+        assert(rhs.unionArray->size() == unionArray->size());
+        double sum = 0.0;
+
+        for (size_t comp = 0; comp < unionArray->size(); ++comp)
+            sum += (*this)[comp].getDConst() * rhs[comp].getDConst();
+
+        return sum;
+    }
+
+    bool empty() const { return unionArray == nullptr; }
+
+protected:
+    typedef TVector<TConstUnion> TConstUnionVector;
+    TConstUnionVector* unionArray;
+};
+
+} // end namespace glslang
+
+#endif // _CONSTANT_UNION_INCLUDED_

+ 144 - 0
src/libraries/glslang/glslang/Include/InfoSink.h

@@ -0,0 +1,144 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _INFOSINK_INCLUDED_
+#define _INFOSINK_INCLUDED_
+
+#include "../Include/Common.h"
+#include <cmath>
+
+namespace glslang {
+
+//
+// TPrefixType is used to centralize how info log messages start.
+// See below.
+//
+enum TPrefixType {
+    EPrefixNone,
+    EPrefixWarning,
+    EPrefixError,
+    EPrefixInternalError,
+    EPrefixUnimplemented,
+    EPrefixNote
+};
+
+enum TOutputStream {
+    ENull = 0,
+    EDebugger = 0x01,
+    EStdOut = 0x02,
+    EString = 0x04,
+};
+//
+// Encapsulate info logs for all objects that have them.
+//
+// The methods are a general set of tools for getting a variety of
+// messages and types inserted into the log.
+//
+class TInfoSinkBase {
+public:
+    TInfoSinkBase() : outputStream(4) {}
+    void erase() { sink.erase(); }
+    TInfoSinkBase& operator<<(const TPersistString& t) { append(t); return *this; }
+    TInfoSinkBase& operator<<(char c)                  { append(1, c); return *this; }
+    TInfoSinkBase& operator<<(const char* s)           { append(s); return *this; }
+    TInfoSinkBase& operator<<(int n)                   { append(String(n)); return *this; }
+    TInfoSinkBase& operator<<(unsigned int n)          { append(String(n)); return *this; }
+    TInfoSinkBase& operator<<(float n)                 { const int size = 40; char buf[size];
+                                                         snprintf(buf, size, (fabs(n) > 1e-8 && fabs(n) < 1e8) || n == 0.0f ? "%f" : "%g", n);
+                                                         append(buf);
+                                                         return *this; }
+    TInfoSinkBase& operator+(const TPersistString& t)  { append(t); return *this; }
+    TInfoSinkBase& operator+(const TString& t)         { append(t); return *this; }
+    TInfoSinkBase& operator<<(const TString& t)        { append(t); return *this; }
+    TInfoSinkBase& operator+(const char* s)            { append(s); return *this; }
+    const char* c_str() const { return sink.c_str(); }
+    void prefix(TPrefixType message) {
+        switch(message) {
+        case EPrefixNone:                                      break;
+        case EPrefixWarning:       append("WARNING: ");        break;
+        case EPrefixError:         append("ERROR: ");          break;
+        case EPrefixInternalError: append("INTERNAL ERROR: "); break;
+        case EPrefixUnimplemented: append("UNIMPLEMENTED: ");  break;
+        case EPrefixNote:          append("NOTE: ");           break;
+        default:                   append("UNKNOWN ERROR: ");   break;
+        }
+    }
+    void location(const TSourceLoc& loc) {
+        const int maxSize = 24;
+        char locText[maxSize];
+        snprintf(locText, maxSize, ":%d", loc.line);
+        append(loc.getStringNameOrNum(false).c_str());
+        append(locText);
+        append(": ");
+    }
+    void message(TPrefixType message, const char* s) {
+        prefix(message);
+        append(s);
+        append("\n");
+    }
+    void message(TPrefixType message, const char* s, const TSourceLoc& loc) {
+        prefix(message);
+        location(loc);
+        append(s);
+        append("\n");
+    }
+
+    void setOutputStream(int output = 4)
+    {
+        outputStream = output;
+    }
+
+protected:
+    void append(const char* s);
+
+    void append(int count, char c);
+    void append(const TPersistString& t);
+    void append(const TString& t);
+
+    void checkMem(size_t growth) { if (sink.capacity() < sink.size() + growth + 2)
+                                       sink.reserve(sink.capacity() +  sink.capacity() / 2); }
+    void appendToStream(const char* s);
+    TPersistString sink;
+    int outputStream;
+};
+
+} // end namespace glslang
+
+class TInfoSink {
+public:
+    glslang::TInfoSinkBase info;
+    glslang::TInfoSinkBase debug;
+};
+
+#endif // _INFOSINK_INCLUDED_

+ 47 - 0
src/libraries/glslang/glslang/Include/InitializeGlobals.h

@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef __INITIALIZE_GLOBALS_INCLUDED_
+#define __INITIALIZE_GLOBALS_INCLUDED_
+
+namespace glslang {
+
+void InitializeMemoryPools();
+void FreeGlobalPools();
+bool InitializePoolIndex();
+void FreePoolIndex();
+
+} // end namespace glslang
+
+#endif // __INITIALIZE_GLOBALS_INCLUDED_

+ 324 - 0
src/libraries/glslang/glslang/Include/PoolAlloc.h

@@ -0,0 +1,324 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _POOLALLOC_INCLUDED_
+#define _POOLALLOC_INCLUDED_
+
+#ifdef _DEBUG
+#  define GUARD_BLOCKS  // define to enable guard block sanity checking
+#endif
+
+//
+// This header defines an allocator that can be used to efficiently
+// allocate a large number of small requests for heap memory, with the
+// intention that they are not individually deallocated, but rather
+// collectively deallocated at one time.
+//
+// This simultaneously
+//
+// * Makes each individual allocation much more efficient; the
+//     typical allocation is trivial.
+// * Completely avoids the cost of doing individual deallocation.
+// * Saves the trouble of tracking down and plugging a large class of leaks.
+//
+// Individual classes can use this allocator by supplying their own
+// new and delete methods.
+//
+// STL containers can use this allocator by using the pool_allocator
+// class as the allocator (second) template argument.
+//
+
+#include <cstddef>
+#include <cstring>
+#include <vector>
+
+namespace glslang {
+
+// If we are using guard blocks, we must track each individual
+// allocation.  If we aren't using guard blocks, these
+// never get instantiated, so won't have any impact.
+//
+
+class TAllocation {
+public:
+    TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) :
+        size(size), mem(mem), prevAlloc(prev) {
+        // Allocations are bracketed:
+        //    [allocationHeader][initialGuardBlock][userData][finalGuardBlock]
+        // This would be cleaner with if (guardBlockSize)..., but that
+        // makes the compiler print warnings about 0 length memsets,
+        // even with the if() protecting them.
+#       ifdef GUARD_BLOCKS
+            memset(preGuard(),  guardBlockBeginVal, guardBlockSize);
+            memset(data(),      userDataFill,       size);
+            memset(postGuard(), guardBlockEndVal,   guardBlockSize);
+#       endif
+    }
+
+    void check() const {
+        checkGuardBlock(preGuard(),  guardBlockBeginVal, "before");
+        checkGuardBlock(postGuard(), guardBlockEndVal,   "after");
+    }
+
+    void checkAllocList() const;
+
+    // Return total size needed to accommodate user buffer of 'size',
+    // plus our tracking data.
+    inline static size_t allocationSize(size_t size) {
+        return size + 2 * guardBlockSize + headerSize();
+    }
+
+    // Offset from surrounding buffer to get to user data buffer.
+    inline static unsigned char* offsetAllocation(unsigned char* m) {
+        return m + guardBlockSize + headerSize();
+    }
+
+private:
+    void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const;
+
+    // Find offsets to pre and post guard blocks, and user data buffer
+    unsigned char* preGuard()  const { return mem + headerSize(); }
+    unsigned char* data()      const { return preGuard() + guardBlockSize; }
+    unsigned char* postGuard() const { return data() + size; }
+
+    size_t size;                  // size of the user data area
+    unsigned char* mem;           // beginning of our allocation (pts to header)
+    TAllocation* prevAlloc;       // prior allocation in the chain
+
+    const static unsigned char guardBlockBeginVal;
+    const static unsigned char guardBlockEndVal;
+    const static unsigned char userDataFill;
+
+    const static size_t guardBlockSize;
+#   ifdef GUARD_BLOCKS
+    inline static size_t headerSize() { return sizeof(TAllocation); }
+#   else
+    inline static size_t headerSize() { return 0; }
+#   endif
+};
+
+//
+// There are several stacks.  One is to track the pushing and popping
+// of the user, and not yet implemented.  The others are simply a
+// repositories of free pages or used pages.
+//
+// Page stacks are linked together with a simple header at the beginning
+// of each allocation obtained from the underlying OS.  Multi-page allocations
+// are returned to the OS.  Individual page allocations are kept for future
+// re-use.
+//
+// The "page size" used is not, nor must it match, the underlying OS
+// page size.  But, having it be about that size or equal to a set of
+// pages is likely most optimal.
+//
+class TPoolAllocator {
+public:
+    TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16);
+
+    //
+    // Don't call the destructor just to free up the memory, call pop()
+    //
+    ~TPoolAllocator();
+
+    //
+    // Call push() to establish a new place to pop memory too.  Does not
+    // have to be called to get things started.
+    //
+    void push();
+
+    //
+    // Call pop() to free all memory allocated since the last call to push(),
+    // or if no last call to push, frees all memory since first allocation.
+    //
+    void pop();
+
+    //
+    // Call popAll() to free all memory allocated.
+    //
+    void popAll();
+
+    //
+    // Call allocate() to actually acquire memory.  Returns 0 if no memory
+    // available, otherwise a properly aligned pointer to 'numBytes' of memory.
+    //
+    void* allocate(size_t numBytes);
+
+    //
+    // There is no deallocate.  The point of this class is that
+    // deallocation can be skipped by the user of it, as the model
+    // of use is to simultaneously deallocate everything at once
+    // by calling pop(), and to not have to solve memory leak problems.
+    //
+
+protected:
+    friend struct tHeader;
+
+    struct tHeader {
+        tHeader(tHeader* nextPage, size_t pageCount) :
+#ifdef GUARD_BLOCKS
+        lastAllocation(0),
+#endif
+        nextPage(nextPage), pageCount(pageCount) { }
+
+        ~tHeader() {
+#ifdef GUARD_BLOCKS
+            if (lastAllocation)
+                lastAllocation->checkAllocList();
+#endif
+        }
+
+#ifdef GUARD_BLOCKS
+        TAllocation* lastAllocation;
+#endif
+        tHeader* nextPage;
+        size_t pageCount;
+    };
+
+    struct tAllocState {
+        size_t offset;
+        tHeader* page;
+    };
+    typedef std::vector<tAllocState> tAllocStack;
+
+    // Track allocations if and only if we're using guard blocks
+#ifndef GUARD_BLOCKS
+    void* initializeAllocation(tHeader*, unsigned char* memory, size_t) {
+#else
+    void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) {
+        new(memory) TAllocation(numBytes, memory, block->lastAllocation);
+        block->lastAllocation = reinterpret_cast<TAllocation*>(memory);
+#endif
+
+        // This is optimized entirely away if GUARD_BLOCKS is not defined.
+        return TAllocation::offsetAllocation(memory);
+    }
+
+    size_t pageSize;        // granularity of allocation from the OS
+    size_t alignment;       // all returned allocations will be aligned at
+                            //      this granularity, which will be a power of 2
+    size_t alignmentMask;
+    size_t headerSkip;      // amount of memory to skip to make room for the
+                            //      header (basically, size of header, rounded
+                            //      up to make it aligned
+    size_t currentPageOffset;  // next offset in top of inUseList to allocate from
+    tHeader* freeList;      // list of popped memory
+    tHeader* inUseList;     // list of all memory currently being used
+    tAllocStack stack;      // stack of where to allocate from, to partition pool
+
+    int numCalls;           // just an interesting statistic
+    size_t totalBytes;      // just an interesting statistic
+private:
+    TPoolAllocator& operator=(const TPoolAllocator&);  // don't allow assignment operator
+    TPoolAllocator(const TPoolAllocator&);  // don't allow default copy constructor
+};
+
+//
+// There could potentially be many pools with pops happening at
+// different times.  But a simple use is to have a global pop
+// with everyone using the same global allocator.
+//
+typedef TPoolAllocator* PoolAllocatorPointer;
+extern TPoolAllocator& GetThreadPoolAllocator();
+
+struct TThreadMemoryPools
+{
+    TPoolAllocator* threadPoolAllocator;
+};
+
+void SetThreadPoolAllocator(TPoolAllocator& poolAllocator);
+
+//
+// This STL compatible allocator is intended to be used as the allocator
+// parameter to templatized STL containers, like vector and map.
+//
+// It will use the pools for allocation, and not
+// do any deallocation, but will still do destruction.
+//
+template<class T>
+class pool_allocator {
+public:
+    typedef size_t size_type;
+    typedef ptrdiff_t difference_type;
+    typedef T *pointer;
+    typedef const T *const_pointer;
+    typedef T& reference;
+    typedef const T& const_reference;
+    typedef T value_type;
+    template<class Other>
+        struct rebind {
+            typedef pool_allocator<Other> other;
+        };
+    pointer address(reference x) const { return &x; }
+    const_pointer address(const_reference x) const { return &x; }
+
+    pool_allocator() : allocator(GetThreadPoolAllocator()) { }
+    pool_allocator(TPoolAllocator& a) : allocator(a) { }
+    pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
+
+    template<class Other>
+        pool_allocator(const pool_allocator<Other>& p) : allocator(p.getAllocator()) { }
+
+    pointer allocate(size_type n) {
+        return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); }
+    pointer allocate(size_type n, const void*) {
+        return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); }
+
+    void deallocate(void*, size_type) { }
+    void deallocate(pointer, size_type) { }
+
+    pointer _Charalloc(size_t n) {
+        return reinterpret_cast<pointer>(getAllocator().allocate(n)); }
+
+    void construct(pointer p, const T& val) { new ((void *)p) T(val); }
+    void destroy(pointer p) { p->T::~T(); }
+
+    bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); }
+    bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); }
+
+    size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
+    size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
+
+    void setAllocator(TPoolAllocator* a) { allocator = *a; }
+    TPoolAllocator& getAllocator() const { return allocator; }
+
+protected:
+    pool_allocator& operator=(const pool_allocator&) { return *this; }
+    TPoolAllocator& allocator;
+};
+
+} // end namespace glslang
+
+#endif // _POOLALLOC_INCLUDED_

+ 140 - 0
src/libraries/glslang/glslang/Include/ResourceLimits.h

@@ -0,0 +1,140 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _RESOURCE_LIMITS_INCLUDED_
+#define _RESOURCE_LIMITS_INCLUDED_
+
+struct TLimits {
+    bool nonInductiveForLoops;
+    bool whileLoops;
+    bool doWhileLoops;
+    bool generalUniformIndexing;
+    bool generalAttributeMatrixVectorIndexing;
+    bool generalVaryingIndexing;
+    bool generalSamplerIndexing;
+    bool generalVariableIndexing;
+    bool generalConstantMatrixVectorIndexing;
+};
+
+struct TBuiltInResource {
+    int maxLights;
+    int maxClipPlanes;
+    int maxTextureUnits;
+    int maxTextureCoords;
+    int maxVertexAttribs;
+    int maxVertexUniformComponents;
+    int maxVaryingFloats;
+    int maxVertexTextureImageUnits;
+    int maxCombinedTextureImageUnits;
+    int maxTextureImageUnits;
+    int maxFragmentUniformComponents;
+    int maxDrawBuffers;
+    int maxVertexUniformVectors;
+    int maxVaryingVectors;
+    int maxFragmentUniformVectors;
+    int maxVertexOutputVectors;
+    int maxFragmentInputVectors;
+    int minProgramTexelOffset;
+    int maxProgramTexelOffset;
+    int maxClipDistances;
+    int maxComputeWorkGroupCountX;
+    int maxComputeWorkGroupCountY;
+    int maxComputeWorkGroupCountZ;
+    int maxComputeWorkGroupSizeX;
+    int maxComputeWorkGroupSizeY;
+    int maxComputeWorkGroupSizeZ;
+    int maxComputeUniformComponents;
+    int maxComputeTextureImageUnits;
+    int maxComputeImageUniforms;
+    int maxComputeAtomicCounters;
+    int maxComputeAtomicCounterBuffers;
+    int maxVaryingComponents;
+    int maxVertexOutputComponents;
+    int maxGeometryInputComponents;
+    int maxGeometryOutputComponents;
+    int maxFragmentInputComponents;
+    int maxImageUnits;
+    int maxCombinedImageUnitsAndFragmentOutputs;
+    int maxCombinedShaderOutputResources;
+    int maxImageSamples;
+    int maxVertexImageUniforms;
+    int maxTessControlImageUniforms;
+    int maxTessEvaluationImageUniforms;
+    int maxGeometryImageUniforms;
+    int maxFragmentImageUniforms;
+    int maxCombinedImageUniforms;
+    int maxGeometryTextureImageUnits;
+    int maxGeometryOutputVertices;
+    int maxGeometryTotalOutputComponents;
+    int maxGeometryUniformComponents;
+    int maxGeometryVaryingComponents;
+    int maxTessControlInputComponents;
+    int maxTessControlOutputComponents;
+    int maxTessControlTextureImageUnits;
+    int maxTessControlUniformComponents;
+    int maxTessControlTotalOutputComponents;
+    int maxTessEvaluationInputComponents;
+    int maxTessEvaluationOutputComponents;
+    int maxTessEvaluationTextureImageUnits;
+    int maxTessEvaluationUniformComponents;
+    int maxTessPatchComponents;
+    int maxPatchVertices;
+    int maxTessGenLevel;
+    int maxViewports;
+    int maxVertexAtomicCounters;
+    int maxTessControlAtomicCounters;
+    int maxTessEvaluationAtomicCounters;
+    int maxGeometryAtomicCounters;
+    int maxFragmentAtomicCounters;
+    int maxCombinedAtomicCounters;
+    int maxAtomicCounterBindings;
+    int maxVertexAtomicCounterBuffers;
+    int maxTessControlAtomicCounterBuffers;
+    int maxTessEvaluationAtomicCounterBuffers;
+    int maxGeometryAtomicCounterBuffers;
+    int maxFragmentAtomicCounterBuffers;
+    int maxCombinedAtomicCounterBuffers;
+    int maxAtomicCounterBufferSize;
+    int maxTransformFeedbackBuffers;
+    int maxTransformFeedbackInterleavedComponents;
+    int maxCullDistances;
+    int maxCombinedClipAndCullDistances;
+    int maxSamples;
+
+    TLimits limits;
+};
+
+#endif // _RESOURCE_LIMITS_INCLUDED_

+ 173 - 0
src/libraries/glslang/glslang/Include/ShHandle.h

@@ -0,0 +1,173 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _SHHANDLE_INCLUDED_
+#define _SHHANDLE_INCLUDED_
+
+//
+// Machine independent part of the compiler private objects
+// sent as ShHandle to the driver.
+//
+// This should not be included by driver code.
+//
+
+#define SH_EXPORTING
+#include "../Public/ShaderLang.h"
+#include "../MachineIndependent/Versions.h"
+#include "InfoSink.h"
+
+class TCompiler;
+class TLinker;
+class TUniformMap;
+
+//
+// The base class used to back handles returned to the driver.
+//
+class TShHandleBase {
+public:
+    TShHandleBase() { }
+    virtual ~TShHandleBase() { }
+    virtual TCompiler* getAsCompiler() { return 0; }
+    virtual TLinker* getAsLinker() { return 0; }
+    virtual TUniformMap* getAsUniformMap() { return 0; }
+};
+
+//
+// The base class for the machine dependent linker to derive from
+// for managing where uniforms live.
+//
+class TUniformMap : public TShHandleBase {
+public:
+    TUniformMap() { }
+    virtual ~TUniformMap() { }
+    virtual TUniformMap* getAsUniformMap() { return this; }
+    virtual int getLocation(const char* name) = 0;
+    virtual TInfoSink& getInfoSink() { return infoSink; }
+    TInfoSink infoSink;
+};
+
+class TIntermNode;
+
+//
+// The base class for the machine dependent compiler to derive from
+// for managing object code from the compile.
+//
+class TCompiler : public TShHandleBase {
+public:
+    TCompiler(EShLanguage l, TInfoSink& sink) : infoSink(sink) , language(l), haveValidObjectCode(false) { }
+    virtual ~TCompiler() { }
+    EShLanguage getLanguage() { return language; }
+    virtual TInfoSink& getInfoSink() { return infoSink; }
+
+    virtual bool compile(TIntermNode* root, int version = 0, EProfile profile = ENoProfile) = 0;
+
+    virtual TCompiler* getAsCompiler() { return this; }
+    virtual bool linkable() { return haveValidObjectCode; }
+
+    TInfoSink& infoSink;
+protected:
+    TCompiler& operator=(TCompiler&);
+
+    EShLanguage language;
+    bool haveValidObjectCode;
+};
+
+//
+// Link operations are based on a list of compile results...
+//
+typedef glslang::TVector<TCompiler*> TCompilerList;
+typedef glslang::TVector<TShHandleBase*> THandleList;
+
+//
+// The base class for the machine dependent linker to derive from
+// to manage the resulting executable.
+//
+
+class TLinker : public TShHandleBase {
+public:
+    TLinker(EShExecutable e, TInfoSink& iSink) :
+        infoSink(iSink),
+        executable(e),
+        haveReturnableObjectCode(false),
+        appAttributeBindings(0),
+        fixedAttributeBindings(0),
+        excludedAttributes(0),
+        excludedCount(0),
+        uniformBindings(0) { }
+    virtual TLinker* getAsLinker() { return this; }
+    virtual ~TLinker() { }
+    virtual bool link(TCompilerList&, TUniformMap*) = 0;
+    virtual bool link(THandleList&) { return false; }
+    virtual void setAppAttributeBindings(const ShBindingTable* t)   { appAttributeBindings = t; }
+    virtual void setFixedAttributeBindings(const ShBindingTable* t) { fixedAttributeBindings = t; }
+    virtual void getAttributeBindings(ShBindingTable const **t) const = 0;
+    virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; }
+    virtual ShBindingTable* getUniformBindings() const  { return uniformBindings; }
+    virtual const void* getObjectCode() const { return 0; } // a real compiler would be returning object code here
+    virtual TInfoSink& getInfoSink() { return infoSink; }
+    TInfoSink& infoSink;
+protected:
+    TLinker& operator=(TLinker&);
+    EShExecutable executable;
+    bool haveReturnableObjectCode;  // true when objectCode is acceptable to send to driver
+
+    const ShBindingTable* appAttributeBindings;
+    const ShBindingTable* fixedAttributeBindings;
+    const int* excludedAttributes;
+    int excludedCount;
+    ShBindingTable* uniformBindings;                // created by the linker
+};
+
+//
+// This is the interface between the machine independent code
+// and the machine dependent code.
+//
+// The machine dependent code should derive from the classes
+// above. Then Construct*() and Delete*() will create and
+// destroy the machine dependent objects, which contain the
+// above machine independent information.
+//
+TCompiler* ConstructCompiler(EShLanguage, int);
+
+TShHandleBase* ConstructLinker(EShExecutable, int);
+TShHandleBase* ConstructBindings();
+void DeleteLinker(TShHandleBase*);
+void DeleteBindingList(TShHandleBase* bindingList);
+
+TUniformMap* ConstructUniformMap();
+void DeleteCompiler(TCompiler*);
+
+void DeleteUniformMap(TUniformMap*);
+
+#endif // _SHHANDLE_INCLUDED_

+ 1915 - 0
src/libraries/glslang/glslang/Include/Types.h

@@ -0,0 +1,1915 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2016 LunarG, Inc.
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _TYPES_INCLUDED
+#define _TYPES_INCLUDED
+
+#include "../Include/Common.h"
+#include "../Include/BaseTypes.h"
+#include "../Public/ShaderLang.h"
+#include "arrays.h"
+
+#include <algorithm>
+
+namespace glslang {
+
+const int GlslangMaxTypeLength = 200;  // TODO: need to print block/struct one member per line, so this can stay bounded
+
+const char* const AnonymousPrefix = "anon@"; // for something like a block whose members can be directly accessed
+inline bool IsAnonymous(const TString& name)
+{
+    return name.compare(0, 5, AnonymousPrefix) == 0;
+}
+
+//
+// Details within a sampler type
+//
+enum TSamplerDim {
+    EsdNone,
+    Esd1D,
+    Esd2D,
+    Esd3D,
+    EsdCube,
+    EsdRect,
+    EsdBuffer,
+    EsdSubpass,  // goes only with non-sampled image (image is true)
+    EsdNumDims
+};
+
+struct TSampler {   // misnomer now; includes images, textures without sampler, and textures with sampler
+    TBasicType type : 8;  // type returned by sampler
+    TSamplerDim dim : 8;
+    bool    arrayed : 1;
+    bool     shadow : 1;
+    bool         ms : 1;
+    bool      image : 1;  // image, combined should be false
+    bool   combined : 1;  // true means texture is combined with a sampler, false means texture with no sampler
+    bool    sampler : 1;  // true means a pure sampler, other fields should be clear()
+    bool   external : 1;  // GL_OES_EGL_image_external
+    unsigned int vectorSize : 3;  // return vector size.  TODO: support arbitrary types.
+
+    bool isImage()       const { return image && dim != EsdSubpass; }
+    bool isSubpass()     const { return dim == EsdSubpass; }
+    bool isCombined()    const { return combined; }
+    bool isPureSampler() const { return sampler; }
+    bool isTexture()     const { return !sampler && !image; }
+    bool isShadow()      const { return shadow; }
+    bool isArrayed()     const { return arrayed; }
+    bool isMultiSample() const { return ms; }
+
+    void clear()
+    {
+        type = EbtVoid;
+        dim = EsdNone;
+        arrayed = false;
+        shadow = false;
+        ms = false;
+        image = false;
+        combined = false;
+        sampler = false;
+        external = false;
+        vectorSize = 4;
+    }
+
+    // make a combined sampler and texture
+    void set(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
+    {
+        clear();
+        type = t;
+        dim = d;
+        arrayed = a;
+        shadow = s;
+        ms = m;
+        combined = true;
+    }
+
+    // make an image
+    void setImage(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
+    {
+        clear();
+        type = t;
+        dim = d;
+        arrayed = a;
+        shadow = s;
+        ms = m;
+        image = true;
+    }
+
+    // make a texture with no sampler
+    void setTexture(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
+    {
+        clear();
+        type = t;
+        dim = d;
+        arrayed = a;
+        shadow = s;
+        ms = m;
+    }
+
+    // make a subpass input attachment
+    void setSubpass(TBasicType t, bool m = false)
+    {
+        clear();
+        type = t;
+        image = true;
+        dim = EsdSubpass;
+        ms = m;
+    }
+
+    // make a pure sampler, no texture, no image, nothing combined, the 'sampler' keyword
+    void setPureSampler(bool s)
+    {
+        clear();
+        sampler = true;
+        shadow = s;
+    }
+
+    bool operator==(const TSampler& right) const
+    {
+        return type == right.type &&
+                dim == right.dim &&
+            arrayed == right.arrayed &&
+             shadow == right.shadow &&
+                 ms == right.ms &&
+              image == right.image &&
+           combined == right.combined &&
+            sampler == right.sampler &&
+           external == right.external &&
+         vectorSize == right.vectorSize;
+    }
+
+    bool operator!=(const TSampler& right) const
+    {
+        return ! operator==(right);
+    }
+
+    TString getString() const
+    {
+        TString s;
+
+        if (sampler) {
+            s.append("sampler");
+            return s;
+        }
+
+        switch (type) {
+        case EbtFloat:               break;
+        case EbtInt:  s.append("i"); break;
+        case EbtUint: s.append("u"); break;
+        default:  break;  // some compilers want this
+        }
+        if (image) {
+            if (dim == EsdSubpass)
+                s.append("subpass");
+            else
+                s.append("image");
+        } else if (combined) {
+            s.append("sampler");
+        } else {
+            s.append("texture");
+        }
+        if (external) {
+            s.append("ExternalOES");
+            return s;
+        }
+        switch (dim) {
+        case Esd1D:      s.append("1D");      break;
+        case Esd2D:      s.append("2D");      break;
+        case Esd3D:      s.append("3D");      break;
+        case EsdCube:    s.append("Cube");    break;
+        case EsdRect:    s.append("2DRect");  break;
+        case EsdBuffer:  s.append("Buffer");  break;
+        case EsdSubpass: s.append("Input"); break;
+        default:  break;  // some compilers want this
+        }
+        if (ms)
+            s.append("MS");
+        if (arrayed)
+            s.append("Array");
+        if (shadow)
+            s.append("Shadow");
+
+        return s;
+    }
+};
+
+//
+// Need to have association of line numbers to types in a list for building structs.
+//
+class TType;
+struct TTypeLoc {
+    TType* type;
+    TSourceLoc loc;
+};
+typedef TVector<TTypeLoc> TTypeList;
+
+typedef TVector<TString*> TIdentifierList;
+
+//
+// Following are a series of helper enums for managing layouts and qualifiers,
+// used for TPublicType, TType, others.
+//
+
+enum TLayoutPacking {
+    ElpNone,
+    ElpShared,      // default, but different than saying nothing
+    ElpStd140,
+    ElpStd430,
+    ElpPacked,
+    ElpCount        // If expanding, see bitfield width below
+};
+
+enum TLayoutMatrix {
+    ElmNone,
+    ElmRowMajor,
+    ElmColumnMajor, // default, but different than saying nothing
+    ElmCount        // If expanding, see bitfield width below
+};
+
+// Union of geometry shader and tessellation shader geometry types.
+// They don't go into TType, but rather have current state per shader or
+// active parser type (TPublicType).
+enum TLayoutGeometry {
+    ElgNone,
+    ElgPoints,
+    ElgLines,
+    ElgLinesAdjacency,
+    ElgLineStrip,
+    ElgTriangles,
+    ElgTrianglesAdjacency,
+    ElgTriangleStrip,
+    ElgQuads,
+    ElgIsolines,
+};
+
+enum TVertexSpacing {
+    EvsNone,
+    EvsEqual,
+    EvsFractionalEven,
+    EvsFractionalOdd
+};
+
+enum TVertexOrder {
+    EvoNone,
+    EvoCw,
+    EvoCcw
+};
+
+// Note: order matters, as type of format is done by comparison.
+enum TLayoutFormat {
+    ElfNone,
+
+    // Float image
+    ElfRgba32f,
+    ElfRgba16f,
+    ElfR32f,
+    ElfRgba8,
+    ElfRgba8Snorm,
+
+    ElfEsFloatGuard,    // to help with comparisons
+
+    ElfRg32f,
+    ElfRg16f,
+    ElfR11fG11fB10f,
+    ElfR16f,
+    ElfRgba16,
+    ElfRgb10A2,
+    ElfRg16,
+    ElfRg8,
+    ElfR16,
+    ElfR8,
+    ElfRgba16Snorm,
+    ElfRg16Snorm,
+    ElfRg8Snorm,
+    ElfR16Snorm,
+    ElfR8Snorm,
+
+    ElfFloatGuard,      // to help with comparisons
+
+    // Int image
+    ElfRgba32i,
+    ElfRgba16i,
+    ElfRgba8i,
+    ElfR32i,
+
+    ElfEsIntGuard,     // to help with comparisons
+
+    ElfRg32i,
+    ElfRg16i,
+    ElfRg8i,
+    ElfR16i,
+    ElfR8i,
+
+    ElfIntGuard,       // to help with comparisons
+
+    // Uint image
+    ElfRgba32ui,
+    ElfRgba16ui,
+    ElfRgba8ui,
+    ElfR32ui,
+
+    ElfEsUintGuard,    // to help with comparisons
+
+    ElfRg32ui,
+    ElfRg16ui,
+    ElfRgb10a2ui,
+    ElfRg8ui,
+    ElfR16ui,
+    ElfR8ui,
+
+    ElfCount
+};
+
+enum TLayoutDepth {
+    EldNone,
+    EldAny,
+    EldGreater,
+    EldLess,
+    EldUnchanged,
+
+    EldCount
+};
+
+enum TBlendEquationShift {
+    // No 'EBlendNone':
+    // These are used as bit-shift amounts.  A mask of such shifts will have type 'int',
+    // and in that space, 0 means no bits set, or none.  In this enum, 0 means (1 << 0), a bit is set.
+    EBlendMultiply,
+    EBlendScreen,
+    EBlendOverlay,
+    EBlendDarken,
+    EBlendLighten,
+    EBlendColordodge,
+    EBlendColorburn,
+    EBlendHardlight,
+    EBlendSoftlight,
+    EBlendDifference,
+    EBlendExclusion,
+    EBlendHslHue,
+    EBlendHslSaturation,
+    EBlendHslColor,
+    EBlendHslLuminosity,
+    EBlendAllEquations,
+
+    EBlendCount
+};
+
+class TQualifier {
+public:
+    static const int layoutNotSet = -1;
+
+    void clear()
+    {
+        precision = EpqNone;
+        invariant = false;
+        noContraction = false;
+        makeTemporary();
+        declaredBuiltIn = EbvNone;
+    }
+
+    // drop qualifiers that don't belong in a temporary variable
+    void makeTemporary()
+    {
+        semanticName = nullptr;
+        storage = EvqTemporary;
+        builtIn = EbvNone;
+        clearInterstage();
+        clearMemory();
+        specConstant = false;
+        clearLayout();
+    }
+
+    void clearInterstage()
+    {
+        clearInterpolation();
+        patch = false;
+        sample = false;
+    }
+
+    void clearInterpolation()
+    {
+        centroid     = false;
+        smooth       = false;
+        flat         = false;
+        nopersp      = false;
+#ifdef AMD_EXTENSIONS
+        explicitInterp = false;
+#endif
+    }
+
+    void clearMemory()
+    {
+        coherent     = false;
+        volatil      = false;
+        restrict     = false;
+        readonly     = false;
+        writeonly    = false;
+    }
+
+    // Drop just the storage qualification, which perhaps should
+    // never be done, as it is fundamentally inconsistent, but need to
+    // explore what downstream consumers need.
+    // E.g., in a deference, it is an inconsistency between:
+    // A) partially dereferenced resource is still in the storage class it started in
+    // B) partially dereferenced resource is a new temporary object
+    // If A, then nothing should change, if B, then everything should change, but this is half way.
+    void makePartialTemporary()
+    {
+        storage      = EvqTemporary;
+        specConstant = false;
+    }
+
+    const char*         semanticName;
+    TStorageQualifier   storage   : 6;
+    TBuiltInVariable    builtIn   : 8;
+    TBuiltInVariable    declaredBuiltIn : 8;
+    TPrecisionQualifier precision : 3;
+    bool invariant    : 1; // require canonical treatment for cross-shader invariance
+    bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects
+    bool centroid     : 1;
+    bool smooth       : 1;
+    bool flat         : 1;
+    bool nopersp      : 1;
+#ifdef AMD_EXTENSIONS
+    bool explicitInterp : 1;
+#endif
+    bool patch        : 1;
+    bool sample       : 1;
+    bool coherent     : 1;
+    bool volatil      : 1;
+    bool restrict     : 1;
+    bool readonly     : 1;
+    bool writeonly    : 1;
+    bool specConstant : 1;  // having a constant_id is not sufficient: expressions have no id, but are still specConstant
+
+    bool isMemory() const
+    {
+        return coherent || volatil || restrict || readonly || writeonly;
+    }
+    bool isInterpolation() const
+    {
+#ifdef AMD_EXTENSIONS
+        return flat || smooth || nopersp || explicitInterp;
+#else
+        return flat || smooth || nopersp;
+#endif
+    }
+    bool isAuxiliary() const
+    {
+        return centroid || patch || sample;
+    }
+
+    bool isPipeInput() const
+    {
+        switch (storage) {
+        case EvqVaryingIn:
+        case EvqFragCoord:
+        case EvqPointCoord:
+        case EvqFace:
+        case EvqVertexId:
+        case EvqInstanceId:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isPipeOutput() const
+    {
+        switch (storage) {
+        case EvqPosition:
+        case EvqPointSize:
+        case EvqClipVertex:
+        case EvqVaryingOut:
+        case EvqFragColor:
+        case EvqFragDepth:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isParamInput() const
+    {
+        switch (storage) {
+        case EvqIn:
+        case EvqInOut:
+        case EvqConstReadOnly:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isParamOutput() const
+    {
+        switch (storage) {
+        case EvqOut:
+        case EvqInOut:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isUniformOrBuffer() const
+    {
+        switch (storage) {
+        case EvqUniform:
+        case EvqBuffer:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isIo() const
+    {
+        switch (storage) {
+        case EvqUniform:
+        case EvqBuffer:
+        case EvqVaryingIn:
+        case EvqFragCoord:
+        case EvqPointCoord:
+        case EvqFace:
+        case EvqVertexId:
+        case EvqInstanceId:
+        case EvqPosition:
+        case EvqPointSize:
+        case EvqClipVertex:
+        case EvqVaryingOut:
+        case EvqFragColor:
+        case EvqFragDepth:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    // True if this type of IO is supposed to be arrayed with extra level for per-vertex data
+    bool isArrayedIo(EShLanguage language) const
+    {
+        switch (language) {
+        case EShLangGeometry:
+            return isPipeInput();
+        case EShLangTessControl:
+            return ! patch && (isPipeInput() || isPipeOutput());
+        case EShLangTessEvaluation:
+            return ! patch && isPipeInput();
+        default:
+            return false;
+        }
+    }
+
+    // Implementing an embedded layout-qualifier class here, since C++ can't have a real class bitfield
+    void clearLayout()  // all layout
+    {
+        clearUniformLayout();
+
+        layoutPushConstant = false;
+#ifdef NV_EXTENSIONS
+        layoutPassthrough = false;
+        layoutViewportRelative = false;
+        // -2048 as the default value indicating layoutSecondaryViewportRelative is not set
+        layoutSecondaryViewportRelativeOffset = -2048;
+#endif
+
+        clearInterstageLayout();
+
+        layoutSpecConstantId = layoutSpecConstantIdEnd;
+
+        layoutFormat = ElfNone;
+    }
+    void clearInterstageLayout()
+    {
+        layoutLocation = layoutLocationEnd;
+        layoutComponent = layoutComponentEnd;
+        layoutIndex = layoutIndexEnd;
+        clearStreamLayout();
+        clearXfbLayout();
+    }
+    void clearStreamLayout()
+    {
+        layoutStream = layoutStreamEnd;
+    }
+    void clearXfbLayout()
+    {
+        layoutXfbBuffer = layoutXfbBufferEnd;
+        layoutXfbStride = layoutXfbStrideEnd;
+        layoutXfbOffset = layoutXfbOffsetEnd;
+    }
+
+    bool hasLayout() const
+    {
+        return hasUniformLayout() ||
+               hasAnyLocation() ||
+               hasStream() ||
+               hasXfb() ||
+               hasFormat() ||
+               layoutPushConstant;
+    }
+    TLayoutMatrix  layoutMatrix  : 3;
+    TLayoutPacking layoutPacking : 4;
+    int layoutOffset;
+    int layoutAlign;
+
+                 unsigned int layoutLocation            :12;
+    static const unsigned int layoutLocationEnd    =  0xFFF;
+
+                 unsigned int layoutComponent           : 3;
+    static const unsigned int layoutComponentEnd    =     4;
+
+                 unsigned int layoutSet                 : 7;
+    static const unsigned int layoutSetEnd         =   0x3F;
+
+                 unsigned int layoutBinding            : 16;
+    static const unsigned int layoutBindingEnd    =  0xFFFF;
+
+                 unsigned int layoutIndex              :  8;
+    static const unsigned int layoutIndexEnd    =      0xFF;
+
+                 unsigned int layoutStream              : 8;
+    static const unsigned int layoutStreamEnd    =     0xFF;
+
+                 unsigned int layoutXfbBuffer           : 4;
+    static const unsigned int layoutXfbBufferEnd    =   0xF;
+
+                 unsigned int layoutXfbStride          : 10;
+    static const unsigned int layoutXfbStrideEnd    = 0x3FF;
+
+                 unsigned int layoutXfbOffset          : 10;
+    static const unsigned int layoutXfbOffsetEnd    = 0x3FF;
+
+                 unsigned int layoutAttachment          : 8;  // for input_attachment_index
+    static const unsigned int layoutAttachmentEnd    = 0XFF;
+
+                 unsigned int layoutSpecConstantId       : 11;
+    static const unsigned int layoutSpecConstantIdEnd = 0x7FF;
+
+    TLayoutFormat layoutFormat                         :  8;
+
+    bool layoutPushConstant;
+
+#ifdef NV_EXTENSIONS
+    bool layoutPassthrough;
+    bool layoutViewportRelative;
+    int layoutSecondaryViewportRelativeOffset;
+#endif
+
+    bool hasUniformLayout() const
+    {
+        return hasMatrix() ||
+               hasPacking() ||
+               hasOffset() ||
+               hasBinding() ||
+               hasSet() ||
+               hasAlign();
+    }
+    void clearUniformLayout() // only uniform specific
+    {
+        layoutMatrix = ElmNone;
+        layoutPacking = ElpNone;
+        layoutOffset = layoutNotSet;
+        layoutAlign = layoutNotSet;
+
+        layoutSet = layoutSetEnd;
+        layoutBinding = layoutBindingEnd;
+        layoutAttachment = layoutAttachmentEnd;
+    }
+
+    bool hasMatrix() const
+    {
+        return layoutMatrix != ElmNone;
+    }
+    bool hasPacking() const
+    {
+        return layoutPacking != ElpNone;
+    }
+    bool hasOffset() const
+    {
+        return layoutOffset != layoutNotSet;
+    }
+    bool hasAlign() const
+    {
+        return layoutAlign != layoutNotSet;
+    }
+    bool hasAnyLocation() const
+    {
+        return hasLocation() ||
+               hasComponent() ||
+               hasIndex();
+    }
+    bool hasLocation() const
+    {
+        return layoutLocation != layoutLocationEnd;
+    }
+    bool hasComponent() const
+    {
+        return layoutComponent != layoutComponentEnd;
+    }
+    bool hasIndex() const
+    {
+        return layoutIndex != layoutIndexEnd;
+    }
+    bool hasSet() const
+    {
+        return layoutSet != layoutSetEnd;
+    }
+    bool hasBinding() const
+    {
+        return layoutBinding != layoutBindingEnd;
+    }
+    bool hasStream() const
+    {
+        return layoutStream != layoutStreamEnd;
+    }
+    bool hasFormat() const
+    {
+        return layoutFormat != ElfNone;
+    }
+    bool hasXfb() const
+    {
+        return hasXfbBuffer() ||
+               hasXfbStride() ||
+               hasXfbOffset();
+    }
+    bool hasXfbBuffer() const
+    {
+        return layoutXfbBuffer != layoutXfbBufferEnd;
+    }
+    bool hasXfbStride() const
+    {
+        return layoutXfbStride != layoutXfbStrideEnd;
+    }
+    bool hasXfbOffset() const
+    {
+        return layoutXfbOffset != layoutXfbOffsetEnd;
+    }
+    bool hasAttachment() const
+    {
+        return layoutAttachment != layoutAttachmentEnd;
+    }
+    bool hasSpecConstantId() const
+    {
+        // Not the same thing as being a specialization constant, this
+        // is just whether or not it was declared with an ID.
+        return layoutSpecConstantId != layoutSpecConstantIdEnd;
+    }
+    bool isSpecConstant() const
+    {
+        // True if type is a specialization constant, whether or not it
+        // had a specialization-constant ID, and false if it is not a
+        // true front-end constant.
+        return specConstant;
+    }
+    bool isFrontEndConstant() const
+    {
+        // True if the front-end knows the final constant value.
+        // This allows front-end constant folding.
+        return storage == EvqConst && ! specConstant;
+    }
+    bool isConstant() const
+    {
+        // True if is either kind of constant; specialization or regular.
+        return isFrontEndConstant() || isSpecConstant();
+    }
+    void makeSpecConstant()
+    {
+        storage = EvqConst;
+        specConstant = true;
+    }
+    static const char* getLayoutPackingString(TLayoutPacking packing)
+    {
+        switch (packing) {
+        case ElpPacked:   return "packed";
+        case ElpShared:   return "shared";
+        case ElpStd140:   return "std140";
+        case ElpStd430:   return "std430";
+        default:          return "none";
+        }
+    }
+    static const char* getLayoutMatrixString(TLayoutMatrix m)
+    {
+        switch (m) {
+        case ElmColumnMajor: return "column_major";
+        case ElmRowMajor:    return "row_major";
+        default:             return "none";
+        }
+    }
+    static const char* getLayoutFormatString(TLayoutFormat f)
+    {
+        switch (f) {
+        case ElfRgba32f:      return "rgba32f";
+        case ElfRgba16f:      return "rgba16f";
+        case ElfRg32f:        return "rg32f";
+        case ElfRg16f:        return "rg16f";
+        case ElfR11fG11fB10f: return "r11f_g11f_b10f";
+        case ElfR32f:         return "r32f";
+        case ElfR16f:         return "r16f";
+        case ElfRgba16:       return "rgba16";
+        case ElfRgb10A2:      return "rgb10_a2";
+        case ElfRgba8:        return "rgba8";
+        case ElfRg16:         return "rg16";
+        case ElfRg8:          return "rg8";
+        case ElfR16:          return "r16";
+        case ElfR8:           return "r8";
+        case ElfRgba16Snorm:  return "rgba16_snorm";
+        case ElfRgba8Snorm:   return "rgba8_snorm";
+        case ElfRg16Snorm:    return "rg16_snorm";
+        case ElfRg8Snorm:     return "rg8_snorm";
+        case ElfR16Snorm:     return "r16_snorm";
+        case ElfR8Snorm:      return "r8_snorm";
+
+        case ElfRgba32i:      return "rgba32i";
+        case ElfRgba16i:      return "rgba16i";
+        case ElfRgba8i:       return "rgba8i";
+        case ElfRg32i:        return "rg32i";
+        case ElfRg16i:        return "rg16i";
+        case ElfRg8i:         return "rg8i";
+        case ElfR32i:         return "r32i";
+        case ElfR16i:         return "r16i";
+        case ElfR8i:          return "r8i";
+
+        case ElfRgba32ui:     return "rgba32ui";
+        case ElfRgba16ui:     return "rgba16ui";
+        case ElfRgba8ui:      return "rgba8ui";
+        case ElfRg32ui:       return "rg32ui";
+        case ElfRg16ui:       return "rg16ui";
+        case ElfRgb10a2ui:    return "rgb10_a2ui";
+        case ElfRg8ui:        return "rg8ui";
+        case ElfR32ui:        return "r32ui";
+        case ElfR16ui:        return "r16ui";
+        case ElfR8ui:         return "r8ui";
+        default:              return "none";
+        }
+    }
+    static const char* getLayoutDepthString(TLayoutDepth d)
+    {
+        switch (d) {
+        case EldAny:       return "depth_any";
+        case EldGreater:   return "depth_greater";
+        case EldLess:      return "depth_less";
+        case EldUnchanged: return "depth_unchanged";
+        default:           return "none";
+        }
+    }
+    static const char* getBlendEquationString(TBlendEquationShift e)
+    {
+        switch (e) {
+        case EBlendMultiply:      return "blend_support_multiply";
+        case EBlendScreen:        return "blend_support_screen";
+        case EBlendOverlay:       return "blend_support_overlay";
+        case EBlendDarken:        return "blend_support_darken";
+        case EBlendLighten:       return "blend_support_lighten";
+        case EBlendColordodge:    return "blend_support_colordodge";
+        case EBlendColorburn:     return "blend_support_colorburn";
+        case EBlendHardlight:     return "blend_support_hardlight";
+        case EBlendSoftlight:     return "blend_support_softlight";
+        case EBlendDifference:    return "blend_support_difference";
+        case EBlendExclusion:     return "blend_support_exclusion";
+        case EBlendHslHue:        return "blend_support_hsl_hue";
+        case EBlendHslSaturation: return "blend_support_hsl_saturation";
+        case EBlendHslColor:      return "blend_support_hsl_color";
+        case EBlendHslLuminosity: return "blend_support_hsl_luminosity";
+        case EBlendAllEquations:  return "blend_support_all_equations";
+        default:                  return "unknown";
+        }
+    }
+    static const char* getGeometryString(TLayoutGeometry geometry)
+    {
+        switch (geometry) {
+        case ElgPoints:             return "points";
+        case ElgLines:              return "lines";
+        case ElgLinesAdjacency:     return "lines_adjacency";
+        case ElgLineStrip:          return "line_strip";
+        case ElgTriangles:          return "triangles";
+        case ElgTrianglesAdjacency: return "triangles_adjacency";
+        case ElgTriangleStrip:      return "triangle_strip";
+        case ElgQuads:              return "quads";
+        case ElgIsolines:           return "isolines";
+        default:                    return "none";
+        }
+    }
+    static const char* getVertexSpacingString(TVertexSpacing spacing)
+    {
+        switch (spacing) {
+        case EvsEqual:              return "equal_spacing";
+        case EvsFractionalEven:     return "fractional_even_spacing";
+        case EvsFractionalOdd:      return "fractional_odd_spacing";
+        default:                    return "none";
+        }
+    }
+    static const char* getVertexOrderString(TVertexOrder order)
+    {
+        switch (order) {
+        case EvoCw:                 return "cw";
+        case EvoCcw:                return "ccw";
+        default:                    return "none";
+        }
+    }
+    static int mapGeometryToSize(TLayoutGeometry geometry)
+    {
+        switch (geometry) {
+        case ElgPoints:             return 1;
+        case ElgLines:              return 2;
+        case ElgLinesAdjacency:     return 4;
+        case ElgTriangles:          return 3;
+        case ElgTrianglesAdjacency: return 6;
+        default:                    return 0;
+        }
+    }
+};
+
+// Qualifiers that don't need to be keep per object.  They have shader scope, not object scope.
+// So, they will not be part of TType, TQualifier, etc.
+struct TShaderQualifiers {
+    TLayoutGeometry geometry; // geometry/tessellation shader in/out primitives
+    bool pixelCenterInteger;  // fragment shader
+    bool originUpperLeft;     // fragment shader
+    int invocations;
+    int vertices;             // both for tessellation "vertices" and geometry "max_vertices"
+    TVertexSpacing spacing;
+    TVertexOrder order;
+    bool pointMode;
+    int localSize[3];         // compute shader
+    int localSizeSpecId[3];   // compute shader specialization id for gl_WorkGroupSize
+    bool earlyFragmentTests;  // fragment input
+    TLayoutDepth layoutDepth;
+    bool blendEquation;       // true if any blend equation was specified
+
+#ifdef NV_EXTENSIONS
+    bool layoutOverrideCoverage;    // true if layout override_coverage set
+#endif
+
+    void init()
+    {
+        geometry = ElgNone;
+        originUpperLeft = false;
+        pixelCenterInteger = false;
+        invocations = TQualifier::layoutNotSet;
+        vertices = TQualifier::layoutNotSet;
+        spacing = EvsNone;
+        order = EvoNone;
+        pointMode = false;
+        localSize[0] = 1;
+        localSize[1] = 1;
+        localSize[2] = 1;
+        localSizeSpecId[0] = TQualifier::layoutNotSet;
+        localSizeSpecId[1] = TQualifier::layoutNotSet;
+        localSizeSpecId[2] = TQualifier::layoutNotSet;
+        earlyFragmentTests = false;
+        layoutDepth = EldNone;
+        blendEquation = false;
+#ifdef NV_EXTENSIONS
+        layoutOverrideCoverage = false;
+#endif
+    }
+
+    // Merge in characteristics from the 'src' qualifier.  They can override when
+    // set, but never erase when not set.
+    void merge(const TShaderQualifiers& src)
+    {
+        if (src.geometry != ElgNone)
+            geometry = src.geometry;
+        if (src.pixelCenterInteger)
+            pixelCenterInteger = src.pixelCenterInteger;
+        if (src.originUpperLeft)
+            originUpperLeft = src.originUpperLeft;
+        if (src.invocations != TQualifier::layoutNotSet)
+            invocations = src.invocations;
+        if (src.vertices != TQualifier::layoutNotSet)
+            vertices = src.vertices;
+        if (src.spacing != EvsNone)
+            spacing = src.spacing;
+        if (src.order != EvoNone)
+            order = src.order;
+        if (src.pointMode)
+            pointMode = true;
+        for (int i = 0; i < 3; ++i) {
+            if (src.localSize[i] > 1)
+                localSize[i] = src.localSize[i];
+        }
+        for (int i = 0; i < 3; ++i) {
+            if (src.localSizeSpecId[i] != TQualifier::layoutNotSet)
+                localSizeSpecId[i] = src.localSizeSpecId[i];
+        }
+        if (src.earlyFragmentTests)
+            earlyFragmentTests = true;
+        if (src.layoutDepth)
+            layoutDepth = src.layoutDepth;
+        if (src.blendEquation)
+            blendEquation = src.blendEquation;
+#ifdef NV_EXTENSIONS
+        if (src.layoutOverrideCoverage)
+            layoutOverrideCoverage = src.layoutOverrideCoverage;
+#endif
+    }
+};
+
+//
+// TPublicType is just temporarily used while parsing and not quite the same
+// information kept per node in TType.  Due to the bison stack, it can't have
+// types that it thinks have non-trivial constructors.  It should
+// just be used while recognizing the grammar, not anything else.
+// Once enough is known about the situation, the proper information
+// moved into a TType, or the parse context, etc.
+//
+class TPublicType {
+public:
+    TBasicType basicType;
+    TSampler sampler;
+    TQualifier qualifier;
+    TShaderQualifiers shaderQualifiers;
+    int vectorSize : 4;
+    int matrixCols : 4;
+    int matrixRows : 4;
+    TArraySizes* arraySizes;
+    const TType* userDef;
+    TSourceLoc loc;
+
+    void initType(const TSourceLoc& l)
+    {
+        basicType = EbtVoid;
+        vectorSize = 1;
+        matrixRows = 0;
+        matrixCols = 0;
+        arraySizes = nullptr;
+        userDef = nullptr;
+        loc = l;
+    }
+
+    void initQualifiers(bool global = false)
+    {
+        qualifier.clear();
+        if (global)
+            qualifier.storage = EvqGlobal;
+    }
+
+    void init(const TSourceLoc& l, bool global = false)
+    {
+        initType(l);
+        sampler.clear();
+        initQualifiers(global);
+        shaderQualifiers.init();
+    }
+
+    void setVector(int s)
+    {
+        matrixRows = 0;
+        matrixCols = 0;
+        vectorSize = s;
+    }
+
+    void setMatrix(int c, int r)
+    {
+        matrixRows = r;
+        matrixCols = c;
+        vectorSize = 0;
+    }
+
+    bool isScalar() const
+    {
+        return matrixCols == 0 && vectorSize == 1 && arraySizes == nullptr && userDef == nullptr;
+    }
+
+    // "Image" is a superset of "Subpass"
+    bool isImage()   const { return basicType == EbtSampler && sampler.isImage(); }
+    bool isSubpass() const { return basicType == EbtSampler && sampler.isSubpass(); }
+};
+
+//
+// Base class for things that have a type.
+//
+class TType {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    // for "empty" type (no args) or simple scalar/vector/matrix
+    explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0,
+                   bool isVector = false) :
+                            basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
+                            arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            {
+                                sampler.clear();
+                                qualifier.clear();
+                                qualifier.storage = q;
+                            }
+    // for explicit precision qualifier
+    TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0,
+          bool isVector = false) :
+                            basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
+                            arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            {
+                                sampler.clear();
+                                qualifier.clear();
+                                qualifier.storage = q;
+                                qualifier.precision = p;
+                                assert(p >= EpqNone && p <= EpqHigh);
+                            }
+    // for turning a TPublicType into a TType, using a shallow copy
+    explicit TType(const TPublicType& p) :
+                            basicType(p.basicType),
+                            vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false),
+                            arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            {
+                                if (basicType == EbtSampler)
+                                    sampler = p.sampler;
+                                else
+                                    sampler.clear();
+                                qualifier = p.qualifier;
+                                if (p.userDef) {
+                                    structure = p.userDef->getWritableStruct();  // public type is short-lived; there are no sharing issues
+                                    typeName = NewPoolTString(p.userDef->getTypeName().c_str());
+                                }
+                            }
+    // for construction of sampler types
+    TType(const TSampler& sampler, TStorageQualifier q = EvqUniform, TArraySizes* as = nullptr) :
+        basicType(EbtSampler), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+        arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr),
+        sampler(sampler)
+    {
+        qualifier.clear();
+        qualifier.storage = q;
+    }
+    // to efficiently make a dereferenced type
+    // without ever duplicating the outer structure that will be thrown away
+    // and using only shallow copy
+    TType(const TType& type, int derefIndex, bool rowMajor = false)
+                            {
+                                if (type.isArray()) {
+                                    shallowCopy(type);
+                                    if (type.getArraySizes()->getNumDims() == 1) {
+                                        arraySizes = nullptr;
+                                    } else {
+                                        // want our own copy of the array, so we can edit it
+                                        arraySizes = new TArraySizes;
+                                        arraySizes->copyDereferenced(*type.arraySizes);
+                                    }
+                                } else if (type.basicType == EbtStruct || type.basicType == EbtBlock) {
+                                    // do a structure dereference
+                                    const TTypeList& memberList = *type.getStruct();
+                                    shallowCopy(*memberList[derefIndex].type);
+                                    return;
+                                } else {
+                                    // do a vector/matrix dereference
+                                    shallowCopy(type);
+                                    if (matrixCols > 0) {
+                                        // dereference from matrix to vector
+                                        if (rowMajor)
+                                            vectorSize = matrixCols;
+                                        else
+                                            vectorSize = matrixRows;
+                                        matrixCols = 0;
+                                        matrixRows = 0;
+                                        if (vectorSize == 1)
+                                            vector1 = true;
+                                    } else if (isVector()) {
+                                        // dereference from vector to scalar
+                                        vectorSize = 1;
+                                        vector1 = false;
+                                    }
+                                }
+                            }
+    // for making structures, ...
+    TType(TTypeList* userDef, const TString& n) :
+                            basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+                            arraySizes(nullptr), structure(userDef), fieldName(nullptr)
+                            {
+                                sampler.clear();
+                                qualifier.clear();
+                                typeName = NewPoolTString(n.c_str());
+                            }
+    // For interface blocks
+    TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
+                            basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+                            qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr)
+                            {
+                                sampler.clear();
+                                typeName = NewPoolTString(n.c_str());
+                            }
+    virtual ~TType() {}
+
+    // Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
+    // This only works if that information (like a structure's list of types) does not change and
+    // the instances are sharing the same pool.
+    void shallowCopy(const TType& copyOf)
+    {
+        basicType = copyOf.basicType;
+        sampler = copyOf.sampler;
+        qualifier = copyOf.qualifier;
+        vectorSize = copyOf.vectorSize;
+        matrixCols = copyOf.matrixCols;
+        matrixRows = copyOf.matrixRows;
+        vector1 = copyOf.vector1;
+        arraySizes = copyOf.arraySizes;  // copying the pointer only, not the contents
+        structure = copyOf.structure;
+        fieldName = copyOf.fieldName;
+        typeName = copyOf.typeName;
+    }
+
+    // Make complete copy of the whole type graph rooted at 'copyOf'.
+    void deepCopy(const TType& copyOf)
+    {
+        TMap<TTypeList*,TTypeList*> copied;  // to enable copying a type graph as a graph, not a tree
+        deepCopy(copyOf, copied);
+    }
+
+    // Recursively make temporary
+    void makeTemporary()
+    {
+        getQualifier().makeTemporary();
+
+        if (isStruct())
+            for (unsigned int i = 0; i < structure->size(); ++i)
+                (*structure)[i].type->makeTemporary();
+    }
+
+    TType* clone() const
+    {
+        TType *newType = new TType();
+        newType->deepCopy(*this);
+
+        return newType;
+    }
+
+    void makeVector() { vector1 = true; }
+
+    // Merge type from parent, where a parentType is at the beginning of a declaration,
+    // establishing some characteristics for all subsequent names, while this type
+    // is on the individual names.
+    void mergeType(const TPublicType& parentType)
+    {
+        // arrayness is currently the only child aspect that has to be preserved
+        basicType = parentType.basicType;
+        vectorSize = parentType.vectorSize;
+        matrixCols = parentType.matrixCols;
+        matrixRows = parentType.matrixRows;
+        vector1 = false;                      // TPublicType is only GLSL which so far has no vec1
+        qualifier = parentType.qualifier;
+        sampler = parentType.sampler;
+        if (parentType.arraySizes)
+            newArraySizes(*parentType.arraySizes);
+        if (parentType.userDef) {
+            structure = parentType.userDef->getWritableStruct();
+            setTypeName(parentType.userDef->getTypeName());
+        }
+    }
+
+    virtual void hideMember() { basicType = EbtVoid; vectorSize = 1; }
+    virtual bool hiddenMember() const { return basicType == EbtVoid; }
+
+    virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); }
+    virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); }
+    virtual const TString& getTypeName() const
+    {
+        assert(typeName);
+        return *typeName;
+    }
+
+    virtual const TString& getFieldName() const
+    {
+        assert(fieldName);
+        return *fieldName;
+    }
+
+    virtual TBasicType getBasicType() const { return basicType; }
+    virtual const TSampler& getSampler() const { return sampler; }
+    virtual TSampler& getSampler() { return sampler; }
+
+    virtual       TQualifier& getQualifier()       { return qualifier; }
+    virtual const TQualifier& getQualifier() const { return qualifier; }
+
+    virtual int getVectorSize() const { return vectorSize; }  // returns 1 for either scalar or vector of size 1, valid for both
+    virtual int getMatrixCols() const { return matrixCols; }
+    virtual int getMatrixRows() const { return matrixRows; }
+    virtual int getOuterArraySize()  const { return arraySizes->getOuterSize(); }
+    virtual TIntermTyped*  getOuterArrayNode() const { return arraySizes->getOuterNode(); }
+    virtual int getCumulativeArraySize()  const { return arraySizes->getCumulativeSize(); }
+    virtual bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; }
+    virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
+    virtual const TArraySizes* getArraySizes() const { return arraySizes; }
+    virtual       TArraySizes& getArraySizes()       { assert(arraySizes != nullptr); return *arraySizes; }
+
+    virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
+    virtual bool isScalarOrVec1() const { return isScalar() || vector1; }
+    virtual bool isVector() const { return vectorSize > 1 || vector1; }
+    virtual bool isMatrix() const { return matrixCols ? true : false; }
+    virtual bool isArray()  const { return arraySizes != nullptr; }
+    virtual bool isExplicitlySizedArray() const { return isArray() && getOuterArraySize() != UnsizedArraySize; }
+    virtual bool isImplicitlySizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage != EvqBuffer; }
+    virtual bool isRuntimeSizedArray()    const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage == EvqBuffer; }
+    virtual bool isStruct() const { return structure != nullptr; }
+#ifdef AMD_EXTENSIONS
+    virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; }
+#else
+    virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble; }
+#endif
+
+    virtual bool isOpaque() const { return basicType == EbtSampler || basicType == EbtAtomicUint; }
+
+    // "Image" is a superset of "Subpass"
+    virtual bool isImage() const   { return basicType == EbtSampler && getSampler().isImage(); }
+    virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
+
+    virtual bool isBuiltInInterstageIO(EShLanguage language) const
+    {
+        return isPerVertexAndBuiltIn(language) || isLooseAndBuiltIn(language);
+    }
+
+    // Return true if this is an interstage IO builtin
+    virtual bool isPerVertexAndBuiltIn(EShLanguage language) const
+    {
+        if (language == EShLangFragment)
+            return false;
+
+        // Any non-fragment stage
+        switch (getQualifier().builtIn) {
+        case EbvPosition:
+        case EbvPointSize:
+        case EbvClipDistance:
+        case EbvCullDistance:
+#ifdef NV_EXTENSIONS
+        case EbvLayer:
+        case EbvViewportMaskNV:
+        case EbvSecondaryPositionNV:
+        case EbvSecondaryViewportMaskNV:
+        case EbvPositionPerViewNV:
+        case EbvViewportMaskPerViewNV:
+#endif
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    // Return true if this is a loose builtin
+    virtual bool isLooseAndBuiltIn(EShLanguage language) const
+    {
+        if (getQualifier().builtIn == EbvNone)
+            return false;
+
+        return !isPerVertexAndBuiltIn(language);
+    }
+    
+    // return true if this type contains any subtype which satisfies the given predicate.
+    template <typename P> 
+    bool contains(P predicate) const
+    {
+        if (predicate(this))
+            return true;
+
+        const auto hasa = [predicate](const TTypeLoc& tl) { return tl.type->contains(predicate); };
+
+        return structure && std::any_of(structure->begin(), structure->end(), hasa);
+    }
+
+    // Recursively checks if the type contains the given basic type
+    virtual bool containsBasicType(TBasicType checkType) const
+    {
+        return contains([checkType](const TType* t) { return t->basicType == checkType; } );
+    }
+
+    // Recursively check the structure for any arrays, needed for some error checks
+    virtual bool containsArray() const
+    {
+        return contains([](const TType* t) { return t->isArray(); } );
+    }
+
+    // Check the structure for any structures, needed for some error checks
+    virtual bool containsStructure() const
+    {
+        return contains([this](const TType* t) { return t != this && t->isStruct(); } );
+    }
+
+    // Recursively check the structure for any implicitly-sized arrays, needed for triggering a copyUp().
+    virtual bool containsImplicitlySizedArray() const
+    {
+        return contains([](const TType* t) { return t->isImplicitlySizedArray(); } );
+    }
+
+    virtual bool containsOpaque() const
+    {
+        return contains([](const TType* t) { return t->isOpaque(); } );
+    }
+
+    // Recursively checks if the type contains an interstage IO builtin
+    virtual bool containsBuiltInInterstageIO(EShLanguage language) const
+    {
+        return contains([language](const TType* t) { return t->isBuiltInInterstageIO(language); } );
+    }
+
+    virtual bool containsNonOpaque() const
+    {
+        const auto nonOpaque = [](const TType* t) {
+            switch (t->basicType) {
+            case EbtVoid:
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+            case EbtInt:
+            case EbtUint:
+            case EbtInt64:
+            case EbtUint64:
+#ifdef AMD_EXTENSIONS
+            case EbtInt16:
+            case EbtUint16:
+#endif
+            case EbtBool:
+            return true;
+            default:
+            return false;
+            }
+        };
+
+        return contains(nonOpaque);
+    }
+
+    virtual bool containsSpecializationSize() const
+    {
+        return contains([](const TType* t) { return t->isArray() && t->arraySizes->isOuterSpecialization(); } );
+    }
+
+    // Array editing methods.  Array descriptors can be shared across
+    // type instances.  This allows all uses of the same array
+    // to be updated at once.  E.g., all nodes can be explicitly sized
+    // by tracking and correcting one implicit size.  Or, all nodes
+    // can get the explicit size on a redeclaration that gives size.
+    //
+    // N.B.:  Don't share with the shared symbol tables (symbols are
+    // marked as isReadOnly().  Such symbols with arrays that will be
+    // edited need to copyUp() on first use, so that
+    // A) the edits don't effect the shared symbol table, and
+    // B) the edits are shared across all users.
+    void updateArraySizes(const TType& type)
+    {
+        // For when we may already be sharing existing array descriptors,
+        // keeping the pointers the same, just updating the contents.
+        assert(arraySizes != nullptr);
+        assert(type.arraySizes != nullptr);
+        *arraySizes = *type.arraySizes;
+    }
+    void newArraySizes(const TArraySizes& s)
+    {
+        // For setting a fresh new set of array sizes, not yet worrying about sharing.
+        arraySizes = new TArraySizes;
+        *arraySizes = s;
+    }
+    void clearArraySizes()
+    {
+        arraySizes = 0;
+    }
+    void addArrayOuterSizes(const TArraySizes& s)
+    {
+        if (arraySizes == nullptr)
+            newArraySizes(s);
+        else
+            arraySizes->addOuterSizes(s);
+    }
+    void changeOuterArraySize(int s) { arraySizes->changeOuterSize(s); }
+    void setImplicitArraySize(int s) { arraySizes->setImplicitSize(s); }
+
+    // Recursively make the implicit array size the explicit array size, through the type tree.
+    void adoptImplicitArraySizes()
+    {
+        if (isImplicitlySizedArray())
+            changeOuterArraySize(getImplicitArraySize());
+        if (isStruct()) {
+            for (int i = 0; i < (int)structure->size(); ++i)
+                (*structure)[i].type->adoptImplicitArraySizes();
+        }
+    }
+
+    const char* getBasicString() const
+    {
+        return TType::getBasicString(basicType);
+    }
+
+    static const char* getBasicString(TBasicType t)
+    {
+        switch (t) {
+        case EbtVoid:              return "void";
+        case EbtFloat:             return "float";
+        case EbtDouble:            return "double";
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:           return "float16_t";
+#endif
+        case EbtInt:               return "int";
+        case EbtUint:              return "uint";
+        case EbtInt64:             return "int64_t";
+        case EbtUint64:            return "uint64_t";
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:             return "int16_t";
+        case EbtUint16:            return "uint16_t";
+#endif
+        case EbtBool:              return "bool";
+        case EbtAtomicUint:        return "atomic_uint";
+        case EbtSampler:           return "sampler/image";
+        case EbtStruct:            return "structure";
+        case EbtBlock:             return "block";
+        default:                   return "unknown type";
+        }
+    }
+
+    TString getCompleteString() const
+    {
+        TString typeString;
+
+        const auto appendStr  = [&](const char* s)  { typeString.append(s); };
+        const auto appendUint = [&](unsigned int u) { typeString.append(std::to_string(u).c_str()); };
+        const auto appendInt  = [&](int i)          { typeString.append(std::to_string(i).c_str()); };
+
+        if (qualifier.hasLayout()) {
+            // To reduce noise, skip this if the only layout is an xfb_buffer
+            // with no triggering xfb_offset.
+            TQualifier noXfbBuffer = qualifier;
+            noXfbBuffer.layoutXfbBuffer = TQualifier::layoutXfbBufferEnd;
+            if (noXfbBuffer.hasLayout()) {
+                appendStr("layout(");
+                if (qualifier.hasAnyLocation()) {
+                    appendStr(" location=");
+                    appendUint(qualifier.layoutLocation);
+                    if (qualifier.hasComponent()) {
+                        appendStr(" component=");
+                        appendUint(qualifier.layoutComponent);
+                    }
+                    if (qualifier.hasIndex()) {
+                        appendStr(" index=");
+                        appendUint(qualifier.layoutIndex);
+                    }
+                }
+                if (qualifier.hasSet()) {
+                    appendStr(" set=");
+                    appendUint(qualifier.layoutSet);
+                }
+                if (qualifier.hasBinding()) {
+                    appendStr(" binding=");
+                    appendUint(qualifier.layoutBinding);
+                }
+                if (qualifier.hasStream()) {
+                    appendStr(" stream=");
+                    appendUint(qualifier.layoutStream);
+                }
+                if (qualifier.hasMatrix()) {
+                    appendStr(" ");
+                    appendStr(TQualifier::getLayoutMatrixString(qualifier.layoutMatrix));
+                }
+                if (qualifier.hasPacking()) {
+                    appendStr(" ");
+                    appendStr(TQualifier::getLayoutPackingString(qualifier.layoutPacking));
+                }
+                if (qualifier.hasOffset()) {
+                    appendStr(" offset=");
+                    appendInt(qualifier.layoutOffset);
+                }
+                if (qualifier.hasAlign()) {
+                    appendStr(" align=");
+                    appendInt(qualifier.layoutAlign);
+                }
+                if (qualifier.hasFormat()) {
+                    appendStr(" ");
+                    appendStr(TQualifier::getLayoutFormatString(qualifier.layoutFormat));
+                }
+                if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset()) {
+                    appendStr(" xfb_buffer=");
+                    appendUint(qualifier.layoutXfbBuffer);
+                }
+                if (qualifier.hasXfbOffset()) {
+                    appendStr(" xfb_offset=");
+                    appendUint(qualifier.layoutXfbOffset);
+                }
+                if (qualifier.hasXfbStride()) {
+                    appendStr(" xfb_stride=");
+                    appendUint(qualifier.layoutXfbStride);
+                }
+                if (qualifier.hasAttachment()) {
+                    appendStr(" input_attachment_index=");
+                    appendUint(qualifier.layoutAttachment);
+                }
+                if (qualifier.hasSpecConstantId()) {
+                    appendStr(" constant_id=");
+                    appendUint(qualifier.layoutSpecConstantId);
+                }
+                if (qualifier.layoutPushConstant)
+                    appendStr(" push_constant");
+
+#ifdef NV_EXTENSIONS
+                if (qualifier.layoutPassthrough)
+                    appendStr(" passthrough");
+                if (qualifier.layoutViewportRelative)
+                    appendStr(" layoutViewportRelative");
+                if (qualifier.layoutSecondaryViewportRelativeOffset != -2048) {
+                    appendStr(" layoutSecondaryViewportRelativeOffset=");
+                    appendInt(qualifier.layoutSecondaryViewportRelativeOffset);
+                }
+#endif
+
+                appendStr(")");
+            }
+        }
+
+        if (qualifier.invariant)
+            appendStr(" invariant");
+        if (qualifier.noContraction)
+            appendStr(" noContraction");
+        if (qualifier.centroid)
+            appendStr(" centroid");
+        if (qualifier.smooth)
+            appendStr(" smooth");
+        if (qualifier.flat)
+            appendStr(" flat");
+        if (qualifier.nopersp)
+            appendStr(" noperspective");
+#ifdef AMD_EXTENSIONS
+        if (qualifier.explicitInterp)
+            appendStr(" __explicitInterpAMD");
+#endif
+        if (qualifier.patch)
+            appendStr(" patch");
+        if (qualifier.sample)
+            appendStr(" sample");
+        if (qualifier.coherent)
+            appendStr(" coherent");
+        if (qualifier.volatil)
+            appendStr(" volatile");
+        if (qualifier.restrict)
+            appendStr(" restrict");
+        if (qualifier.readonly)
+            appendStr(" readonly");
+        if (qualifier.writeonly)
+            appendStr(" writeonly");
+        if (qualifier.specConstant)
+            appendStr(" specialization-constant");
+        appendStr(" ");
+        appendStr(getStorageQualifierString());
+        if (isArray()) {
+            for(int i = 0; i < (int)arraySizes->getNumDims(); ++i) {
+                int size = arraySizes->getDimSize(i);
+                if (size == 0)
+                    appendStr(" implicitly-sized array of");
+                else {
+                    appendStr(" ");
+                    appendInt(arraySizes->getDimSize(i));
+                    appendStr("-element array of");
+                }
+            }
+        }
+        if (qualifier.precision != EpqNone) {
+            appendStr(" ");
+            appendStr(getPrecisionQualifierString());
+        }
+        if (isMatrix()) {
+            appendStr(" ");
+            appendInt(matrixCols);
+            appendStr("X");
+            appendInt(matrixRows);
+            appendStr(" matrix of");
+        } else if (isVector()) {
+            appendStr(" ");
+            appendInt(vectorSize);
+            appendStr("-component vector of");
+        }
+
+        appendStr(" ");
+        typeString.append(getBasicTypeString());
+
+        if (qualifier.builtIn != EbvNone) {
+            appendStr(" ");
+            appendStr(getBuiltInVariableString());
+        }
+
+        // Add struct/block members
+        if (structure) {
+            appendStr("{");
+            for (size_t i = 0; i < structure->size(); ++i) {
+                if (! (*structure)[i].type->hiddenMember()) {
+                    typeString.append((*structure)[i].type->getCompleteString());
+                    typeString.append(" ");
+                    typeString.append((*structure)[i].type->getFieldName());
+                    if (i < structure->size() - 1)
+                        appendStr(", ");
+                }
+            }
+            appendStr("}");
+        }
+
+        return typeString;
+    }
+
+    TString getBasicTypeString() const
+    {
+        if (basicType == EbtSampler)
+            return sampler.getString();
+        else
+            return getBasicString();
+    }
+
+    const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
+    const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); }
+    const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
+    const TTypeList* getStruct() const { return structure; }
+    void setStruct(TTypeList* s) { structure = s; }
+    TTypeList* getWritableStruct() const { return structure; }  // This should only be used when known to not be sharing with other threads
+
+    int computeNumComponents() const
+    {
+        int components = 0;
+
+        if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) {
+            for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
+                components += ((*tl).type)->computeNumComponents();
+        } else if (matrixCols)
+            components = matrixCols * matrixRows;
+        else
+            components = vectorSize;
+
+        if (arraySizes != nullptr) {
+            components *= arraySizes->getCumulativeSize();
+        }
+
+        return components;
+    }
+
+    // append this type's mangled name to the passed in 'name'
+    void appendMangledName(TString& name) const
+    {
+        buildMangledName(name);
+        name += ';' ;
+    }
+
+    // Do two structure types match?  They could be declared independently,
+    // in different places, but still might satisfy the definition of matching.
+    // From the spec:
+    //
+    // "Structures must have the same name, sequence of type names, and
+    //  type definitions, and member names to be considered the same type.
+    //  This rule applies recursively for nested or embedded types."
+    //
+    bool sameStructType(const TType& right) const
+    {
+        // Most commonly, they are both nullptr, or the same pointer to the same actual structure
+        if (structure == right.structure)
+            return true;
+
+        // Both being nullptr was caught above, now they both have to be structures of the same number of elements
+        if (structure == nullptr || right.structure == nullptr ||
+            structure->size() != right.structure->size())
+            return false;
+
+        // Structure names have to match
+        if (*typeName != *right.typeName)
+            return false;
+
+        // Compare the names and types of all the members, which have to match
+        for (unsigned int i = 0; i < structure->size(); ++i) {
+            if ((*structure)[i].type->getFieldName() != (*right.structure)[i].type->getFieldName())
+                return false;
+
+            if (*(*structure)[i].type != *(*right.structure)[i].type)
+                return false;
+        }
+
+        return true;
+    }
+
+    // See if two types match, in all aspects except arrayness
+    bool sameElementType(const TType& right) const
+    {
+        return basicType == right.basicType && sameElementShape(right);
+    }
+
+    // See if two type's arrayness match
+    bool sameArrayness(const TType& right) const
+    {
+        return ((arraySizes == nullptr && right.arraySizes == nullptr) ||
+                (arraySizes != nullptr && right.arraySizes != nullptr && *arraySizes == *right.arraySizes));
+    }
+
+    // See if two type's arrayness match in everything except their outer dimension
+    bool sameInnerArrayness(const TType& right) const
+    {
+        assert(arraySizes != nullptr && right.arraySizes != nullptr);
+        return arraySizes->sameInnerArrayness(*right.arraySizes);
+    }
+
+    // See if two type's elements match in all ways except basic type
+    bool sameElementShape(const TType& right) const
+    {
+        return    sampler == right.sampler    &&
+               vectorSize == right.vectorSize &&
+               matrixCols == right.matrixCols &&
+               matrixRows == right.matrixRows &&
+                  vector1 == right.vector1    &&
+               sameStructType(right);
+    }
+
+    // See if two types match in all ways (just the actual type, not qualification)
+    bool operator==(const TType& right) const
+    {
+        return sameElementType(right) && sameArrayness(right);
+    }
+
+    bool operator!=(const TType& right) const
+    {
+        return ! operator==(right);
+    }
+
+protected:
+    // Require consumer to pick between deep copy and shallow copy.
+    TType(const TType& type);
+    TType& operator=(const TType& type);
+
+    // Recursively copy a type graph, while preserving the graph-like
+    // quality. That is, don't make more than one copy of a structure that
+    // gets reused multiple times in the type graph.
+    void deepCopy(const TType& copyOf, TMap<TTypeList*,TTypeList*>& copiedMap)
+    {
+        shallowCopy(copyOf);
+
+        if (copyOf.arraySizes) {
+            arraySizes = new TArraySizes;
+            *arraySizes = *copyOf.arraySizes;
+        }
+
+        if (copyOf.structure) {
+            auto prevCopy = copiedMap.find(copyOf.structure);
+            if (prevCopy != copiedMap.end())
+                structure = prevCopy->second;
+            else {
+                structure = new TTypeList;
+                copiedMap[copyOf.structure] = structure;
+                for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
+                    TTypeLoc typeLoc;
+                    typeLoc.loc = (*copyOf.structure)[i].loc;
+                    typeLoc.type = new TType();
+                    typeLoc.type->deepCopy(*(*copyOf.structure)[i].type, copiedMap);
+                    structure->push_back(typeLoc);
+                }
+            }
+        }
+
+        if (copyOf.fieldName)
+            fieldName = NewPoolTString(copyOf.fieldName->c_str());
+        if (copyOf.typeName)
+            typeName = NewPoolTString(copyOf.typeName->c_str());
+    }
+
+
+    void buildMangledName(TString&) const;
+
+    TBasicType basicType : 8;
+    int vectorSize       : 4;  // 1 means either scalar or 1-component vector; see vector1 to disambiguate.
+    int matrixCols       : 4;
+    int matrixRows       : 4;
+    bool vector1         : 1;  // Backward-compatible tracking of a 1-component vector distinguished from a scalar.
+                               // GLSL 4.5 never has a 1-component vector; so this will always be false until such
+                               // functionality is added.
+                               // HLSL does have a 1-component vectors, so this will be true to disambiguate
+                               // from a scalar.
+    TQualifier qualifier;
+
+    TArraySizes* arraySizes;    // nullptr unless an array; can be shared across types
+    TTypeList* structure;       // nullptr unless this is a struct; can be shared across types
+    TString *fieldName;         // for structure field names
+    TString *typeName;          // for structure type name
+    TSampler sampler;
+};
+
+} // end namespace glslang
+
+#endif // _TYPES_INCLUDED_

+ 320 - 0
src/libraries/glslang/glslang/Include/arrays.h

@@ -0,0 +1,320 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Implement types for tracking GLSL arrays, arrays of arrays, etc.
+//
+
+#ifndef _ARRAYS_INCLUDED
+#define _ARRAYS_INCLUDED
+
+namespace glslang {
+
+// This is used to mean there is no size yet (unsized), it is waiting to get a size from somewhere else.
+const int UnsizedArraySize = 0;
+
+class TIntermTyped;
+extern bool SameSpecializationConstants(TIntermTyped*, TIntermTyped*);
+
+// Specialization constants need both a nominal size and a node that defines
+// the specialization constant being used.  Array types are the same when their
+// size and specialization constant nodes are the same.
+struct TArraySize {
+    unsigned int size;
+    TIntermTyped* node;  // nullptr means no specialization constant node
+    bool operator==(const TArraySize& rhs) const
+    {
+        if (size != rhs.size)
+            return false;
+        if (node == nullptr || rhs.node == nullptr)
+            return node == rhs.node;
+
+        return SameSpecializationConstants(node, rhs.node);
+    }
+};
+
+//
+// TSmallArrayVector is used as the container for the set of sizes in TArraySizes.
+// It has generic-container semantics, while TArraySizes has array-of-array semantics.
+// That is, TSmallArrayVector should be more focused on mechanism and TArraySizes on policy.
+//
+struct TSmallArrayVector {
+    //
+    // TODO: memory: TSmallArrayVector is intended to be smaller.
+    // Almost all arrays could be handled by two sizes each fitting
+    // in 16 bits, needing a real vector only in the cases where there
+    // are more than 3 sizes or a size needing more than 16 bits.
+    //
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    TSmallArrayVector() : sizes(nullptr) { }
+    virtual ~TSmallArrayVector() { dealloc(); }
+
+    // For breaking into two non-shared copies, independently modifiable.
+    TSmallArrayVector& operator=(const TSmallArrayVector& from)
+    {
+        if (from.sizes == nullptr)
+            sizes = nullptr;
+        else {
+            alloc();
+            *sizes = *from.sizes;
+        }
+
+        return *this;
+    }
+
+    int size() const
+    {
+        if (sizes == nullptr)
+            return 0;
+        return (int)sizes->size();
+    }
+
+    unsigned int frontSize() const
+    {
+        assert(sizes != nullptr && sizes->size() > 0);
+        return sizes->front().size;
+    }
+
+    TIntermTyped* frontNode() const
+    {
+        assert(sizes != nullptr && sizes->size() > 0);
+        return sizes->front().node;
+    }
+
+    void changeFront(unsigned int s)
+    {
+        assert(sizes != nullptr);
+        // this should only happen for implicitly sized arrays, not specialization constants
+        assert(sizes->front().node == nullptr);
+        sizes->front().size = s;
+    }
+
+    void push_back(unsigned int e, TIntermTyped* n)
+    {
+        alloc();
+        TArraySize pair = { e, n };
+        sizes->push_back(pair);
+    }
+
+    void push_front(const TSmallArrayVector& newDims)
+    {
+        alloc();
+        sizes->insert(sizes->begin(), newDims.sizes->begin(), newDims.sizes->end());
+    }
+
+    void pop_front()
+    {
+        assert(sizes != nullptr && sizes->size() > 0);
+        if (sizes->size() == 1)
+            dealloc();
+        else
+            sizes->erase(sizes->begin());
+    }
+
+    // 'this' should currently not be holding anything, and copyNonFront
+    // will make it hold a copy of all but the first element of rhs.
+    // (This would be useful for making a type that is dereferenced by
+    // one dimension.)
+    void copyNonFront(const TSmallArrayVector& rhs)
+    {
+        assert(sizes == nullptr);
+        if (rhs.size() > 1) {
+            alloc();
+            sizes->insert(sizes->begin(), rhs.sizes->begin() + 1, rhs.sizes->end());
+        }
+    }
+
+    unsigned int getDimSize(int i) const
+    {
+        assert(sizes != nullptr && (int)sizes->size() > i);
+        return (*sizes)[i].size;
+    }
+
+    void setDimSize(int i, unsigned int size) const
+    {
+        assert(sizes != nullptr && (int)sizes->size() > i);
+        assert((*sizes)[i].node == nullptr);
+        (*sizes)[i].size = size;
+    }
+
+    TIntermTyped* getDimNode(int i) const
+    {
+        assert(sizes != nullptr && (int)sizes->size() > i);
+        return (*sizes)[i].node;
+    }
+
+    bool operator==(const TSmallArrayVector& rhs) const
+    {
+        if (sizes == nullptr && rhs.sizes == nullptr)
+            return true;
+        if (sizes == nullptr || rhs.sizes == nullptr)
+            return false;
+        return *sizes == *rhs.sizes;
+    }
+    bool operator!=(const TSmallArrayVector& rhs) const { return ! operator==(rhs); }
+
+protected:
+    TSmallArrayVector(const TSmallArrayVector&);
+
+    void alloc()
+    {
+        if (sizes == nullptr)
+            sizes = new TVector<TArraySize>;
+    }
+    void dealloc()
+    {
+        delete sizes;
+        sizes = nullptr;
+    }
+
+    TVector<TArraySize>* sizes; // will either hold such a pointer, or in the future, hold the two array sizes
+};
+
+//
+// Represent an array, or array of arrays, to arbitrary depth.  This is not
+// done through a hierarchy of types in a type tree, rather all contiguous arrayness
+// in the type hierarchy is localized into this single cumulative object.
+//
+// The arrayness in TTtype is a pointer, so that it can be non-allocated and zero
+// for the vast majority of types that are non-array types.
+//
+// Order Policy: these are all identical:
+//  - left to right order within a contiguous set of ...[..][..][..]... in the source language
+//  - index order 0, 1, 2, ... within the 'sizes' member below
+//  - outer-most to inner-most
+//
+struct TArraySizes {
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+    TArraySizes() : implicitArraySize(1) { }
+
+    // For breaking into two non-shared copies, independently modifiable.
+    TArraySizes& operator=(const TArraySizes& from)
+    {
+        implicitArraySize = from.implicitArraySize;
+        sizes = from.sizes;
+
+        return *this;
+    }
+
+    // translate from array-of-array semantics to container semantics
+    int getNumDims() const { return sizes.size(); }
+    int getDimSize(int dim) const { return sizes.getDimSize(dim); }
+    TIntermTyped* getDimNode(int dim) const { return sizes.getDimNode(dim); }
+    void setDimSize(int dim, int size) { sizes.setDimSize(dim, size); }
+    int getOuterSize() const { return sizes.frontSize(); }
+    TIntermTyped* getOuterNode() const { return sizes.frontNode(); }
+    int getCumulativeSize() const
+    {
+        int size = 1;
+        for (int d = 0; d < sizes.size(); ++d) {
+            // this only makes sense in paths that have a known array size
+            assert(sizes.getDimSize(d) != UnsizedArraySize);
+            size *= sizes.getDimSize(d);
+        }
+        return size;
+    }
+    void addInnerSize() { addInnerSize((unsigned)UnsizedArraySize); }
+    void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); }
+    void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); }
+    void addInnerSize(TArraySize pair) { sizes.push_back(pair.size, pair.node); }
+    void changeOuterSize(int s) { sizes.changeFront((unsigned)s); }
+    int getImplicitSize() const { return (int)implicitArraySize; }
+    void setImplicitSize(int s) { implicitArraySize = s; }
+    bool isInnerImplicit() const
+    {
+        for (int d = 1; d < sizes.size(); ++d) {
+            if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize)
+                return true;
+        }
+
+        return false;
+    }
+    bool isInnerSpecialization() const
+    {
+        for (int d = 1; d < sizes.size(); ++d) {
+            if (sizes.getDimNode(d) != nullptr)
+                return true;
+        }
+
+        return false;
+    }
+    bool isOuterSpecialization()
+    {
+        return sizes.getDimNode(0) != nullptr;
+    }
+
+    bool isImplicit() const { return getOuterSize() == UnsizedArraySize || isInnerImplicit(); }
+    void addOuterSizes(const TArraySizes& s) { sizes.push_front(s.sizes); }
+    void dereference() { sizes.pop_front(); }
+    void copyDereferenced(const TArraySizes& rhs)
+    {
+        assert(sizes.size() == 0);
+        if (rhs.sizes.size() > 1)
+            sizes.copyNonFront(rhs.sizes);
+    }
+
+    bool sameInnerArrayness(const TArraySizes& rhs) const
+    {
+        if (sizes.size() != rhs.sizes.size())
+            return false;
+
+        for (int d = 1; d < sizes.size(); ++d) {
+            if (sizes.getDimSize(d) != rhs.sizes.getDimSize(d) ||
+                sizes.getDimNode(d) != rhs.sizes.getDimNode(d))
+                return false;
+        }
+
+        return true;
+    }
+
+    bool operator==(const TArraySizes& rhs) { return sizes == rhs.sizes; }
+    bool operator!=(const TArraySizes& rhs) { return sizes != rhs.sizes; }
+
+protected:
+    TSmallArrayVector sizes;
+
+    TArraySizes(const TArraySizes&);
+
+    // for tracking maximum referenced index, before an explicit size is given
+    // applies only to the outer-most dimension
+    int implicitArraySize;
+};
+
+} // end namespace glslang
+
+#endif // _ARRAYS_INCLUDED_

+ 1406 - 0
src/libraries/glslang/glslang/Include/intermediate.h

@@ -0,0 +1,1406 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Definition of the in-memory high-level intermediate representation
+// of shaders.  This is a tree that parser creates.
+//
+// Nodes in the tree are defined as a hierarchy of classes derived from
+// TIntermNode. Each is a node in a tree.  There is no preset branching factor;
+// each node can have it's own type of list of children.
+//
+
+#ifndef __INTERMEDIATE_H
+#define __INTERMEDIATE_H
+
+#if _MSC_VER >= 1900
+    #pragma warning(disable : 4464) // relative include path contains '..'
+    #pragma warning(disable : 5026) // 'glslang::TIntermUnary': move constructor was implicitly defined as deleted
+#endif
+
+#include "../Include/Common.h"
+#include "../Include/Types.h"
+#include "../Include/ConstantUnion.h"
+
+namespace glslang {
+
+class TIntermediate;
+
+//
+// Operators used by the high-level (parse tree) representation.
+//
+enum TOperator {
+    EOpNull,            // if in a node, should only mean a node is still being built
+    EOpSequence,        // denotes a list of statements, or parameters, etc.
+    EOpLinkerObjects,   // for aggregate node of objects the linker may need, if not reference by the rest of the AST
+    EOpFunctionCall,
+    EOpFunction,        // For function definition
+    EOpParameters,      // an aggregate listing the parameters to a function
+
+    //
+    // Unary operators
+    //
+
+    EOpNegative,
+    EOpLogicalNot,
+    EOpVectorLogicalNot,
+    EOpBitwiseNot,
+
+    EOpPostIncrement,
+    EOpPostDecrement,
+    EOpPreIncrement,
+    EOpPreDecrement,
+
+    EOpConvIntToBool,
+    EOpConvUintToBool,
+    EOpConvFloatToBool,
+    EOpConvDoubleToBool,
+    EOpConvInt64ToBool,
+    EOpConvUint64ToBool,
+    EOpConvBoolToFloat,
+    EOpConvIntToFloat,
+    EOpConvUintToFloat,
+    EOpConvDoubleToFloat,
+    EOpConvInt64ToFloat,
+    EOpConvUint64ToFloat,
+    EOpConvUintToInt,
+    EOpConvFloatToInt,
+    EOpConvBoolToInt,
+    EOpConvDoubleToInt,
+    EOpConvInt64ToInt,
+    EOpConvUint64ToInt,
+    EOpConvIntToUint,
+    EOpConvFloatToUint,
+    EOpConvBoolToUint,
+    EOpConvDoubleToUint,
+    EOpConvInt64ToUint,
+    EOpConvUint64ToUint,
+    EOpConvIntToDouble,
+    EOpConvUintToDouble,
+    EOpConvFloatToDouble,
+    EOpConvBoolToDouble,
+    EOpConvInt64ToDouble,
+    EOpConvUint64ToDouble,
+    EOpConvBoolToInt64,
+    EOpConvIntToInt64,
+    EOpConvUintToInt64,
+    EOpConvFloatToInt64,
+    EOpConvDoubleToInt64,
+    EOpConvUint64ToInt64,
+    EOpConvBoolToUint64,
+    EOpConvIntToUint64,
+    EOpConvUintToUint64,
+    EOpConvFloatToUint64,
+    EOpConvDoubleToUint64,
+    EOpConvInt64ToUint64,
+#ifdef AMD_EXTENSIONS
+    EOpConvBoolToFloat16,
+    EOpConvIntToFloat16,
+    EOpConvUintToFloat16,
+    EOpConvFloatToFloat16,
+    EOpConvDoubleToFloat16,
+    EOpConvInt64ToFloat16,
+    EOpConvUint64ToFloat16,
+    EOpConvFloat16ToBool,
+    EOpConvFloat16ToInt,
+    EOpConvFloat16ToUint,
+    EOpConvFloat16ToFloat,
+    EOpConvFloat16ToDouble,
+    EOpConvFloat16ToInt64,
+    EOpConvFloat16ToUint64,
+
+    EOpConvBoolToInt16,
+    EOpConvIntToInt16,
+    EOpConvUintToInt16,
+    EOpConvFloatToInt16,
+    EOpConvDoubleToInt16,
+    EOpConvFloat16ToInt16,
+    EOpConvInt64ToInt16,
+    EOpConvUint64ToInt16,
+    EOpConvUint16ToInt16,
+    EOpConvInt16ToBool,
+    EOpConvInt16ToInt,
+    EOpConvInt16ToUint,
+    EOpConvInt16ToFloat,
+    EOpConvInt16ToDouble,
+    EOpConvInt16ToFloat16,
+    EOpConvInt16ToInt64,
+    EOpConvInt16ToUint64,
+
+    EOpConvBoolToUint16,
+    EOpConvIntToUint16,
+    EOpConvUintToUint16,
+    EOpConvFloatToUint16,
+    EOpConvDoubleToUint16,
+    EOpConvFloat16ToUint16,
+    EOpConvInt64ToUint16,
+    EOpConvUint64ToUint16,
+    EOpConvInt16ToUint16,
+    EOpConvUint16ToBool,
+    EOpConvUint16ToInt,
+    EOpConvUint16ToUint,
+    EOpConvUint16ToFloat,
+    EOpConvUint16ToDouble,
+    EOpConvUint16ToFloat16,
+    EOpConvUint16ToInt64,
+    EOpConvUint16ToUint64,
+#endif
+
+    //
+    // binary operations
+    //
+
+    EOpAdd,
+    EOpSub,
+    EOpMul,
+    EOpDiv,
+    EOpMod,
+    EOpRightShift,
+    EOpLeftShift,
+    EOpAnd,
+    EOpInclusiveOr,
+    EOpExclusiveOr,
+    EOpEqual,
+    EOpNotEqual,
+    EOpVectorEqual,
+    EOpVectorNotEqual,
+    EOpLessThan,
+    EOpGreaterThan,
+    EOpLessThanEqual,
+    EOpGreaterThanEqual,
+    EOpComma,
+
+    EOpVectorTimesScalar,
+    EOpVectorTimesMatrix,
+    EOpMatrixTimesVector,
+    EOpMatrixTimesScalar,
+
+    EOpLogicalOr,
+    EOpLogicalXor,
+    EOpLogicalAnd,
+
+    EOpIndexDirect,
+    EOpIndexIndirect,
+    EOpIndexDirectStruct,
+
+    EOpVectorSwizzle,
+
+    EOpMethod,
+    EOpScoping,
+
+    //
+    // Built-in functions mapped to operators
+    //
+
+    EOpRadians,
+    EOpDegrees,
+    EOpSin,
+    EOpCos,
+    EOpTan,
+    EOpAsin,
+    EOpAcos,
+    EOpAtan,
+    EOpSinh,
+    EOpCosh,
+    EOpTanh,
+    EOpAsinh,
+    EOpAcosh,
+    EOpAtanh,
+
+    EOpPow,
+    EOpExp,
+    EOpLog,
+    EOpExp2,
+    EOpLog2,
+    EOpSqrt,
+    EOpInverseSqrt,
+
+    EOpAbs,
+    EOpSign,
+    EOpFloor,
+    EOpTrunc,
+    EOpRound,
+    EOpRoundEven,
+    EOpCeil,
+    EOpFract,
+    EOpModf,
+    EOpMin,
+    EOpMax,
+    EOpClamp,
+    EOpMix,
+    EOpStep,
+    EOpSmoothStep,
+
+    EOpIsNan,
+    EOpIsInf,
+
+    EOpFma,
+
+    EOpFrexp,
+    EOpLdexp,
+
+    EOpFloatBitsToInt,
+    EOpFloatBitsToUint,
+    EOpIntBitsToFloat,
+    EOpUintBitsToFloat,
+    EOpDoubleBitsToInt64,
+    EOpDoubleBitsToUint64,
+    EOpInt64BitsToDouble,
+    EOpUint64BitsToDouble,
+#ifdef AMD_EXTENSIONS
+    EOpFloat16BitsToInt16,
+    EOpFloat16BitsToUint16,
+    EOpInt16BitsToFloat16,
+    EOpUint16BitsToFloat16,
+#endif
+    EOpPackSnorm2x16,
+    EOpUnpackSnorm2x16,
+    EOpPackUnorm2x16,
+    EOpUnpackUnorm2x16,
+    EOpPackSnorm4x8,
+    EOpUnpackSnorm4x8,
+    EOpPackUnorm4x8,
+    EOpUnpackUnorm4x8,
+    EOpPackHalf2x16,
+    EOpUnpackHalf2x16,
+    EOpPackDouble2x32,
+    EOpUnpackDouble2x32,
+    EOpPackInt2x32,
+    EOpUnpackInt2x32,
+    EOpPackUint2x32,
+    EOpUnpackUint2x32,
+#ifdef AMD_EXTENSIONS
+    EOpPackFloat2x16,
+    EOpUnpackFloat2x16,
+    EOpPackInt2x16,
+    EOpUnpackInt2x16,
+    EOpPackUint2x16,
+    EOpUnpackUint2x16,
+    EOpPackInt4x16,
+    EOpUnpackInt4x16,
+    EOpPackUint4x16,
+    EOpUnpackUint4x16,
+#endif
+
+    EOpLength,
+    EOpDistance,
+    EOpDot,
+    EOpCross,
+    EOpNormalize,
+    EOpFaceForward,
+    EOpReflect,
+    EOpRefract,
+
+#ifdef AMD_EXTENSIONS
+    EOpMin3,
+    EOpMax3,
+    EOpMid3,
+#endif
+
+    EOpDPdx,            // Fragment only
+    EOpDPdy,            // Fragment only
+    EOpFwidth,          // Fragment only
+    EOpDPdxFine,        // Fragment only
+    EOpDPdyFine,        // Fragment only
+    EOpFwidthFine,      // Fragment only
+    EOpDPdxCoarse,      // Fragment only
+    EOpDPdyCoarse,      // Fragment only
+    EOpFwidthCoarse,    // Fragment only
+
+    EOpInterpolateAtCentroid, // Fragment only
+    EOpInterpolateAtSample,   // Fragment only
+    EOpInterpolateAtOffset,   // Fragment only
+
+#ifdef AMD_EXTENSIONS
+    EOpInterpolateAtVertex,
+#endif
+
+    EOpMatrixTimesMatrix,
+    EOpOuterProduct,
+    EOpDeterminant,
+    EOpMatrixInverse,
+    EOpTranspose,
+
+    EOpFtransform,
+
+    EOpNoise,
+
+    EOpEmitVertex,           // geometry only
+    EOpEndPrimitive,         // geometry only
+    EOpEmitStreamVertex,     // geometry only
+    EOpEndStreamPrimitive,   // geometry only
+
+    EOpBarrier,
+    EOpMemoryBarrier,
+    EOpMemoryBarrierAtomicCounter,
+    EOpMemoryBarrierBuffer,
+    EOpMemoryBarrierImage,
+    EOpMemoryBarrierShared,  // compute only
+    EOpGroupMemoryBarrier,   // compute only
+
+    EOpBallot,
+    EOpReadInvocation,
+    EOpReadFirstInvocation,
+
+    EOpAnyInvocation,
+    EOpAllInvocations,
+    EOpAllInvocationsEqual,
+
+#ifdef AMD_EXTENSIONS
+    EOpMinInvocations,
+    EOpMaxInvocations,
+    EOpAddInvocations,
+    EOpMinInvocationsNonUniform,
+    EOpMaxInvocationsNonUniform,
+    EOpAddInvocationsNonUniform,
+    EOpMinInvocationsInclusiveScan,
+    EOpMaxInvocationsInclusiveScan,
+    EOpAddInvocationsInclusiveScan,
+    EOpMinInvocationsInclusiveScanNonUniform,
+    EOpMaxInvocationsInclusiveScanNonUniform,
+    EOpAddInvocationsInclusiveScanNonUniform,
+    EOpMinInvocationsExclusiveScan,
+    EOpMaxInvocationsExclusiveScan,
+    EOpAddInvocationsExclusiveScan,
+    EOpMinInvocationsExclusiveScanNonUniform,
+    EOpMaxInvocationsExclusiveScanNonUniform,
+    EOpAddInvocationsExclusiveScanNonUniform,
+    EOpSwizzleInvocations,
+    EOpSwizzleInvocationsMasked,
+    EOpWriteInvocation,
+    EOpMbcnt,
+
+    EOpCubeFaceIndex,
+    EOpCubeFaceCoord,
+    EOpTime,
+#endif
+
+    EOpAtomicAdd,
+    EOpAtomicMin,
+    EOpAtomicMax,
+    EOpAtomicAnd,
+    EOpAtomicOr,
+    EOpAtomicXor,
+    EOpAtomicExchange,
+    EOpAtomicCompSwap,
+
+    EOpAtomicCounterIncrement,
+    EOpAtomicCounterDecrement,
+    EOpAtomicCounter,
+
+    EOpAny,
+    EOpAll,
+
+    //
+    // Branch
+    //
+
+    EOpKill,            // Fragment only
+    EOpReturn,
+    EOpBreak,
+    EOpContinue,
+    EOpCase,
+    EOpDefault,
+
+    //
+    // Constructors
+    //
+
+    EOpConstructGuardStart,
+    EOpConstructInt,          // these first scalar forms also identify what implicit conversion is needed
+    EOpConstructUint,
+    EOpConstructInt64,
+    EOpConstructUint64,
+#ifdef AMD_EXTENSIONS
+    EOpConstructInt16,
+    EOpConstructUint16,
+#endif
+    EOpConstructBool,
+    EOpConstructFloat,
+    EOpConstructDouble,
+#ifdef AMD_EXTENSIONS
+    EOpConstructFloat16,
+#endif
+    EOpConstructVec2,
+    EOpConstructVec3,
+    EOpConstructVec4,
+    EOpConstructDVec2,
+    EOpConstructDVec3,
+    EOpConstructDVec4,
+#ifdef AMD_EXTENSIONS
+    EOpConstructF16Vec2,
+    EOpConstructF16Vec3,
+    EOpConstructF16Vec4,
+#endif
+    EOpConstructBVec2,
+    EOpConstructBVec3,
+    EOpConstructBVec4,
+    EOpConstructIVec2,
+    EOpConstructIVec3,
+    EOpConstructIVec4,
+    EOpConstructUVec2,
+    EOpConstructUVec3,
+    EOpConstructUVec4,
+    EOpConstructI64Vec2,
+    EOpConstructI64Vec3,
+    EOpConstructI64Vec4,
+    EOpConstructU64Vec2,
+    EOpConstructU64Vec3,
+    EOpConstructU64Vec4,
+#ifdef AMD_EXTENSIONS
+    EOpConstructI16Vec2,
+    EOpConstructI16Vec3,
+    EOpConstructI16Vec4,
+    EOpConstructU16Vec2,
+    EOpConstructU16Vec3,
+    EOpConstructU16Vec4,
+#endif
+    EOpConstructMat2x2,
+    EOpConstructMat2x3,
+    EOpConstructMat2x4,
+    EOpConstructMat3x2,
+    EOpConstructMat3x3,
+    EOpConstructMat3x4,
+    EOpConstructMat4x2,
+    EOpConstructMat4x3,
+    EOpConstructMat4x4,
+    EOpConstructDMat2x2,
+    EOpConstructDMat2x3,
+    EOpConstructDMat2x4,
+    EOpConstructDMat3x2,
+    EOpConstructDMat3x3,
+    EOpConstructDMat3x4,
+    EOpConstructDMat4x2,
+    EOpConstructDMat4x3,
+    EOpConstructDMat4x4,
+    EOpConstructIMat2x2,
+    EOpConstructIMat2x3,
+    EOpConstructIMat2x4,
+    EOpConstructIMat3x2,
+    EOpConstructIMat3x3,
+    EOpConstructIMat3x4,
+    EOpConstructIMat4x2,
+    EOpConstructIMat4x3,
+    EOpConstructIMat4x4,
+    EOpConstructUMat2x2,
+    EOpConstructUMat2x3,
+    EOpConstructUMat2x4,
+    EOpConstructUMat3x2,
+    EOpConstructUMat3x3,
+    EOpConstructUMat3x4,
+    EOpConstructUMat4x2,
+    EOpConstructUMat4x3,
+    EOpConstructUMat4x4,
+    EOpConstructBMat2x2,
+    EOpConstructBMat2x3,
+    EOpConstructBMat2x4,
+    EOpConstructBMat3x2,
+    EOpConstructBMat3x3,
+    EOpConstructBMat3x4,
+    EOpConstructBMat4x2,
+    EOpConstructBMat4x3,
+    EOpConstructBMat4x4,
+#ifdef AMD_EXTENSIONS
+    EOpConstructF16Mat2x2,
+    EOpConstructF16Mat2x3,
+    EOpConstructF16Mat2x4,
+    EOpConstructF16Mat3x2,
+    EOpConstructF16Mat3x3,
+    EOpConstructF16Mat3x4,
+    EOpConstructF16Mat4x2,
+    EOpConstructF16Mat4x3,
+    EOpConstructF16Mat4x4,
+#endif
+    EOpConstructStruct,
+    EOpConstructTextureSampler,
+    EOpConstructGuardEnd,
+
+    //
+    // moves
+    //
+
+    EOpAssign,
+    EOpAddAssign,
+    EOpSubAssign,
+    EOpMulAssign,
+    EOpVectorTimesMatrixAssign,
+    EOpVectorTimesScalarAssign,
+    EOpMatrixTimesScalarAssign,
+    EOpMatrixTimesMatrixAssign,
+    EOpDivAssign,
+    EOpModAssign,
+    EOpAndAssign,
+    EOpInclusiveOrAssign,
+    EOpExclusiveOrAssign,
+    EOpLeftShiftAssign,
+    EOpRightShiftAssign,
+
+    //
+    // Array operators
+    //
+
+    EOpArrayLength,      // "Array" distinguishes from length(v) built-in function, but it applies to vectors and matrices as well.
+
+    //
+    // Image operations
+    //
+
+    EOpImageGuardBegin,
+
+    EOpImageQuerySize,
+    EOpImageQuerySamples,
+    EOpImageLoad,
+    EOpImageStore,
+    EOpImageAtomicAdd,
+    EOpImageAtomicMin,
+    EOpImageAtomicMax,
+    EOpImageAtomicAnd,
+    EOpImageAtomicOr,
+    EOpImageAtomicXor,
+    EOpImageAtomicExchange,
+    EOpImageAtomicCompSwap,
+
+    EOpSubpassLoad,
+    EOpSubpassLoadMS,
+    EOpSparseImageLoad,
+
+    EOpImageGuardEnd,
+
+    //
+    // Texture operations
+    //
+
+    EOpTextureGuardBegin,
+
+    EOpTextureQuerySize,
+    EOpTextureQueryLod,
+    EOpTextureQueryLevels,
+    EOpTextureQuerySamples,
+
+    EOpSamplingGuardBegin,
+
+    EOpTexture,
+    EOpTextureProj,
+    EOpTextureLod,
+    EOpTextureOffset,
+    EOpTextureFetch,
+    EOpTextureFetchOffset,
+    EOpTextureProjOffset,
+    EOpTextureLodOffset,
+    EOpTextureProjLod,
+    EOpTextureProjLodOffset,
+    EOpTextureGrad,
+    EOpTextureGradOffset,
+    EOpTextureProjGrad,
+    EOpTextureProjGradOffset,
+    EOpTextureGather,
+    EOpTextureGatherOffset,
+    EOpTextureGatherOffsets,
+    EOpTextureClamp,
+    EOpTextureOffsetClamp,
+    EOpTextureGradClamp,
+    EOpTextureGradOffsetClamp,
+#ifdef AMD_EXTENSIONS
+    EOpTextureGatherLod,
+    EOpTextureGatherLodOffset,
+    EOpTextureGatherLodOffsets,
+#endif
+
+    EOpSparseTextureGuardBegin,
+
+    EOpSparseTexture,
+    EOpSparseTextureLod,
+    EOpSparseTextureOffset,
+    EOpSparseTextureFetch,
+    EOpSparseTextureFetchOffset,
+    EOpSparseTextureLodOffset,
+    EOpSparseTextureGrad,
+    EOpSparseTextureGradOffset,
+    EOpSparseTextureGather,
+    EOpSparseTextureGatherOffset,
+    EOpSparseTextureGatherOffsets,
+    EOpSparseTexelsResident,
+    EOpSparseTextureClamp,
+    EOpSparseTextureOffsetClamp,
+    EOpSparseTextureGradClamp,
+    EOpSparseTextureGradOffsetClamp,
+#ifdef AMD_EXTENSIONS
+    EOpSparseTextureGatherLod,
+    EOpSparseTextureGatherLodOffset,
+    EOpSparseTextureGatherLodOffsets,
+#endif
+
+    EOpSparseTextureGuardEnd,
+    EOpSamplingGuardEnd,
+    EOpTextureGuardEnd,
+
+    //
+    // Integer operations
+    //
+
+    EOpAddCarry,
+    EOpSubBorrow,
+    EOpUMulExtended,
+    EOpIMulExtended,
+    EOpBitfieldExtract,
+    EOpBitfieldInsert,
+    EOpBitFieldReverse,
+    EOpBitCount,
+    EOpFindLSB,
+    EOpFindMSB,
+
+    //
+    // HLSL operations
+    //
+
+    EOpClip,                // discard if input value < 0
+    EOpIsFinite,
+    EOpLog10,               // base 10 log
+    EOpRcp,                 // 1/x
+    EOpSaturate,            // clamp from 0 to 1
+    EOpSinCos,              // sin and cos in out parameters
+    EOpGenMul,              // mul(x,y) on any of mat/vec/scalars
+    EOpDst,                 // x = 1, y=src0.y * src1.y, z=src0.z, w=src1.w
+    EOpInterlockedAdd,      // atomic ops, but uses [optional] out arg instead of return
+    EOpInterlockedAnd,      // ...
+    EOpInterlockedCompareExchange, // ...
+    EOpInterlockedCompareStore,    // ...
+    EOpInterlockedExchange, // ...
+    EOpInterlockedMax,      // ...
+    EOpInterlockedMin,      // ...
+    EOpInterlockedOr,       // ...
+    EOpInterlockedXor,      // ...
+    EOpAllMemoryBarrierWithGroupSync,    // memory barriers without non-hlsl AST equivalents
+    EOpGroupMemoryBarrierWithGroupSync,  // ...
+    EOpWorkgroupMemoryBarrier,           // ...
+    EOpWorkgroupMemoryBarrierWithGroupSync, // ...
+    EOpEvaluateAttributeSnapped,         // InterpolateAtOffset with int position on 16x16 grid
+    EOpF32tof16,                         // HLSL conversion: half of a PackHalf2x16
+    EOpF16tof32,                         // HLSL conversion: half of an UnpackHalf2x16
+    EOpLit,                              // HLSL lighting coefficient vector
+    EOpTextureBias,                      // HLSL texture bias: will be lowered to EOpTexture
+    EOpAsDouble,                         // slightly different from EOpUint64BitsToDouble
+    EOpD3DCOLORtoUBYTE4,                 // convert and swizzle 4-component color to UBYTE4 range
+
+    EOpMethodSample,                     // Texture object methods.  These are translated to existing
+    EOpMethodSampleBias,                 // AST methods, and exist to represent HLSL semantics until that
+    EOpMethodSampleCmp,                  // translation is performed.  See HlslParseContext::decomposeSampleMethods().
+    EOpMethodSampleCmpLevelZero,         // ...
+    EOpMethodSampleGrad,                 // ...
+    EOpMethodSampleLevel,                // ...
+    EOpMethodLoad,                       // ...
+    EOpMethodGetDimensions,              // ...
+    EOpMethodGetSamplePosition,          // ...
+    EOpMethodGather,                     // ...
+    EOpMethodCalculateLevelOfDetail,     // ...
+    EOpMethodCalculateLevelOfDetailUnclamped,     // ...
+
+    // Load already defined above for textures
+    EOpMethodLoad2,                      // Structure buffer object methods.  These are translated to existing
+    EOpMethodLoad3,                      // AST methods, and exist to represent HLSL semantics until that
+    EOpMethodLoad4,                      // translation is performed.  See HlslParseContext::decomposeSampleMethods().
+    EOpMethodStore,                      // ...
+    EOpMethodStore2,                     // ...
+    EOpMethodStore3,                     // ...
+    EOpMethodStore4,                     // ...
+    EOpMethodIncrementCounter,           // ...
+    EOpMethodDecrementCounter,           // ...
+    // EOpMethodAppend is defined for geo shaders below
+    EOpMethodConsume,
+
+    // SM5 texture methods
+    EOpMethodGatherRed,                  // These are covered under the above EOpMethodSample comment about
+    EOpMethodGatherGreen,                // translation to existing AST opcodes.  They exist temporarily
+    EOpMethodGatherBlue,                 // because HLSL arguments are slightly different.
+    EOpMethodGatherAlpha,                // ...
+    EOpMethodGatherCmp,                  // ...
+    EOpMethodGatherCmpRed,               // ...
+    EOpMethodGatherCmpGreen,             // ...
+    EOpMethodGatherCmpBlue,              // ...
+    EOpMethodGatherCmpAlpha,             // ...
+
+    // geometry methods
+    EOpMethodAppend,                     // Geometry shader methods
+    EOpMethodRestartStrip,               // ...
+
+    // matrix
+    EOpMatrixSwizzle,                    // select multiple matrix components (non-column)
+};
+
+class TIntermTraverser;
+class TIntermOperator;
+class TIntermAggregate;
+class TIntermUnary;
+class TIntermBinary;
+class TIntermConstantUnion;
+class TIntermSelection;
+class TIntermSwitch;
+class TIntermBranch;
+class TIntermTyped;
+class TIntermMethod;
+class TIntermSymbol;
+
+} // end namespace glslang
+
+//
+// Base class for the tree nodes
+//
+// (Put outside the glslang namespace, as it's used as part of the external interface.)
+//
+class TIntermNode {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(glslang::GetThreadPoolAllocator())
+
+    TIntermNode() { loc.init(); }
+    virtual const glslang::TSourceLoc& getLoc() const { return loc; }
+    virtual void setLoc(const glslang::TSourceLoc& l) { loc = l; }
+    virtual void traverse(glslang::TIntermTraverser*) = 0;
+    virtual       glslang::TIntermTyped*         getAsTyped()               { return 0; }
+    virtual       glslang::TIntermOperator*      getAsOperator()            { return 0; }
+    virtual       glslang::TIntermConstantUnion* getAsConstantUnion()       { return 0; }
+    virtual       glslang::TIntermAggregate*     getAsAggregate()           { return 0; }
+    virtual       glslang::TIntermUnary*         getAsUnaryNode()           { return 0; }
+    virtual       glslang::TIntermBinary*        getAsBinaryNode()          { return 0; }
+    virtual       glslang::TIntermSelection*     getAsSelectionNode()       { return 0; }
+    virtual       glslang::TIntermSwitch*        getAsSwitchNode()          { return 0; }
+    virtual       glslang::TIntermMethod*        getAsMethodNode()          { return 0; }
+    virtual       glslang::TIntermSymbol*        getAsSymbolNode()          { return 0; }
+    virtual       glslang::TIntermBranch*        getAsBranchNode()          { return 0; }
+
+    virtual const glslang::TIntermTyped*         getAsTyped()         const { return 0; }
+    virtual const glslang::TIntermOperator*      getAsOperator()      const { return 0; }
+    virtual const glslang::TIntermConstantUnion* getAsConstantUnion() const { return 0; }
+    virtual const glslang::TIntermAggregate*     getAsAggregate()     const { return 0; }
+    virtual const glslang::TIntermUnary*         getAsUnaryNode()     const { return 0; }
+    virtual const glslang::TIntermBinary*        getAsBinaryNode()    const { return 0; }
+    virtual const glslang::TIntermSelection*     getAsSelectionNode() const { return 0; }
+    virtual const glslang::TIntermSwitch*        getAsSwitchNode()    const { return 0; }
+    virtual const glslang::TIntermMethod*        getAsMethodNode()    const { return 0; }
+    virtual const glslang::TIntermSymbol*        getAsSymbolNode()    const { return 0; }
+    virtual const glslang::TIntermBranch*        getAsBranchNode()    const { return 0; }
+    virtual ~TIntermNode() { }
+
+protected:
+    TIntermNode(const TIntermNode&);
+    TIntermNode& operator=(const TIntermNode&);
+    glslang::TSourceLoc loc;
+};
+
+namespace glslang {
+
+//
+// This is just to help yacc.
+//
+struct TIntermNodePair {
+    TIntermNode* node1;
+    TIntermNode* node2;
+};
+
+//
+// Intermediate class for nodes that have a type.
+//
+class TIntermTyped : public TIntermNode {
+public:
+    TIntermTyped(const TType& t) { type.shallowCopy(t); }
+    TIntermTyped(TBasicType basicType) { TType bt(basicType); type.shallowCopy(bt); }
+    virtual       TIntermTyped* getAsTyped()       { return this; }
+    virtual const TIntermTyped* getAsTyped() const { return this; }
+    virtual void setType(const TType& t) { type.shallowCopy(t); }
+    virtual const TType& getType() const { return type; }
+    virtual TType& getWritableType() { return type; }
+
+    virtual TBasicType getBasicType() const { return type.getBasicType(); }
+    virtual TQualifier& getQualifier() { return type.getQualifier(); }
+    virtual const TQualifier& getQualifier() const { return type.getQualifier(); }
+    virtual void propagatePrecision(TPrecisionQualifier);
+    virtual int getVectorSize() const { return type.getVectorSize(); }
+    virtual int getMatrixCols() const { return type.getMatrixCols(); }
+    virtual int getMatrixRows() const { return type.getMatrixRows(); }
+    virtual bool isMatrix() const { return type.isMatrix(); }
+    virtual bool isArray()  const { return type.isArray(); }
+    virtual bool isVector() const { return type.isVector(); }
+    virtual bool isScalar() const { return type.isScalar(); }
+    virtual bool isStruct() const { return type.isStruct(); }
+    TString getCompleteString() const { return type.getCompleteString(); }
+
+protected:
+    TIntermTyped& operator=(const TIntermTyped&);
+    TType type;
+};
+
+//
+// Loop control hints
+//
+enum TLoopControl {
+    ELoopControlNone,
+    ELoopControlUnroll,
+    ELoopControlDontUnroll,
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+class TIntermLoop : public TIntermNode {
+public:
+    TIntermLoop(TIntermNode* aBody, TIntermTyped* aTest, TIntermTyped* aTerminal, bool testFirst) :
+        body(aBody),
+        test(aTest),
+        terminal(aTerminal),
+        first(testFirst),
+        control(ELoopControlNone)
+    { }
+
+    virtual void traverse(TIntermTraverser*);
+    TIntermNode*  getBody() const { return body; }
+    TIntermTyped* getTest() const { return test; }
+    TIntermTyped* getTerminal() const { return terminal; }
+    bool testFirst() const { return first; }
+
+    void setLoopControl(TLoopControl c) { control = c; }
+    TLoopControl getLoopControl() const { return control; }
+
+protected:
+    TIntermNode* body;       // code to loop over
+    TIntermTyped* test;      // exit condition associated with loop, could be 0 for 'for' loops
+    TIntermTyped* terminal;  // exists for for-loops
+    bool first;              // true for while and for, not for do-while
+    TLoopControl control;    // loop control hint
+};
+
+//
+// Handle case, break, continue, return, and kill.
+//
+class TIntermBranch : public TIntermNode {
+public:
+    TIntermBranch(TOperator op, TIntermTyped* e) :
+        flowOp(op),
+        expression(e) { }
+    virtual       TIntermBranch* getAsBranchNode()       { return this; }
+    virtual const TIntermBranch* getAsBranchNode() const { return this; }
+    virtual void traverse(TIntermTraverser*);
+    TOperator getFlowOp() const { return flowOp; }
+    TIntermTyped* getExpression() const { return expression; }
+protected:
+    TOperator flowOp;
+    TIntermTyped* expression;
+};
+
+//
+// Represent method names before seeing their calling signature
+// or resolving them to operations.  Just an expression as the base object
+// and a textural name.
+//
+class TIntermMethod : public TIntermTyped {
+public:
+    TIntermMethod(TIntermTyped* o, const TType& t, const TString& m) : TIntermTyped(t), object(o), method(m) { }
+    virtual       TIntermMethod* getAsMethodNode()       { return this; }
+    virtual const TIntermMethod* getAsMethodNode() const { return this; }
+    virtual const TString& getMethodName() const { return method; }
+    virtual TIntermTyped* getObject() const { return object; }
+    virtual void traverse(TIntermTraverser*);
+protected:
+    TIntermTyped* object;
+    TString method;
+};
+
+//
+// Nodes that correspond to symbols or constants in the source code.
+//
+class TIntermSymbol : public TIntermTyped {
+public:
+    // if symbol is initialized as symbol(sym), the memory comes from the pool allocator of sym. If sym comes from
+    // per process threadPoolAllocator, then it causes increased memory usage per compile
+    // it is essential to use "symbol = sym" to assign to symbol
+    TIntermSymbol(int i, const TString& n, const TType& t)
+        : TIntermTyped(t), id(i), constSubtree(nullptr)
+          { name = n; }
+    virtual int getId() const { return id; }
+    virtual const TString& getName() const { return name; }
+    virtual void traverse(TIntermTraverser*);
+    virtual       TIntermSymbol* getAsSymbolNode()       { return this; }
+    virtual const TIntermSymbol* getAsSymbolNode() const { return this; }
+    void setConstArray(const TConstUnionArray& c) { constArray = c; }
+    const TConstUnionArray& getConstArray() const { return constArray; }
+    void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
+    TIntermTyped* getConstSubtree() const { return constSubtree; }
+
+protected:
+    int id;                      // the unique id of the symbol this node represents
+    TString name;                // the name of the symbol this node represents
+    TConstUnionArray constArray; // if the symbol is a front-end compile-time constant, this is its value
+    TIntermTyped* constSubtree;
+};
+
+class TIntermConstantUnion : public TIntermTyped {
+public:
+    TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), constArray(ua), literal(false) { }
+    const TConstUnionArray& getConstArray() const { return constArray; }
+    virtual       TIntermConstantUnion* getAsConstantUnion()       { return this; }
+    virtual const TIntermConstantUnion* getAsConstantUnion() const { return this; }
+    virtual void traverse(TIntermTraverser*);
+    virtual TIntermTyped* fold(TOperator, const TIntermTyped*) const;
+    virtual TIntermTyped* fold(TOperator, const TType&) const;
+    void setLiteral() { literal = true; }
+    void setExpression() { literal = false; }
+    bool isLiteral() const { return literal; }
+
+protected:
+    TIntermConstantUnion& operator=(const TIntermConstantUnion&);
+
+    const TConstUnionArray constArray;
+    bool literal;  // true if node represents a literal in the source code
+};
+
+// Represent the independent aspects of a texturing TOperator
+struct TCrackedTextureOp {
+    bool query;
+    bool proj;
+    bool lod;
+    bool fetch;
+    bool offset;
+    bool offsets;
+    bool gather;
+    bool grad;
+    bool subpass;
+    bool lodClamp;
+};
+
+//
+// Intermediate class for node types that hold operators.
+//
+class TIntermOperator : public TIntermTyped {
+public:
+    virtual       TIntermOperator* getAsOperator()       { return this; }
+    virtual const TIntermOperator* getAsOperator() const { return this; }
+    TOperator getOp() const { return op; }
+    void setOp(TOperator newOp) { op = newOp; }
+    bool modifiesState() const;
+    bool isConstructor() const;
+    bool isTexture()  const { return op > EOpTextureGuardBegin  && op < EOpTextureGuardEnd; }
+    bool isSampling() const { return op > EOpSamplingGuardBegin && op < EOpSamplingGuardEnd; }
+    bool isImage()    const { return op > EOpImageGuardBegin    && op < EOpImageGuardEnd; }
+    bool isSparseTexture() const { return op > EOpSparseTextureGuardBegin && op < EOpSparseTextureGuardEnd; }
+    bool isSparseImage()   const { return op == EOpSparseImageLoad; }
+
+    void setOperationPrecision(TPrecisionQualifier p) { operationPrecision = p; }
+    TPrecisionQualifier getOperationPrecision() const { return operationPrecision != EpqNone ?
+                                                                                     operationPrecision :
+                                                                                     type.getQualifier().precision; }
+    TString getCompleteString() const
+    {
+        TString cs = type.getCompleteString();
+        if (getOperationPrecision() != type.getQualifier().precision) {
+            cs += ", operation at ";
+            cs += GetPrecisionQualifierString(getOperationPrecision());
+        }
+
+        return cs;
+    }
+
+    // Crack the op into the individual dimensions of texturing operation.
+    void crackTexture(TSampler sampler, TCrackedTextureOp& cracked) const
+    {
+        cracked.query = false;
+        cracked.proj = false;
+        cracked.lod = false;
+        cracked.fetch = false;
+        cracked.offset = false;
+        cracked.offsets = false;
+        cracked.gather = false;
+        cracked.grad = false;
+        cracked.subpass = false;
+        cracked.lodClamp = false;
+
+        switch (op) {
+        case EOpImageQuerySize:
+        case EOpImageQuerySamples:
+        case EOpTextureQuerySize:
+        case EOpTextureQueryLod:
+        case EOpTextureQueryLevels:
+        case EOpTextureQuerySamples:
+        case EOpSparseTexelsResident:
+            cracked.query = true;
+            break;
+        case EOpTexture:
+        case EOpSparseTexture:
+            break;
+        case EOpTextureClamp:
+        case EOpSparseTextureClamp:
+            cracked.lodClamp = true;
+            break;
+        case EOpTextureProj:
+            cracked.proj = true;
+            break;
+        case EOpTextureLod:
+        case EOpSparseTextureLod:
+            cracked.lod = true;
+            break;
+        case EOpTextureOffset:
+        case EOpSparseTextureOffset:
+            cracked.offset = true;
+            break;
+        case EOpTextureOffsetClamp:
+        case EOpSparseTextureOffsetClamp:
+            cracked.offset = true;
+            cracked.lodClamp = true;
+            break;
+        case EOpTextureFetch:
+        case EOpSparseTextureFetch:
+            cracked.fetch = true;
+            if (sampler.dim == Esd1D || (sampler.dim == Esd2D && ! sampler.ms) || sampler.dim == Esd3D)
+                cracked.lod = true;
+            break;
+        case EOpTextureFetchOffset:
+        case EOpSparseTextureFetchOffset:
+            cracked.fetch = true;
+            cracked.offset = true;
+            if (sampler.dim == Esd1D || (sampler.dim == Esd2D && ! sampler.ms) || sampler.dim == Esd3D)
+                cracked.lod = true;
+            break;
+        case EOpTextureProjOffset:
+            cracked.offset = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureLodOffset:
+        case EOpSparseTextureLodOffset:
+            cracked.offset = true;
+            cracked.lod = true;
+            break;
+        case EOpTextureProjLod:
+            cracked.lod = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureProjLodOffset:
+            cracked.offset = true;
+            cracked.lod = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureGrad:
+        case EOpSparseTextureGrad:
+            cracked.grad = true;
+            break;
+        case EOpTextureGradClamp:
+        case EOpSparseTextureGradClamp:
+            cracked.grad = true;
+            cracked.lodClamp = true;
+            break;
+        case EOpTextureGradOffset:
+        case EOpSparseTextureGradOffset:
+            cracked.grad = true;
+            cracked.offset = true;
+            break;
+        case EOpTextureProjGrad:
+            cracked.grad = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureProjGradOffset:
+            cracked.grad = true;
+            cracked.offset = true;
+            cracked.proj = true;
+            break;
+        case EOpTextureGradOffsetClamp:
+        case EOpSparseTextureGradOffsetClamp:
+            cracked.grad = true;
+            cracked.offset = true;
+            cracked.lodClamp = true;
+            break;
+        case EOpTextureGather:
+        case EOpSparseTextureGather:
+            cracked.gather = true;
+            break;
+        case EOpTextureGatherOffset:
+        case EOpSparseTextureGatherOffset:
+            cracked.gather = true;
+            cracked.offset = true;
+            break;
+        case EOpTextureGatherOffsets:
+        case EOpSparseTextureGatherOffsets:
+            cracked.gather = true;
+            cracked.offsets = true;
+            break;
+#ifdef AMD_EXTENSIONS
+        case EOpTextureGatherLod:
+        case EOpSparseTextureGatherLod:
+            cracked.gather = true;
+            cracked.lod    = true;
+            break;
+        case EOpTextureGatherLodOffset:
+        case EOpSparseTextureGatherLodOffset:
+            cracked.gather = true;
+            cracked.offset = true;
+            cracked.lod    = true;
+            break;
+        case EOpTextureGatherLodOffsets:
+        case EOpSparseTextureGatherLodOffsets:
+            cracked.gather  = true;
+            cracked.offsets = true;
+            cracked.lod     = true;
+            break;
+#endif
+        case EOpSubpassLoad:
+        case EOpSubpassLoadMS:
+            cracked.subpass = true;
+            break;
+        default:
+            break;
+        }
+    }
+
+protected:
+    TIntermOperator(TOperator o) : TIntermTyped(EbtFloat), op(o), operationPrecision(EpqNone) {}
+    TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o), operationPrecision(EpqNone) {}
+    TOperator op;
+    // The result precision is in the inherited TType, and is usually meant to be both
+    // the operation precision and the result precision. However, some more complex things,
+    // like built-in function calls, distinguish between the two, in which case non-EqpNone
+    // 'operationPrecision' overrides the result precision as far as operation precision
+    // is concerned.
+    TPrecisionQualifier operationPrecision;
+};
+
+//
+// Nodes for all the basic binary math operators.
+//
+class TIntermBinary : public TIntermOperator {
+public:
+    TIntermBinary(TOperator o) : TIntermOperator(o) {}
+    virtual void traverse(TIntermTraverser*);
+    virtual void setLeft(TIntermTyped* n) { left = n; }
+    virtual void setRight(TIntermTyped* n) { right = n; }
+    virtual TIntermTyped* getLeft() const { return left; }
+    virtual TIntermTyped* getRight() const { return right; }
+    virtual       TIntermBinary* getAsBinaryNode()       { return this; }
+    virtual const TIntermBinary* getAsBinaryNode() const { return this; }
+    virtual void updatePrecision();
+protected:
+    TIntermTyped* left;
+    TIntermTyped* right;
+};
+
+//
+// Nodes for unary math operators.
+//
+class TIntermUnary : public TIntermOperator {
+public:
+    TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0) {}
+    TIntermUnary(TOperator o) : TIntermOperator(o), operand(0) {}
+    virtual void traverse(TIntermTraverser*);
+    virtual void setOperand(TIntermTyped* o) { operand = o; }
+    virtual       TIntermTyped* getOperand() { return operand; }
+    virtual const TIntermTyped* getOperand() const { return operand; }
+    virtual       TIntermUnary* getAsUnaryNode()       { return this; }
+    virtual const TIntermUnary* getAsUnaryNode() const { return this; }
+    virtual void updatePrecision();
+protected:
+    TIntermTyped* operand;
+};
+
+typedef TVector<TIntermNode*> TIntermSequence;
+typedef TVector<int> TQualifierList;
+//
+// Nodes that operate on an arbitrary sized set of children.
+//
+class TIntermAggregate : public TIntermOperator {
+public:
+    TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(0) { }
+    TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(0) { }
+    ~TIntermAggregate() { delete pragmaTable; }
+    virtual       TIntermAggregate* getAsAggregate()       { return this; }
+    virtual const TIntermAggregate* getAsAggregate() const { return this; }
+    virtual void setOperator(TOperator o) { op = o; }
+    virtual       TIntermSequence& getSequence()       { return sequence; }
+    virtual const TIntermSequence& getSequence() const { return sequence; }
+    virtual void setName(const TString& n) { name = n; }
+    virtual const TString& getName() const { return name; }
+    virtual void traverse(TIntermTraverser*);
+    virtual void setUserDefined() { userDefined = true; }
+    virtual bool isUserDefined() { return userDefined; }
+    virtual TQualifierList& getQualifierList() { return qualifier; }
+    virtual const TQualifierList& getQualifierList() const { return qualifier; }
+    void setOptimize(bool o) { optimize = o; }
+    void setDebug(bool d) { debug = d; }
+    bool getOptimize() const { return optimize; }
+    bool getDebug() const { return debug; }
+    void addToPragmaTable(const TPragmaTable& pTable);
+    const TPragmaTable& getPragmaTable() const { return *pragmaTable; }
+protected:
+    TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
+    TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
+    TIntermSequence sequence;
+    TQualifierList qualifier;
+    TString name;
+    bool userDefined; // used for user defined function names
+    bool optimize;
+    bool debug;
+    TPragmaTable* pragmaTable;
+};
+
+//
+// For if tests.
+//
+class TIntermSelection : public TIntermTyped {
+public:
+    TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
+        TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+    TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
+        TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+    virtual void traverse(TIntermTraverser*);
+    virtual TIntermTyped* getCondition() const { return condition; }
+    virtual TIntermNode* getTrueBlock() const { return trueBlock; }
+    virtual TIntermNode* getFalseBlock() const { return falseBlock; }
+    virtual       TIntermSelection* getAsSelectionNode()       { return this; }
+    virtual const TIntermSelection* getAsSelectionNode() const { return this; }
+protected:
+    TIntermTyped* condition;
+    TIntermNode* trueBlock;
+    TIntermNode* falseBlock;
+};
+
+//
+// For switch statements.  Designed use is that a switch will have sequence of nodes
+// that are either case/default nodes or a *single* node that represents all the code
+// in between (if any) consecutive case/defaults.  So, a traversal need only deal with
+// 0 or 1 nodes per case/default statement.
+//
+class TIntermSwitch : public TIntermNode {
+public:
+    TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b) { }
+    virtual void traverse(TIntermTraverser*);
+    virtual TIntermNode* getCondition() const { return condition; }
+    virtual TIntermAggregate* getBody() const { return body; }
+    virtual       TIntermSwitch* getAsSwitchNode()       { return this; }
+    virtual const TIntermSwitch* getAsSwitchNode() const { return this; }
+protected:
+    TIntermTyped* condition;
+    TIntermAggregate* body;
+};
+
+enum TVisit
+{
+    EvPreVisit,
+    EvInVisit,
+    EvPostVisit
+};
+
+//
+// For traversing the tree.  User should derive from this,
+// put their traversal specific data in it, and then pass
+// it to a Traverse method.
+//
+// When using this, just fill in the methods for nodes you want visited.
+// Return false from a pre-visit to skip visiting that node's subtree.
+//
+// Explicitly set postVisit to true if you want post visiting, otherwise,
+// filled in methods will only be called at pre-visit time (before processing
+// the subtree).  Similarly for inVisit for in-order visiting of nodes with
+// multiple children.
+//
+// If you only want post-visits, explicitly turn off preVisit (and inVisit)
+// and turn on postVisit.
+//
+// In general, for the visit*() methods, return true from interior nodes
+// to have the traversal continue on to children.
+//
+// If you process children yourself, or don't want them processed, return false.
+//
+class TIntermTraverser {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(glslang::GetThreadPoolAllocator())
+    TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
+            preVisit(preVisit),
+            inVisit(inVisit),
+            postVisit(postVisit),
+            rightToLeft(rightToLeft),
+            depth(0),
+            maxDepth(0) { }
+    virtual ~TIntermTraverser() { }
+
+    virtual void visitSymbol(TIntermSymbol*)               { }
+    virtual void visitConstantUnion(TIntermConstantUnion*) { }
+    virtual bool visitBinary(TVisit, TIntermBinary*)       { return true; }
+    virtual bool visitUnary(TVisit, TIntermUnary*)         { return true; }
+    virtual bool visitSelection(TVisit, TIntermSelection*) { return true; }
+    virtual bool visitAggregate(TVisit, TIntermAggregate*) { return true; }
+    virtual bool visitLoop(TVisit, TIntermLoop*)           { return true; }
+    virtual bool visitBranch(TVisit, TIntermBranch*)       { return true; }
+    virtual bool visitSwitch(TVisit, TIntermSwitch*)       { return true; }
+
+    int getMaxDepth() const { return maxDepth; }
+
+    void incrementDepth(TIntermNode *current)
+    {
+        depth++;
+        maxDepth = (std::max)(maxDepth, depth);
+        path.push_back(current);
+    }
+
+    void decrementDepth()
+    {
+        depth--;
+        path.pop_back();
+    }
+
+    TIntermNode *getParentNode()
+    {
+        return path.size() == 0 ? NULL : path.back();
+    }
+
+    const bool preVisit;
+    const bool inVisit;
+    const bool postVisit;
+    const bool rightToLeft;
+
+protected:
+    TIntermTraverser& operator=(TIntermTraverser&);
+
+    int depth;
+    int maxDepth;
+
+    // All the nodes from root to the current node's parent during traversing.
+    TVector<TIntermNode *> path;
+};
+
+// KHR_vulkan_glsl says "Two arrays sized with specialization constants are the same type only if
+// sized with the same symbol, involving no operations"
+inline bool SameSpecializationConstants(TIntermTyped* node1, TIntermTyped* node2)
+{
+    return node1->getAsSymbolNode() && node2->getAsSymbolNode() &&
+           node1->getAsSymbolNode()->getId() == node2->getAsSymbolNode()->getId();
+}
+
+} // end namespace glslang
+
+#endif // __INTERMEDIATE_H

+ 6 - 0
src/libraries/glslang/glslang/Include/revision.h

@@ -0,0 +1,6 @@
+// This header is generated by the make-revision script.
+// For the version, it uses the latest git tag followed by the number of commits.
+// For the date, it uses the current date (when then script is run).
+
+#define GLSLANG_REVISION "Overload400-PrecQual.2000"
+#define GLSLANG_DATE "12-Apr-2017"

+ 1029 - 0
src/libraries/glslang/glslang/MachineIndependent/Constant.cpp

@@ -0,0 +1,1029 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2013 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "localintermediate.h"
+#include <cmath>
+#include <cfloat>
+#include <cstdlib>
+
+namespace {
+
+using namespace glslang;
+
+typedef union {
+    double d;
+    int i[2];
+} DoubleIntUnion;
+
+// Some helper functions
+
+bool isNan(double x)
+{
+    DoubleIntUnion u;
+    // tough to find a platform independent library function, do it directly
+    u.d = x;
+    int bitPatternL = u.i[0];
+    int bitPatternH = u.i[1];
+    return (bitPatternH & 0x7ff80000) == 0x7ff80000 &&
+           ((bitPatternH & 0xFFFFF) != 0 || bitPatternL != 0);
+}
+
+bool isInf(double x)
+{
+    DoubleIntUnion u;
+    // tough to find a platform independent library function, do it directly
+    u.d = x;
+    int bitPatternL = u.i[0];
+    int bitPatternH = u.i[1];
+    return (bitPatternH & 0x7ff00000) == 0x7ff00000 &&
+           (bitPatternH & 0xFFFFF) == 0 && bitPatternL == 0;
+}
+
+const double pi = 3.1415926535897932384626433832795;
+
+} // end anonymous namespace
+
+
+namespace glslang {
+
+//
+// The fold functions see if an operation on a constant can be done in place,
+// without generating run-time code.
+//
+// Returns the node to keep using, which may or may not be the node passed in.
+//
+// Note: As of version 1.2, all constant operations must be folded.  It is
+// not opportunistic, but rather a semantic requirement.
+//
+
+//
+// Do folding between a pair of nodes.
+// 'this' is the left-hand operand and 'rightConstantNode' is the right-hand operand.
+//
+// Returns a new node representing the result.
+//
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* rightConstantNode) const
+{
+    // For most cases, the return type matches the argument type, so set that
+    // up and just code to exceptions below.
+    TType returnType;
+    returnType.shallowCopy(getType());
+
+    //
+    // A pair of nodes is to be folded together
+    //
+
+    const TIntermConstantUnion *rightNode = rightConstantNode->getAsConstantUnion();
+    TConstUnionArray leftUnionArray = getConstArray();
+    TConstUnionArray rightUnionArray = rightNode->getConstArray();
+
+    // Figure out the size of the result
+    int newComps;
+    int constComps;
+    switch(op) {
+    case EOpMatrixTimesMatrix:
+        newComps = rightNode->getMatrixCols() * getMatrixRows();
+        break;
+    case EOpMatrixTimesVector:
+        newComps = getMatrixRows();
+        break;
+    case EOpVectorTimesMatrix:
+        newComps = rightNode->getMatrixCols();
+        break;
+    default:
+        newComps = getType().computeNumComponents();
+        constComps = rightConstantNode->getType().computeNumComponents();
+        if (constComps == 1 && newComps > 1) {
+            // for a case like vec4 f = vec4(2,3,4,5) + 1.2;
+            TConstUnionArray smearedArray(newComps, rightNode->getConstArray()[0]);
+            rightUnionArray = smearedArray;
+        } else if (constComps > 1 && newComps == 1) {
+            // for a case like vec4 f = 1.2 + vec4(2,3,4,5);
+            newComps = constComps;
+            rightUnionArray = rightNode->getConstArray();
+            TConstUnionArray smearedArray(newComps, getConstArray()[0]);
+            leftUnionArray = smearedArray;
+            returnType.shallowCopy(rightNode->getType());
+        }
+        break;
+    }
+
+    TConstUnionArray newConstArray(newComps);
+    TType constBool(EbtBool, EvqConst);
+
+    switch(op) {
+    case EOpAdd:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] + rightUnionArray[i];
+        break;
+    case EOpSub:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] - rightUnionArray[i];
+        break;
+
+    case EOpMul:
+    case EOpVectorTimesScalar:
+    case EOpMatrixTimesScalar:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] * rightUnionArray[i];
+        break;
+    case EOpMatrixTimesMatrix:
+        for (int row = 0; row < getMatrixRows(); row++) {
+            for (int column = 0; column < rightNode->getMatrixCols(); column++) {
+                double sum = 0.0f;
+                for (int i = 0; i < rightNode->getMatrixRows(); i++)
+                    sum += leftUnionArray[i * getMatrixRows() + row].getDConst() * rightUnionArray[column * rightNode->getMatrixRows() + i].getDConst();
+                newConstArray[column * getMatrixRows() + row].setDConst(sum);
+            }
+        }
+        returnType.shallowCopy(TType(getType().getBasicType(), EvqConst, 0, rightNode->getMatrixCols(), getMatrixRows()));
+        break;
+    case EOpDiv:
+        for (int i = 0; i < newComps; i++) {
+            switch (getType().getBasicType()) {
+            case EbtDouble:
+            case EbtFloat:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                newConstArray[i].setDConst(leftUnionArray[i].getDConst() / rightUnionArray[i].getDConst());
+                break;
+
+            case EbtInt:
+                if (rightUnionArray[i] == 0)
+                    newConstArray[i].setIConst(0x7FFFFFFF);
+                else if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == (int)0x80000000)
+                    newConstArray[i].setIConst(0x80000000);
+                else
+                    newConstArray[i].setIConst(leftUnionArray[i].getIConst() / rightUnionArray[i].getIConst());
+                break;
+
+            case EbtUint:
+                if (rightUnionArray[i] == 0) {
+                    newConstArray[i].setUConst(0xFFFFFFFFu);
+                } else
+                    newConstArray[i].setUConst(leftUnionArray[i].getUConst() / rightUnionArray[i].getUConst());
+                break;
+
+            case EbtInt64:
+                if (rightUnionArray[i] == 0)
+                    newConstArray[i].setI64Const(0x7FFFFFFFFFFFFFFFll);
+                else if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == (long long)0x8000000000000000)
+                    newConstArray[i].setI64Const(0x8000000000000000);
+                else
+                    newConstArray[i].setI64Const(leftUnionArray[i].getI64Const() / rightUnionArray[i].getI64Const());
+                break;
+
+            case EbtUint64:
+                if (rightUnionArray[i] == 0) {
+                    newConstArray[i].setU64Const(0xFFFFFFFFFFFFFFFFull);
+                } else
+                    newConstArray[i].setU64Const(leftUnionArray[i].getU64Const() / rightUnionArray[i].getU64Const());
+                break;
+#ifdef AMD_EXTENSIONS
+            case EbtInt16:
+                if (rightUnionArray[i] == 0)
+                    newConstArray[i].setIConst(0x7FFF);
+                else if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == (int)0x8000)
+                    newConstArray[i].setIConst(0x8000);
+                else
+                    newConstArray[i].setIConst(leftUnionArray[i].getIConst() / rightUnionArray[i].getIConst());
+                break;
+
+            case EbtUint16:
+                if (rightUnionArray[i] == 0) {
+                    newConstArray[i].setUConst(0xFFFFu);
+                } else
+                    newConstArray[i].setUConst(leftUnionArray[i].getUConst() / rightUnionArray[i].getUConst());
+                break;
+#endif
+            default:
+                return 0;
+            }
+        }
+        break;
+
+    case EOpMatrixTimesVector:
+        for (int i = 0; i < getMatrixRows(); i++) {
+            double sum = 0.0f;
+            for (int j = 0; j < rightNode->getVectorSize(); j++) {
+                sum += leftUnionArray[j*getMatrixRows() + i].getDConst() * rightUnionArray[j].getDConst();
+            }
+            newConstArray[i].setDConst(sum);
+        }
+
+        returnType.shallowCopy(TType(getBasicType(), EvqConst, getMatrixRows()));
+        break;
+
+    case EOpVectorTimesMatrix:
+        for (int i = 0; i < rightNode->getMatrixCols(); i++) {
+            double sum = 0.0f;
+            for (int j = 0; j < getVectorSize(); j++)
+                sum += leftUnionArray[j].getDConst() * rightUnionArray[i*rightNode->getMatrixRows() + j].getDConst();
+            newConstArray[i].setDConst(sum);
+        }
+
+        returnType.shallowCopy(TType(getBasicType(), EvqConst, rightNode->getMatrixCols()));
+        break;
+
+    case EOpMod:
+        for (int i = 0; i < newComps; i++) {
+            if (rightUnionArray[i] == 0)
+                newConstArray[i] = leftUnionArray[i];
+            else
+                newConstArray[i] = leftUnionArray[i] % rightUnionArray[i];
+        }
+        break;
+
+    case EOpRightShift:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] >> rightUnionArray[i];
+        break;
+
+    case EOpLeftShift:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] << rightUnionArray[i];
+        break;
+
+    case EOpAnd:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] & rightUnionArray[i];
+        break;
+    case EOpInclusiveOr:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] | rightUnionArray[i];
+        break;
+    case EOpExclusiveOr:
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] ^ rightUnionArray[i];
+        break;
+
+    case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] && rightUnionArray[i];
+        break;
+
+    case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
+        for (int i = 0; i < newComps; i++)
+            newConstArray[i] = leftUnionArray[i] || rightUnionArray[i];
+        break;
+
+    case EOpLogicalXor:
+        for (int i = 0; i < newComps; i++) {
+            switch (getType().getBasicType()) {
+            case EbtBool: newConstArray[i].setBConst((leftUnionArray[i] == rightUnionArray[i]) ? false : true); break;
+            default: assert(false && "Default missing");
+            }
+        }
+        break;
+
+    case EOpLessThan:
+        newConstArray[0].setBConst(leftUnionArray[0] < rightUnionArray[0]);
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpGreaterThan:
+        newConstArray[0].setBConst(leftUnionArray[0] > rightUnionArray[0]);
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpLessThanEqual:
+        newConstArray[0].setBConst(! (leftUnionArray[0] > rightUnionArray[0]));
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpGreaterThanEqual:
+        newConstArray[0].setBConst(! (leftUnionArray[0] < rightUnionArray[0]));
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpEqual:
+        newConstArray[0].setBConst(rightNode->getConstArray() == leftUnionArray);
+        returnType.shallowCopy(constBool);
+        break;
+    case EOpNotEqual:
+        newConstArray[0].setBConst(rightNode->getConstArray() != leftUnionArray);
+        returnType.shallowCopy(constBool);
+        break;
+
+    default:
+        return 0;
+    }
+
+    TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
+    newNode->setLoc(getLoc());
+
+    return newNode;
+}
+
+//
+// Do single unary node folding
+//
+// Returns a new node representing the result.
+//
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) const
+{
+    // First, size the result, which is mostly the same as the argument's size,
+    // but not always, and classify what is componentwise.
+    // Also, eliminate cases that can't be compile-time constant.
+    int resultSize;
+    bool componentWise = true;
+
+    int objectSize = getType().computeNumComponents();
+    switch (op) {
+    case EOpDeterminant:
+    case EOpAny:
+    case EOpAll:
+    case EOpLength:
+        componentWise = false;
+        resultSize = 1;
+        break;
+
+    case EOpEmitStreamVertex:
+    case EOpEndStreamPrimitive:
+        // These don't actually fold
+        return 0;
+
+    case EOpPackSnorm2x16:
+    case EOpPackUnorm2x16:
+    case EOpPackHalf2x16:
+        componentWise = false;
+        resultSize = 1;
+        break;
+
+    case EOpUnpackSnorm2x16:
+    case EOpUnpackUnorm2x16:
+    case EOpUnpackHalf2x16:
+        componentWise = false;
+        resultSize = 2;
+        break;
+
+    case EOpNormalize:
+        componentWise = false;
+        resultSize = objectSize;
+        break;
+
+    default:
+        resultSize = objectSize;
+        break;
+    }
+
+    // Set up for processing
+    TConstUnionArray newConstArray(resultSize);
+    const TConstUnionArray& unionArray = getConstArray();
+
+    // Process non-component-wise operations
+    switch (op) {
+    case EOpLength:
+    case EOpNormalize:
+    {
+        double sum = 0;
+        for (int i = 0; i < objectSize; i++)
+            sum += unionArray[i].getDConst() * unionArray[i].getDConst();
+        double length = sqrt(sum);
+        if (op == EOpLength)
+            newConstArray[0].setDConst(length);
+        else {
+            for (int i = 0; i < objectSize; i++)
+                newConstArray[i].setDConst(unionArray[i].getDConst() / length);
+        }
+        break;
+    }
+
+    case EOpAny:
+    {
+        bool result = false;
+        for (int i = 0; i < objectSize; i++) {
+            if (unionArray[i].getBConst())
+                result = true;
+        }
+        newConstArray[0].setBConst(result);
+        break;
+    }
+    case EOpAll:
+    {
+        bool result = true;
+        for (int i = 0; i < objectSize; i++) {
+            if (! unionArray[i].getBConst())
+                result = false;
+        }
+        newConstArray[0].setBConst(result);
+        break;
+    }
+
+    // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
+
+    case EOpPackSnorm2x16:
+    case EOpPackUnorm2x16:
+    case EOpPackHalf2x16:
+
+    case EOpUnpackSnorm2x16:
+    case EOpUnpackUnorm2x16:
+    case EOpUnpackHalf2x16:
+
+    case EOpDeterminant:
+    case EOpMatrixInverse:
+    case EOpTranspose:
+        return 0;
+
+    default:
+        assert(componentWise);
+        break;
+    }
+
+    // Turn off the componentwise loop
+    if (! componentWise)
+        objectSize = 0;
+
+    // Process component-wise operations
+    for (int i = 0; i < objectSize; i++) {
+        switch (op) {
+        case EOpNegative:
+            switch (getType().getBasicType()) {
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+            case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break;
+#ifdef AMD_EXTENSIONS
+            case EbtInt16:
+#endif
+            case EbtInt:   newConstArray[i].setIConst(-unionArray[i].getIConst()); break;
+#ifdef AMD_EXTENSIONS
+            case EbtUint16:
+#endif
+            case EbtUint:  newConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst())));  break;
+            case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break;
+            case EbtUint64: newConstArray[i].setU64Const(static_cast<unsigned long long>(-static_cast<long long>(unionArray[i].getU64Const())));  break;
+            default:
+                return 0;
+            }
+            break;
+        case EOpLogicalNot:
+        case EOpVectorLogicalNot:
+            switch (getType().getBasicType()) {
+            case EbtBool:  newConstArray[i].setBConst(!unionArray[i].getBConst()); break;
+            default:
+                return 0;
+            }
+            break;
+        case EOpBitwiseNot:
+            newConstArray[i] = ~unionArray[i];
+            break;
+        case EOpRadians:
+            newConstArray[i].setDConst(unionArray[i].getDConst() * pi / 180.0);
+            break;
+        case EOpDegrees:
+            newConstArray[i].setDConst(unionArray[i].getDConst() * 180.0 / pi);
+            break;
+        case EOpSin:
+            newConstArray[i].setDConst(sin(unionArray[i].getDConst()));
+            break;
+        case EOpCos:
+            newConstArray[i].setDConst(cos(unionArray[i].getDConst()));
+            break;
+        case EOpTan:
+            newConstArray[i].setDConst(tan(unionArray[i].getDConst()));
+            break;
+        case EOpAsin:
+            newConstArray[i].setDConst(asin(unionArray[i].getDConst()));
+            break;
+        case EOpAcos:
+            newConstArray[i].setDConst(acos(unionArray[i].getDConst()));
+            break;
+        case EOpAtan:
+            newConstArray[i].setDConst(atan(unionArray[i].getDConst()));
+            break;
+
+        case EOpDPdx:
+        case EOpDPdy:
+        case EOpFwidth:
+        case EOpDPdxFine:
+        case EOpDPdyFine:
+        case EOpFwidthFine:
+        case EOpDPdxCoarse:
+        case EOpDPdyCoarse:
+        case EOpFwidthCoarse:
+            // The derivatives are all mandated to create a constant 0.
+            newConstArray[i].setDConst(0.0);
+            break;
+
+        case EOpExp:
+            newConstArray[i].setDConst(exp(unionArray[i].getDConst()));
+            break;
+        case EOpLog:
+            newConstArray[i].setDConst(log(unionArray[i].getDConst()));
+            break;
+        case EOpExp2:
+            {
+                const double inv_log2_e = 0.69314718055994530941723212145818;
+                newConstArray[i].setDConst(exp(unionArray[i].getDConst() * inv_log2_e));
+                break;
+            }
+        case EOpLog2:
+            {
+                const double log2_e = 1.4426950408889634073599246810019;
+                newConstArray[i].setDConst(log2_e * log(unionArray[i].getDConst()));
+                break;
+            }
+        case EOpSqrt:
+            newConstArray[i].setDConst(sqrt(unionArray[i].getDConst()));
+            break;
+        case EOpInverseSqrt:
+            newConstArray[i].setDConst(1.0 / sqrt(unionArray[i].getDConst()));
+            break;
+
+        case EOpAbs:
+            if (unionArray[i].getType() == EbtDouble)
+                newConstArray[i].setDConst(fabs(unionArray[i].getDConst()));
+            else if (unionArray[i].getType() == EbtInt)
+                newConstArray[i].setIConst(abs(unionArray[i].getIConst()));
+            else
+                newConstArray[i] = unionArray[i];
+            break;
+        case EOpSign:
+            #define SIGN(X) (X == 0 ? 0 : (X < 0 ? -1 : 1))
+            if (unionArray[i].getType() == EbtDouble)
+                newConstArray[i].setDConst(SIGN(unionArray[i].getDConst()));
+            else
+                newConstArray[i].setIConst(SIGN(unionArray[i].getIConst()));
+            break;
+        case EOpFloor:
+            newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
+            break;
+        case EOpTrunc:
+            if (unionArray[i].getDConst() > 0)
+                newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
+            else
+                newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
+            break;
+        case EOpRound:
+            newConstArray[i].setDConst(floor(0.5 + unionArray[i].getDConst()));
+            break;
+        case EOpRoundEven:
+        {
+            double flr = floor(unionArray[i].getDConst());
+            bool even = flr / 2.0 == floor(flr / 2.0);
+            double rounded = even ? ceil(unionArray[i].getDConst() - 0.5) : floor(unionArray[i].getDConst() + 0.5);
+            newConstArray[i].setDConst(rounded);
+            break;
+        }
+        case EOpCeil:
+            newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
+            break;
+        case EOpFract:
+        {
+            double x = unionArray[i].getDConst();
+            newConstArray[i].setDConst(x - floor(x));
+            break;
+        }
+
+        case EOpIsNan:
+        {
+            newConstArray[i].setBConst(isNan(unionArray[i].getDConst()));
+            break;
+        }
+        case EOpIsInf:
+        {
+            newConstArray[i].setBConst(isInf(unionArray[i].getDConst()));
+            break;
+        }
+
+        // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
+
+        case EOpSinh:
+        case EOpCosh:
+        case EOpTanh:
+        case EOpAsinh:
+        case EOpAcosh:
+        case EOpAtanh:
+
+        case EOpFloatBitsToInt:
+        case EOpFloatBitsToUint:
+        case EOpIntBitsToFloat:
+        case EOpUintBitsToFloat:
+        case EOpDoubleBitsToInt64:
+        case EOpDoubleBitsToUint64:
+        case EOpInt64BitsToDouble:
+        case EOpUint64BitsToDouble:
+#ifdef AMD_EXTENSIONS
+        case EOpFloat16BitsToInt16:
+        case EOpFloat16BitsToUint16:
+        case EOpInt16BitsToFloat16:
+        case EOpUint16BitsToFloat16:
+#endif
+
+        default:
+            return 0;
+        }
+    }
+
+    TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
+    newNode->getWritableType().getQualifier().storage = EvqConst;
+    newNode->setLoc(getLoc());
+
+    return newNode;
+}
+
+//
+// Do constant folding for an aggregate node that has all its children
+// as constants and an operator that requires constant folding.
+//
+TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
+{
+    if (aggrNode == nullptr)
+        return aggrNode;
+
+    if (! areAllChildConst(aggrNode))
+        return aggrNode;
+
+    if (aggrNode->isConstructor())
+        return foldConstructor(aggrNode);
+
+    TIntermSequence& children = aggrNode->getSequence();
+
+    // First, see if this is an operation to constant fold, kick out if not,
+    // see what size the result is if so.
+
+    bool componentwise = false;  // will also say componentwise if a scalar argument gets repeated to make per-component results
+    int objectSize;
+    switch (aggrNode->getOp()) {
+    case EOpAtan:
+    case EOpPow:
+    case EOpMin:
+    case EOpMax:
+    case EOpMix:
+    case EOpClamp:
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+    case EOpVectorEqual:
+    case EOpVectorNotEqual:
+        componentwise = true;
+        objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
+        break;
+    case EOpCross:
+    case EOpReflect:
+    case EOpRefract:
+    case EOpFaceForward:
+        objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
+        break;
+    case EOpDistance:
+    case EOpDot:
+        objectSize = 1;
+        break;
+    case EOpOuterProduct:
+        objectSize = children[0]->getAsTyped()->getType().getVectorSize() *
+                     children[1]->getAsTyped()->getType().getVectorSize();
+        break;
+    case EOpStep:
+        componentwise = true;
+        objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
+                              children[1]->getAsTyped()->getType().getVectorSize());
+        break;
+    case EOpSmoothStep:
+        componentwise = true;
+        objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
+                              children[2]->getAsTyped()->getType().getVectorSize());
+        break;
+    default:
+        return aggrNode;
+    }
+    TConstUnionArray newConstArray(objectSize);
+
+    TVector<TConstUnionArray> childConstUnions;
+    for (unsigned int arg = 0; arg < children.size(); ++arg)
+        childConstUnions.push_back(children[arg]->getAsConstantUnion()->getConstArray());
+
+    // Second, do the actual folding
+
+    bool isFloatingPoint = children[0]->getAsTyped()->getBasicType() == EbtFloat ||
+#ifdef AMD_EXTENSIONS
+                           children[0]->getAsTyped()->getBasicType() == EbtFloat16 ||
+#endif
+                           children[0]->getAsTyped()->getBasicType() == EbtDouble;
+    bool isSigned = children[0]->getAsTyped()->getBasicType() == EbtInt ||
+#ifdef AMD_EXTENSIONS
+                    children[0]->getAsTyped()->getBasicType() == EbtInt16 ||
+#endif
+                    children[0]->getAsTyped()->getBasicType() == EbtInt64;
+    bool isInt64 = children[0]->getAsTyped()->getBasicType() == EbtInt64 ||
+                   children[0]->getAsTyped()->getBasicType() == EbtUint64;
+    if (componentwise) {
+        for (int comp = 0; comp < objectSize; comp++) {
+
+            // some arguments are scalars instead of matching vectors; simulate a smear
+            int arg0comp = std::min(comp, children[0]->getAsTyped()->getType().getVectorSize() - 1);
+            int arg1comp = 0;
+            if (children.size() > 1)
+                arg1comp = std::min(comp, children[1]->getAsTyped()->getType().getVectorSize() - 1);
+            int arg2comp = 0;
+            if (children.size() > 2)
+                arg2comp = std::min(comp, children[2]->getAsTyped()->getType().getVectorSize() - 1);
+
+            switch (aggrNode->getOp()) {
+            case EOpAtan:
+                newConstArray[comp].setDConst(atan2(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+                break;
+            case EOpPow:
+                newConstArray[comp].setDConst(pow(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+                break;
+            case EOpMin:
+                if (isFloatingPoint)
+                    newConstArray[comp].setDConst(std::min(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+                else if (isSigned) {
+                    if (isInt64)
+                        newConstArray[comp].setI64Const(std::min(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
+                    else
+                        newConstArray[comp].setIConst(std::min(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
+                } else {
+                    if (isInt64)
+                        newConstArray[comp].setU64Const(std::min(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
+                    else
+                        newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
+                }
+                break;
+            case EOpMax:
+                if (isFloatingPoint)
+                    newConstArray[comp].setDConst(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
+                else if (isSigned) {
+                    if (isInt64)
+                        newConstArray[comp].setI64Const(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
+                    else
+                        newConstArray[comp].setIConst(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
+                } else {
+                    if (isInt64)
+                        newConstArray[comp].setU64Const(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
+                    else
+                        newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
+                }
+                break;
+            case EOpClamp:
+                if (isFloatingPoint)
+                    newConstArray[comp].setDConst(std::min(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()),
+                                                                                                               childConstUnions[2][arg2comp].getDConst()));
+                else if (isSigned) {
+                    if (isInt64)
+                        newConstArray[comp].setI64Const(std::min(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()),
+                                                                                                                       childConstUnions[2][arg2comp].getI64Const()));
+                    else
+                        newConstArray[comp].setIConst(std::min(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()),
+                                                                                                                   childConstUnions[2][arg2comp].getIConst()));
+                } else {
+                    if (isInt64)
+                        newConstArray[comp].setU64Const(std::min(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()),
+                                                                                                                       childConstUnions[2][arg2comp].getU64Const()));
+                    else
+                        newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()),
+                                                                                                                   childConstUnions[2][arg2comp].getUConst()));
+                }
+                break;
+            case EOpLessThan:
+                newConstArray[comp].setBConst(childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]);
+                break;
+            case EOpGreaterThan:
+                newConstArray[comp].setBConst(childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]);
+                break;
+            case EOpLessThanEqual:
+                newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]));
+                break;
+            case EOpGreaterThanEqual:
+                newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]));
+                break;
+            case EOpVectorEqual:
+                newConstArray[comp].setBConst(childConstUnions[0][arg0comp] == childConstUnions[1][arg1comp]);
+                break;
+            case EOpVectorNotEqual:
+                newConstArray[comp].setBConst(childConstUnions[0][arg0comp] != childConstUnions[1][arg1comp]);
+                break;
+            case EOpMix:
+                if (children[2]->getAsTyped()->getBasicType() == EbtBool)
+                    newConstArray[comp].setDConst(childConstUnions[2][arg2comp].getBConst() ? childConstUnions[1][arg1comp].getDConst() :
+                                                                                              childConstUnions[0][arg0comp].getDConst());
+                else
+                    newConstArray[comp].setDConst(childConstUnions[0][arg0comp].getDConst() * (1.0 - childConstUnions[2][arg2comp].getDConst()) +
+                                                  childConstUnions[1][arg1comp].getDConst() *        childConstUnions[2][arg2comp].getDConst());
+                break;
+            case EOpStep:
+                newConstArray[comp].setDConst(childConstUnions[1][arg1comp].getDConst() < childConstUnions[0][arg0comp].getDConst() ? 0.0 : 1.0);
+                break;
+            case EOpSmoothStep:
+            {
+                double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) /
+                           (childConstUnions[1][arg1comp].getDConst() - childConstUnions[0][arg0comp].getDConst());
+                if (t < 0.0)
+                    t = 0.0;
+                if (t > 1.0)
+                    t = 1.0;
+                newConstArray[comp].setDConst(t * t * (3.0 - 2.0 * t));
+                break;
+            }
+            default:
+                return aggrNode;
+            }
+        }
+    } else {
+        // Non-componentwise...
+
+        int numComps = children[0]->getAsConstantUnion()->getType().computeNumComponents();
+        double dot;
+
+        switch (aggrNode->getOp()) {
+        case EOpDistance:
+        {
+            double sum = 0.0;
+            for (int comp = 0; comp < numComps; ++comp) {
+                double diff = childConstUnions[1][comp].getDConst() - childConstUnions[0][comp].getDConst();
+                sum += diff * diff;
+            }
+            newConstArray[0].setDConst(sqrt(sum));
+            break;
+        }
+        case EOpDot:
+            newConstArray[0].setDConst(childConstUnions[0].dot(childConstUnions[1]));
+            break;
+        case EOpCross:
+            newConstArray[0] = childConstUnions[0][1] * childConstUnions[1][2] - childConstUnions[0][2] * childConstUnions[1][1];
+            newConstArray[1] = childConstUnions[0][2] * childConstUnions[1][0] - childConstUnions[0][0] * childConstUnions[1][2];
+            newConstArray[2] = childConstUnions[0][0] * childConstUnions[1][1] - childConstUnions[0][1] * childConstUnions[1][0];
+            break;
+        case EOpFaceForward:
+            // If dot(Nref, I) < 0 return N, otherwise return -N:  Arguments are (N, I, Nref).
+            dot = childConstUnions[1].dot(childConstUnions[2]);
+            for (int comp = 0; comp < numComps; ++comp) {
+                if (dot < 0.0)
+                    newConstArray[comp] = childConstUnions[0][comp];
+                else
+                    newConstArray[comp].setDConst(-childConstUnions[0][comp].getDConst());
+            }
+            break;
+        case EOpReflect:
+            // I - 2 * dot(N, I) * N:  Arguments are (I, N).
+            dot = childConstUnions[0].dot(childConstUnions[1]);
+            dot *= 2.0;
+            for (int comp = 0; comp < numComps; ++comp)
+                newConstArray[comp].setDConst(childConstUnions[0][comp].getDConst() - dot * childConstUnions[1][comp].getDConst());
+            break;
+        case EOpRefract:
+        {
+            // Arguments are (I, N, eta).
+            // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
+            // if (k < 0.0)
+            //     return dvec(0.0)
+            // else
+            //     return eta * I - (eta * dot(N, I) + sqrt(k)) * N
+            dot = childConstUnions[0].dot(childConstUnions[1]);
+            double eta = childConstUnions[2][0].getDConst();
+            double k = 1.0 - eta * eta * (1.0 - dot * dot);
+            if (k < 0.0) {
+                for (int comp = 0; comp < numComps; ++comp)
+                    newConstArray[comp].setDConst(0.0);
+            } else {
+                for (int comp = 0; comp < numComps; ++comp)
+                    newConstArray[comp].setDConst(eta * childConstUnions[0][comp].getDConst() - (eta * dot + sqrt(k)) * childConstUnions[1][comp].getDConst());
+            }
+            break;
+        }
+        case EOpOuterProduct:
+        {
+            int numRows = numComps;
+            int numCols = children[1]->getAsConstantUnion()->getType().computeNumComponents();
+            for (int row = 0; row < numRows; ++row)
+                for (int col = 0; col < numCols; ++col)
+                    newConstArray[col * numRows + row] = childConstUnions[0][row] * childConstUnions[1][col];
+            break;
+        }
+        default:
+            return aggrNode;
+        }
+    }
+
+    TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, aggrNode->getType());
+    newNode->getWritableType().getQualifier().storage = EvqConst;
+    newNode->setLoc(aggrNode->getLoc());
+
+    return newNode;
+}
+
+bool TIntermediate::areAllChildConst(TIntermAggregate* aggrNode)
+{
+    bool allConstant = true;
+
+    // check if all the child nodes are constants so that they can be inserted into
+    // the parent node
+    if (aggrNode) {
+        TIntermSequence& childSequenceVector = aggrNode->getSequence();
+        for (TIntermSequence::iterator p  = childSequenceVector.begin();
+                                       p != childSequenceVector.end(); p++) {
+            if (!(*p)->getAsTyped()->getAsConstantUnion())
+                return false;
+        }
+    }
+
+    return allConstant;
+}
+
+TIntermTyped* TIntermediate::foldConstructor(TIntermAggregate* aggrNode)
+{
+    bool error = false;
+
+    TConstUnionArray unionArray(aggrNode->getType().computeNumComponents());
+    if (aggrNode->getSequence().size() == 1)
+        error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
+    else
+        error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
+
+    if (error)
+        return aggrNode;
+
+    return addConstantUnion(unionArray, aggrNode->getType(), aggrNode->getLoc());
+}
+
+//
+// Constant folding of a bracket (array-style) dereference or struct-like dot
+// dereference.  Can handle anything except a multi-character swizzle, though
+// all swizzles may go to foldSwizzle().
+//
+TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, const TSourceLoc& loc)
+{
+    TType dereferencedType(node->getType(), index);
+    dereferencedType.getQualifier().storage = EvqConst;
+    TIntermTyped* result = 0;
+    int size = dereferencedType.computeNumComponents();
+
+    // arrays, vectors, matrices, all use simple multiplicative math
+    // while structures need to add up heterogeneous members
+    int start;
+    if (node->isArray() || ! node->isStruct())
+        start = size * index;
+    else {
+        // it is a structure
+        assert(node->isStruct());
+        start = 0;
+        for (int i = 0; i < index; ++i)
+            start += (*node->getType().getStruct())[i].type->computeNumComponents();
+    }
+
+    result = addConstantUnion(TConstUnionArray(node->getAsConstantUnion()->getConstArray(), start, size), node->getType(), loc);
+
+    if (result == 0)
+        result = node;
+    else
+        result->setType(dereferencedType);
+
+    return result;
+}
+
+//
+// Make a constant vector node or constant scalar node, representing a given
+// constant vector and constant swizzle into it.
+//
+TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TSwizzleSelectors<TVectorSelector>& selectors, const TSourceLoc& loc)
+{
+    const TConstUnionArray& unionArray = node->getAsConstantUnion()->getConstArray();
+    TConstUnionArray constArray(selectors.size());
+
+    for (int i = 0; i < selectors.size(); i++)
+        constArray[i] = unionArray[selectors[i]];
+
+    TIntermTyped* result = addConstantUnion(constArray, node->getType(), loc);
+
+    if (result == 0)
+        result = node;
+    else
+        result->setType(TType(node->getBasicType(), EvqConst, selectors.size()));
+
+    return result;
+}
+
+} // end namespace glslang

+ 113 - 0
src/libraries/glslang/glslang/MachineIndependent/InfoSink.cpp

@@ -0,0 +1,113 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/InfoSink.h"
+
+#include <cstring>
+
+namespace glslang {
+
+void TInfoSinkBase::append(const char* s)
+{
+    if (outputStream & EString) {
+        if (s == nullptr)
+            sink.append("(null)");
+        else {
+            checkMem(strlen(s));
+            sink.append(s);
+        }
+    }
+
+//#ifdef _WIN32
+//    if (outputStream & EDebugger)
+//        OutputDebugString(s);
+//#endif
+
+    if (outputStream & EStdOut)
+        fprintf(stdout, "%s", s);
+}
+
+void TInfoSinkBase::append(int count, char c)
+{
+    if (outputStream & EString) {
+        checkMem(count);
+        sink.append(count, c);
+    }
+
+//#ifdef _WIN32
+//    if (outputStream & EDebugger) {
+//        char str[2];
+//        str[0] = c;
+//        str[1] = '\0';
+//        OutputDebugString(str);
+//    }
+//#endif
+
+    if (outputStream & EStdOut)
+        fprintf(stdout, "%c", c);
+}
+
+void TInfoSinkBase::append(const TPersistString& t)
+{
+    if (outputStream & EString) {
+        checkMem(t.size());
+        sink.append(t);
+    }
+
+//#ifdef _WIN32
+//    if (outputStream & EDebugger)
+//        OutputDebugString(t.c_str());
+//#endif
+
+    if (outputStream & EStdOut)
+        fprintf(stdout, "%s", t.c_str());
+}
+
+void TInfoSinkBase::append(const TString& t)
+{
+    if (outputStream & EString) {
+        checkMem(t.size());
+        sink.append(t.c_str());
+    }
+
+//#ifdef _WIN32
+//    if (outputStream & EDebugger)
+//        OutputDebugString(t.c_str());
+//#endif
+
+    if (outputStream & EStdOut)
+        fprintf(stdout, "%s", t.c_str());
+}
+
+} // end namespace glslang

+ 6207 - 0
src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp

@@ -0,0 +1,6207 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2016 LunarG, Inc.
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Create strings that declare built-in definitions, add built-ins programmatically
+// that cannot be expressed in the strings, and establish mappings between
+// built-in functions and operators.
+//
+// Where to put a built-in:
+//   TBuiltIns::initialize(version,profile)       context-independent textual built-ins; add them to the right string
+//   TBuiltIns::initialize(resources,...)         context-dependent textual built-ins; add them to the right string
+//   TBuiltIns::identifyBuiltIns(...,symbolTable) context-independent programmatic additions/mappings to the symbol table,
+//                                                including identifying what extensions are needed if a version does not allow a symbol
+//   TBuiltIns::identifyBuiltIns(...,symbolTable, resources) context-dependent programmatic additions/mappings to the symbol table,
+//                                                including identifying what extensions are needed if a version does not allow a symbol
+//
+
+#include "../Include/intermediate.h"
+#include "Initialize.h"
+
+namespace glslang {
+
+// TODO: ARB_Compatability: do full extension support
+const bool ARBCompatibility = true;
+
+const bool ForwardCompatibility = false;
+
+// change this back to false if depending on textual spellings of texturing calls when consuming the AST
+// Using PureOperatorBuiltins=false is deprecated.
+bool PureOperatorBuiltins = true;
+
+inline bool IncludeLegacy(int version, EProfile profile, const SpvVersion& spvVersion)
+{
+    return profile != EEsProfile && (version <= 130 || (spvVersion.spv == 0 && ARBCompatibility) || profile == ECompatibilityProfile);
+}
+
+// Construct TBuiltInParseables base class.  This can be used for language-common constructs.
+TBuiltInParseables::TBuiltInParseables()
+{
+}
+
+// Destroy TBuiltInParseables.
+TBuiltInParseables::~TBuiltInParseables()
+{
+}
+
+TBuiltIns::TBuiltIns()
+{
+    // Set up textual representations for making all the permutations
+    // of texturing/imaging functions.
+    prefixes[EbtFloat] =  "";
+    prefixes[EbtInt]   = "i";
+    prefixes[EbtUint]  = "u";
+    postfixes[2] = "2";
+    postfixes[3] = "3";
+    postfixes[4] = "4";
+
+    // Map from symbolic class of texturing dimension to numeric dimensions.
+    dimMap[Esd1D] = 1;
+    dimMap[Esd2D] = 2;
+    dimMap[EsdRect] = 2;
+    dimMap[Esd3D] = 3;
+    dimMap[EsdCube] = 3;
+    dimMap[EsdBuffer] = 1;
+    dimMap[EsdSubpass] = 2;  // potientially unused for now
+}
+
+TBuiltIns::~TBuiltIns()
+{
+}
+
+
+//
+// Add all context-independent built-in functions and variables that are present
+// for the given version and profile.  Share common ones across stages, otherwise
+// make stage-specific entries.
+//
+// Most built-ins variables can be added as simple text strings.  Some need to
+// be added programmatically, which is done later in IdentifyBuiltIns() below.
+//
+void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvVersion)
+{
+    //============================================================================
+    //
+    // Prototypes for built-in functions seen by both vertex and fragment shaders.
+    //
+    //============================================================================
+
+    //
+    // Angle and Trigonometric Functions.
+    //
+    commonBuiltins.append(
+        "float radians(float degrees);"
+        "vec2  radians(vec2  degrees);"
+        "vec3  radians(vec3  degrees);"
+        "vec4  radians(vec4  degrees);"
+
+        "float degrees(float radians);"
+        "vec2  degrees(vec2  radians);"
+        "vec3  degrees(vec3  radians);"
+        "vec4  degrees(vec4  radians);"
+
+        "float sin(float angle);"
+        "vec2  sin(vec2  angle);"
+        "vec3  sin(vec3  angle);"
+        "vec4  sin(vec4  angle);"
+
+        "float cos(float angle);"
+        "vec2  cos(vec2  angle);"
+        "vec3  cos(vec3  angle);"
+        "vec4  cos(vec4  angle);"
+
+        "float tan(float angle);"
+        "vec2  tan(vec2  angle);"
+        "vec3  tan(vec3  angle);"
+        "vec4  tan(vec4  angle);"
+
+        "float asin(float x);"
+        "vec2  asin(vec2  x);"
+        "vec3  asin(vec3  x);"
+        "vec4  asin(vec4  x);"
+
+        "float acos(float x);"
+        "vec2  acos(vec2  x);"
+        "vec3  acos(vec3  x);"
+        "vec4  acos(vec4  x);"
+
+        "float atan(float y, float x);"
+        "vec2  atan(vec2  y, vec2  x);"
+        "vec3  atan(vec3  y, vec3  x);"
+        "vec4  atan(vec4  y, vec4  x);"
+
+        "float atan(float y_over_x);"
+        "vec2  atan(vec2  y_over_x);"
+        "vec3  atan(vec3  y_over_x);"
+        "vec4  atan(vec4  y_over_x);"
+
+        "\n");
+
+    if (version >= 130) {
+        commonBuiltins.append(
+            "float sinh(float angle);"
+            "vec2  sinh(vec2  angle);"
+            "vec3  sinh(vec3  angle);"
+            "vec4  sinh(vec4  angle);"
+
+            "float cosh(float angle);"
+            "vec2  cosh(vec2  angle);"
+            "vec3  cosh(vec3  angle);"
+            "vec4  cosh(vec4  angle);"
+
+            "float tanh(float angle);"
+            "vec2  tanh(vec2  angle);"
+            "vec3  tanh(vec3  angle);"
+            "vec4  tanh(vec4  angle);"
+
+            "float asinh(float x);"
+            "vec2  asinh(vec2  x);"
+            "vec3  asinh(vec3  x);"
+            "vec4  asinh(vec4  x);"
+
+            "float acosh(float x);"
+            "vec2  acosh(vec2  x);"
+            "vec3  acosh(vec3  x);"
+            "vec4  acosh(vec4  x);"
+
+            "float atanh(float y_over_x);"
+            "vec2  atanh(vec2  y_over_x);"
+            "vec3  atanh(vec3  y_over_x);"
+            "vec4  atanh(vec4  y_over_x);"
+
+            "\n");
+    }
+
+    //
+    // Exponential Functions.
+    //
+    commonBuiltins.append(
+        "float pow(float x, float y);"
+        "vec2  pow(vec2  x, vec2  y);"
+        "vec3  pow(vec3  x, vec3  y);"
+        "vec4  pow(vec4  x, vec4  y);"
+
+        "float exp(float x);"
+        "vec2  exp(vec2  x);"
+        "vec3  exp(vec3  x);"
+        "vec4  exp(vec4  x);"
+
+        "float log(float x);"
+        "vec2  log(vec2  x);"
+        "vec3  log(vec3  x);"
+        "vec4  log(vec4  x);"
+
+        "float exp2(float x);"
+        "vec2  exp2(vec2  x);"
+        "vec3  exp2(vec3  x);"
+        "vec4  exp2(vec4  x);"
+
+        "float log2(float x);"
+        "vec2  log2(vec2  x);"
+        "vec3  log2(vec3  x);"
+        "vec4  log2(vec4  x);"
+
+        "float sqrt(float x);"
+        "vec2  sqrt(vec2  x);"
+        "vec3  sqrt(vec3  x);"
+        "vec4  sqrt(vec4  x);"
+
+        "float inversesqrt(float x);"
+        "vec2  inversesqrt(vec2  x);"
+        "vec3  inversesqrt(vec3  x);"
+        "vec4  inversesqrt(vec4  x);"
+
+        "\n");
+
+    //
+    // Common Functions.
+    //
+    commonBuiltins.append(
+        "float abs(float x);"
+        "vec2  abs(vec2  x);"
+        "vec3  abs(vec3  x);"
+        "vec4  abs(vec4  x);"
+
+        "float sign(float x);"
+        "vec2  sign(vec2  x);"
+        "vec3  sign(vec3  x);"
+        "vec4  sign(vec4  x);"
+
+        "float floor(float x);"
+        "vec2  floor(vec2  x);"
+        "vec3  floor(vec3  x);"
+        "vec4  floor(vec4  x);"
+
+        "float ceil(float x);"
+        "vec2  ceil(vec2  x);"
+        "vec3  ceil(vec3  x);"
+        "vec4  ceil(vec4  x);"
+
+        "float fract(float x);"
+        "vec2  fract(vec2  x);"
+        "vec3  fract(vec3  x);"
+        "vec4  fract(vec4  x);"
+
+        "float mod(float x, float y);"
+        "vec2  mod(vec2  x, float y);"
+        "vec3  mod(vec3  x, float y);"
+        "vec4  mod(vec4  x, float y);"
+        "vec2  mod(vec2  x, vec2  y);"
+        "vec3  mod(vec3  x, vec3  y);"
+        "vec4  mod(vec4  x, vec4  y);"
+
+        "float min(float x, float y);"
+        "vec2  min(vec2  x, float y);"
+        "vec3  min(vec3  x, float y);"
+        "vec4  min(vec4  x, float y);"
+        "vec2  min(vec2  x, vec2  y);"
+        "vec3  min(vec3  x, vec3  y);"
+        "vec4  min(vec4  x, vec4  y);"
+
+        "float max(float x, float y);"
+        "vec2  max(vec2  x, float y);"
+        "vec3  max(vec3  x, float y);"
+        "vec4  max(vec4  x, float y);"
+        "vec2  max(vec2  x, vec2  y);"
+        "vec3  max(vec3  x, vec3  y);"
+        "vec4  max(vec4  x, vec4  y);"
+
+        "float clamp(float x, float minVal, float maxVal);"
+        "vec2  clamp(vec2  x, float minVal, float maxVal);"
+        "vec3  clamp(vec3  x, float minVal, float maxVal);"
+        "vec4  clamp(vec4  x, float minVal, float maxVal);"
+        "vec2  clamp(vec2  x, vec2  minVal, vec2  maxVal);"
+        "vec3  clamp(vec3  x, vec3  minVal, vec3  maxVal);"
+        "vec4  clamp(vec4  x, vec4  minVal, vec4  maxVal);"
+
+        "float mix(float x, float y, float a);"
+        "vec2  mix(vec2  x, vec2  y, float a);"
+        "vec3  mix(vec3  x, vec3  y, float a);"
+        "vec4  mix(vec4  x, vec4  y, float a);"
+        "vec2  mix(vec2  x, vec2  y, vec2  a);"
+        "vec3  mix(vec3  x, vec3  y, vec3  a);"
+        "vec4  mix(vec4  x, vec4  y, vec4  a);"
+
+        "float step(float edge, float x);"
+        "vec2  step(vec2  edge, vec2  x);"
+        "vec3  step(vec3  edge, vec3  x);"
+        "vec4  step(vec4  edge, vec4  x);"
+        "vec2  step(float edge, vec2  x);"
+        "vec3  step(float edge, vec3  x);"
+        "vec4  step(float edge, vec4  x);"
+
+        "float smoothstep(float edge0, float edge1, float x);"
+        "vec2  smoothstep(vec2  edge0, vec2  edge1, vec2  x);"
+        "vec3  smoothstep(vec3  edge0, vec3  edge1, vec3  x);"
+        "vec4  smoothstep(vec4  edge0, vec4  edge1, vec4  x);"
+        "vec2  smoothstep(float edge0, float edge1, vec2  x);"
+        "vec3  smoothstep(float edge0, float edge1, vec3  x);"
+        "vec4  smoothstep(float edge0, float edge1, vec4  x);"
+
+        "\n");
+
+    if (version >= 130) {
+        commonBuiltins.append(
+            "  int abs(  int x);"
+            "ivec2 abs(ivec2 x);"
+            "ivec3 abs(ivec3 x);"
+            "ivec4 abs(ivec4 x);"
+
+            "  int sign(  int x);"
+            "ivec2 sign(ivec2 x);"
+            "ivec3 sign(ivec3 x);"
+            "ivec4 sign(ivec4 x);"
+
+            "float trunc(float x);"
+            "vec2  trunc(vec2  x);"
+            "vec3  trunc(vec3  x);"
+            "vec4  trunc(vec4  x);"
+
+            "float round(float x);"
+            "vec2  round(vec2  x);"
+            "vec3  round(vec3  x);"
+            "vec4  round(vec4  x);"
+
+            "float roundEven(float x);"
+            "vec2  roundEven(vec2  x);"
+            "vec3  roundEven(vec3  x);"
+            "vec4  roundEven(vec4  x);"
+
+            "float modf(float, out float);"
+            "vec2  modf(vec2,  out vec2 );"
+            "vec3  modf(vec3,  out vec3 );"
+            "vec4  modf(vec4,  out vec4 );"
+
+            "  int min(int    x, int y);"
+            "ivec2 min(ivec2  x, int y);"
+            "ivec3 min(ivec3  x, int y);"
+            "ivec4 min(ivec4  x, int y);"
+            "ivec2 min(ivec2  x, ivec2  y);"
+            "ivec3 min(ivec3  x, ivec3  y);"
+            "ivec4 min(ivec4  x, ivec4  y);"
+
+            " uint min(uint   x, uint y);"
+            "uvec2 min(uvec2  x, uint y);"
+            "uvec3 min(uvec3  x, uint y);"
+            "uvec4 min(uvec4  x, uint y);"
+            "uvec2 min(uvec2  x, uvec2  y);"
+            "uvec3 min(uvec3  x, uvec3  y);"
+            "uvec4 min(uvec4  x, uvec4  y);"
+
+            "  int max(int    x, int y);"
+            "ivec2 max(ivec2  x, int y);"
+            "ivec3 max(ivec3  x, int y);"
+            "ivec4 max(ivec4  x, int y);"
+            "ivec2 max(ivec2  x, ivec2  y);"
+            "ivec3 max(ivec3  x, ivec3  y);"
+            "ivec4 max(ivec4  x, ivec4  y);"
+
+            " uint max(uint   x, uint y);"
+            "uvec2 max(uvec2  x, uint y);"
+            "uvec3 max(uvec3  x, uint y);"
+            "uvec4 max(uvec4  x, uint y);"
+            "uvec2 max(uvec2  x, uvec2  y);"
+            "uvec3 max(uvec3  x, uvec3  y);"
+            "uvec4 max(uvec4  x, uvec4  y);"
+
+            "int    clamp(int x, int minVal, int maxVal);"
+            "ivec2  clamp(ivec2  x, int minVal, int maxVal);"
+            "ivec3  clamp(ivec3  x, int minVal, int maxVal);"
+            "ivec4  clamp(ivec4  x, int minVal, int maxVal);"
+            "ivec2  clamp(ivec2  x, ivec2  minVal, ivec2  maxVal);"
+            "ivec3  clamp(ivec3  x, ivec3  minVal, ivec3  maxVal);"
+            "ivec4  clamp(ivec4  x, ivec4  minVal, ivec4  maxVal);"
+
+            "uint   clamp(uint x, uint minVal, uint maxVal);"
+            "uvec2  clamp(uvec2  x, uint minVal, uint maxVal);"
+            "uvec3  clamp(uvec3  x, uint minVal, uint maxVal);"
+            "uvec4  clamp(uvec4  x, uint minVal, uint maxVal);"
+            "uvec2  clamp(uvec2  x, uvec2  minVal, uvec2  maxVal);"
+            "uvec3  clamp(uvec3  x, uvec3  minVal, uvec3  maxVal);"
+            "uvec4  clamp(uvec4  x, uvec4  minVal, uvec4  maxVal);"
+
+            "float mix(float x, float y, bool  a);"
+            "vec2  mix(vec2  x, vec2  y, bvec2 a);"
+            "vec3  mix(vec3  x, vec3  y, bvec3 a);"
+            "vec4  mix(vec4  x, vec4  y, bvec4 a);"
+
+            "bool  isnan(float x);"
+            "bvec2 isnan(vec2  x);"
+            "bvec3 isnan(vec3  x);"
+            "bvec4 isnan(vec4  x);"
+
+            "bool  isinf(float x);"
+            "bvec2 isinf(vec2  x);"
+            "bvec3 isinf(vec3  x);"
+            "bvec4 isinf(vec4  x);"
+
+            "\n");
+    }
+
+    //
+    // double functions added to desktop 4.00, but not fma, frexp, ldexp, or pack/unpack
+    //
+    if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+
+            "double sqrt(double);"
+            "dvec2  sqrt(dvec2);"
+            "dvec3  sqrt(dvec3);"
+            "dvec4  sqrt(dvec4);"
+
+            "double inversesqrt(double);"
+            "dvec2  inversesqrt(dvec2);"
+            "dvec3  inversesqrt(dvec3);"
+            "dvec4  inversesqrt(dvec4);"
+
+            "double abs(double);"
+            "dvec2  abs(dvec2);"
+            "dvec3  abs(dvec3);"
+            "dvec4  abs(dvec4);"
+
+            "double sign(double);"
+            "dvec2  sign(dvec2);"
+            "dvec3  sign(dvec3);"
+            "dvec4  sign(dvec4);"
+
+            "double floor(double);"
+            "dvec2  floor(dvec2);"
+            "dvec3  floor(dvec3);"
+            "dvec4  floor(dvec4);"
+
+            "double trunc(double);"
+            "dvec2  trunc(dvec2);"
+            "dvec3  trunc(dvec3);"
+            "dvec4  trunc(dvec4);"
+
+            "double round(double);"
+            "dvec2  round(dvec2);"
+            "dvec3  round(dvec3);"
+            "dvec4  round(dvec4);"
+
+            "double roundEven(double);"
+            "dvec2  roundEven(dvec2);"
+            "dvec3  roundEven(dvec3);"
+            "dvec4  roundEven(dvec4);"
+
+            "double ceil(double);"
+            "dvec2  ceil(dvec2);"
+            "dvec3  ceil(dvec3);"
+            "dvec4  ceil(dvec4);"
+
+            "double fract(double);"
+            "dvec2  fract(dvec2);"
+            "dvec3  fract(dvec3);"
+            "dvec4  fract(dvec4);"
+
+            "double mod(double, double);"
+            "dvec2  mod(dvec2 , double);"
+            "dvec3  mod(dvec3 , double);"
+            "dvec4  mod(dvec4 , double);"
+            "dvec2  mod(dvec2 , dvec2);"
+            "dvec3  mod(dvec3 , dvec3);"
+            "dvec4  mod(dvec4 , dvec4);"
+
+            "double modf(double, out double);"
+            "dvec2  modf(dvec2,  out dvec2);"
+            "dvec3  modf(dvec3,  out dvec3);"
+            "dvec4  modf(dvec4,  out dvec4);"
+
+            "double min(double, double);"
+            "dvec2  min(dvec2,  double);"
+            "dvec3  min(dvec3,  double);"
+            "dvec4  min(dvec4,  double);"
+            "dvec2  min(dvec2,  dvec2);"
+            "dvec3  min(dvec3,  dvec3);"
+            "dvec4  min(dvec4,  dvec4);"
+
+            "double max(double, double);"
+            "dvec2  max(dvec2 , double);"
+            "dvec3  max(dvec3 , double);"
+            "dvec4  max(dvec4 , double);"
+            "dvec2  max(dvec2 , dvec2);"
+            "dvec3  max(dvec3 , dvec3);"
+            "dvec4  max(dvec4 , dvec4);"
+
+            "double clamp(double, double, double);"
+            "dvec2  clamp(dvec2 , double, double);"
+            "dvec3  clamp(dvec3 , double, double);"
+            "dvec4  clamp(dvec4 , double, double);"
+            "dvec2  clamp(dvec2 , dvec2 , dvec2);"
+            "dvec3  clamp(dvec3 , dvec3 , dvec3);"
+            "dvec4  clamp(dvec4 , dvec4 , dvec4);"
+
+            "double mix(double, double, double);"
+            "dvec2  mix(dvec2,  dvec2,  double);"
+            "dvec3  mix(dvec3,  dvec3,  double);"
+            "dvec4  mix(dvec4,  dvec4,  double);"
+            "dvec2  mix(dvec2,  dvec2,  dvec2);"
+            "dvec3  mix(dvec3,  dvec3,  dvec3);"
+            "dvec4  mix(dvec4,  dvec4,  dvec4);"
+            "double mix(double, double, bool);"
+            "dvec2  mix(dvec2,  dvec2,  bvec2);"
+            "dvec3  mix(dvec3,  dvec3,  bvec3);"
+            "dvec4  mix(dvec4,  dvec4,  bvec4);"
+
+            "double step(double, double);"
+            "dvec2  step(dvec2 , dvec2);"
+            "dvec3  step(dvec3 , dvec3);"
+            "dvec4  step(dvec4 , dvec4);"
+            "dvec2  step(double, dvec2);"
+            "dvec3  step(double, dvec3);"
+            "dvec4  step(double, dvec4);"
+
+            "double smoothstep(double, double, double);"
+            "dvec2  smoothstep(dvec2 , dvec2 , dvec2);"
+            "dvec3  smoothstep(dvec3 , dvec3 , dvec3);"
+            "dvec4  smoothstep(dvec4 , dvec4 , dvec4);"
+            "dvec2  smoothstep(double, double, dvec2);"
+            "dvec3  smoothstep(double, double, dvec3);"
+            "dvec4  smoothstep(double, double, dvec4);"
+
+            "bool  isnan(double);"
+            "bvec2 isnan(dvec2);"
+            "bvec3 isnan(dvec3);"
+            "bvec4 isnan(dvec4);"
+
+            "bool  isinf(double);"
+            "bvec2 isinf(dvec2);"
+            "bvec3 isinf(dvec3);"
+            "bvec4 isinf(dvec4);"
+
+            "double length(double);"
+            "double length(dvec2);"
+            "double length(dvec3);"
+            "double length(dvec4);"
+
+            "double distance(double, double);"
+            "double distance(dvec2 , dvec2);"
+            "double distance(dvec3 , dvec3);"
+            "double distance(dvec4 , dvec4);"
+
+            "double dot(double, double);"
+            "double dot(dvec2 , dvec2);"
+            "double dot(dvec3 , dvec3);"
+            "double dot(dvec4 , dvec4);"
+
+            "dvec3 cross(dvec3, dvec3);"
+
+            "double normalize(double);"
+            "dvec2  normalize(dvec2);"
+            "dvec3  normalize(dvec3);"
+            "dvec4  normalize(dvec4);"
+
+            "double faceforward(double, double, double);"
+            "dvec2  faceforward(dvec2,  dvec2,  dvec2);"
+            "dvec3  faceforward(dvec3,  dvec3,  dvec3);"
+            "dvec4  faceforward(dvec4,  dvec4,  dvec4);"
+
+            "double reflect(double, double);"
+            "dvec2  reflect(dvec2 , dvec2 );"
+            "dvec3  reflect(dvec3 , dvec3 );"
+            "dvec4  reflect(dvec4 , dvec4 );"
+
+            "double refract(double, double, double);"
+            "dvec2  refract(dvec2 , dvec2 , double);"
+            "dvec3  refract(dvec3 , dvec3 , double);"
+            "dvec4  refract(dvec4 , dvec4 , double);"
+
+            "dmat2 matrixCompMult(dmat2, dmat2);"
+            "dmat3 matrixCompMult(dmat3, dmat3);"
+            "dmat4 matrixCompMult(dmat4, dmat4);"
+            "dmat2x3 matrixCompMult(dmat2x3, dmat2x3);"
+            "dmat2x4 matrixCompMult(dmat2x4, dmat2x4);"
+            "dmat3x2 matrixCompMult(dmat3x2, dmat3x2);"
+            "dmat3x4 matrixCompMult(dmat3x4, dmat3x4);"
+            "dmat4x2 matrixCompMult(dmat4x2, dmat4x2);"
+            "dmat4x3 matrixCompMult(dmat4x3, dmat4x3);"
+
+            "dmat2   outerProduct(dvec2, dvec2);"
+            "dmat3   outerProduct(dvec3, dvec3);"
+            "dmat4   outerProduct(dvec4, dvec4);"
+            "dmat2x3 outerProduct(dvec3, dvec2);"
+            "dmat3x2 outerProduct(dvec2, dvec3);"
+            "dmat2x4 outerProduct(dvec4, dvec2);"
+            "dmat4x2 outerProduct(dvec2, dvec4);"
+            "dmat3x4 outerProduct(dvec4, dvec3);"
+            "dmat4x3 outerProduct(dvec3, dvec4);"
+
+            "dmat2   transpose(dmat2);"
+            "dmat3   transpose(dmat3);"
+            "dmat4   transpose(dmat4);"
+            "dmat2x3 transpose(dmat3x2);"
+            "dmat3x2 transpose(dmat2x3);"
+            "dmat2x4 transpose(dmat4x2);"
+            "dmat4x2 transpose(dmat2x4);"
+            "dmat3x4 transpose(dmat4x3);"
+            "dmat4x3 transpose(dmat3x4);"
+
+            "double determinant(dmat2);"
+            "double determinant(dmat3);"
+            "double determinant(dmat4);"
+
+            "dmat2 inverse(dmat2);"
+            "dmat3 inverse(dmat3);"
+            "dmat4 inverse(dmat4);"
+
+            "bvec2 lessThan(dvec2, dvec2);"
+            "bvec3 lessThan(dvec3, dvec3);"
+            "bvec4 lessThan(dvec4, dvec4);"
+
+            "bvec2 lessThanEqual(dvec2, dvec2);"
+            "bvec3 lessThanEqual(dvec3, dvec3);"
+            "bvec4 lessThanEqual(dvec4, dvec4);"
+
+            "bvec2 greaterThan(dvec2, dvec2);"
+            "bvec3 greaterThan(dvec3, dvec3);"
+            "bvec4 greaterThan(dvec4, dvec4);"
+
+            "bvec2 greaterThanEqual(dvec2, dvec2);"
+            "bvec3 greaterThanEqual(dvec3, dvec3);"
+            "bvec4 greaterThanEqual(dvec4, dvec4);"
+
+            "bvec2 equal(dvec2, dvec2);"
+            "bvec3 equal(dvec3, dvec3);"
+            "bvec4 equal(dvec4, dvec4);"
+
+            "bvec2 notEqual(dvec2, dvec2);"
+            "bvec3 notEqual(dvec3, dvec3);"
+            "bvec4 notEqual(dvec4, dvec4);"
+
+            "\n");
+    }
+
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+
+            "int64_t abs(int64_t);"
+            "i64vec2 abs(i64vec2);"
+            "i64vec3 abs(i64vec3);"
+            "i64vec4 abs(i64vec4);"
+
+            "int64_t sign(int64_t);"
+            "i64vec2 sign(i64vec2);"
+            "i64vec3 sign(i64vec3);"
+            "i64vec4 sign(i64vec4);"
+
+            "int64_t  min(int64_t,  int64_t);"
+            "i64vec2  min(i64vec2,  int64_t);"
+            "i64vec3  min(i64vec3,  int64_t);"
+            "i64vec4  min(i64vec4,  int64_t);"
+            "i64vec2  min(i64vec2,  i64vec2);"
+            "i64vec3  min(i64vec3,  i64vec3);"
+            "i64vec4  min(i64vec4,  i64vec4);"
+            "uint64_t min(uint64_t, uint64_t);"
+            "u64vec2  min(u64vec2,  uint64_t);"
+            "u64vec3  min(u64vec3,  uint64_t);"
+            "u64vec4  min(u64vec4,  uint64_t);"
+            "u64vec2  min(u64vec2,  u64vec2);"
+            "u64vec3  min(u64vec3,  u64vec3);"
+            "u64vec4  min(u64vec4,  u64vec4);"
+
+            "int64_t  max(int64_t,  int64_t);"
+            "i64vec2  max(i64vec2,  int64_t);"
+            "i64vec3  max(i64vec3,  int64_t);"
+            "i64vec4  max(i64vec4,  int64_t);"
+            "i64vec2  max(i64vec2,  i64vec2);"
+            "i64vec3  max(i64vec3,  i64vec3);"
+            "i64vec4  max(i64vec4,  i64vec4);"
+            "uint64_t max(uint64_t, uint64_t);"
+            "u64vec2  max(u64vec2,  uint64_t);"
+            "u64vec3  max(u64vec3,  uint64_t);"
+            "u64vec4  max(u64vec4,  uint64_t);"
+            "u64vec2  max(u64vec2,  u64vec2);"
+            "u64vec3  max(u64vec3,  u64vec3);"
+            "u64vec4  max(u64vec4,  u64vec4);"
+
+            "int64_t  clamp(int64_t,  int64_t,  int64_t);"
+            "i64vec2  clamp(i64vec2,  int64_t,  int64_t);"
+            "i64vec3  clamp(i64vec3,  int64_t,  int64_t);"
+            "i64vec4  clamp(i64vec4,  int64_t,  int64_t);"
+            "i64vec2  clamp(i64vec2,  i64vec2,  i64vec2);"
+            "i64vec3  clamp(i64vec3,  i64vec3,  i64vec3);"
+            "i64vec4  clamp(i64vec4,  i64vec4,  i64vec4);"
+            "uint64_t clamp(uint64_t, uint64_t, uint64_t);"
+            "u64vec2  clamp(u64vec2,  uint64_t, uint64_t);"
+            "u64vec3  clamp(u64vec3,  uint64_t, uint64_t);"
+            "u64vec4  clamp(u64vec4,  uint64_t, uint64_t);"
+            "u64vec2  clamp(u64vec2,  u64vec2,  u64vec2);"
+            "u64vec3  clamp(u64vec3,  u64vec3,  u64vec3);"
+            "u64vec4  clamp(u64vec4,  u64vec4,  u64vec4);"
+
+            "int64_t  mix(int64_t,  int64_t,  bool);"
+            "i64vec2  mix(i64vec2,  i64vec2,  bvec2);"
+            "i64vec3  mix(i64vec3,  i64vec3,  bvec3);"
+            "i64vec4  mix(i64vec4,  i64vec4,  bvec4);"
+            "uint64_t mix(uint64_t, uint64_t, bool);"
+            "u64vec2  mix(u64vec2,  u64vec2,  bvec2);"
+            "u64vec3  mix(u64vec3,  u64vec3,  bvec3);"
+            "u64vec4  mix(u64vec4,  u64vec4,  bvec4);"
+
+            "int64_t doubleBitsToInt64(double);"
+            "i64vec2 doubleBitsToInt64(dvec2);"
+            "i64vec3 doubleBitsToInt64(dvec3);"
+            "i64vec4 doubleBitsToInt64(dvec4);"
+
+            "uint64_t doubleBitsToUint64(double);"
+            "u64vec2  doubleBitsToUint64(dvec2);"
+            "u64vec3  doubleBitsToUint64(dvec3);"
+            "u64vec4  doubleBitsToUint64(dvec4);"
+
+            "double int64BitsToDouble(int64_t);"
+            "dvec2  int64BitsToDouble(i64vec2);"
+            "dvec3  int64BitsToDouble(i64vec3);"
+            "dvec4  int64BitsToDouble(i64vec4);"
+
+            "double uint64BitsToDouble(uint64_t);"
+            "dvec2  uint64BitsToDouble(u64vec2);"
+            "dvec3  uint64BitsToDouble(u64vec3);"
+            "dvec4  uint64BitsToDouble(u64vec4);"
+
+            "int64_t  packInt2x32(ivec2);"
+            "uint64_t packUint2x32(uvec2);"
+            "ivec2    unpackInt2x32(int64_t);"
+            "uvec2    unpackUint2x32(uint64_t);"
+
+            "bvec2 lessThan(i64vec2, i64vec2);"
+            "bvec3 lessThan(i64vec3, i64vec3);"
+            "bvec4 lessThan(i64vec4, i64vec4);"
+            "bvec2 lessThan(u64vec2, u64vec2);"
+            "bvec3 lessThan(u64vec3, u64vec3);"
+            "bvec4 lessThan(u64vec4, u64vec4);"
+
+            "bvec2 lessThanEqual(i64vec2, i64vec2);"
+            "bvec3 lessThanEqual(i64vec3, i64vec3);"
+            "bvec4 lessThanEqual(i64vec4, i64vec4);"
+            "bvec2 lessThanEqual(u64vec2, u64vec2);"
+            "bvec3 lessThanEqual(u64vec3, u64vec3);"
+            "bvec4 lessThanEqual(u64vec4, u64vec4);"
+
+            "bvec2 greaterThan(i64vec2, i64vec2);"
+            "bvec3 greaterThan(i64vec3, i64vec3);"
+            "bvec4 greaterThan(i64vec4, i64vec4);"
+            "bvec2 greaterThan(u64vec2, u64vec2);"
+            "bvec3 greaterThan(u64vec3, u64vec3);"
+            "bvec4 greaterThan(u64vec4, u64vec4);"
+
+            "bvec2 greaterThanEqual(i64vec2, i64vec2);"
+            "bvec3 greaterThanEqual(i64vec3, i64vec3);"
+            "bvec4 greaterThanEqual(i64vec4, i64vec4);"
+            "bvec2 greaterThanEqual(u64vec2, u64vec2);"
+            "bvec3 greaterThanEqual(u64vec3, u64vec3);"
+            "bvec4 greaterThanEqual(u64vec4, u64vec4);"
+
+            "bvec2 equal(i64vec2, i64vec2);"
+            "bvec3 equal(i64vec3, i64vec3);"
+            "bvec4 equal(i64vec4, i64vec4);"
+            "bvec2 equal(u64vec2, u64vec2);"
+            "bvec3 equal(u64vec3, u64vec3);"
+            "bvec4 equal(u64vec4, u64vec4);"
+
+            "bvec2 notEqual(i64vec2, i64vec2);"
+            "bvec3 notEqual(i64vec3, i64vec3);"
+            "bvec4 notEqual(i64vec4, i64vec4);"
+            "bvec2 notEqual(u64vec2, u64vec2);"
+            "bvec3 notEqual(u64vec3, u64vec3);"
+            "bvec4 notEqual(u64vec4, u64vec4);"
+
+#ifdef AMD_EXTENSIONS
+            "int   findLSB(int64_t);"
+            "ivec2 findLSB(i64vec2);"
+            "ivec3 findLSB(i64vec3);"
+            "ivec4 findLSB(i64vec4);"
+
+            "int   findLSB(uint64_t);"
+            "ivec2 findLSB(u64vec2);"
+            "ivec3 findLSB(u64vec3);"
+            "ivec4 findLSB(u64vec4);"
+
+            "int   findMSB(int64_t);"
+            "ivec2 findMSB(i64vec2);"
+            "ivec3 findMSB(i64vec3);"
+            "ivec4 findMSB(i64vec4);"
+
+            "int   findMSB(uint64_t);"
+            "ivec2 findMSB(u64vec2);"
+            "ivec3 findMSB(u64vec3);"
+            "ivec4 findMSB(u64vec4);"
+#endif
+            "\n"
+        );
+    }
+
+#ifdef AMD_EXTENSIONS
+    // GL_AMD_shader_trinary_minmax
+    if (profile != EEsProfile && version >= 430) {
+        commonBuiltins.append(
+            "float min3(float, float, float);"
+            "vec2  min3(vec2,  vec2,  vec2);"
+            "vec3  min3(vec3,  vec3,  vec3);"
+            "vec4  min3(vec4,  vec4,  vec4);"
+
+            "int   min3(int,   int,   int);"
+            "ivec2 min3(ivec2, ivec2, ivec2);"
+            "ivec3 min3(ivec3, ivec3, ivec3);"
+            "ivec4 min3(ivec4, ivec4, ivec4);"
+
+            "uint  min3(uint,  uint,  uint);"
+            "uvec2 min3(uvec2, uvec2, uvec2);"
+            "uvec3 min3(uvec3, uvec3, uvec3);"
+            "uvec4 min3(uvec4, uvec4, uvec4);"
+
+            "float max3(float, float, float);"
+            "vec2  max3(vec2,  vec2,  vec2);"
+            "vec3  max3(vec3,  vec3,  vec3);"
+            "vec4  max3(vec4,  vec4,  vec4);"
+
+            "int   max3(int,   int,   int);"
+            "ivec2 max3(ivec2, ivec2, ivec2);"
+            "ivec3 max3(ivec3, ivec3, ivec3);"
+            "ivec4 max3(ivec4, ivec4, ivec4);"
+
+            "uint  max3(uint,  uint,  uint);"
+            "uvec2 max3(uvec2, uvec2, uvec2);"
+            "uvec3 max3(uvec3, uvec3, uvec3);"
+            "uvec4 max3(uvec4, uvec4, uvec4);"
+
+            "float mid3(float, float, float);"
+            "vec2  mid3(vec2,  vec2,  vec2);"
+            "vec3  mid3(vec3,  vec3,  vec3);"
+            "vec4  mid3(vec4,  vec4,  vec4);"
+
+            "int   mid3(int,   int,   int);"
+            "ivec2 mid3(ivec2, ivec2, ivec2);"
+            "ivec3 mid3(ivec3, ivec3, ivec3);"
+            "ivec4 mid3(ivec4, ivec4, ivec4);"
+
+            "uint  mid3(uint,  uint,  uint);"
+            "uvec2 mid3(uvec2, uvec2, uvec2);"
+            "uvec3 mid3(uvec3, uvec3, uvec3);"
+            "uvec4 mid3(uvec4, uvec4, uvec4);"
+
+            "float16_t min3(float16_t, float16_t, float16_t);"
+            "f16vec2   min3(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   min3(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   min3(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t max3(float16_t, float16_t, float16_t);"
+            "f16vec2   max3(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   max3(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   max3(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t mid3(float16_t, float16_t, float16_t);"
+            "f16vec2   mid3(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   mid3(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   mid3(f16vec4,   f16vec4,   f16vec4);"
+
+            "\n"
+        );
+    }
+#endif
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 430)) {
+        commonBuiltins.append(
+            "uint atomicAdd(coherent volatile inout uint, uint);"
+            " int atomicAdd(coherent volatile inout  int,  int);"
+
+            "uint atomicMin(coherent volatile inout uint, uint);"
+            " int atomicMin(coherent volatile inout  int,  int);"
+
+            "uint atomicMax(coherent volatile inout uint, uint);"
+            " int atomicMax(coherent volatile inout  int,  int);"
+
+            "uint atomicAnd(coherent volatile inout uint, uint);"
+            " int atomicAnd(coherent volatile inout  int,  int);"
+
+            "uint atomicOr (coherent volatile inout uint, uint);"
+            " int atomicOr (coherent volatile inout  int,  int);"
+
+            "uint atomicXor(coherent volatile inout uint, uint);"
+            " int atomicXor(coherent volatile inout  int,  int);"
+
+            "uint atomicExchange(coherent volatile inout uint, uint);"
+            " int atomicExchange(coherent volatile inout  int,  int);"
+
+            "uint atomicCompSwap(coherent volatile inout uint, uint, uint);"
+            " int atomicCompSwap(coherent volatile inout  int,  int,  int);"
+
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 450)) {
+        commonBuiltins.append(
+            "int    mix(int    x, int    y, bool  a);"
+            "ivec2  mix(ivec2  x, ivec2  y, bvec2 a);"
+            "ivec3  mix(ivec3  x, ivec3  y, bvec3 a);"
+            "ivec4  mix(ivec4  x, ivec4  y, bvec4 a);"
+
+            "uint   mix(uint   x, uint   y, bool  a);"
+            "uvec2  mix(uvec2  x, uvec2  y, bvec2 a);"
+            "uvec3  mix(uvec3  x, uvec3  y, bvec3 a);"
+            "uvec4  mix(uvec4  x, uvec4  y, bvec4 a);"
+
+            "bool   mix(bool   x, bool   y, bool  a);"
+            "bvec2  mix(bvec2  x, bvec2  y, bvec2 a);"
+            "bvec3  mix(bvec3  x, bvec3  y, bvec3 a);"
+            "bvec4  mix(bvec4  x, bvec4  y, bvec4 a);"
+
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 300) ||
+        (profile != EEsProfile && version >= 330)) {
+        commonBuiltins.append(
+            "int   floatBitsToInt(highp float value);"
+            "ivec2 floatBitsToInt(highp vec2  value);"
+            "ivec3 floatBitsToInt(highp vec3  value);"
+            "ivec4 floatBitsToInt(highp vec4  value);"
+
+            "uint  floatBitsToUint(highp float value);"
+            "uvec2 floatBitsToUint(highp vec2  value);"
+            "uvec3 floatBitsToUint(highp vec3  value);"
+            "uvec4 floatBitsToUint(highp vec4  value);"
+
+            "float intBitsToFloat(highp int   value);"
+            "vec2  intBitsToFloat(highp ivec2 value);"
+            "vec3  intBitsToFloat(highp ivec3 value);"
+            "vec4  intBitsToFloat(highp ivec4 value);"
+
+            "float uintBitsToFloat(highp uint  value);"
+            "vec2  uintBitsToFloat(highp uvec2 value);"
+            "vec3  uintBitsToFloat(highp uvec3 value);"
+            "vec4  uintBitsToFloat(highp uvec4 value);"
+
+            "\n");
+    }
+
+    if ((profile != EEsProfile && version >= 400) ||
+        (profile == EEsProfile && version >= 310)) {    // GL_OES_gpu_shader5
+
+        commonBuiltins.append(
+            "float  fma(float,  float,  float );"
+            "vec2   fma(vec2,   vec2,   vec2  );"
+            "vec3   fma(vec3,   vec3,   vec3  );"
+            "vec4   fma(vec4,   vec4,   vec4  );"
+            "\n");
+
+        if (profile != EEsProfile) {
+            commonBuiltins.append(
+                "double fma(double, double, double);"
+                "dvec2  fma(dvec2,  dvec2,  dvec2 );"
+                "dvec3  fma(dvec3,  dvec3,  dvec3 );"
+                "dvec4  fma(dvec4,  dvec4,  dvec4 );"
+                "\n");
+        }
+    }
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            "float frexp(highp float, out highp int);"
+            "vec2  frexp(highp vec2,  out highp ivec2);"
+            "vec3  frexp(highp vec3,  out highp ivec3);"
+            "vec4  frexp(highp vec4,  out highp ivec4);"
+
+            "float ldexp(highp float, highp int);"
+            "vec2  ldexp(highp vec2,  highp ivec2);"
+            "vec3  ldexp(highp vec3,  highp ivec3);"
+            "vec4  ldexp(highp vec4,  highp ivec4);"
+
+            "\n");
+    }
+
+    if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+            "double frexp(double, out int);"
+            "dvec2  frexp( dvec2, out ivec2);"
+            "dvec3  frexp( dvec3, out ivec3);"
+            "dvec4  frexp( dvec4, out ivec4);"
+
+            "double ldexp(double, int);"
+            "dvec2  ldexp( dvec2, ivec2);"
+            "dvec3  ldexp( dvec3, ivec3);"
+            "dvec4  ldexp( dvec4, ivec4);"
+
+            "double packDouble2x32(uvec2);"
+            "uvec2 unpackDouble2x32(double);"
+
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 300) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            "highp uint packUnorm2x16(vec2);"
+                  "vec2 unpackUnorm2x16(highp uint);"
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 300) ||
+        (profile != EEsProfile && version >= 420)) {
+        commonBuiltins.append(
+            "highp uint packSnorm2x16(vec2);"
+            "      vec2 unpackSnorm2x16(highp uint);"
+            "highp uint packHalf2x16(vec2);"
+            "\n");
+    }
+
+    if (profile == EEsProfile && version >= 300) {
+        commonBuiltins.append(
+            "mediump vec2 unpackHalf2x16(highp uint);"
+            "\n");
+    } else if (profile != EEsProfile && version >= 420) {
+        commonBuiltins.append(
+            "        vec2 unpackHalf2x16(highp uint);"
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            "highp uint packSnorm4x8(vec4);"
+            "highp uint packUnorm4x8(vec4);"
+            "\n");
+    }
+
+    if (profile == EEsProfile && version >= 310) {
+        commonBuiltins.append(
+            "mediump vec4 unpackSnorm4x8(highp uint);"
+            "mediump vec4 unpackUnorm4x8(highp uint);"
+            "\n");
+    } else if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+                    "vec4 unpackSnorm4x8(highp uint);"
+                    "vec4 unpackUnorm4x8(highp uint);"
+            "\n");
+    }
+
+    //
+    // Geometric Functions.
+    //
+    commonBuiltins.append(
+        "float length(float x);"
+        "float length(vec2  x);"
+        "float length(vec3  x);"
+        "float length(vec4  x);"
+
+        "float distance(float p0, float p1);"
+        "float distance(vec2  p0, vec2  p1);"
+        "float distance(vec3  p0, vec3  p1);"
+        "float distance(vec4  p0, vec4  p1);"
+
+        "float dot(float x, float y);"
+        "float dot(vec2  x, vec2  y);"
+        "float dot(vec3  x, vec3  y);"
+        "float dot(vec4  x, vec4  y);"
+
+        "vec3 cross(vec3 x, vec3 y);"
+        "float normalize(float x);"
+        "vec2  normalize(vec2  x);"
+        "vec3  normalize(vec3  x);"
+        "vec4  normalize(vec4  x);"
+
+        "float faceforward(float N, float I, float Nref);"
+        "vec2  faceforward(vec2  N, vec2  I, vec2  Nref);"
+        "vec3  faceforward(vec3  N, vec3  I, vec3  Nref);"
+        "vec4  faceforward(vec4  N, vec4  I, vec4  Nref);"
+
+        "float reflect(float I, float N);"
+        "vec2  reflect(vec2  I, vec2  N);"
+        "vec3  reflect(vec3  I, vec3  N);"
+        "vec4  reflect(vec4  I, vec4  N);"
+
+        "float refract(float I, float N, float eta);"
+        "vec2  refract(vec2  I, vec2  N, float eta);"
+        "vec3  refract(vec3  I, vec3  N, float eta);"
+        "vec4  refract(vec4  I, vec4  N, float eta);"
+
+        "\n");
+
+    //
+    // Matrix Functions.
+    //
+    commonBuiltins.append(
+        "mat2 matrixCompMult(mat2 x, mat2 y);"
+        "mat3 matrixCompMult(mat3 x, mat3 y);"
+        "mat4 matrixCompMult(mat4 x, mat4 y);"
+
+        "\n");
+
+    // 120 is correct for both ES and desktop
+    if (version >= 120) {
+        commonBuiltins.append(
+            "mat2   outerProduct(vec2 c, vec2 r);"
+            "mat3   outerProduct(vec3 c, vec3 r);"
+            "mat4   outerProduct(vec4 c, vec4 r);"
+            "mat2x3 outerProduct(vec3 c, vec2 r);"
+            "mat3x2 outerProduct(vec2 c, vec3 r);"
+            "mat2x4 outerProduct(vec4 c, vec2 r);"
+            "mat4x2 outerProduct(vec2 c, vec4 r);"
+            "mat3x4 outerProduct(vec4 c, vec3 r);"
+            "mat4x3 outerProduct(vec3 c, vec4 r);"
+
+            "mat2   transpose(mat2   m);"
+            "mat3   transpose(mat3   m);"
+            "mat4   transpose(mat4   m);"
+            "mat2x3 transpose(mat3x2 m);"
+            "mat3x2 transpose(mat2x3 m);"
+            "mat2x4 transpose(mat4x2 m);"
+            "mat4x2 transpose(mat2x4 m);"
+            "mat3x4 transpose(mat4x3 m);"
+            "mat4x3 transpose(mat3x4 m);"
+
+            "mat2x3 matrixCompMult(mat2x3, mat2x3);"
+            "mat2x4 matrixCompMult(mat2x4, mat2x4);"
+            "mat3x2 matrixCompMult(mat3x2, mat3x2);"
+            "mat3x4 matrixCompMult(mat3x4, mat3x4);"
+            "mat4x2 matrixCompMult(mat4x2, mat4x2);"
+            "mat4x3 matrixCompMult(mat4x3, mat4x3);"
+
+            "\n");
+
+        // 150 is correct for both ES and desktop
+        if (version >= 150) {
+            commonBuiltins.append(
+                "float determinant(mat2 m);"
+                "float determinant(mat3 m);"
+                "float determinant(mat4 m);"
+
+                "mat2 inverse(mat2 m);"
+                "mat3 inverse(mat3 m);"
+                "mat4 inverse(mat4 m);"
+
+                "\n");
+        }
+    }
+
+    //
+    // Vector relational functions.
+    //
+    commonBuiltins.append(
+        "bvec2 lessThan(vec2 x, vec2 y);"
+        "bvec3 lessThan(vec3 x, vec3 y);"
+        "bvec4 lessThan(vec4 x, vec4 y);"
+
+        "bvec2 lessThan(ivec2 x, ivec2 y);"
+        "bvec3 lessThan(ivec3 x, ivec3 y);"
+        "bvec4 lessThan(ivec4 x, ivec4 y);"
+
+        "bvec2 lessThanEqual(vec2 x, vec2 y);"
+        "bvec3 lessThanEqual(vec3 x, vec3 y);"
+        "bvec4 lessThanEqual(vec4 x, vec4 y);"
+
+        "bvec2 lessThanEqual(ivec2 x, ivec2 y);"
+        "bvec3 lessThanEqual(ivec3 x, ivec3 y);"
+        "bvec4 lessThanEqual(ivec4 x, ivec4 y);"
+
+        "bvec2 greaterThan(vec2 x, vec2 y);"
+        "bvec3 greaterThan(vec3 x, vec3 y);"
+        "bvec4 greaterThan(vec4 x, vec4 y);"
+
+        "bvec2 greaterThan(ivec2 x, ivec2 y);"
+        "bvec3 greaterThan(ivec3 x, ivec3 y);"
+        "bvec4 greaterThan(ivec4 x, ivec4 y);"
+
+        "bvec2 greaterThanEqual(vec2 x, vec2 y);"
+        "bvec3 greaterThanEqual(vec3 x, vec3 y);"
+        "bvec4 greaterThanEqual(vec4 x, vec4 y);"
+
+        "bvec2 greaterThanEqual(ivec2 x, ivec2 y);"
+        "bvec3 greaterThanEqual(ivec3 x, ivec3 y);"
+        "bvec4 greaterThanEqual(ivec4 x, ivec4 y);"
+
+        "bvec2 equal(vec2 x, vec2 y);"
+        "bvec3 equal(vec3 x, vec3 y);"
+        "bvec4 equal(vec4 x, vec4 y);"
+
+        "bvec2 equal(ivec2 x, ivec2 y);"
+        "bvec3 equal(ivec3 x, ivec3 y);"
+        "bvec4 equal(ivec4 x, ivec4 y);"
+
+        "bvec2 equal(bvec2 x, bvec2 y);"
+        "bvec3 equal(bvec3 x, bvec3 y);"
+        "bvec4 equal(bvec4 x, bvec4 y);"
+
+        "bvec2 notEqual(vec2 x, vec2 y);"
+        "bvec3 notEqual(vec3 x, vec3 y);"
+        "bvec4 notEqual(vec4 x, vec4 y);"
+
+        "bvec2 notEqual(ivec2 x, ivec2 y);"
+        "bvec3 notEqual(ivec3 x, ivec3 y);"
+        "bvec4 notEqual(ivec4 x, ivec4 y);"
+
+        "bvec2 notEqual(bvec2 x, bvec2 y);"
+        "bvec3 notEqual(bvec3 x, bvec3 y);"
+        "bvec4 notEqual(bvec4 x, bvec4 y);"
+
+        "bool any(bvec2 x);"
+        "bool any(bvec3 x);"
+        "bool any(bvec4 x);"
+
+        "bool all(bvec2 x);"
+        "bool all(bvec3 x);"
+        "bool all(bvec4 x);"
+
+        "bvec2 not(bvec2 x);"
+        "bvec3 not(bvec3 x);"
+        "bvec4 not(bvec4 x);"
+
+        "\n");
+
+    if (version >= 130) {
+        commonBuiltins.append(
+            "bvec2 lessThan(uvec2 x, uvec2 y);"
+            "bvec3 lessThan(uvec3 x, uvec3 y);"
+            "bvec4 lessThan(uvec4 x, uvec4 y);"
+
+            "bvec2 lessThanEqual(uvec2 x, uvec2 y);"
+            "bvec3 lessThanEqual(uvec3 x, uvec3 y);"
+            "bvec4 lessThanEqual(uvec4 x, uvec4 y);"
+
+            "bvec2 greaterThan(uvec2 x, uvec2 y);"
+            "bvec3 greaterThan(uvec3 x, uvec3 y);"
+            "bvec4 greaterThan(uvec4 x, uvec4 y);"
+
+            "bvec2 greaterThanEqual(uvec2 x, uvec2 y);"
+            "bvec3 greaterThanEqual(uvec3 x, uvec3 y);"
+            "bvec4 greaterThanEqual(uvec4 x, uvec4 y);"
+
+            "bvec2 equal(uvec2 x, uvec2 y);"
+            "bvec3 equal(uvec3 x, uvec3 y);"
+            "bvec4 equal(uvec4 x, uvec4 y);"
+
+            "bvec2 notEqual(uvec2 x, uvec2 y);"
+            "bvec3 notEqual(uvec3 x, uvec3 y);"
+            "bvec4 notEqual(uvec4 x, uvec4 y);"
+
+            "\n");
+    }
+
+    //
+    // Original-style texture functions existing in all stages.
+    // (Per-stage functions below.)
+    //
+    if ((profile == EEsProfile && version == 100) ||
+         profile == ECompatibilityProfile ||
+        (profile == ECoreProfile && version < 420) ||
+         profile == ENoProfile) {
+        if (spvVersion.spv == 0) {
+            commonBuiltins.append(
+                "vec4 texture2D(sampler2D, vec2);"
+
+                "vec4 texture2DProj(sampler2D, vec3);"
+                "vec4 texture2DProj(sampler2D, vec4);"
+
+                "vec4 texture3D(sampler3D, vec3);"     // OES_texture_3D, but caught by keyword check
+                "vec4 texture3DProj(sampler3D, vec4);" // OES_texture_3D, but caught by keyword check
+
+                "vec4 textureCube(samplerCube, vec3);"
+
+                "vec4 texture2DArray(sampler2DArray, vec3);" // GL_EXT_texture_array
+
+                "\n");
+        }
+    }
+
+    if ( profile == ECompatibilityProfile ||
+        (profile == ECoreProfile && version < 420) ||
+         profile == ENoProfile) {
+        if (spvVersion.spv == 0) {
+            commonBuiltins.append(
+                "vec4 texture1D(sampler1D, float);"
+
+                "vec4 texture1DProj(sampler1D, vec2);"
+                "vec4 texture1DProj(sampler1D, vec4);"
+
+                "vec4 shadow1D(sampler1DShadow, vec3);"
+                "vec4 shadow2D(sampler2DShadow, vec3);"
+                "vec4 shadow1DProj(sampler1DShadow, vec4);"
+                "vec4 shadow2DProj(sampler2DShadow, vec4);"
+
+                "vec4 texture2DRect(sampler2DRect, vec2);"          // GL_ARB_texture_rectangle, caught by keyword check
+                "vec4 texture2DRectProj(sampler2DRect, vec3);"      // GL_ARB_texture_rectangle, caught by keyword check
+                "vec4 texture2DRectProj(sampler2DRect, vec4);"      // GL_ARB_texture_rectangle, caught by keyword check
+                "vec4 shadow2DRect(sampler2DRectShadow, vec3);"     // GL_ARB_texture_rectangle, caught by keyword check
+                "vec4 shadow2DRectProj(sampler2DRectShadow, vec4);" // GL_ARB_texture_rectangle, caught by keyword check
+
+                "vec4 texture1DArray(sampler1DArray, vec2);"      // GL_EXT_texture_array
+                "vec4 shadow1DArray(sampler1DArrayShadow, vec3);" // GL_EXT_texture_array
+                "vec4 shadow2DArray(sampler2DArrayShadow, vec4);" // GL_EXT_texture_array
+
+                "\n");
+        }
+    }
+
+    if (profile == EEsProfile) {
+        if (spvVersion.spv == 0) {
+            commonBuiltins.append(
+                "vec4 texture2D(samplerExternalOES, vec2 coord);"  // GL_OES_EGL_image_external, caught by keyword check
+                "vec4 texture2DProj(samplerExternalOES, vec3);"    // GL_OES_EGL_image_external, caught by keyword check
+                "vec4 texture2DProj(samplerExternalOES, vec4);"    // GL_OES_EGL_image_external, caught by keyword check
+                "vec4 texture2DGradEXT(sampler2D, vec2, vec2, vec2);"      // GL_EXT_shader_texture_lod
+                "vec4 texture2DProjGradEXT(sampler2D, vec3, vec2, vec2);"  // GL_EXT_shader_texture_lod
+                "vec4 texture2DProjGradEXT(sampler2D, vec4, vec2, vec2);"  // GL_EXT_shader_texture_lod
+                "vec4 textureCubeGradEXT(samplerCube, vec3, vec3, vec3);"  // GL_EXT_shader_texture_lod
+
+                "\n");
+        }
+    }
+
+    //
+    // Noise functions.
+    //
+    if (profile != EEsProfile) {
+        commonBuiltins.append(
+            "float noise1(float x);"
+            "float noise1(vec2  x);"
+            "float noise1(vec3  x);"
+            "float noise1(vec4  x);"
+
+            "vec2 noise2(float x);"
+            "vec2 noise2(vec2  x);"
+            "vec2 noise2(vec3  x);"
+            "vec2 noise2(vec4  x);"
+
+            "vec3 noise3(float x);"
+            "vec3 noise3(vec2  x);"
+            "vec3 noise3(vec3  x);"
+            "vec3 noise3(vec4  x);"
+
+            "vec4 noise4(float x);"
+            "vec4 noise4(vec2  x);"
+            "vec4 noise4(vec3  x);"
+            "vec4 noise4(vec4  x);"
+
+            "\n");
+    }
+
+    if (spvVersion.vulkan == 0) {
+        //
+        // Atomic counter functions.
+        //
+        if ((profile != EEsProfile && version >= 300) ||
+            (profile == EEsProfile && version >= 310)) {
+            commonBuiltins.append(
+                "uint atomicCounterIncrement(atomic_uint x);"
+                "uint atomicCounterDecrement(atomic_uint x);"
+                "uint atomicCounter(atomic_uint x);"
+
+                "\n");
+        }
+    }
+
+    // Bitfield
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            "  int bitfieldExtract(  int, int, int);"
+            "ivec2 bitfieldExtract(ivec2, int, int);"
+            "ivec3 bitfieldExtract(ivec3, int, int);"
+            "ivec4 bitfieldExtract(ivec4, int, int);"
+
+            " uint bitfieldExtract( uint, int, int);"
+            "uvec2 bitfieldExtract(uvec2, int, int);"
+            "uvec3 bitfieldExtract(uvec3, int, int);"
+            "uvec4 bitfieldExtract(uvec4, int, int);"
+
+            "  int bitfieldInsert(  int base,   int, int, int);"
+            "ivec2 bitfieldInsert(ivec2 base, ivec2, int, int);"
+            "ivec3 bitfieldInsert(ivec3 base, ivec3, int, int);"
+            "ivec4 bitfieldInsert(ivec4 base, ivec4, int, int);"
+
+            " uint bitfieldInsert( uint base,  uint, int, int);"
+            "uvec2 bitfieldInsert(uvec2 base, uvec2, int, int);"
+            "uvec3 bitfieldInsert(uvec3 base, uvec3, int, int);"
+            "uvec4 bitfieldInsert(uvec4 base, uvec4, int, int);"
+
+            "\n");
+    }
+
+    if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+            "  int findLSB(  int);"
+            "ivec2 findLSB(ivec2);"
+            "ivec3 findLSB(ivec3);"
+            "ivec4 findLSB(ivec4);"
+
+            "  int findLSB( uint);"
+            "ivec2 findLSB(uvec2);"
+            "ivec3 findLSB(uvec3);"
+            "ivec4 findLSB(uvec4);"
+
+            "\n");
+    } else if (profile == EEsProfile && version >= 310) {
+        commonBuiltins.append(
+            "lowp   int findLSB(  int);"
+            "lowp ivec2 findLSB(ivec2);"
+            "lowp ivec3 findLSB(ivec3);"
+            "lowp ivec4 findLSB(ivec4);"
+
+            "lowp   int findLSB( uint);"
+            "lowp ivec2 findLSB(uvec2);"
+            "lowp ivec3 findLSB(uvec3);"
+            "lowp ivec4 findLSB(uvec4);"
+
+            "\n");
+    }
+
+    if (profile != EEsProfile && version >= 400) {
+        commonBuiltins.append(
+            "  int bitCount(  int);"
+            "ivec2 bitCount(ivec2);"
+            "ivec3 bitCount(ivec3);"
+            "ivec4 bitCount(ivec4);"
+
+            "  int bitCount( uint);"
+            "ivec2 bitCount(uvec2);"
+            "ivec3 bitCount(uvec3);"
+            "ivec4 bitCount(uvec4);"
+
+            "  int findMSB(highp   int);"
+            "ivec2 findMSB(highp ivec2);"
+            "ivec3 findMSB(highp ivec3);"
+            "ivec4 findMSB(highp ivec4);"
+
+            "  int findMSB(highp  uint);"
+            "ivec2 findMSB(highp uvec2);"
+            "ivec3 findMSB(highp uvec3);"
+            "ivec4 findMSB(highp uvec4);"
+
+            "\n");
+    }
+
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        commonBuiltins.append(
+            " uint uaddCarry(highp  uint, highp  uint, out lowp  uint carry);"
+            "uvec2 uaddCarry(highp uvec2, highp uvec2, out lowp uvec2 carry);"
+            "uvec3 uaddCarry(highp uvec3, highp uvec3, out lowp uvec3 carry);"
+            "uvec4 uaddCarry(highp uvec4, highp uvec4, out lowp uvec4 carry);"
+
+            " uint usubBorrow(highp  uint, highp  uint, out lowp  uint borrow);"
+            "uvec2 usubBorrow(highp uvec2, highp uvec2, out lowp uvec2 borrow);"
+            "uvec3 usubBorrow(highp uvec3, highp uvec3, out lowp uvec3 borrow);"
+            "uvec4 usubBorrow(highp uvec4, highp uvec4, out lowp uvec4 borrow);"
+
+            "void umulExtended(highp  uint, highp  uint, out highp  uint, out highp  uint lsb);"
+            "void umulExtended(highp uvec2, highp uvec2, out highp uvec2, out highp uvec2 lsb);"
+            "void umulExtended(highp uvec3, highp uvec3, out highp uvec3, out highp uvec3 lsb);"
+            "void umulExtended(highp uvec4, highp uvec4, out highp uvec4, out highp uvec4 lsb);"
+
+            "void imulExtended(highp   int, highp   int, out highp   int, out highp   int lsb);"
+            "void imulExtended(highp ivec2, highp ivec2, out highp ivec2, out highp ivec2 lsb);"
+            "void imulExtended(highp ivec3, highp ivec3, out highp ivec3, out highp ivec3 lsb);"
+            "void imulExtended(highp ivec4, highp ivec4, out highp ivec4, out highp ivec4 lsb);"
+
+            "  int bitfieldReverse(highp   int);"
+            "ivec2 bitfieldReverse(highp ivec2);"
+            "ivec3 bitfieldReverse(highp ivec3);"
+            "ivec4 bitfieldReverse(highp ivec4);"
+
+            " uint bitfieldReverse(highp  uint);"
+            "uvec2 bitfieldReverse(highp uvec2);"
+            "uvec3 bitfieldReverse(highp uvec3);"
+            "uvec4 bitfieldReverse(highp uvec4);"
+
+            "\n");
+    }
+
+    if (profile == EEsProfile && version >= 310) {
+        commonBuiltins.append(
+            "lowp   int bitCount(  int);"
+            "lowp ivec2 bitCount(ivec2);"
+            "lowp ivec3 bitCount(ivec3);"
+            "lowp ivec4 bitCount(ivec4);"
+
+            "lowp   int bitCount( uint);"
+            "lowp ivec2 bitCount(uvec2);"
+            "lowp ivec3 bitCount(uvec3);"
+            "lowp ivec4 bitCount(uvec4);"
+
+            "lowp   int findMSB(highp   int);"
+            "lowp ivec2 findMSB(highp ivec2);"
+            "lowp ivec3 findMSB(highp ivec3);"
+            "lowp ivec4 findMSB(highp ivec4);"
+
+            "lowp   int findMSB(highp  uint);"
+            "lowp ivec2 findMSB(highp uvec2);"
+            "lowp ivec3 findMSB(highp uvec3);"
+            "lowp ivec4 findMSB(highp uvec4);"
+
+            "\n");
+    }
+
+    // GL_ARB_shader_ballot
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "uint64_t ballotARB(bool);"
+
+            "float readInvocationARB(float, uint);"
+            "vec2  readInvocationARB(vec2,  uint);"
+            "vec3  readInvocationARB(vec3,  uint);"
+            "vec4  readInvocationARB(vec4,  uint);"
+
+            "int   readInvocationARB(int,   uint);"
+            "ivec2 readInvocationARB(ivec2, uint);"
+            "ivec3 readInvocationARB(ivec3, uint);"
+            "ivec4 readInvocationARB(ivec4, uint);"
+
+            "uint  readInvocationARB(uint,  uint);"
+            "uvec2 readInvocationARB(uvec2, uint);"
+            "uvec3 readInvocationARB(uvec3, uint);"
+            "uvec4 readInvocationARB(uvec4, uint);"
+
+            "float readFirstInvocationARB(float);"
+            "vec2  readFirstInvocationARB(vec2);"
+            "vec3  readFirstInvocationARB(vec3);"
+            "vec4  readFirstInvocationARB(vec4);"
+
+            "int   readFirstInvocationARB(int);"
+            "ivec2 readFirstInvocationARB(ivec2);"
+            "ivec3 readFirstInvocationARB(ivec3);"
+            "ivec4 readFirstInvocationARB(ivec4);"
+
+            "uint  readFirstInvocationARB(uint);"
+            "uvec2 readFirstInvocationARB(uvec2);"
+            "uvec3 readFirstInvocationARB(uvec3);"
+            "uvec4 readFirstInvocationARB(uvec4);"
+
+            "\n");
+    }
+
+        // GL_ARB_shader_group_vote
+    if (profile != EEsProfile && version >= 430) {
+        commonBuiltins.append(
+            "bool anyInvocationARB(bool);"
+            "bool allInvocationsARB(bool);"
+            "bool allInvocationsEqualARB(bool);"
+
+            "\n");
+    }
+
+#ifdef AMD_EXTENSIONS
+    // GL_AMD_shader_ballot
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "float minInvocationsAMD(float);"
+            "vec2  minInvocationsAMD(vec2);"
+            "vec3  minInvocationsAMD(vec3);"
+            "vec4  minInvocationsAMD(vec4);"
+
+            "int   minInvocationsAMD(int);"
+            "ivec2 minInvocationsAMD(ivec2);"
+            "ivec3 minInvocationsAMD(ivec3);"
+            "ivec4 minInvocationsAMD(ivec4);"
+
+            "uint  minInvocationsAMD(uint);"
+            "uvec2 minInvocationsAMD(uvec2);"
+            "uvec3 minInvocationsAMD(uvec3);"
+            "uvec4 minInvocationsAMD(uvec4);"
+
+            "double minInvocationsAMD(double);"
+            "dvec2  minInvocationsAMD(dvec2);"
+            "dvec3  minInvocationsAMD(dvec3);"
+            "dvec4  minInvocationsAMD(dvec4);"
+
+            "int64_t minInvocationsAMD(int64_t);"
+            "i64vec2 minInvocationsAMD(i64vec2);"
+            "i64vec3 minInvocationsAMD(i64vec3);"
+            "i64vec4 minInvocationsAMD(i64vec4);"
+
+            "uint64_t minInvocationsAMD(uint64_t);"
+            "u64vec2  minInvocationsAMD(u64vec2);"
+            "u64vec3  minInvocationsAMD(u64vec3);"
+            "u64vec4  minInvocationsAMD(u64vec4);"
+
+            "float16_t minInvocationsAMD(float16_t);"
+            "f16vec2   minInvocationsAMD(f16vec2);"
+            "f16vec3   minInvocationsAMD(f16vec3);"
+            "f16vec4   minInvocationsAMD(f16vec4);"
+
+            "float minInvocationsInclusiveScanAMD(float);"
+            "vec2  minInvocationsInclusiveScanAMD(vec2);"
+            "vec3  minInvocationsInclusiveScanAMD(vec3);"
+            "vec4  minInvocationsInclusiveScanAMD(vec4);"
+
+            "int   minInvocationsInclusiveScanAMD(int);"
+            "ivec2 minInvocationsInclusiveScanAMD(ivec2);"
+            "ivec3 minInvocationsInclusiveScanAMD(ivec3);"
+            "ivec4 minInvocationsInclusiveScanAMD(ivec4);"
+
+            "uint  minInvocationsInclusiveScanAMD(uint);"
+            "uvec2 minInvocationsInclusiveScanAMD(uvec2);"
+            "uvec3 minInvocationsInclusiveScanAMD(uvec3);"
+            "uvec4 minInvocationsInclusiveScanAMD(uvec4);"
+
+            "double minInvocationsInclusiveScanAMD(double);"
+            "dvec2  minInvocationsInclusiveScanAMD(dvec2);"
+            "dvec3  minInvocationsInclusiveScanAMD(dvec3);"
+            "dvec4  minInvocationsInclusiveScanAMD(dvec4);"
+
+            "int64_t minInvocationsInclusiveScanAMD(int64_t);"
+            "i64vec2 minInvocationsInclusiveScanAMD(i64vec2);"
+            "i64vec3 minInvocationsInclusiveScanAMD(i64vec3);"
+            "i64vec4 minInvocationsInclusiveScanAMD(i64vec4);"
+
+            "uint64_t minInvocationsInclusiveScanAMD(uint64_t);"
+            "u64vec2  minInvocationsInclusiveScanAMD(u64vec2);"
+            "u64vec3  minInvocationsInclusiveScanAMD(u64vec3);"
+            "u64vec4  minInvocationsInclusiveScanAMD(u64vec4);"
+
+            "float16_t minInvocationsInclusiveScanAMD(float16_t);"
+            "f16vec2   minInvocationsInclusiveScanAMD(f16vec2);"
+            "f16vec3   minInvocationsInclusiveScanAMD(f16vec3);"
+            "f16vec4   minInvocationsInclusiveScanAMD(f16vec4);"
+
+            "float minInvocationsExclusiveScanAMD(float);"
+            "vec2  minInvocationsExclusiveScanAMD(vec2);"
+            "vec3  minInvocationsExclusiveScanAMD(vec3);"
+            "vec4  minInvocationsExclusiveScanAMD(vec4);"
+
+            "int   minInvocationsExclusiveScanAMD(int);"
+            "ivec2 minInvocationsExclusiveScanAMD(ivec2);"
+            "ivec3 minInvocationsExclusiveScanAMD(ivec3);"
+            "ivec4 minInvocationsExclusiveScanAMD(ivec4);"
+
+            "uint  minInvocationsExclusiveScanAMD(uint);"
+            "uvec2 minInvocationsExclusiveScanAMD(uvec2);"
+            "uvec3 minInvocationsExclusiveScanAMD(uvec3);"
+            "uvec4 minInvocationsExclusiveScanAMD(uvec4);"
+
+            "double minInvocationsExclusiveScanAMD(double);"
+            "dvec2  minInvocationsExclusiveScanAMD(dvec2);"
+            "dvec3  minInvocationsExclusiveScanAMD(dvec3);"
+            "dvec4  minInvocationsExclusiveScanAMD(dvec4);"
+
+            "int64_t minInvocationsExclusiveScanAMD(int64_t);"
+            "i64vec2 minInvocationsExclusiveScanAMD(i64vec2);"
+            "i64vec3 minInvocationsExclusiveScanAMD(i64vec3);"
+            "i64vec4 minInvocationsExclusiveScanAMD(i64vec4);"
+
+            "uint64_t minInvocationsExclusiveScanAMD(uint64_t);"
+            "u64vec2  minInvocationsExclusiveScanAMD(u64vec2);"
+            "u64vec3  minInvocationsExclusiveScanAMD(u64vec3);"
+            "u64vec4  minInvocationsExclusiveScanAMD(u64vec4);"
+
+            "float16_t minInvocationsExclusiveScanAMD(float16_t);"
+            "f16vec2   minInvocationsExclusiveScanAMD(f16vec2);"
+            "f16vec3   minInvocationsExclusiveScanAMD(f16vec3);"
+            "f16vec4   minInvocationsExclusiveScanAMD(f16vec4);"
+
+            "float maxInvocationsAMD(float);"
+            "vec2  maxInvocationsAMD(vec2);"
+            "vec3  maxInvocationsAMD(vec3);"
+            "vec4  maxInvocationsAMD(vec4);"
+
+            "int   maxInvocationsAMD(int);"
+            "ivec2 maxInvocationsAMD(ivec2);"
+            "ivec3 maxInvocationsAMD(ivec3);"
+            "ivec4 maxInvocationsAMD(ivec4);"
+
+            "uint  maxInvocationsAMD(uint);"
+            "uvec2 maxInvocationsAMD(uvec2);"
+            "uvec3 maxInvocationsAMD(uvec3);"
+            "uvec4 maxInvocationsAMD(uvec4);"
+
+            "double maxInvocationsAMD(double);"
+            "dvec2  maxInvocationsAMD(dvec2);"
+            "dvec3  maxInvocationsAMD(dvec3);"
+            "dvec4  maxInvocationsAMD(dvec4);"
+
+            "int64_t maxInvocationsAMD(int64_t);"
+            "i64vec2 maxInvocationsAMD(i64vec2);"
+            "i64vec3 maxInvocationsAMD(i64vec3);"
+            "i64vec4 maxInvocationsAMD(i64vec4);"
+
+            "uint64_t maxInvocationsAMD(uint64_t);"
+            "u64vec2  maxInvocationsAMD(u64vec2);"
+            "u64vec3  maxInvocationsAMD(u64vec3);"
+            "u64vec4  maxInvocationsAMD(u64vec4);"
+
+            "float16_t maxInvocationsAMD(float16_t);"
+            "f16vec2   maxInvocationsAMD(f16vec2);"
+            "f16vec3   maxInvocationsAMD(f16vec3);"
+            "f16vec4   maxInvocationsAMD(f16vec4);"
+
+            "float maxInvocationsInclusiveScanAMD(float);"
+            "vec2  maxInvocationsInclusiveScanAMD(vec2);"
+            "vec3  maxInvocationsInclusiveScanAMD(vec3);"
+            "vec4  maxInvocationsInclusiveScanAMD(vec4);"
+
+            "int   maxInvocationsInclusiveScanAMD(int);"
+            "ivec2 maxInvocationsInclusiveScanAMD(ivec2);"
+            "ivec3 maxInvocationsInclusiveScanAMD(ivec3);"
+            "ivec4 maxInvocationsInclusiveScanAMD(ivec4);"
+
+            "uint  maxInvocationsInclusiveScanAMD(uint);"
+            "uvec2 maxInvocationsInclusiveScanAMD(uvec2);"
+            "uvec3 maxInvocationsInclusiveScanAMD(uvec3);"
+            "uvec4 maxInvocationsInclusiveScanAMD(uvec4);"
+
+            "double maxInvocationsInclusiveScanAMD(double);"
+            "dvec2  maxInvocationsInclusiveScanAMD(dvec2);"
+            "dvec3  maxInvocationsInclusiveScanAMD(dvec3);"
+            "dvec4  maxInvocationsInclusiveScanAMD(dvec4);"
+
+            "int64_t maxInvocationsInclusiveScanAMD(int64_t);"
+            "i64vec2 maxInvocationsInclusiveScanAMD(i64vec2);"
+            "i64vec3 maxInvocationsInclusiveScanAMD(i64vec3);"
+            "i64vec4 maxInvocationsInclusiveScanAMD(i64vec4);"
+
+            "uint64_t maxInvocationsInclusiveScanAMD(uint64_t);"
+            "u64vec2  maxInvocationsInclusiveScanAMD(u64vec2);"
+            "u64vec3  maxInvocationsInclusiveScanAMD(u64vec3);"
+            "u64vec4  maxInvocationsInclusiveScanAMD(u64vec4);"
+
+            "float16_t maxInvocationsInclusiveScanAMD(float16_t);"
+            "f16vec2   maxInvocationsInclusiveScanAMD(f16vec2);"
+            "f16vec3   maxInvocationsInclusiveScanAMD(f16vec3);"
+            "f16vec4   maxInvocationsInclusiveScanAMD(f16vec4);"
+
+            "float maxInvocationsExclusiveScanAMD(float);"
+            "vec2  maxInvocationsExclusiveScanAMD(vec2);"
+            "vec3  maxInvocationsExclusiveScanAMD(vec3);"
+            "vec4  maxInvocationsExclusiveScanAMD(vec4);"
+
+            "int   maxInvocationsExclusiveScanAMD(int);"
+            "ivec2 maxInvocationsExclusiveScanAMD(ivec2);"
+            "ivec3 maxInvocationsExclusiveScanAMD(ivec3);"
+            "ivec4 maxInvocationsExclusiveScanAMD(ivec4);"
+
+            "uint  maxInvocationsExclusiveScanAMD(uint);"
+            "uvec2 maxInvocationsExclusiveScanAMD(uvec2);"
+            "uvec3 maxInvocationsExclusiveScanAMD(uvec3);"
+            "uvec4 maxInvocationsExclusiveScanAMD(uvec4);"
+
+            "double maxInvocationsExclusiveScanAMD(double);"
+            "dvec2  maxInvocationsExclusiveScanAMD(dvec2);"
+            "dvec3  maxInvocationsExclusiveScanAMD(dvec3);"
+            "dvec4  maxInvocationsExclusiveScanAMD(dvec4);"
+
+            "int64_t maxInvocationsExclusiveScanAMD(int64_t);"
+            "i64vec2 maxInvocationsExclusiveScanAMD(i64vec2);"
+            "i64vec3 maxInvocationsExclusiveScanAMD(i64vec3);"
+            "i64vec4 maxInvocationsExclusiveScanAMD(i64vec4);"
+
+            "uint64_t maxInvocationsExclusiveScanAMD(uint64_t);"
+            "u64vec2  maxInvocationsExclusiveScanAMD(u64vec2);"
+            "u64vec3  maxInvocationsExclusiveScanAMD(u64vec3);"
+            "u64vec4  maxInvocationsExclusiveScanAMD(u64vec4);"
+
+            "float16_t maxInvocationsExclusiveScanAMD(float16_t);"
+            "f16vec2   maxInvocationsExclusiveScanAMD(f16vec2);"
+            "f16vec3   maxInvocationsExclusiveScanAMD(f16vec3);"
+            "f16vec4   maxInvocationsExclusiveScanAMD(f16vec4);"
+
+            "float addInvocationsAMD(float);"
+            "vec2  addInvocationsAMD(vec2);"
+            "vec3  addInvocationsAMD(vec3);"
+            "vec4  addInvocationsAMD(vec4);"
+
+            "int   addInvocationsAMD(int);"
+            "ivec2 addInvocationsAMD(ivec2);"
+            "ivec3 addInvocationsAMD(ivec3);"
+            "ivec4 addInvocationsAMD(ivec4);"
+
+            "uint  addInvocationsAMD(uint);"
+            "uvec2 addInvocationsAMD(uvec2);"
+            "uvec3 addInvocationsAMD(uvec3);"
+            "uvec4 addInvocationsAMD(uvec4);"
+
+            "double  addInvocationsAMD(double);"
+            "dvec2   addInvocationsAMD(dvec2);"
+            "dvec3   addInvocationsAMD(dvec3);"
+            "dvec4   addInvocationsAMD(dvec4);"
+
+            "int64_t addInvocationsAMD(int64_t);"
+            "i64vec2 addInvocationsAMD(i64vec2);"
+            "i64vec3 addInvocationsAMD(i64vec3);"
+            "i64vec4 addInvocationsAMD(i64vec4);"
+
+            "uint64_t addInvocationsAMD(uint64_t);"
+            "u64vec2  addInvocationsAMD(u64vec2);"
+            "u64vec3  addInvocationsAMD(u64vec3);"
+            "u64vec4  addInvocationsAMD(u64vec4);"
+
+            "float16_t addInvocationsAMD(float16_t);"
+            "f16vec2   addInvocationsAMD(f16vec2);"
+            "f16vec3   addInvocationsAMD(f16vec3);"
+            "f16vec4   addInvocationsAMD(f16vec4);"
+
+            "float addInvocationsInclusiveScanAMD(float);"
+            "vec2  addInvocationsInclusiveScanAMD(vec2);"
+            "vec3  addInvocationsInclusiveScanAMD(vec3);"
+            "vec4  addInvocationsInclusiveScanAMD(vec4);"
+
+            "int   addInvocationsInclusiveScanAMD(int);"
+            "ivec2 addInvocationsInclusiveScanAMD(ivec2);"
+            "ivec3 addInvocationsInclusiveScanAMD(ivec3);"
+            "ivec4 addInvocationsInclusiveScanAMD(ivec4);"
+
+            "uint  addInvocationsInclusiveScanAMD(uint);"
+            "uvec2 addInvocationsInclusiveScanAMD(uvec2);"
+            "uvec3 addInvocationsInclusiveScanAMD(uvec3);"
+            "uvec4 addInvocationsInclusiveScanAMD(uvec4);"
+
+            "double  addInvocationsInclusiveScanAMD(double);"
+            "dvec2   addInvocationsInclusiveScanAMD(dvec2);"
+            "dvec3   addInvocationsInclusiveScanAMD(dvec3);"
+            "dvec4   addInvocationsInclusiveScanAMD(dvec4);"
+
+            "int64_t addInvocationsInclusiveScanAMD(int64_t);"
+            "i64vec2 addInvocationsInclusiveScanAMD(i64vec2);"
+            "i64vec3 addInvocationsInclusiveScanAMD(i64vec3);"
+            "i64vec4 addInvocationsInclusiveScanAMD(i64vec4);"
+
+            "uint64_t addInvocationsInclusiveScanAMD(uint64_t);"
+            "u64vec2  addInvocationsInclusiveScanAMD(u64vec2);"
+            "u64vec3  addInvocationsInclusiveScanAMD(u64vec3);"
+            "u64vec4  addInvocationsInclusiveScanAMD(u64vec4);"
+
+            "float16_t addInvocationsInclusiveScanAMD(float16_t);"
+            "f16vec2   addInvocationsInclusiveScanAMD(f16vec2);"
+            "f16vec3   addInvocationsInclusiveScanAMD(f16vec3);"
+            "f16vec4   addInvocationsInclusiveScanAMD(f16vec4);"
+
+            "float addInvocationsExclusiveScanAMD(float);"
+            "vec2  addInvocationsExclusiveScanAMD(vec2);"
+            "vec3  addInvocationsExclusiveScanAMD(vec3);"
+            "vec4  addInvocationsExclusiveScanAMD(vec4);"
+
+            "int   addInvocationsExclusiveScanAMD(int);"
+            "ivec2 addInvocationsExclusiveScanAMD(ivec2);"
+            "ivec3 addInvocationsExclusiveScanAMD(ivec3);"
+            "ivec4 addInvocationsExclusiveScanAMD(ivec4);"
+
+            "uint  addInvocationsExclusiveScanAMD(uint);"
+            "uvec2 addInvocationsExclusiveScanAMD(uvec2);"
+            "uvec3 addInvocationsExclusiveScanAMD(uvec3);"
+            "uvec4 addInvocationsExclusiveScanAMD(uvec4);"
+
+            "double  addInvocationsExclusiveScanAMD(double);"
+            "dvec2   addInvocationsExclusiveScanAMD(dvec2);"
+            "dvec3   addInvocationsExclusiveScanAMD(dvec3);"
+            "dvec4   addInvocationsExclusiveScanAMD(dvec4);"
+
+            "int64_t addInvocationsExclusiveScanAMD(int64_t);"
+            "i64vec2 addInvocationsExclusiveScanAMD(i64vec2);"
+            "i64vec3 addInvocationsExclusiveScanAMD(i64vec3);"
+            "i64vec4 addInvocationsExclusiveScanAMD(i64vec4);"
+
+            "uint64_t addInvocationsExclusiveScanAMD(uint64_t);"
+            "u64vec2  addInvocationsExclusiveScanAMD(u64vec2);"
+            "u64vec3  addInvocationsExclusiveScanAMD(u64vec3);"
+            "u64vec4  addInvocationsExclusiveScanAMD(u64vec4);"
+
+            "float16_t addInvocationsExclusiveScanAMD(float16_t);"
+            "f16vec2   addInvocationsExclusiveScanAMD(f16vec2);"
+            "f16vec3   addInvocationsExclusiveScanAMD(f16vec3);"
+            "f16vec4   addInvocationsExclusiveScanAMD(f16vec4);"
+
+            "float minInvocationsNonUniformAMD(float);"
+            "vec2  minInvocationsNonUniformAMD(vec2);"
+            "vec3  minInvocationsNonUniformAMD(vec3);"
+            "vec4  minInvocationsNonUniformAMD(vec4);"
+
+            "int   minInvocationsNonUniformAMD(int);"
+            "ivec2 minInvocationsNonUniformAMD(ivec2);"
+            "ivec3 minInvocationsNonUniformAMD(ivec3);"
+            "ivec4 minInvocationsNonUniformAMD(ivec4);"
+
+            "uint  minInvocationsNonUniformAMD(uint);"
+            "uvec2 minInvocationsNonUniformAMD(uvec2);"
+            "uvec3 minInvocationsNonUniformAMD(uvec3);"
+            "uvec4 minInvocationsNonUniformAMD(uvec4);"
+
+            "double minInvocationsNonUniformAMD(double);"
+            "dvec2  minInvocationsNonUniformAMD(dvec2);"
+            "dvec3  minInvocationsNonUniformAMD(dvec3);"
+            "dvec4  minInvocationsNonUniformAMD(dvec4);"
+
+            "int64_t minInvocationsNonUniformAMD(int64_t);"
+            "i64vec2 minInvocationsNonUniformAMD(i64vec2);"
+            "i64vec3 minInvocationsNonUniformAMD(i64vec3);"
+            "i64vec4 minInvocationsNonUniformAMD(i64vec4);"
+
+            "uint64_t minInvocationsNonUniformAMD(uint64_t);"
+            "u64vec2  minInvocationsNonUniformAMD(u64vec2);"
+            "u64vec3  minInvocationsNonUniformAMD(u64vec3);"
+            "u64vec4  minInvocationsNonUniformAMD(u64vec4);"
+
+            "float16_t minInvocationsNonUniformAMD(float16_t);"
+            "f16vec2   minInvocationsNonUniformAMD(f16vec2);"
+            "f16vec3   minInvocationsNonUniformAMD(f16vec3);"
+            "f16vec4   minInvocationsNonUniformAMD(f16vec4);"
+
+            "float minInvocationsInclusiveScanNonUniformAMD(float);"
+            "vec2  minInvocationsInclusiveScanNonUniformAMD(vec2);"
+            "vec3  minInvocationsInclusiveScanNonUniformAMD(vec3);"
+            "vec4  minInvocationsInclusiveScanNonUniformAMD(vec4);"
+
+            "int   minInvocationsInclusiveScanNonUniformAMD(int);"
+            "ivec2 minInvocationsInclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 minInvocationsInclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 minInvocationsInclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  minInvocationsInclusiveScanNonUniformAMD(uint);"
+            "uvec2 minInvocationsInclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 minInvocationsInclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 minInvocationsInclusiveScanNonUniformAMD(uvec4);"
+
+            "double minInvocationsInclusiveScanNonUniformAMD(double);"
+            "dvec2  minInvocationsInclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  minInvocationsInclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  minInvocationsInclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t minInvocationsInclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 minInvocationsInclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 minInvocationsInclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 minInvocationsInclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t minInvocationsInclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  minInvocationsInclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  minInvocationsInclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  minInvocationsInclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t minInvocationsInclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   minInvocationsInclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   minInvocationsInclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   minInvocationsInclusiveScanNonUniformAMD(f16vec4);"
+
+            "float minInvocationsExclusiveScanNonUniformAMD(float);"
+            "vec2  minInvocationsExclusiveScanNonUniformAMD(vec2);"
+            "vec3  minInvocationsExclusiveScanNonUniformAMD(vec3);"
+            "vec4  minInvocationsExclusiveScanNonUniformAMD(vec4);"
+
+            "int   minInvocationsExclusiveScanNonUniformAMD(int);"
+            "ivec2 minInvocationsExclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 minInvocationsExclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 minInvocationsExclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  minInvocationsExclusiveScanNonUniformAMD(uint);"
+            "uvec2 minInvocationsExclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 minInvocationsExclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 minInvocationsExclusiveScanNonUniformAMD(uvec4);"
+
+            "double minInvocationsExclusiveScanNonUniformAMD(double);"
+            "dvec2  minInvocationsExclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  minInvocationsExclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  minInvocationsExclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t minInvocationsExclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 minInvocationsExclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 minInvocationsExclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 minInvocationsExclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t minInvocationsExclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  minInvocationsExclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  minInvocationsExclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  minInvocationsExclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t minInvocationsExclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   minInvocationsExclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   minInvocationsExclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   minInvocationsExclusiveScanNonUniformAMD(f16vec4);"
+
+            "float maxInvocationsNonUniformAMD(float);"
+            "vec2  maxInvocationsNonUniformAMD(vec2);"
+            "vec3  maxInvocationsNonUniformAMD(vec3);"
+            "vec4  maxInvocationsNonUniformAMD(vec4);"
+
+            "int   maxInvocationsNonUniformAMD(int);"
+            "ivec2 maxInvocationsNonUniformAMD(ivec2);"
+            "ivec3 maxInvocationsNonUniformAMD(ivec3);"
+            "ivec4 maxInvocationsNonUniformAMD(ivec4);"
+
+            "uint  maxInvocationsNonUniformAMD(uint);"
+            "uvec2 maxInvocationsNonUniformAMD(uvec2);"
+            "uvec3 maxInvocationsNonUniformAMD(uvec3);"
+            "uvec4 maxInvocationsNonUniformAMD(uvec4);"
+
+            "double maxInvocationsNonUniformAMD(double);"
+            "dvec2  maxInvocationsNonUniformAMD(dvec2);"
+            "dvec3  maxInvocationsNonUniformAMD(dvec3);"
+            "dvec4  maxInvocationsNonUniformAMD(dvec4);"
+
+            "int64_t maxInvocationsNonUniformAMD(int64_t);"
+            "i64vec2 maxInvocationsNonUniformAMD(i64vec2);"
+            "i64vec3 maxInvocationsNonUniformAMD(i64vec3);"
+            "i64vec4 maxInvocationsNonUniformAMD(i64vec4);"
+
+            "uint64_t maxInvocationsNonUniformAMD(uint64_t);"
+            "u64vec2  maxInvocationsNonUniformAMD(u64vec2);"
+            "u64vec3  maxInvocationsNonUniformAMD(u64vec3);"
+            "u64vec4  maxInvocationsNonUniformAMD(u64vec4);"
+
+            "float16_t maxInvocationsNonUniformAMD(float16_t);"
+            "f16vec2   maxInvocationsNonUniformAMD(f16vec2);"
+            "f16vec3   maxInvocationsNonUniformAMD(f16vec3);"
+            "f16vec4   maxInvocationsNonUniformAMD(f16vec4);"
+
+            "float maxInvocationsInclusiveScanNonUniformAMD(float);"
+            "vec2  maxInvocationsInclusiveScanNonUniformAMD(vec2);"
+            "vec3  maxInvocationsInclusiveScanNonUniformAMD(vec3);"
+            "vec4  maxInvocationsInclusiveScanNonUniformAMD(vec4);"
+
+            "int   maxInvocationsInclusiveScanNonUniformAMD(int);"
+            "ivec2 maxInvocationsInclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 maxInvocationsInclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 maxInvocationsInclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  maxInvocationsInclusiveScanNonUniformAMD(uint);"
+            "uvec2 maxInvocationsInclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 maxInvocationsInclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 maxInvocationsInclusiveScanNonUniformAMD(uvec4);"
+
+            "double maxInvocationsInclusiveScanNonUniformAMD(double);"
+            "dvec2  maxInvocationsInclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  maxInvocationsInclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  maxInvocationsInclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t maxInvocationsInclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 maxInvocationsInclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 maxInvocationsInclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 maxInvocationsInclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t maxInvocationsInclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  maxInvocationsInclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  maxInvocationsInclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  maxInvocationsInclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t maxInvocationsInclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   maxInvocationsInclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   maxInvocationsInclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   maxInvocationsInclusiveScanNonUniformAMD(f16vec4);"
+
+            "float maxInvocationsExclusiveScanNonUniformAMD(float);"
+            "vec2  maxInvocationsExclusiveScanNonUniformAMD(vec2);"
+            "vec3  maxInvocationsExclusiveScanNonUniformAMD(vec3);"
+            "vec4  maxInvocationsExclusiveScanNonUniformAMD(vec4);"
+
+            "int   maxInvocationsExclusiveScanNonUniformAMD(int);"
+            "ivec2 maxInvocationsExclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 maxInvocationsExclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 maxInvocationsExclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  maxInvocationsExclusiveScanNonUniformAMD(uint);"
+            "uvec2 maxInvocationsExclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 maxInvocationsExclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 maxInvocationsExclusiveScanNonUniformAMD(uvec4);"
+
+            "double maxInvocationsExclusiveScanNonUniformAMD(double);"
+            "dvec2  maxInvocationsExclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  maxInvocationsExclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  maxInvocationsExclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t maxInvocationsExclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 maxInvocationsExclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 maxInvocationsExclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 maxInvocationsExclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t maxInvocationsExclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  maxInvocationsExclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  maxInvocationsExclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  maxInvocationsExclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t maxInvocationsExclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   maxInvocationsExclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   maxInvocationsExclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   maxInvocationsExclusiveScanNonUniformAMD(f16vec4);"
+
+            "float addInvocationsNonUniformAMD(float);"
+            "vec2  addInvocationsNonUniformAMD(vec2);"
+            "vec3  addInvocationsNonUniformAMD(vec3);"
+            "vec4  addInvocationsNonUniformAMD(vec4);"
+
+            "int   addInvocationsNonUniformAMD(int);"
+            "ivec2 addInvocationsNonUniformAMD(ivec2);"
+            "ivec3 addInvocationsNonUniformAMD(ivec3);"
+            "ivec4 addInvocationsNonUniformAMD(ivec4);"
+
+            "uint  addInvocationsNonUniformAMD(uint);"
+            "uvec2 addInvocationsNonUniformAMD(uvec2);"
+            "uvec3 addInvocationsNonUniformAMD(uvec3);"
+            "uvec4 addInvocationsNonUniformAMD(uvec4);"
+
+            "double addInvocationsNonUniformAMD(double);"
+            "dvec2  addInvocationsNonUniformAMD(dvec2);"
+            "dvec3  addInvocationsNonUniformAMD(dvec3);"
+            "dvec4  addInvocationsNonUniformAMD(dvec4);"
+
+            "int64_t addInvocationsNonUniformAMD(int64_t);"
+            "i64vec2 addInvocationsNonUniformAMD(i64vec2);"
+            "i64vec3 addInvocationsNonUniformAMD(i64vec3);"
+            "i64vec4 addInvocationsNonUniformAMD(i64vec4);"
+
+            "uint64_t addInvocationsNonUniformAMD(uint64_t);"
+            "u64vec2  addInvocationsNonUniformAMD(u64vec2);"
+            "u64vec3  addInvocationsNonUniformAMD(u64vec3);"
+            "u64vec4  addInvocationsNonUniformAMD(u64vec4);"
+
+            "float16_t addInvocationsNonUniformAMD(float16_t);"
+            "f16vec2   addInvocationsNonUniformAMD(f16vec2);"
+            "f16vec3   addInvocationsNonUniformAMD(f16vec3);"
+            "f16vec4   addInvocationsNonUniformAMD(f16vec4);"
+
+            "float addInvocationsInclusiveScanNonUniformAMD(float);"
+            "vec2  addInvocationsInclusiveScanNonUniformAMD(vec2);"
+            "vec3  addInvocationsInclusiveScanNonUniformAMD(vec3);"
+            "vec4  addInvocationsInclusiveScanNonUniformAMD(vec4);"
+
+            "int   addInvocationsInclusiveScanNonUniformAMD(int);"
+            "ivec2 addInvocationsInclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 addInvocationsInclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 addInvocationsInclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  addInvocationsInclusiveScanNonUniformAMD(uint);"
+            "uvec2 addInvocationsInclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 addInvocationsInclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 addInvocationsInclusiveScanNonUniformAMD(uvec4);"
+
+            "double addInvocationsInclusiveScanNonUniformAMD(double);"
+            "dvec2  addInvocationsInclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  addInvocationsInclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  addInvocationsInclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t addInvocationsInclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 addInvocationsInclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 addInvocationsInclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 addInvocationsInclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t addInvocationsInclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  addInvocationsInclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  addInvocationsInclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  addInvocationsInclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t addInvocationsInclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   addInvocationsInclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   addInvocationsInclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   addInvocationsInclusiveScanNonUniformAMD(f16vec4);"
+
+            "float addInvocationsExclusiveScanNonUniformAMD(float);"
+            "vec2  addInvocationsExclusiveScanNonUniformAMD(vec2);"
+            "vec3  addInvocationsExclusiveScanNonUniformAMD(vec3);"
+            "vec4  addInvocationsExclusiveScanNonUniformAMD(vec4);"
+
+            "int   addInvocationsExclusiveScanNonUniformAMD(int);"
+            "ivec2 addInvocationsExclusiveScanNonUniformAMD(ivec2);"
+            "ivec3 addInvocationsExclusiveScanNonUniformAMD(ivec3);"
+            "ivec4 addInvocationsExclusiveScanNonUniformAMD(ivec4);"
+
+            "uint  addInvocationsExclusiveScanNonUniformAMD(uint);"
+            "uvec2 addInvocationsExclusiveScanNonUniformAMD(uvec2);"
+            "uvec3 addInvocationsExclusiveScanNonUniformAMD(uvec3);"
+            "uvec4 addInvocationsExclusiveScanNonUniformAMD(uvec4);"
+
+            "double addInvocationsExclusiveScanNonUniformAMD(double);"
+            "dvec2  addInvocationsExclusiveScanNonUniformAMD(dvec2);"
+            "dvec3  addInvocationsExclusiveScanNonUniformAMD(dvec3);"
+            "dvec4  addInvocationsExclusiveScanNonUniformAMD(dvec4);"
+
+            "int64_t addInvocationsExclusiveScanNonUniformAMD(int64_t);"
+            "i64vec2 addInvocationsExclusiveScanNonUniformAMD(i64vec2);"
+            "i64vec3 addInvocationsExclusiveScanNonUniformAMD(i64vec3);"
+            "i64vec4 addInvocationsExclusiveScanNonUniformAMD(i64vec4);"
+
+            "uint64_t addInvocationsExclusiveScanNonUniformAMD(uint64_t);"
+            "u64vec2  addInvocationsExclusiveScanNonUniformAMD(u64vec2);"
+            "u64vec3  addInvocationsExclusiveScanNonUniformAMD(u64vec3);"
+            "u64vec4  addInvocationsExclusiveScanNonUniformAMD(u64vec4);"
+
+            "float16_t addInvocationsExclusiveScanNonUniformAMD(float16_t);"
+            "f16vec2   addInvocationsExclusiveScanNonUniformAMD(f16vec2);"
+            "f16vec3   addInvocationsExclusiveScanNonUniformAMD(f16vec3);"
+            "f16vec4   addInvocationsExclusiveScanNonUniformAMD(f16vec4);"
+
+            "float swizzleInvocationsAMD(float, uvec4);"
+            "vec2  swizzleInvocationsAMD(vec2,  uvec4);"
+            "vec3  swizzleInvocationsAMD(vec3,  uvec4);"
+            "vec4  swizzleInvocationsAMD(vec4,  uvec4);"
+
+            "int   swizzleInvocationsAMD(int,   uvec4);"
+            "ivec2 swizzleInvocationsAMD(ivec2, uvec4);"
+            "ivec3 swizzleInvocationsAMD(ivec3, uvec4);"
+            "ivec4 swizzleInvocationsAMD(ivec4, uvec4);"
+
+            "uint  swizzleInvocationsAMD(uint,  uvec4);"
+            "uvec2 swizzleInvocationsAMD(uvec2, uvec4);"
+            "uvec3 swizzleInvocationsAMD(uvec3, uvec4);"
+            "uvec4 swizzleInvocationsAMD(uvec4, uvec4);"
+
+            "float swizzleInvocationsMaskedAMD(float, uvec3);"
+            "vec2  swizzleInvocationsMaskedAMD(vec2,  uvec3);"
+            "vec3  swizzleInvocationsMaskedAMD(vec3,  uvec3);"
+            "vec4  swizzleInvocationsMaskedAMD(vec4,  uvec3);"
+
+            "int   swizzleInvocationsMaskedAMD(int,   uvec3);"
+            "ivec2 swizzleInvocationsMaskedAMD(ivec2, uvec3);"
+            "ivec3 swizzleInvocationsMaskedAMD(ivec3, uvec3);"
+            "ivec4 swizzleInvocationsMaskedAMD(ivec4, uvec3);"
+
+            "uint  swizzleInvocationsMaskedAMD(uint,  uvec3);"
+            "uvec2 swizzleInvocationsMaskedAMD(uvec2, uvec3);"
+            "uvec3 swizzleInvocationsMaskedAMD(uvec3, uvec3);"
+            "uvec4 swizzleInvocationsMaskedAMD(uvec4, uvec3);"
+
+            "float writeInvocationAMD(float, float, uint);"
+            "vec2  writeInvocationAMD(vec2,  vec2,  uint);"
+            "vec3  writeInvocationAMD(vec3,  vec3,  uint);"
+            "vec4  writeInvocationAMD(vec4,  vec4,  uint);"
+
+            "int   writeInvocationAMD(int,   int,   uint);"
+            "ivec2 writeInvocationAMD(ivec2, ivec2, uint);"
+            "ivec3 writeInvocationAMD(ivec3, ivec3, uint);"
+            "ivec4 writeInvocationAMD(ivec4, ivec4, uint);"
+
+            "uint  writeInvocationAMD(uint,  uint,  uint);"
+            "uvec2 writeInvocationAMD(uvec2, uvec2, uint);"
+            "uvec3 writeInvocationAMD(uvec3, uvec3, uint);"
+            "uvec4 writeInvocationAMD(uvec4, uvec4, uint);"
+
+            "uint mbcntAMD(uint64_t);"
+
+            "\n");
+    }
+
+    // GL_AMD_gcn_shader
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "float cubeFaceIndexAMD(vec3);"
+            "vec2 cubeFaceCoordAMD(vec3);"
+            "uint64_t timeAMD();"
+
+            "\n");
+    }
+
+    // GL_AMD_gpu_shader_half_float
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "float16_t radians(float16_t);"
+            "f16vec2   radians(f16vec2);"
+            "f16vec3   radians(f16vec3);"
+            "f16vec4   radians(f16vec4);"
+
+            "float16_t degrees(float16_t);"
+            "f16vec2   degrees(f16vec2);"
+            "f16vec3   degrees(f16vec3);"
+            "f16vec4   degrees(f16vec4);"
+
+            "float16_t sin(float16_t);"
+            "f16vec2   sin(f16vec2);"
+            "f16vec3   sin(f16vec3);"
+            "f16vec4   sin(f16vec4);"
+
+            "float16_t cos(float16_t);"
+            "f16vec2   cos(f16vec2);"
+            "f16vec3   cos(f16vec3);"
+            "f16vec4   cos(f16vec4);"
+
+            "float16_t tan(float16_t);"
+            "f16vec2   tan(f16vec2);"
+            "f16vec3   tan(f16vec3);"
+            "f16vec4   tan(f16vec4);"
+
+            "float16_t asin(float16_t);"
+            "f16vec2   asin(f16vec2);"
+            "f16vec3   asin(f16vec3);"
+            "f16vec4   asin(f16vec4);"
+
+            "float16_t acos(float16_t);"
+            "f16vec2   acos(f16vec2);"
+            "f16vec3   acos(f16vec3);"
+            "f16vec4   acos(f16vec4);"
+
+            "float16_t atan(float16_t, float16_t);"
+            "f16vec2   atan(f16vec2,   f16vec2);"
+            "f16vec3   atan(f16vec3,   f16vec3);"
+            "f16vec4   atan(f16vec4,   f16vec4);"
+
+            "float16_t atan(float16_t);"
+            "f16vec2   atan(f16vec2);"
+            "f16vec3   atan(f16vec3);"
+            "f16vec4   atan(f16vec4);"
+
+            "float16_t sinh(float16_t);"
+            "f16vec2   sinh(f16vec2);"
+            "f16vec3   sinh(f16vec3);"
+            "f16vec4   sinh(f16vec4);"
+
+            "float16_t cosh(float16_t);"
+            "f16vec2   cosh(f16vec2);"
+            "f16vec3   cosh(f16vec3);"
+            "f16vec4   cosh(f16vec4);"
+
+            "float16_t tanh(float16_t);"
+            "f16vec2   tanh(f16vec2);"
+            "f16vec3   tanh(f16vec3);"
+            "f16vec4   tanh(f16vec4);"
+
+            "float16_t asinh(float16_t);"
+            "f16vec2   asinh(f16vec2);"
+            "f16vec3   asinh(f16vec3);"
+            "f16vec4   asinh(f16vec4);"
+
+            "float16_t acosh(float16_t);"
+            "f16vec2   acosh(f16vec2);"
+            "f16vec3   acosh(f16vec3);"
+            "f16vec4   acosh(f16vec4);"
+
+            "float16_t atanh(float16_t);"
+            "f16vec2   atanh(f16vec2);"
+            "f16vec3   atanh(f16vec3);"
+            "f16vec4   atanh(f16vec4);"
+
+            "float16_t pow(float16_t, float16_t);"
+            "f16vec2   pow(f16vec2,   f16vec2);"
+            "f16vec3   pow(f16vec3,   f16vec3);"
+            "f16vec4   pow(f16vec4,   f16vec4);"
+
+            "float16_t exp(float16_t);"
+            "f16vec2   exp(f16vec2);"
+            "f16vec3   exp(f16vec3);"
+            "f16vec4   exp(f16vec4);"
+
+            "float16_t log(float16_t);"
+            "f16vec2   log(f16vec2);"
+            "f16vec3   log(f16vec3);"
+            "f16vec4   log(f16vec4);"
+
+            "float16_t exp2(float16_t);"
+            "f16vec2   exp2(f16vec2);"
+            "f16vec3   exp2(f16vec3);"
+            "f16vec4   exp2(f16vec4);"
+
+            "float16_t log2(float16_t);"
+            "f16vec2   log2(f16vec2);"
+            "f16vec3   log2(f16vec3);"
+            "f16vec4   log2(f16vec4);"
+
+            "float16_t sqrt(float16_t);"
+            "f16vec2   sqrt(f16vec2);"
+            "f16vec3   sqrt(f16vec3);"
+            "f16vec4   sqrt(f16vec4);"
+
+            "float16_t inversesqrt(float16_t);"
+            "f16vec2   inversesqrt(f16vec2);"
+            "f16vec3   inversesqrt(f16vec3);"
+            "f16vec4   inversesqrt(f16vec4);"
+
+            "float16_t abs(float16_t);"
+            "f16vec2   abs(f16vec2);"
+            "f16vec3   abs(f16vec3);"
+            "f16vec4   abs(f16vec4);"
+
+            "float16_t sign(float16_t);"
+            "f16vec2   sign(f16vec2);"
+            "f16vec3   sign(f16vec3);"
+            "f16vec4   sign(f16vec4);"
+
+            "float16_t floor(float16_t);"
+            "f16vec2   floor(f16vec2);"
+            "f16vec3   floor(f16vec3);"
+            "f16vec4   floor(f16vec4);"
+
+            "float16_t trunc(float16_t);"
+            "f16vec2   trunc(f16vec2);"
+            "f16vec3   trunc(f16vec3);"
+            "f16vec4   trunc(f16vec4);"
+
+            "float16_t round(float16_t);"
+            "f16vec2   round(f16vec2);"
+            "f16vec3   round(f16vec3);"
+            "f16vec4   round(f16vec4);"
+
+            "float16_t roundEven(float16_t);"
+            "f16vec2   roundEven(f16vec2);"
+            "f16vec3   roundEven(f16vec3);"
+            "f16vec4   roundEven(f16vec4);"
+
+            "float16_t ceil(float16_t);"
+            "f16vec2   ceil(f16vec2);"
+            "f16vec3   ceil(f16vec3);"
+            "f16vec4   ceil(f16vec4);"
+
+            "float16_t fract(float16_t);"
+            "f16vec2   fract(f16vec2);"
+            "f16vec3   fract(f16vec3);"
+            "f16vec4   fract(f16vec4);"
+
+            "float16_t mod(float16_t, float16_t);"
+            "f16vec2   mod(f16vec2,   float16_t);"
+            "f16vec3   mod(f16vec3,   float16_t);"
+            "f16vec4   mod(f16vec4,   float16_t);"
+            "f16vec2   mod(f16vec2,   f16vec2);"
+            "f16vec3   mod(f16vec3,   f16vec3);"
+            "f16vec4   mod(f16vec4,   f16vec4);"
+
+            "float16_t modf(float16_t, out float16_t);"
+            "f16vec2   modf(f16vec2,   out f16vec2);"
+            "f16vec3   modf(f16vec3,   out f16vec3);"
+            "f16vec4   modf(f16vec4,   out f16vec4);"
+
+            "float16_t min(float16_t, float16_t);"
+            "f16vec2   min(f16vec2,   float16_t);"
+            "f16vec3   min(f16vec3,   float16_t);"
+            "f16vec4   min(f16vec4,   float16_t);"
+            "f16vec2   min(f16vec2,   f16vec2);"
+            "f16vec3   min(f16vec3,   f16vec3);"
+            "f16vec4   min(f16vec4,   f16vec4);"
+
+            "float16_t max(float16_t, float16_t);"
+            "f16vec2   max(f16vec2,   float16_t);"
+            "f16vec3   max(f16vec3,   float16_t);"
+            "f16vec4   max(f16vec4,   float16_t);"
+            "f16vec2   max(f16vec2,   f16vec2);"
+            "f16vec3   max(f16vec3,   f16vec3);"
+            "f16vec4   max(f16vec4,   f16vec4);"
+
+            "float16_t clamp(float16_t, float16_t, float16_t);"
+            "f16vec2   clamp(f16vec2,   float16_t, float16_t);"
+            "f16vec3   clamp(f16vec3,   float16_t, float16_t);"
+            "f16vec4   clamp(f16vec4,   float16_t, float16_t);"
+            "f16vec2   clamp(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   clamp(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   clamp(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t mix(float16_t, float16_t, float16_t);"
+            "f16vec2   mix(f16vec2,   f16vec2,   float16_t);"
+            "f16vec3   mix(f16vec3,   f16vec3,   float16_t);"
+            "f16vec4   mix(f16vec4,   f16vec4,   float16_t);"
+            "f16vec2   mix(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   mix(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   mix(f16vec4,   f16vec4,   f16vec4);"
+            "float16_t mix(float16_t, float16_t, bool);"
+            "f16vec2   mix(f16vec2,   f16vec2,   bvec2);"
+            "f16vec3   mix(f16vec3,   f16vec3,   bvec3);"
+            "f16vec4   mix(f16vec4,   f16vec4,   bvec4);"
+
+            "float16_t step(float16_t, float16_t);"
+            "f16vec2   step(f16vec2,   f16vec2);"
+            "f16vec3   step(f16vec3,   f16vec3);"
+            "f16vec4   step(f16vec4,   f16vec4);"
+            "f16vec2   step(float16_t, f16vec2);"
+            "f16vec3   step(float16_t, f16vec3);"
+            "f16vec4   step(float16_t, f16vec4);"
+
+            "float16_t smoothstep(float16_t, float16_t, float16_t);"
+            "f16vec2   smoothstep(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   smoothstep(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   smoothstep(f16vec4,   f16vec4,   f16vec4);"
+            "f16vec2   smoothstep(float16_t, float16_t, f16vec2);"
+            "f16vec3   smoothstep(float16_t, float16_t, f16vec3);"
+            "f16vec4   smoothstep(float16_t, float16_t, f16vec4);"
+
+            "bool  isnan(float16_t);"
+            "bvec2 isnan(f16vec2);"
+            "bvec3 isnan(f16vec3);"
+            "bvec4 isnan(f16vec4);"
+
+            "bool  isinf(float16_t);"
+            "bvec2 isinf(f16vec2);"
+            "bvec3 isinf(f16vec3);"
+            "bvec4 isinf(f16vec4);"
+
+            "float16_t fma(float16_t, float16_t, float16_t);"
+            "f16vec2   fma(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   fma(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   fma(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t frexp(float16_t, out int);"
+            "f16vec2   frexp(f16vec2,   out ivec2);"
+            "f16vec3   frexp(f16vec3,   out ivec3);"
+            "f16vec4   frexp(f16vec4,   out ivec4);"
+
+            "float16_t ldexp(float16_t, in int);"
+            "f16vec2   ldexp(f16vec2,   in ivec2);"
+            "f16vec3   ldexp(f16vec3,   in ivec3);"
+            "f16vec4   ldexp(f16vec4,   in ivec4);"
+
+            "uint    packFloat2x16(f16vec2);"
+            "f16vec2 unpackFloat2x16(uint);"
+
+            "float16_t length(float16_t);"
+            "float16_t length(f16vec2);"
+            "float16_t length(f16vec3);"
+            "float16_t length(f16vec4);"
+
+            "float16_t distance(float16_t, float16_t);"
+            "float16_t distance(f16vec2,   f16vec2);"
+            "float16_t distance(f16vec3,   f16vec3);"
+            "float16_t distance(f16vec4,   f16vec4);"
+
+            "float16_t dot(float16_t, float16_t);"
+            "float16_t dot(f16vec2,   f16vec2);"
+            "float16_t dot(f16vec3,   f16vec3);"
+            "float16_t dot(f16vec4,   f16vec4);"
+
+            "f16vec3 cross(f16vec3, f16vec3);"
+
+            "float16_t normalize(float16_t);"
+            "f16vec2   normalize(f16vec2);"
+            "f16vec3   normalize(f16vec3);"
+            "f16vec4   normalize(f16vec4);"
+
+            "float16_t faceforward(float16_t, float16_t, float16_t);"
+            "f16vec2   faceforward(f16vec2,   f16vec2,   f16vec2);"
+            "f16vec3   faceforward(f16vec3,   f16vec3,   f16vec3);"
+            "f16vec4   faceforward(f16vec4,   f16vec4,   f16vec4);"
+
+            "float16_t reflect(float16_t, float16_t);"
+            "f16vec2   reflect(f16vec2,   f16vec2);"
+            "f16vec3   reflect(f16vec3,   f16vec3);"
+            "f16vec4   reflect(f16vec4,   f16vec4);"
+
+            "float16_t refract(float16_t, float16_t, float16_t);"
+            "f16vec2   refract(f16vec2,   f16vec2,   float16_t);"
+            "f16vec3   refract(f16vec3,   f16vec3,   float16_t);"
+            "f16vec4   refract(f16vec4,   f16vec4,   float16_t);"
+
+            "f16mat2   matrixCompMult(f16mat2,   f16mat2);"
+            "f16mat3   matrixCompMult(f16mat3,   f16mat3);"
+            "f16mat4   matrixCompMult(f16mat4,   f16mat4);"
+            "f16mat2x3 matrixCompMult(f16mat2x3, f16mat2x3);"
+            "f16mat2x4 matrixCompMult(f16mat2x4, f16mat2x4);"
+            "f16mat3x2 matrixCompMult(f16mat3x2, f16mat3x2);"
+            "f16mat3x4 matrixCompMult(f16mat3x4, f16mat3x4);"
+            "f16mat4x2 matrixCompMult(f16mat4x2, f16mat4x2);"
+            "f16mat4x3 matrixCompMult(f16mat4x3, f16mat4x3);"
+
+            "f16mat2   outerProduct(f16vec2, f16vec2);"
+            "f16mat3   outerProduct(f16vec3, f16vec3);"
+            "f16mat4   outerProduct(f16vec4, f16vec4);"
+            "f16mat2x3 outerProduct(f16vec3, f16vec2);"
+            "f16mat3x2 outerProduct(f16vec2, f16vec3);"
+            "f16mat2x4 outerProduct(f16vec4, f16vec2);"
+            "f16mat4x2 outerProduct(f16vec2, f16vec4);"
+            "f16mat3x4 outerProduct(f16vec4, f16vec3);"
+            "f16mat4x3 outerProduct(f16vec3, f16vec4);"
+
+            "f16mat2   transpose(f16mat2);"
+            "f16mat3   transpose(f16mat3);"
+            "f16mat4   transpose(f16mat4);"
+            "f16mat2x3 transpose(f16mat3x2);"
+            "f16mat3x2 transpose(f16mat2x3);"
+            "f16mat2x4 transpose(f16mat4x2);"
+            "f16mat4x2 transpose(f16mat2x4);"
+            "f16mat3x4 transpose(f16mat4x3);"
+            "f16mat4x3 transpose(f16mat3x4);"
+
+            "float16_t determinant(f16mat2);"
+            "float16_t determinant(f16mat3);"
+            "float16_t determinant(f16mat4);"
+
+            "f16mat2 inverse(f16mat2);"
+            "f16mat3 inverse(f16mat3);"
+            "f16mat4 inverse(f16mat4);"
+
+            "bvec2 lessThan(f16vec2, f16vec2);"
+            "bvec3 lessThan(f16vec3, f16vec3);"
+            "bvec4 lessThan(f16vec4, f16vec4);"
+
+            "bvec2 lessThanEqual(f16vec2, f16vec2);"
+            "bvec3 lessThanEqual(f16vec3, f16vec3);"
+            "bvec4 lessThanEqual(f16vec4, f16vec4);"
+
+            "bvec2 greaterThan(f16vec2, f16vec2);"
+            "bvec3 greaterThan(f16vec3, f16vec3);"
+            "bvec4 greaterThan(f16vec4, f16vec4);"
+
+            "bvec2 greaterThanEqual(f16vec2, f16vec2);"
+            "bvec3 greaterThanEqual(f16vec3, f16vec3);"
+            "bvec4 greaterThanEqual(f16vec4, f16vec4);"
+
+            "bvec2 equal(f16vec2, f16vec2);"
+            "bvec3 equal(f16vec3, f16vec3);"
+            "bvec4 equal(f16vec4, f16vec4);"
+
+            "bvec2 notEqual(f16vec2, f16vec2);"
+            "bvec3 notEqual(f16vec3, f16vec3);"
+            "bvec4 notEqual(f16vec4, f16vec4);"
+
+            "\n");
+    }
+
+    // GL_AMD_gpu_shader_int16
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "int16_t abs(int16_t);"
+            "i16vec2 abs(i16vec2);"
+            "i16vec3 abs(i16vec3);"
+            "i16vec4 abs(i16vec4);"
+
+            "int16_t sign(int16_t);"
+            "i16vec2 sign(i16vec2);"
+            "i16vec3 sign(i16vec3);"
+            "i16vec4 sign(i16vec4);"
+
+            "int16_t  min(int16_t,  int16_t);"
+            "i16vec2  min(i16vec2,  int16_t);"
+            "i16vec3  min(i16vec3,  int16_t);"
+            "i16vec4  min(i16vec4,  int16_t);"
+            "i16vec2  min(i16vec2,  i16vec2);"
+            "i16vec3  min(i16vec3,  i16vec3);"
+            "i16vec4  min(i16vec4,  i16vec4);"
+            "uint16_t min(uint16_t, uint16_t);"
+            "u16vec2  min(u16vec2,  uint16_t);"
+            "u16vec3  min(u16vec3,  uint16_t);"
+            "u16vec4  min(u16vec4,  uint16_t);"
+            "u16vec2  min(u16vec2,  u16vec2);"
+            "u16vec3  min(u16vec3,  u16vec3);"
+            "u16vec4  min(u16vec4,  u16vec4);"
+
+            "int16_t  max(int16_t,  int16_t);"
+            "i16vec2  max(i16vec2,  int16_t);"
+            "i16vec3  max(i16vec3,  int16_t);"
+            "i16vec4  max(i16vec4,  int16_t);"
+            "i16vec2  max(i16vec2,  i16vec2);"
+            "i16vec3  max(i16vec3,  i16vec3);"
+            "i16vec4  max(i16vec4,  i16vec4);"
+            "uint16_t max(uint16_t, uint16_t);"
+            "u16vec2  max(u16vec2,  uint16_t);"
+            "u16vec3  max(u16vec3,  uint16_t);"
+            "u16vec4  max(u16vec4,  uint16_t);"
+            "u16vec2  max(u16vec2,  u16vec2);"
+            "u16vec3  max(u16vec3,  u16vec3);"
+            "u16vec4  max(u16vec4,  u16vec4);"
+
+            "int16_t  clamp(int16_t,  int16_t,  int16_t);"
+            "i16vec2  clamp(i16vec2,  int16_t,  int16_t);"
+            "i16vec3  clamp(i16vec3,  int16_t,  int16_t);"
+            "i16vec4  clamp(i16vec4,  int16_t,  int16_t);"
+            "i16vec2  clamp(i16vec2,  i16vec2,  i16vec2);"
+            "i16vec3  clamp(i16vec3,  i16vec3,  i16vec3);"
+            "i16vec4  clamp(i16vec4,  i16vec4,  i16vec4);"
+            "uint16_t clamp(uint16_t, uint16_t, uint16_t);"
+            "u16vec2  clamp(u16vec2,  uint16_t, uint16_t);"
+            "u16vec3  clamp(u16vec3,  uint16_t, uint16_t);"
+            "u16vec4  clamp(u16vec4,  uint16_t, uint16_t);"
+            "u16vec2  clamp(u16vec2,  u16vec2,  u16vec2);"
+            "u16vec3  clamp(u16vec3,  u16vec3,  u16vec3);"
+            "u16vec4  clamp(u16vec4,  u16vec4,  u16vec4);"
+
+            "int16_t  mix(int16_t,  int16_t,  bool);"
+            "i16vec2  mix(i16vec2,  i16vec2,  bvec2);"
+            "i16vec3  mix(i16vec3,  i16vec3,  bvec3);"
+            "i16vec4  mix(i16vec4,  i16vec4,  bvec4);"
+            "uint16_t mix(uint16_t, uint16_t, bool);"
+            "u16vec2  mix(u16vec2,  u16vec2,  bvec2);"
+            "u16vec3  mix(u16vec3,  u16vec3,  bvec3);"
+            "u16vec4  mix(u16vec4,  u16vec4,  bvec4);"
+
+            "float16_t frexp(float16_t, out int16_t);"
+            "f16vec2   frexp(f16vec2,   out i16vec2);"
+            "f16vec3   frexp(f16vec3,   out i16vec3);"
+            "f16vec4   frexp(f16vec4,   out i16vec4);"
+
+            "float16_t ldexp(float16_t, int16_t);"
+            "f16vec2   ldexp(f16vec2,   i16vec2);"
+            "f16vec3   ldexp(f16vec3,   i16vec3);"
+            "f16vec4   ldexp(f16vec4,   i16vec4);"
+
+            "int16_t float16BitsToInt16(float16_t);"
+            "i16vec2 float16BitsToInt16(f16vec2);"
+            "i16vec3 float16BitsToInt16(f16vec3);"
+            "i16vec4 float16BitsToInt16(f16vec4);"
+
+            "uint16_t float16BitsToUint16(float16_t);"
+            "u16vec2  float16BitsToUint16(f16vec2);"
+            "u16vec3  float16BitsToUint16(f16vec3);"
+            "u16vec4  float16BitsToUint16(f16vec4);"
+
+            "float16_t int16BitsToFloat16(int16_t);"
+            "f16vec2   int16BitsToFloat16(i16vec2);"
+            "f16vec3   int16BitsToFloat16(i16vec3);"
+            "f16vec4   int16BitsToFloat16(i16vec4);"
+
+            "float16_t uint16BitsToFloat16(uint16_t);"
+            "f16vec2   uint16BitsToFloat16(u16vec2);"
+            "f16vec3   uint16BitsToFloat16(u16vec3);"
+            "f16vec4   uint16BitsToFloat16(u16vec4);"
+
+            "int      packInt2x16(i16vec2);"
+            "uint     packUint2x16(u16vec2);"
+            "int64_t  packInt4x16(i16vec4);"
+            "uint64_t packUint4x16(u16vec4);"
+            "i16vec2  unpackInt2x16(int);"
+            "u16vec2  unpackUint2x16(uint);"
+            "i16vec4  unpackInt4x16(int64_t);"
+            "u16vec4  unpackUint4x16(uint64_t);"
+
+            "bvec2 lessThan(i16vec2, i16vec2);"
+            "bvec3 lessThan(i16vec3, i16vec3);"
+            "bvec4 lessThan(i16vec4, i16vec4);"
+            "bvec2 lessThan(u16vec2, u16vec2);"
+            "bvec3 lessThan(u16vec3, u16vec3);"
+            "bvec4 lessThan(u16vec4, u16vec4);"
+
+            "bvec2 lessThanEqual(i16vec2, i16vec2);"
+            "bvec3 lessThanEqual(i16vec3, i16vec3);"
+            "bvec4 lessThanEqual(i16vec4, i16vec4);"
+            "bvec2 lessThanEqual(u16vec2, u16vec2);"
+            "bvec3 lessThanEqual(u16vec3, u16vec3);"
+            "bvec4 lessThanEqual(u16vec4, u16vec4);"
+
+            "bvec2 greaterThan(i16vec2, i16vec2);"
+            "bvec3 greaterThan(i16vec3, i16vec3);"
+            "bvec4 greaterThan(i16vec4, i16vec4);"
+            "bvec2 greaterThan(u16vec2, u16vec2);"
+            "bvec3 greaterThan(u16vec3, u16vec3);"
+            "bvec4 greaterThan(u16vec4, u16vec4);"
+
+            "bvec2 greaterThanEqual(i16vec2, i16vec2);"
+            "bvec3 greaterThanEqual(i16vec3, i16vec3);"
+            "bvec4 greaterThanEqual(i16vec4, i16vec4);"
+            "bvec2 greaterThanEqual(u16vec2, u16vec2);"
+            "bvec3 greaterThanEqual(u16vec3, u16vec3);"
+            "bvec4 greaterThanEqual(u16vec4, u16vec4);"
+
+            "bvec2 equal(i16vec2, i16vec2);"
+            "bvec3 equal(i16vec3, i16vec3);"
+            "bvec4 equal(i16vec4, i16vec4);"
+            "bvec2 equal(u16vec2, u16vec2);"
+            "bvec3 equal(u16vec3, u16vec3);"
+            "bvec4 equal(u16vec4, u16vec4);"
+
+            "bvec2 notEqual(i16vec2, i16vec2);"
+            "bvec3 notEqual(i16vec3, i16vec3);"
+            "bvec4 notEqual(i16vec4, i16vec4);"
+            "bvec2 notEqual(u16vec2, u16vec2);"
+            "bvec3 notEqual(u16vec3, u16vec3);"
+            "bvec4 notEqual(u16vec4, u16vec4);"
+
+            "\n");
+    }
+#endif
+
+    //============================================================================
+    //
+    // Prototypes for built-in functions seen by vertex shaders only.
+    // (Except legacy lod functions, where it depends which release they are
+    // vertex only.)
+    //
+    //============================================================================
+
+    //
+    // Geometric Functions.
+    //
+    if (IncludeLegacy(version, profile, spvVersion))
+        stageBuiltins[EShLangVertex].append("vec4 ftransform();");
+
+    //
+    // Original-style texture Functions with lod.
+    //
+    TString* s;
+    if (version == 100)
+        s = &stageBuiltins[EShLangVertex];
+    else
+        s = &commonBuiltins;
+    if ((profile == EEsProfile && version == 100) ||
+         profile == ECompatibilityProfile ||
+        (profile == ECoreProfile && version < 420) ||
+         profile == ENoProfile) {
+        if (spvVersion.spv == 0) {
+            s->append(
+                "vec4 texture2DLod(sampler2D, vec2, float);"         // GL_ARB_shader_texture_lod
+                "vec4 texture2DProjLod(sampler2D, vec3, float);"     // GL_ARB_shader_texture_lod
+                "vec4 texture2DProjLod(sampler2D, vec4, float);"     // GL_ARB_shader_texture_lod
+                "vec4 texture3DLod(sampler3D, vec3, float);"         // GL_ARB_shader_texture_lod  // OES_texture_3D, but caught by keyword check
+                "vec4 texture3DProjLod(sampler3D, vec4, float);"     // GL_ARB_shader_texture_lod  // OES_texture_3D, but caught by keyword check
+                "vec4 textureCubeLod(samplerCube, vec3, float);"     // GL_ARB_shader_texture_lod
+
+                "vec4 texture2DArrayLod(sampler2DArray, vec3, float);"      // GL_EXT_texture_array
+
+                "\n");
+        }
+    }
+    if ( profile == ECompatibilityProfile ||
+        (profile == ECoreProfile && version < 420) ||
+         profile == ENoProfile) {
+        if (spvVersion.spv == 0) {
+            s->append(
+                "vec4 texture1DLod(sampler1D, float, float);"                          // GL_ARB_shader_texture_lod
+                "vec4 texture1DProjLod(sampler1D, vec2, float);"                       // GL_ARB_shader_texture_lod
+                "vec4 texture1DProjLod(sampler1D, vec4, float);"                       // GL_ARB_shader_texture_lod
+                "vec4 shadow1DLod(sampler1DShadow, vec3, float);"                      // GL_ARB_shader_texture_lod
+                "vec4 shadow2DLod(sampler2DShadow, vec3, float);"                      // GL_ARB_shader_texture_lod
+                "vec4 shadow1DProjLod(sampler1DShadow, vec4, float);"                  // GL_ARB_shader_texture_lod
+                "vec4 shadow2DProjLod(sampler2DShadow, vec4, float);"                  // GL_ARB_shader_texture_lod
+
+                "vec4 texture1DGradARB(sampler1D, float, float, float);"               // GL_ARB_shader_texture_lod
+                "vec4 texture1DProjGradARB(sampler1D, vec2, float, float);"            // GL_ARB_shader_texture_lod
+                "vec4 texture1DProjGradARB(sampler1D, vec4, float, float);"            // GL_ARB_shader_texture_lod
+                "vec4 texture2DGradARB(sampler2D, vec2, vec2, vec2);"                  // GL_ARB_shader_texture_lod
+                "vec4 texture2DProjGradARB(sampler2D, vec3, vec2, vec2);"              // GL_ARB_shader_texture_lod
+                "vec4 texture2DProjGradARB(sampler2D, vec4, vec2, vec2);"              // GL_ARB_shader_texture_lod
+                "vec4 texture3DGradARB(sampler3D, vec3, vec3, vec3);"                  // GL_ARB_shader_texture_lod
+                "vec4 texture3DProjGradARB(sampler3D, vec4, vec3, vec3);"              // GL_ARB_shader_texture_lod
+                "vec4 textureCubeGradARB(samplerCube, vec3, vec3, vec3);"              // GL_ARB_shader_texture_lod
+                "vec4 shadow1DGradARB(sampler1DShadow, vec3, float, float);"           // GL_ARB_shader_texture_lod
+                "vec4 shadow1DProjGradARB( sampler1DShadow, vec4, float, float);"      // GL_ARB_shader_texture_lod
+                "vec4 shadow2DGradARB(sampler2DShadow, vec3, vec2, vec2);"             // GL_ARB_shader_texture_lod
+                "vec4 shadow2DProjGradARB( sampler2DShadow, vec4, vec2, vec2);"        // GL_ARB_shader_texture_lod
+                "vec4 texture2DRectGradARB(sampler2DRect, vec2, vec2, vec2);"          // GL_ARB_shader_texture_lod
+                "vec4 texture2DRectProjGradARB( sampler2DRect, vec3, vec2, vec2);"     // GL_ARB_shader_texture_lod
+                "vec4 texture2DRectProjGradARB( sampler2DRect, vec4, vec2, vec2);"     // GL_ARB_shader_texture_lod
+                "vec4 shadow2DRectGradARB( sampler2DRectShadow, vec3, vec2, vec2);"    // GL_ARB_shader_texture_lod
+                "vec4 shadow2DRectProjGradARB(sampler2DRectShadow, vec4, vec2, vec2);" // GL_ARB_shader_texture_lod
+
+                "vec4 texture1DArrayLod(sampler1DArray, vec2, float);"                 // GL_EXT_texture_array
+                "vec4 shadow1DArrayLod(sampler1DArrayShadow, vec3, float);"            // GL_EXT_texture_array
+                "vec4 shadow2DArrayLod(sampler2DArrayShadow, vec4, float);"            // GL_EXT_texture_array
+
+                "\n");
+        }
+    }
+
+    if ((profile != EEsProfile && version >= 150) ||
+        (profile == EEsProfile && version >= 310)) {
+        //============================================================================
+        //
+        // Prototypes for built-in functions seen by geometry shaders only.
+        //
+        //============================================================================
+
+        if (profile != EEsProfile && version >= 400) {
+            stageBuiltins[EShLangGeometry].append(
+                "void EmitStreamVertex(int);"
+                "void EndStreamPrimitive(int);"
+                );
+        }
+        stageBuiltins[EShLangGeometry].append(
+            "void EmitVertex();"
+            "void EndPrimitive();"
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Prototypes for all control functions.
+    //
+    //============================================================================
+    bool esBarrier = (profile == EEsProfile && version >= 310);
+    if ((profile != EEsProfile && version >= 150) || esBarrier)
+        stageBuiltins[EShLangTessControl].append(
+            "void barrier();"
+            );
+    if ((profile != EEsProfile && version >= 420) || esBarrier)
+        stageBuiltins[EShLangCompute].append(
+            "void barrier();"
+            );
+    if ((profile != EEsProfile && version >= 130) || esBarrier)
+        commonBuiltins.append(
+            "void memoryBarrier();"
+            );
+    if ((profile != EEsProfile && version >= 420) || esBarrier) {
+        commonBuiltins.append(
+            "void memoryBarrierAtomicCounter();"
+            "void memoryBarrierBuffer();"
+            "void memoryBarrierImage();"
+            );
+        stageBuiltins[EShLangCompute].append(
+            "void memoryBarrierShared();"
+            "void groupMemoryBarrier();"
+            );
+    }
+
+    //============================================================================
+    //
+    // Prototypes for built-in functions seen by fragment shaders only.
+    //
+    //============================================================================
+
+    //
+    // Original-style texture Functions with bias.
+    //
+    if (spvVersion.spv == 0 && (profile != EEsProfile || version == 100)) {
+        stageBuiltins[EShLangFragment].append(
+            "vec4 texture2D(sampler2D, vec2, float);"
+            "vec4 texture2DProj(sampler2D, vec3, float);"
+            "vec4 texture2DProj(sampler2D, vec4, float);"
+            "vec4 texture3D(sampler3D, vec3, float);"        // OES_texture_3D
+            "vec4 texture3DProj(sampler3D, vec4, float);"    // OES_texture_3D
+            "vec4 textureCube(samplerCube, vec3, float);"
+            "vec4 texture2DArray(sampler2DArray, vec3, float);" // GL_EXT_texture_array
+
+            "\n");
+    }
+    if (spvVersion.spv == 0 && (profile != EEsProfile && version > 100)) {
+        stageBuiltins[EShLangFragment].append(
+            "vec4 texture1D(sampler1D, float, float);"
+            "vec4 texture1DProj(sampler1D, vec2, float);"
+            "vec4 texture1DProj(sampler1D, vec4, float);"
+            "vec4 shadow1D(sampler1DShadow, vec3, float);"
+            "vec4 shadow2D(sampler2DShadow, vec3, float);"
+            "vec4 shadow1DProj(sampler1DShadow, vec4, float);"
+            "vec4 shadow2DProj(sampler2DShadow, vec4, float);"
+            "vec4 texture1DArray(sampler1DArray, vec2, float);"      // GL_EXT_texture_array
+            "vec4 shadow1DArray(sampler1DArrayShadow, vec3, float);" // GL_EXT_texture_array
+            "vec4 shadow2DArray(sampler2DArrayShadow, vec4, float);" // GL_EXT_texture_array
+            "\n");
+    }
+    if (spvVersion.spv == 0 && profile == EEsProfile) {
+        stageBuiltins[EShLangFragment].append(
+            "vec4 texture2DLodEXT(sampler2D, vec2, float);"      // GL_EXT_shader_texture_lod
+            "vec4 texture2DProjLodEXT(sampler2D, vec3, float);"  // GL_EXT_shader_texture_lod
+            "vec4 texture2DProjLodEXT(sampler2D, vec4, float);"  // GL_EXT_shader_texture_lod
+            "vec4 textureCubeLodEXT(samplerCube, vec3, float);"  // GL_EXT_shader_texture_lod
+
+            "\n");
+    }
+
+    stageBuiltins[EShLangFragment].append(
+        "float dFdx(float p);"
+        "vec2  dFdx(vec2  p);"
+        "vec3  dFdx(vec3  p);"
+        "vec4  dFdx(vec4  p);"
+
+        "float dFdy(float p);"
+        "vec2  dFdy(vec2  p);"
+        "vec3  dFdy(vec3  p);"
+        "vec4  dFdy(vec4  p);"
+
+        "float fwidth(float p);"
+        "vec2  fwidth(vec2  p);"
+        "vec3  fwidth(vec3  p);"
+        "vec4  fwidth(vec4  p);"
+
+        "\n");
+
+    // GL_ARB_derivative_control
+    if (profile != EEsProfile && version >= 400) {
+        stageBuiltins[EShLangFragment].append(
+            "float dFdxFine(float p);"
+            "vec2  dFdxFine(vec2  p);"
+            "vec3  dFdxFine(vec3  p);"
+            "vec4  dFdxFine(vec4  p);"
+
+            "float dFdyFine(float p);"
+            "vec2  dFdyFine(vec2  p);"
+            "vec3  dFdyFine(vec3  p);"
+            "vec4  dFdyFine(vec4  p);"
+
+            "float fwidthFine(float p);"
+            "vec2  fwidthFine(vec2  p);"
+            "vec3  fwidthFine(vec3  p);"
+            "vec4  fwidthFine(vec4  p);"
+
+            "\n");
+
+        stageBuiltins[EShLangFragment].append(
+            "float dFdxCoarse(float p);"
+            "vec2  dFdxCoarse(vec2  p);"
+            "vec3  dFdxCoarse(vec3  p);"
+            "vec4  dFdxCoarse(vec4  p);"
+
+            "float dFdyCoarse(float p);"
+            "vec2  dFdyCoarse(vec2  p);"
+            "vec3  dFdyCoarse(vec3  p);"
+            "vec4  dFdyCoarse(vec4  p);"
+
+            "float fwidthCoarse(float p);"
+            "vec2  fwidthCoarse(vec2  p);"
+            "vec3  fwidthCoarse(vec3  p);"
+            "vec4  fwidthCoarse(vec4  p);"
+
+            "\n");
+    }
+
+    // GL_OES_shader_multisample_interpolation
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 400)) {
+        stageBuiltins[EShLangFragment].append(
+            "float interpolateAtCentroid(float);"
+            "vec2  interpolateAtCentroid(vec2);"
+            "vec3  interpolateAtCentroid(vec3);"
+            "vec4  interpolateAtCentroid(vec4);"
+
+            "float interpolateAtSample(float, int);"
+            "vec2  interpolateAtSample(vec2,  int);"
+            "vec3  interpolateAtSample(vec3,  int);"
+            "vec4  interpolateAtSample(vec4,  int);"
+
+            "float interpolateAtOffset(float, vec2);"
+            "vec2  interpolateAtOffset(vec2,  vec2);"
+            "vec3  interpolateAtOffset(vec3,  vec2);"
+            "vec4  interpolateAtOffset(vec4,  vec2);"
+
+            "\n");
+    }
+
+#ifdef AMD_EXTENSIONS
+    // GL_AMD_shader_explicit_vertex_parameter
+    if (profile != EEsProfile && version >= 450) {
+        stageBuiltins[EShLangFragment].append(
+            "float interpolateAtVertexAMD(float, uint);"
+            "vec2  interpolateAtVertexAMD(vec2,  uint);"
+            "vec3  interpolateAtVertexAMD(vec3,  uint);"
+            "vec4  interpolateAtVertexAMD(vec4,  uint);"
+
+            "int   interpolateAtVertexAMD(int,   uint);"
+            "ivec2 interpolateAtVertexAMD(ivec2, uint);"
+            "ivec3 interpolateAtVertexAMD(ivec3, uint);"
+            "ivec4 interpolateAtVertexAMD(ivec4, uint);"
+
+            "uint  interpolateAtVertexAMD(uint,  uint);"
+            "uvec2 interpolateAtVertexAMD(uvec2, uint);"
+            "uvec3 interpolateAtVertexAMD(uvec3, uint);"
+            "uvec4 interpolateAtVertexAMD(uvec4, uint);"
+
+            "float16_t interpolateAtVertexAMD(float16_t, uint);"
+            "f16vec2   interpolateAtVertexAMD(f16vec2,   uint);"
+            "f16vec3   interpolateAtVertexAMD(f16vec3,   uint);"
+            "f16vec4   interpolateAtVertexAMD(f16vec4,   uint);"
+
+            "\n");
+    }
+
+    // GL_AMD_gpu_shader_half_float
+    if (profile != EEsProfile && version >= 450) {
+        stageBuiltins[EShLangFragment].append(
+            "float16_t dFdx(float16_t);"
+            "f16vec2   dFdx(f16vec2);"
+            "f16vec3   dFdx(f16vec3);"
+            "f16vec4   dFdx(f16vec4);"
+
+            "float16_t dFdy(float16_t);"
+            "f16vec2   dFdy(f16vec2);"
+            "f16vec3   dFdy(f16vec3);"
+            "f16vec4   dFdy(f16vec4);"
+
+            "float16_t dFdxFine(float16_t);"
+            "f16vec2   dFdxFine(f16vec2);"
+            "f16vec3   dFdxFine(f16vec3);"
+            "f16vec4   dFdxFine(f16vec4);"
+
+            "float16_t dFdyFine(float16_t);"
+            "f16vec2   dFdyFine(f16vec2);"
+            "f16vec3   dFdyFine(f16vec3);"
+            "f16vec4   dFdyFine(f16vec4);"
+
+            "float16_t dFdxCoarse(float16_t);"
+            "f16vec2   dFdxCoarse(f16vec2);"
+            "f16vec3   dFdxCoarse(f16vec3);"
+            "f16vec4   dFdxCoarse(f16vec4);"
+
+            "float16_t dFdyCoarse(float16_t);"
+            "f16vec2   dFdyCoarse(f16vec2);"
+            "f16vec3   dFdyCoarse(f16vec3);"
+            "f16vec4   dFdyCoarse(f16vec4);"
+
+            "float16_t fwidth(float16_t);"
+            "f16vec2   fwidth(f16vec2);"
+            "f16vec3   fwidth(f16vec3);"
+            "f16vec4   fwidth(f16vec4);"
+
+            "float16_t fwidthFine(float16_t);"
+            "f16vec2   fwidthFine(f16vec2);"
+            "f16vec3   fwidthFine(f16vec3);"
+            "f16vec4   fwidthFine(f16vec4);"
+
+            "float16_t fwidthCoarse(float16_t);"
+            "f16vec2   fwidthCoarse(f16vec2);"
+            "f16vec3   fwidthCoarse(f16vec3);"
+            "f16vec4   fwidthCoarse(f16vec4);"
+
+            "float16_t interpolateAtCentroid(float16_t);"
+            "f16vec2   interpolateAtCentroid(f16vec2);"
+            "f16vec3   interpolateAtCentroid(f16vec3);"
+            "f16vec4   interpolateAtCentroid(f16vec4);"
+
+            "float16_t interpolateAtSample(float16_t, int);"
+            "f16vec2   interpolateAtSample(f16vec2,   int);"
+            "f16vec3   interpolateAtSample(f16vec3,   int);"
+            "f16vec4   interpolateAtSample(f16vec4,   int);"
+
+            "float16_t interpolateAtOffset(float16_t, f16vec2);"
+            "f16vec2   interpolateAtOffset(f16vec2,   f16vec2);"
+            "f16vec3   interpolateAtOffset(f16vec3,   f16vec2);"
+            "f16vec4   interpolateAtOffset(f16vec4,   f16vec2);"
+
+            "\n");
+    }
+#endif
+
+    //============================================================================
+    //
+    // Standard Uniforms
+    //
+    //============================================================================
+
+    //
+    // Depth range in window coordinates, p. 33
+    //
+    if (spvVersion.spv == 0) {
+        commonBuiltins.append(
+            "struct gl_DepthRangeParameters {"
+            );
+        if (profile == EEsProfile) {
+            commonBuiltins.append(
+                "highp float near;"   // n
+                "highp float far;"    // f
+                "highp float diff;"   // f - n
+                );
+        } else {
+            commonBuiltins.append(
+                "float near;"  // n
+                "float far;"   // f
+                "float diff;"  // f - n
+                );
+        }
+
+        commonBuiltins.append(
+            "};"
+            "uniform gl_DepthRangeParameters gl_DepthRange;"
+            "\n");
+    }
+
+    if (spvVersion.spv == 0 && IncludeLegacy(version, profile, spvVersion)) {
+        //
+        // Matrix state. p. 31, 32, 37, 39, 40.
+        //
+        commonBuiltins.append(
+            "uniform mat4  gl_ModelViewMatrix;"
+            "uniform mat4  gl_ProjectionMatrix;"
+            "uniform mat4  gl_ModelViewProjectionMatrix;"
+
+            //
+            // Derived matrix state that provides inverse and transposed versions
+            // of the matrices above.
+            //
+            "uniform mat3  gl_NormalMatrix;"
+
+            "uniform mat4  gl_ModelViewMatrixInverse;"
+            "uniform mat4  gl_ProjectionMatrixInverse;"
+            "uniform mat4  gl_ModelViewProjectionMatrixInverse;"
+
+            "uniform mat4  gl_ModelViewMatrixTranspose;"
+            "uniform mat4  gl_ProjectionMatrixTranspose;"
+            "uniform mat4  gl_ModelViewProjectionMatrixTranspose;"
+
+            "uniform mat4  gl_ModelViewMatrixInverseTranspose;"
+            "uniform mat4  gl_ProjectionMatrixInverseTranspose;"
+            "uniform mat4  gl_ModelViewProjectionMatrixInverseTranspose;"
+
+            //
+            // Normal scaling p. 39.
+            //
+            "uniform float gl_NormalScale;"
+
+            //
+            // Point Size, p. 66, 67.
+            //
+            "struct gl_PointParameters {"
+                "float size;"
+                "float sizeMin;"
+                "float sizeMax;"
+                "float fadeThresholdSize;"
+                "float distanceConstantAttenuation;"
+                "float distanceLinearAttenuation;"
+                "float distanceQuadraticAttenuation;"
+            "};"
+
+            "uniform gl_PointParameters gl_Point;"
+
+            //
+            // Material State p. 50, 55.
+            //
+            "struct gl_MaterialParameters {"
+                "vec4  emission;"    // Ecm
+                "vec4  ambient;"     // Acm
+                "vec4  diffuse;"     // Dcm
+                "vec4  specular;"    // Scm
+                "float shininess;"   // Srm
+            "};"
+            "uniform gl_MaterialParameters  gl_FrontMaterial;"
+            "uniform gl_MaterialParameters  gl_BackMaterial;"
+
+            //
+            // Light State p 50, 53, 55.
+            //
+            "struct gl_LightSourceParameters {"
+                "vec4  ambient;"             // Acli
+                "vec4  diffuse;"             // Dcli
+                "vec4  specular;"            // Scli
+                "vec4  position;"            // Ppli
+                "vec4  halfVector;"          // Derived: Hi
+                "vec3  spotDirection;"       // Sdli
+                "float spotExponent;"        // Srli
+                "float spotCutoff;"          // Crli
+                                                        // (range: [0.0,90.0], 180.0)
+                "float spotCosCutoff;"       // Derived: cos(Crli)
+                                                        // (range: [1.0,0.0],-1.0)
+                "float constantAttenuation;" // K0
+                "float linearAttenuation;"   // K1
+                "float quadraticAttenuation;"// K2
+            "};"
+
+            "struct gl_LightModelParameters {"
+                "vec4  ambient;"       // Acs
+            "};"
+
+            "uniform gl_LightModelParameters  gl_LightModel;"
+
+            //
+            // Derived state from products of light and material.
+            //
+            "struct gl_LightModelProducts {"
+                "vec4  sceneColor;"     // Derived. Ecm + Acm * Acs
+            "};"
+
+            "uniform gl_LightModelProducts gl_FrontLightModelProduct;"
+            "uniform gl_LightModelProducts gl_BackLightModelProduct;"
+
+            "struct gl_LightProducts {"
+                "vec4  ambient;"        // Acm * Acli
+                "vec4  diffuse;"        // Dcm * Dcli
+                "vec4  specular;"       // Scm * Scli
+            "};"
+
+            //
+            // Fog p. 161
+            //
+            "struct gl_FogParameters {"
+                "vec4  color;"
+                "float density;"
+                "float start;"
+                "float end;"
+                "float scale;"   //  1 / (gl_FogEnd - gl_FogStart)
+            "};"
+
+            "uniform gl_FogParameters gl_Fog;"
+
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the compute shader.
+    //
+    //============================================================================
+
+    if ((profile != EEsProfile && version >= 420) ||
+        (profile == EEsProfile && version >= 310)) {
+        stageBuiltins[EShLangCompute].append(
+            "in    highp uvec3 gl_NumWorkGroups;"
+            "const highp uvec3 gl_WorkGroupSize = uvec3(1,1,1);"
+
+            "in highp uvec3 gl_WorkGroupID;"
+            "in highp uvec3 gl_LocalInvocationID;"
+
+            "in highp uvec3 gl_GlobalInvocationID;"
+            "in highp uint gl_LocalInvocationIndex;"
+
+            "\n");
+    }
+
+    if ((profile != EEsProfile && version >= 140) ||
+        (profile == EEsProfile && version >= 310)) {
+        stageBuiltins[EShLangCompute].append(
+            "in highp int gl_DeviceIndex;"     // GL_EXT_device_group
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the vertex shader.
+    //
+    //============================================================================
+
+    if (profile != EEsProfile) {
+        if (version < 130) {
+            stageBuiltins[EShLangVertex].append(
+                "attribute vec4  gl_Color;"
+                "attribute vec4  gl_SecondaryColor;"
+                "attribute vec3  gl_Normal;"
+                "attribute vec4  gl_Vertex;"
+                "attribute vec4  gl_MultiTexCoord0;"
+                "attribute vec4  gl_MultiTexCoord1;"
+                "attribute vec4  gl_MultiTexCoord2;"
+                "attribute vec4  gl_MultiTexCoord3;"
+                "attribute vec4  gl_MultiTexCoord4;"
+                "attribute vec4  gl_MultiTexCoord5;"
+                "attribute vec4  gl_MultiTexCoord6;"
+                "attribute vec4  gl_MultiTexCoord7;"
+                "attribute float gl_FogCoord;"
+                "\n");
+        } else if (IncludeLegacy(version, profile, spvVersion)) {
+            stageBuiltins[EShLangVertex].append(
+                "in vec4  gl_Color;"
+                "in vec4  gl_SecondaryColor;"
+                "in vec3  gl_Normal;"
+                "in vec4  gl_Vertex;"
+                "in vec4  gl_MultiTexCoord0;"
+                "in vec4  gl_MultiTexCoord1;"
+                "in vec4  gl_MultiTexCoord2;"
+                "in vec4  gl_MultiTexCoord3;"
+                "in vec4  gl_MultiTexCoord4;"
+                "in vec4  gl_MultiTexCoord5;"
+                "in vec4  gl_MultiTexCoord6;"
+                "in vec4  gl_MultiTexCoord7;"
+                "in float gl_FogCoord;"
+                "\n");
+        }
+
+        if (version < 150) {
+            if (version < 130) {
+                stageBuiltins[EShLangVertex].append(
+                    "        vec4  gl_ClipVertex;"       // needs qualifier fixed later
+                    "varying vec4  gl_FrontColor;"
+                    "varying vec4  gl_BackColor;"
+                    "varying vec4  gl_FrontSecondaryColor;"
+                    "varying vec4  gl_BackSecondaryColor;"
+                    "varying vec4  gl_TexCoord[];"
+                    "varying float gl_FogFragCoord;"
+                    "\n");
+            } else if (IncludeLegacy(version, profile, spvVersion)) {
+                stageBuiltins[EShLangVertex].append(
+                    "    vec4  gl_ClipVertex;"       // needs qualifier fixed later
+                    "out vec4  gl_FrontColor;"
+                    "out vec4  gl_BackColor;"
+                    "out vec4  gl_FrontSecondaryColor;"
+                    "out vec4  gl_BackSecondaryColor;"
+                    "out vec4  gl_TexCoord[];"
+                    "out float gl_FogFragCoord;"
+                    "\n");
+            }
+            stageBuiltins[EShLangVertex].append(
+                "vec4 gl_Position;"   // needs qualifier fixed later
+                "float gl_PointSize;" // needs qualifier fixed later
+                );
+
+            if (version == 130 || version == 140)
+                stageBuiltins[EShLangVertex].append(
+                    "out float gl_ClipDistance[];"
+                    );
+        } else {
+            // version >= 150
+            stageBuiltins[EShLangVertex].append(
+                "out gl_PerVertex {"
+                    "vec4 gl_Position;"     // needs qualifier fixed later
+                    "float gl_PointSize;"   // needs qualifier fixed later
+                    "float gl_ClipDistance[];"
+                    );
+            if (IncludeLegacy(version, profile, spvVersion))
+                stageBuiltins[EShLangVertex].append(
+                    "vec4 gl_ClipVertex;"   // needs qualifier fixed later
+                    "vec4 gl_FrontColor;"
+                    "vec4 gl_BackColor;"
+                    "vec4 gl_FrontSecondaryColor;"
+                    "vec4 gl_BackSecondaryColor;"
+                    "vec4 gl_TexCoord[];"
+                    "float gl_FogFragCoord;"
+                    );
+            if (version >= 450)
+                stageBuiltins[EShLangVertex].append(
+                    "float gl_CullDistance[];"
+                    );
+            stageBuiltins[EShLangVertex].append(
+                "};"
+                "\n");
+        }
+        if (version >= 130 && spvVersion.vulkan == 0)
+            stageBuiltins[EShLangVertex].append(
+                "int gl_VertexID;"            // needs qualifier fixed later
+                );
+        if (version >= 140 && spvVersion.vulkan == 0)
+            stageBuiltins[EShLangVertex].append(
+                "int gl_InstanceID;"          // needs qualifier fixed later
+                );
+        if (spvVersion.vulkan >= 100 && version >= 140)
+            stageBuiltins[EShLangVertex].append(
+                "in int gl_VertexIndex;"
+                "in int gl_InstanceIndex;"
+                );
+        if (version >= 440) {
+            stageBuiltins[EShLangVertex].append(
+                "in int gl_BaseVertexARB;"
+                "in int gl_BaseInstanceARB;"
+                "in int gl_DrawIDARB;"
+                );
+        }
+
+#ifdef NV_EXTENSIONS
+        if (version >= 450)
+            stageBuiltins[EShLangVertex].append(
+                "out int gl_ViewportIndex;"
+                "out int gl_Layer;"
+                "out int gl_ViewportMask[];"             // GL_NV_viewport_array2
+                "out int gl_SecondaryViewportMaskNV[];"  // GL_NV_stereo_view_rendering
+                "out vec4 gl_SecondaryPositionNV;"       // GL_NV_stereo_view_rendering
+                "out vec4 gl_PositionPerViewNV[];"       // GL_NVX_multiview_per_view_attributes
+                "out int  gl_ViewportMaskPerViewNV[];"   // GL_NVX_multiview_per_view_attributes
+                );
+#endif
+
+    } else {
+        // ES profile
+        if (version == 100) {
+            stageBuiltins[EShLangVertex].append(
+                "highp   vec4  gl_Position;"  // needs qualifier fixed later
+                "mediump float gl_PointSize;" // needs qualifier fixed later
+                );
+        } else {
+            if (spvVersion.vulkan == 0)
+                stageBuiltins[EShLangVertex].append(
+                    "in highp int gl_VertexID;"      // needs qualifier fixed later
+                    "in highp int gl_InstanceID;"    // needs qualifier fixed later
+                    );
+            if (spvVersion.vulkan >= 100)
+                stageBuiltins[EShLangVertex].append(
+                    "in highp int gl_VertexIndex;"
+                    "in highp int gl_InstanceIndex;"
+                    );
+            if (version < 310)
+                stageBuiltins[EShLangVertex].append(
+                    "highp vec4  gl_Position;"    // needs qualifier fixed later
+                    "highp float gl_PointSize;"   // needs qualifier fixed later
+                    );
+            else
+                stageBuiltins[EShLangVertex].append(
+                    "out gl_PerVertex {"
+                        "highp vec4  gl_Position;"    // needs qualifier fixed later
+                        "highp float gl_PointSize;"   // needs qualifier fixed later
+                    "};"
+                    );
+        }
+    }
+
+    if ((profile != EEsProfile && version >= 140) ||
+        (profile == EEsProfile && version >= 310)) {
+        stageBuiltins[EShLangVertex].append(
+            "in highp int gl_DeviceIndex;"     // GL_EXT_device_group
+            "in highp int gl_ViewIndex;"       // GL_EXT_multiview
+            "\n");
+    }
+
+
+    //============================================================================
+    //
+    // Define the interface to the geometry shader.
+    //
+    //============================================================================
+
+    if (profile == ECoreProfile || profile == ECompatibilityProfile) {
+        stageBuiltins[EShLangGeometry].append(
+            "in gl_PerVertex {"
+                "vec4 gl_Position;"
+                "float gl_PointSize;"
+                "float gl_ClipDistance[];"
+                );
+        if (profile == ECompatibilityProfile)
+            stageBuiltins[EShLangGeometry].append(
+                "vec4 gl_ClipVertex;"
+                "vec4 gl_FrontColor;"
+                "vec4 gl_BackColor;"
+                "vec4 gl_FrontSecondaryColor;"
+                "vec4 gl_BackSecondaryColor;"
+                "vec4 gl_TexCoord[];"
+                "float gl_FogFragCoord;"
+                );
+        if (version >= 450)
+            stageBuiltins[EShLangGeometry].append(
+                "float gl_CullDistance[];"
+#ifdef NV_EXTENSIONS
+                "vec4 gl_SecondaryPositionNV;"   // GL_NV_stereo_view_rendering
+                "vec4 gl_PositionPerViewNV[];"   // GL_NVX_multiview_per_view_attributes
+#endif
+                );
+        stageBuiltins[EShLangGeometry].append(
+            "} gl_in[];"
+
+            "in int gl_PrimitiveIDIn;"
+            "out gl_PerVertex {"
+                "vec4 gl_Position;"
+                "float gl_PointSize;"
+                "float gl_ClipDistance[];"
+                "\n");
+        if (profile == ECompatibilityProfile && version >= 400)
+            stageBuiltins[EShLangGeometry].append(
+                "vec4 gl_ClipVertex;"
+                "vec4 gl_FrontColor;"
+                "vec4 gl_BackColor;"
+                "vec4 gl_FrontSecondaryColor;"
+                "vec4 gl_BackSecondaryColor;"
+                "vec4 gl_TexCoord[];"
+                "float gl_FogFragCoord;"
+                );
+        if (version >= 450)
+            stageBuiltins[EShLangGeometry].append(
+                "float gl_CullDistance[];"
+                );
+        stageBuiltins[EShLangGeometry].append(
+            "};"
+
+            "out int gl_PrimitiveID;"
+            "out int gl_Layer;");
+
+        if (profile == ECompatibilityProfile && version < 400)
+            stageBuiltins[EShLangGeometry].append(
+            "out vec4 gl_ClipVertex;"
+            );
+
+        if (version >= 400)
+            stageBuiltins[EShLangGeometry].append(
+            "in int gl_InvocationID;"
+            );
+        // GL_ARB_viewport_array
+        if (version >= 150)
+            stageBuiltins[EShLangGeometry].append(
+            "out int gl_ViewportIndex;"
+            );
+
+#ifdef NV_EXTENSIONS
+        if (version >= 450)
+            stageBuiltins[EShLangGeometry].append(
+                "out int gl_ViewportMask[];"               // GL_NV_viewport_array2
+                "out int gl_SecondaryViewportMaskNV[];"    // GL_NV_stereo_view_rendering
+                "out vec4 gl_SecondaryPositionNV;"         // GL_NV_stereo_view_rendering
+                "out vec4 gl_PositionPerViewNV[];"         // GL_NVX_multiview_per_view_attributes
+                "out int  gl_ViewportMaskPerViewNV[];"     // GL_NVX_multiview_per_view_attributes
+            );
+#endif
+
+        stageBuiltins[EShLangGeometry].append("\n");
+    } else if (profile == EEsProfile && version >= 310) {
+        stageBuiltins[EShLangGeometry].append(
+            "in gl_PerVertex {"
+                "highp vec4 gl_Position;"
+                "highp float gl_PointSize;"
+            "} gl_in[];"
+            "\n"
+            "in highp int gl_PrimitiveIDIn;"
+            "in highp int gl_InvocationID;"
+            "\n"
+            "out gl_PerVertex {"
+                "highp vec4 gl_Position;"
+                "highp float gl_PointSize;"
+            "};"
+            "\n"
+            "out highp int gl_PrimitiveID;"
+            "out highp int gl_Layer;"
+            "\n"
+            );
+    }
+
+    if ((profile != EEsProfile && version >= 140) ||
+        (profile == EEsProfile && version >= 310)) {
+        stageBuiltins[EShLangGeometry].append(
+            "in highp int gl_DeviceIndex;"     // GL_EXT_device_group
+            "in highp int gl_ViewIndex;"       // GL_EXT_multiview
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the tessellation control shader.
+    //
+    //============================================================================
+
+    if (profile != EEsProfile && version >= 150) {
+        // Note:  "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below,
+        // as it depends on the resource sizing of gl_MaxPatchVertices.
+
+        stageBuiltins[EShLangTessControl].append(
+            "in int gl_PatchVerticesIn;"
+            "in int gl_PrimitiveID;"
+            "in int gl_InvocationID;"
+
+            "out gl_PerVertex {"
+                "vec4 gl_Position;"
+                "float gl_PointSize;"
+                "float gl_ClipDistance[];"
+                );
+        if (profile == ECompatibilityProfile)
+            stageBuiltins[EShLangTessControl].append(
+                "vec4 gl_ClipVertex;"
+                "vec4 gl_FrontColor;"
+                "vec4 gl_BackColor;"
+                "vec4 gl_FrontSecondaryColor;"
+                "vec4 gl_BackSecondaryColor;"
+                "vec4 gl_TexCoord[];"
+                "float gl_FogFragCoord;"
+                );
+        if (version >= 450)
+            stageBuiltins[EShLangTessControl].append(
+                "float gl_CullDistance[];"
+#ifdef NV_EXTENSIONS
+                "int  gl_ViewportIndex;"
+                "int  gl_Layer;"
+                "int  gl_ViewportMask[];"             // GL_NV_viewport_array2
+                "vec4 gl_SecondaryPositionNV;"        // GL_NV_stereo_view_rendering
+                "int  gl_SecondaryViewportMaskNV[];"  // GL_NV_stereo_view_rendering
+                "vec4 gl_PositionPerViewNV[];"        // GL_NVX_multiview_per_view_attributes
+                "int  gl_ViewportMaskPerViewNV[];"    // GL_NVX_multiview_per_view_attributes
+#endif
+                );
+        stageBuiltins[EShLangTessControl].append(
+            "} gl_out[];"
+
+            "patch out float gl_TessLevelOuter[4];"
+            "patch out float gl_TessLevelInner[2];"
+            "\n");
+    } else {
+        // Note:  "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below,
+        // as it depends on the resource sizing of gl_MaxPatchVertices.
+
+        stageBuiltins[EShLangTessControl].append(
+            "in highp int gl_PatchVerticesIn;"
+            "in highp int gl_PrimitiveID;"
+            "in highp int gl_InvocationID;"
+
+            "out gl_PerVertex {"
+                "highp vec4 gl_Position;"
+                "highp float gl_PointSize;"
+                );
+        stageBuiltins[EShLangTessControl].append(
+            "} gl_out[];"
+
+            "patch out highp float gl_TessLevelOuter[4];"
+            "patch out highp float gl_TessLevelInner[2];"
+            "patch out highp vec4 gl_BoundingBoxOES[2];"
+            "\n");
+    }
+
+    if ((profile != EEsProfile && version >= 140) ||
+        (profile == EEsProfile && version >= 310)) {
+        stageBuiltins[EShLangTessControl].append(
+            "in highp int gl_DeviceIndex;"     // GL_EXT_device_group
+            "in highp int gl_ViewIndex;"       // GL_EXT_multiview
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the tessellation evaluation shader.
+    //
+    //============================================================================
+
+    if (profile != EEsProfile && version >= 150) {
+        // Note:  "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below,
+        // as it depends on the resource sizing of gl_MaxPatchVertices.
+
+        stageBuiltins[EShLangTessEvaluation].append(
+            "in int gl_PatchVerticesIn;"
+            "in int gl_PrimitiveID;"
+            "in vec3 gl_TessCoord;"
+
+            "patch in float gl_TessLevelOuter[4];"
+            "patch in float gl_TessLevelInner[2];"
+
+            "out gl_PerVertex {"
+                "vec4 gl_Position;"
+                "float gl_PointSize;"
+                "float gl_ClipDistance[];"
+            );
+        if (version >= 400 && profile == ECompatibilityProfile)
+            stageBuiltins[EShLangTessEvaluation].append(
+                "vec4 gl_ClipVertex;"
+                "vec4 gl_FrontColor;"
+                "vec4 gl_BackColor;"
+                "vec4 gl_FrontSecondaryColor;"
+                "vec4 gl_BackSecondaryColor;"
+                "vec4 gl_TexCoord[];"
+                "float gl_FogFragCoord;"
+                );
+        if (version >= 450)
+            stageBuiltins[EShLangTessEvaluation].append(
+                "float gl_CullDistance[];"
+                );
+        stageBuiltins[EShLangTessEvaluation].append(
+            "};"
+            "\n");
+
+#ifdef NV_EXTENSIONS
+        if (version >= 450)
+            stageBuiltins[EShLangTessEvaluation].append(
+                "out int  gl_ViewportIndex;"
+                "out int  gl_Layer;"
+                "out int  gl_ViewportMask[];"             // GL_NV_viewport_array2
+                "out vec4 gl_SecondaryPositionNV;"        // GL_NV_stereo_view_rendering
+                "out int  gl_SecondaryViewportMaskNV[];"  // GL_NV_stereo_view_rendering
+                "out vec4 gl_PositionPerViewNV[];"        // GL_NVX_multiview_per_view_attributes
+                "out int  gl_ViewportMaskPerViewNV[];"    // GL_NVX_multiview_per_view_attributes
+                );
+#endif
+
+    } else if (profile == EEsProfile && version >= 310) {
+        // Note:  "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below,
+        // as it depends on the resource sizing of gl_MaxPatchVertices.
+
+        stageBuiltins[EShLangTessEvaluation].append(
+            "in highp int gl_PatchVerticesIn;"
+            "in highp int gl_PrimitiveID;"
+            "in highp vec3 gl_TessCoord;"
+
+            "patch in highp float gl_TessLevelOuter[4];"
+            "patch in highp float gl_TessLevelInner[2];"
+
+            "out gl_PerVertex {"
+                "highp vec4 gl_Position;"
+                "highp float gl_PointSize;"
+            );
+        stageBuiltins[EShLangTessEvaluation].append(
+            "};"
+            "\n");
+    }
+
+    if ((profile != EEsProfile && version >= 140) ||
+        (profile == EEsProfile && version >= 310)) {
+        stageBuiltins[EShLangTessEvaluation].append(
+            "in highp int gl_DeviceIndex;"     // GL_EXT_device_group
+            "in highp int gl_ViewIndex;"       // GL_EXT_multiview
+            "\n");
+    }
+
+    //============================================================================
+    //
+    // Define the interface to the fragment shader.
+    //
+    //============================================================================
+
+    if (profile != EEsProfile) {
+
+        stageBuiltins[EShLangFragment].append(
+            "vec4  gl_FragCoord;"   // needs qualifier fixed later
+            "bool  gl_FrontFacing;" // needs qualifier fixed later
+            "float gl_FragDepth;"   // needs qualifier fixed later
+            );
+        if (version >= 120)
+            stageBuiltins[EShLangFragment].append(
+                "vec2 gl_PointCoord;"  // needs qualifier fixed later
+                );
+        if (IncludeLegacy(version, profile, spvVersion) || (! ForwardCompatibility && version < 420))
+            stageBuiltins[EShLangFragment].append(
+                "vec4 gl_FragColor;"   // needs qualifier fixed later
+                );
+
+        if (version < 130) {
+            stageBuiltins[EShLangFragment].append(
+                "varying vec4  gl_Color;"
+                "varying vec4  gl_SecondaryColor;"
+                "varying vec4  gl_TexCoord[];"
+                "varying float gl_FogFragCoord;"
+                );
+        } else {
+            stageBuiltins[EShLangFragment].append(
+                "in float gl_ClipDistance[];"
+                );
+
+            if (IncludeLegacy(version, profile, spvVersion)) {
+                if (version < 150)
+                    stageBuiltins[EShLangFragment].append(
+                        "in float gl_FogFragCoord;"
+                        "in vec4  gl_TexCoord[];"
+                        "in vec4  gl_Color;"
+                        "in vec4  gl_SecondaryColor;"
+                        );
+                else
+                    stageBuiltins[EShLangFragment].append(
+                        "in gl_PerFragment {"
+                            "in float gl_FogFragCoord;"
+                            "in vec4  gl_TexCoord[];"
+                            "in vec4  gl_Color;"
+                            "in vec4  gl_SecondaryColor;"
+                        "};"
+                        );
+            }
+        }
+
+        if (version >= 150)
+            stageBuiltins[EShLangFragment].append(
+                "flat in int gl_PrimitiveID;"
+                );
+
+        if (version >= 400) {
+            stageBuiltins[EShLangFragment].append(
+                "flat in  int  gl_SampleID;"
+                "     in  vec2 gl_SamplePosition;"
+                "flat in  int  gl_SampleMaskIn[];"
+                "     out int  gl_SampleMask[];"
+                );
+            if (spvVersion.spv == 0)
+                stageBuiltins[EShLangFragment].append(
+                    "uniform int gl_NumSamples;"
+                    );
+        }
+
+        if (version >= 430)
+            stageBuiltins[EShLangFragment].append(
+                "flat in int gl_Layer;"
+                "flat in int gl_ViewportIndex;"
+                );
+
+        if (version >= 450)
+            stageBuiltins[EShLangFragment].append(
+                "in float gl_CullDistance[];"
+                "bool gl_HelperInvocation;"     // needs qualifier fixed later
+                );
+
+#ifdef AMD_EXTENSIONS
+        if (version >= 450)
+            stageBuiltins[EShLangFragment].append(
+                "in vec2 gl_BaryCoordNoPerspAMD;"
+                "in vec2 gl_BaryCoordNoPerspCentroidAMD;"
+                "in vec2 gl_BaryCoordNoPerspSampleAMD;"
+                "in vec2 gl_BaryCoordSmoothAMD;"
+                "in vec2 gl_BaryCoordSmoothCentroidAMD;"
+                "in vec2 gl_BaryCoordSmoothSampleAMD;"
+                "in vec3 gl_BaryCoordPullModelAMD;"
+                );
+#endif
+    } else {
+        // ES profile
+
+        if (version == 100) {
+            stageBuiltins[EShLangFragment].append(
+                "mediump vec4 gl_FragCoord;"    // needs qualifier fixed later
+                "        bool gl_FrontFacing;"  // needs qualifier fixed later
+                "mediump vec4 gl_FragColor;"    // needs qualifier fixed later
+                "mediump vec2 gl_PointCoord;"   // needs qualifier fixed later
+                );
+        }
+        if (version >= 300) {
+            stageBuiltins[EShLangFragment].append(
+                "highp   vec4  gl_FragCoord;"    // needs qualifier fixed later
+                "        bool  gl_FrontFacing;"  // needs qualifier fixed later
+                "mediump vec2  gl_PointCoord;"   // needs qualifier fixed later
+                "highp   float gl_FragDepth;"    // needs qualifier fixed later
+                );
+        }
+        if (version >= 310) {
+            stageBuiltins[EShLangFragment].append(
+                "bool gl_HelperInvocation;"          // needs qualifier fixed later
+                "flat in highp int gl_PrimitiveID;"  // needs qualifier fixed later
+                "flat in highp int gl_Layer;"        // needs qualifier fixed later
+                );
+
+            stageBuiltins[EShLangFragment].append(  // GL_OES_sample_variables
+                "flat  in lowp     int gl_SampleID;"
+                "      in mediump vec2 gl_SamplePosition;"
+                "flat  in highp    int gl_SampleMaskIn[];"
+                "     out highp    int gl_SampleMask[];"
+                );
+            if (spvVersion.spv == 0)
+                stageBuiltins[EShLangFragment].append(  // GL_OES_sample_variables
+                    "uniform lowp int gl_NumSamples;"
+                    );
+        }
+        stageBuiltins[EShLangFragment].append(
+            "highp float gl_FragDepthEXT;"       // GL_EXT_frag_depth
+            );
+    }
+    stageBuiltins[EShLangFragment].append("\n");
+
+    if (version >= 130)
+        add2ndGenerationSamplingImaging(version, profile, spvVersion);
+
+    // GL_ARB_shader_ballot
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append(
+            "uniform uint gl_SubGroupSizeARB;"
+
+            "in uint     gl_SubGroupInvocationARB;"
+            "in uint64_t gl_SubGroupEqMaskARB;"
+            "in uint64_t gl_SubGroupGeMaskARB;"
+            "in uint64_t gl_SubGroupGtMaskARB;"
+            "in uint64_t gl_SubGroupLeMaskARB;"
+            "in uint64_t gl_SubGroupLtMaskARB;"
+
+            "\n");
+    }
+
+    if ((profile != EEsProfile && version >= 140) ||
+        (profile == EEsProfile && version >= 310)) {
+        stageBuiltins[EShLangFragment].append(
+            "flat in highp int gl_DeviceIndex;"     // GL_EXT_device_group
+            "flat in highp int gl_ViewIndex;"       // GL_EXT_multiview
+            "\n");
+    }
+
+    // printf("%s\n", commonBuiltins.c_str());
+    // printf("%s\n", stageBuiltins[EShLangFragment].c_str());
+}
+
+//
+// Helper function for initialize(), to add the second set of names for texturing,
+// when adding context-independent built-in functions.
+//
+void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, const SpvVersion& spvVersion)
+{
+    //
+    // In this function proper, enumerate the types, then calls the next set of functions
+    // to enumerate all the uses for that type.
+    //
+
+    TBasicType bTypes[3] = { EbtFloat, EbtInt, EbtUint };
+    bool skipBuffer = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 140);
+    bool skipCubeArrayed = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 130);
+
+    // enumerate all the types
+    for (int image = 0; image <= 1; ++image) { // loop over "bool" image vs sampler
+
+        for (int shadow = 0; shadow <= 1; ++shadow) { // loop over "bool" shadow or not
+            for (int ms = 0; ms <=1; ++ms) {
+                if ((ms || image) && shadow)
+                    continue;
+                if (ms && profile != EEsProfile && version < 150)
+                    continue;
+                if (ms && image && profile == EEsProfile)
+                    continue;
+                if (ms && profile == EEsProfile && version < 310)
+                    continue;
+
+                for (int arrayed = 0; arrayed <= 1; ++arrayed) { // loop over "bool" arrayed or not
+                    for (int dim = Esd1D; dim < EsdNumDims; ++dim) { // 1D, 2D, ..., buffer
+                        if (dim == EsdSubpass && spvVersion.vulkan == 0)
+                            continue;
+                        if (dim == EsdSubpass && (image || shadow || arrayed))
+                            continue;
+                        if ((dim == Esd1D || dim == EsdRect) && profile == EEsProfile)
+                            continue;
+                        if (dim != Esd2D && dim != EsdSubpass && ms)
+                            continue;
+                        if ((dim == Esd3D || dim == EsdRect) && arrayed)
+                            continue;
+                        if (dim == Esd3D && shadow)
+                            continue;
+                        if (dim == EsdCube && arrayed && skipCubeArrayed)
+                            continue;
+                        if (dim == EsdBuffer && skipBuffer)
+                            continue;
+                        if (dim == EsdBuffer && (shadow || arrayed || ms))
+                            continue;
+                        if (ms && arrayed && profile == EEsProfile && version < 310)
+                            continue;
+
+                        for (int bType = 0; bType < 3; ++bType) { // float, int, uint results
+
+                            if (shadow && bType > 0)
+                                continue;
+
+                            if (dim == EsdRect && version < 140 && bType > 0)
+                                continue;
+
+                            //
+                            // Now, make all the function prototypes for the type we just built...
+                            //
+
+                            TSampler sampler;
+                            if (dim == EsdSubpass) {
+                                sampler.setSubpass(bTypes[bType], ms ? true : false);
+                            } else if (image) {
+                                sampler.setImage(bTypes[bType], (TSamplerDim)dim, arrayed ? true : false,
+                                                                                  shadow  ? true : false,
+                                                                                  ms      ? true : false);
+                            } else {
+                                sampler.set(bTypes[bType], (TSamplerDim)dim, arrayed ? true : false,
+                                                                             shadow  ? true : false,
+                                                                             ms      ? true : false);
+                            }
+
+                            TString typeName = sampler.getString();
+
+                            if (dim == EsdSubpass) {
+                                addSubpassSampling(sampler, typeName, version, profile);
+                                continue;
+                            }
+
+                            addQueryFunctions(sampler, typeName, version, profile);
+
+                            if (image)
+                                addImageFunctions(sampler, typeName, version, profile);
+                            else {
+                                addSamplingFunctions(sampler, typeName, version, profile);
+                                addGatherFunctions(sampler, typeName, version, profile);
+
+                                if (spvVersion.vulkan > 0 && sampler.dim == EsdBuffer && sampler.isCombined()) {
+                                    // Vulkan wants a textureBuffer to allow texelFetch() --
+                                    // a sampled image with no sampler.
+                                    // So, add sampling functions for both the
+                                    // samplerBuffer and textureBuffer types.
+                                    sampler.setTexture(sampler.type, sampler.dim, sampler.arrayed, sampler.shadow,
+                                                       sampler.ms);
+                                    TString textureTypeName = sampler.getString();
+                                    addSamplingFunctions(sampler, textureTypeName, version, profile);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    //
+    // sparseTexelsResidentARB()
+    //
+
+    if (profile != EEsProfile && version >= 450) {
+        commonBuiltins.append("bool sparseTexelsResidentARB(int code);\n");
+    }
+}
+
+//
+// Helper function for add2ndGenerationSamplingImaging(),
+// when adding context-independent built-in functions.
+//
+// Add all the query functions for the given type.
+//
+void TBuiltIns::addQueryFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile)
+{
+    if (sampler.image && ((profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 430)))
+        return;
+
+    //
+    // textureSize() and imageSize()
+    //
+
+    int sizeDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0) - (sampler.dim == EsdCube ? 1 : 0);
+    if (profile == EEsProfile)
+        commonBuiltins.append("highp ");
+    if (sizeDims == 1)
+        commonBuiltins.append("int");
+    else {
+        commonBuiltins.append("ivec");
+        commonBuiltins.append(postfixes[sizeDims]);
+    }
+    if (sampler.image)
+        commonBuiltins.append(" imageSize(readonly writeonly volatile coherent ");
+    else
+        commonBuiltins.append(" textureSize(");
+    commonBuiltins.append(typeName);
+    if (! sampler.image && sampler.dim != EsdRect && sampler.dim != EsdBuffer && ! sampler.ms)
+        commonBuiltins.append(",int);\n");
+    else
+        commonBuiltins.append(");\n");
+
+    //
+    // textureSamples() and imageSamples()
+    //
+
+    // GL_ARB_shader_texture_image_samples
+    // TODO: spec issue? there are no memory qualifiers; how to query a writeonly/readonly image, etc?
+    if (profile != EEsProfile && version >= 430 && sampler.ms) {
+        commonBuiltins.append("int ");
+        if (sampler.image)
+            commonBuiltins.append("imageSamples(readonly writeonly volatile coherent ");
+        else
+            commonBuiltins.append("textureSamples(");
+        commonBuiltins.append(typeName);
+        commonBuiltins.append(");\n");
+    }
+
+    //
+    // textureQueryLod(), fragment stage only
+    //
+
+    if (profile != EEsProfile && version >= 400 && ! sampler.image && sampler.dim != EsdRect && ! sampler.ms && sampler.dim != EsdBuffer) {
+        stageBuiltins[EShLangFragment].append("vec2 textureQueryLod(");
+        stageBuiltins[EShLangFragment].append(typeName);
+        if (dimMap[sampler.dim] == 1)
+            stageBuiltins[EShLangFragment].append(", float");
+        else {
+            stageBuiltins[EShLangFragment].append(", vec");
+            stageBuiltins[EShLangFragment].append(postfixes[dimMap[sampler.dim]]);
+        }
+        stageBuiltins[EShLangFragment].append(");\n");
+    }
+
+    //
+    // textureQueryLevels()
+    //
+
+    if (profile != EEsProfile && version >= 430 && ! sampler.image && sampler.dim != EsdRect && ! sampler.ms && sampler.dim != EsdBuffer) {
+        commonBuiltins.append("int textureQueryLevels(");
+        commonBuiltins.append(typeName);
+        commonBuiltins.append(");\n");
+    }
+}
+
+//
+// Helper function for add2ndGenerationSamplingImaging(),
+// when adding context-independent built-in functions.
+//
+// Add all the image access functions for the given type.
+//
+void TBuiltIns::addImageFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile)
+{
+    int dims = dimMap[sampler.dim];
+    // most things with an array add a dimension, except for cubemaps
+    if (sampler.arrayed && sampler.dim != EsdCube)
+        ++dims;
+
+    TString imageParams = typeName;
+    if (dims == 1)
+        imageParams.append(", int");
+    else {
+        imageParams.append(", ivec");
+        imageParams.append(postfixes[dims]);
+    }
+    if (sampler.ms)
+        imageParams.append(", int");
+
+    if (profile == EEsProfile)
+        commonBuiltins.append("highp ");
+    commonBuiltins.append(prefixes[sampler.type]);
+    commonBuiltins.append("vec4 imageLoad(readonly volatile coherent ");
+    commonBuiltins.append(imageParams);
+    commonBuiltins.append(");\n");
+
+    commonBuiltins.append("void imageStore(writeonly volatile coherent ");
+    commonBuiltins.append(imageParams);
+    commonBuiltins.append(", ");
+    commonBuiltins.append(prefixes[sampler.type]);
+    commonBuiltins.append("vec4);\n");
+
+    if (sampler.dim != Esd1D && sampler.dim != EsdBuffer && profile != EEsProfile && version >= 450) {
+        commonBuiltins.append("int sparseImageLoadARB(readonly volatile coherent ");
+        commonBuiltins.append(imageParams);
+        commonBuiltins.append(", out ");
+        commonBuiltins.append(prefixes[sampler.type]);
+        commonBuiltins.append("vec4");
+        commonBuiltins.append(");\n");
+    }
+
+    if ( profile != EEsProfile ||
+        (profile == EEsProfile && version >= 310)) {
+        if (sampler.type == EbtInt || sampler.type == EbtUint) {
+            const char* dataType = sampler.type == EbtInt ? "highp int" : "highp uint";
+
+            const int numBuiltins = 7;
+
+            static const char* atomicFunc[numBuiltins] = {
+                " imageAtomicAdd(volatile coherent ",
+                " imageAtomicMin(volatile coherent ",
+                " imageAtomicMax(volatile coherent ",
+                " imageAtomicAnd(volatile coherent ",
+                " imageAtomicOr(volatile coherent ",
+                " imageAtomicXor(volatile coherent ",
+                " imageAtomicExchange(volatile coherent "
+            };
+
+            for (size_t i = 0; i < numBuiltins; ++i) {
+                commonBuiltins.append(dataType);
+                commonBuiltins.append(atomicFunc[i]);
+                commonBuiltins.append(imageParams);
+                commonBuiltins.append(", ");
+                commonBuiltins.append(dataType);
+                commonBuiltins.append(");\n");
+            }
+
+            commonBuiltins.append(dataType);
+            commonBuiltins.append(" imageAtomicCompSwap(volatile coherent ");
+            commonBuiltins.append(imageParams);
+            commonBuiltins.append(", ");
+            commonBuiltins.append(dataType);
+            commonBuiltins.append(", ");
+            commonBuiltins.append(dataType);
+            commonBuiltins.append(");\n");
+        } else {
+            // not int or uint
+            // GL_ARB_ES3_1_compatibility
+            // TODO: spec issue: are there restrictions on the kind of layout() that can be used?  what about dropping memory qualifiers?
+            if ((profile != EEsProfile && version >= 450) ||
+                (profile == EEsProfile && version >= 310)) {
+                commonBuiltins.append("float imageAtomicExchange(volatile coherent ");
+                commonBuiltins.append(imageParams);
+                commonBuiltins.append(", float);\n");
+            }
+        }
+    }
+}
+
+//
+// Helper function for initialize(),
+// when adding context-independent built-in functions.
+//
+// Add all the subpass access functions for the given type.
+//
+void TBuiltIns::addSubpassSampling(TSampler sampler, const TString& typeName, int /*version*/, EProfile /*profile*/)
+{
+    stageBuiltins[EShLangFragment].append(prefixes[sampler.type]);
+    stageBuiltins[EShLangFragment].append("vec4 subpassLoad");
+    stageBuiltins[EShLangFragment].append("(");
+    stageBuiltins[EShLangFragment].append(typeName.c_str());
+    if (sampler.ms)
+        stageBuiltins[EShLangFragment].append(", int");
+    stageBuiltins[EShLangFragment].append(");\n");
+}
+
+//
+// Helper function for add2ndGenerationSamplingImaging(),
+// when adding context-independent built-in functions.
+//
+// Add all the texture lookup functions for the given type.
+//
+void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile)
+{
+    //
+    // texturing
+    //
+    for (int proj = 0; proj <= 1; ++proj) { // loop over "bool" projective or not
+
+        if (proj && (sampler.dim == EsdCube || sampler.dim == EsdBuffer || sampler.arrayed || sampler.ms))
+            continue;
+
+        for (int lod = 0; lod <= 1; ++lod) {
+
+            if (lod && (sampler.dim == EsdBuffer || sampler.dim == EsdRect || sampler.ms))
+                continue;
+            if (lod && sampler.dim == Esd2D && sampler.arrayed && sampler.shadow)
+                continue;
+            if (lod && sampler.dim == EsdCube && sampler.shadow)
+                continue;
+
+            for (int bias = 0; bias <= 1; ++bias) {
+
+                if (bias && (lod || sampler.ms))
+                    continue;
+                if (bias && sampler.dim == Esd2D && sampler.shadow && sampler.arrayed)
+                    continue;
+                if (bias && (sampler.dim == EsdRect || sampler.dim == EsdBuffer))
+                    continue;
+
+                for (int offset = 0; offset <= 1; ++offset) { // loop over "bool" offset or not
+
+                    if (proj + offset + bias + lod > 3)
+                        continue;
+                    if (offset && (sampler.dim == EsdCube || sampler.dim == EsdBuffer || sampler.ms))
+                        continue;
+
+                    for (int fetch = 0; fetch <= 1; ++fetch) { // loop over "bool" fetch or not
+
+                        if (proj + offset + fetch + bias + lod > 3)
+                            continue;
+                        if (fetch && (lod || bias))
+                            continue;
+                        if (fetch && (sampler.shadow || sampler.dim == EsdCube))
+                            continue;
+                        if (fetch == 0 && (sampler.ms || sampler.dim == EsdBuffer))
+                            continue;
+
+                        for (int grad = 0; grad <= 1; ++grad) { // loop over "bool" grad or not
+
+                            if (grad && (lod || bias || sampler.ms))
+                                continue;
+                            if (grad && sampler.dim == EsdBuffer)
+                                continue;
+                            if (proj + offset + fetch + grad + bias + lod > 3)
+                                continue;
+
+                            for (int extraProj = 0; extraProj <= 1; ++extraProj) {
+                                bool compare = false;
+                                int totalDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0);
+                                // skip dummy unused second component for 1D non-array shadows
+                                if (sampler.shadow && totalDims < 2)
+                                    totalDims = 2;
+                                totalDims += (sampler.shadow ? 1 : 0) + proj;
+                                if (totalDims > 4 && sampler.shadow) {
+                                    compare = true;
+                                    totalDims = 4;
+                                }
+                                assert(totalDims <= 4);
+
+                                if (extraProj && ! proj)
+                                    continue;
+                                if (extraProj && (sampler.dim == Esd3D || sampler.shadow))
+                                    continue;
+
+                                for (int lodClamp = 0; lodClamp <= 1 ;++lodClamp) { // loop over "bool" lod clamp
+
+                                    if (lodClamp && (profile == EEsProfile || version < 450))
+                                        continue;
+                                    if (lodClamp && (proj || lod || fetch))
+                                        continue;
+
+                                    for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not
+
+                                        if (sparse && (profile == EEsProfile || version < 450))
+                                            continue;
+                                        // Sparse sampling is not for 1D/1D array texture, buffer texture, and projective texture
+                                        if (sparse && (sampler.dim == Esd1D || sampler.dim == EsdBuffer || proj))
+                                            continue;
+
+                                        TString s;
+
+                                        // return type
+                                        if (sparse)
+                                            s.append("int ");
+                                        else {
+                                            if (sampler.shadow)
+                                                s.append("float ");
+                                            else {
+                                                s.append(prefixes[sampler.type]);
+                                                s.append("vec4 ");
+                                            }
+                                        }
+
+                                        // name
+                                        if (sparse) {
+                                            if (fetch)
+                                                s.append("sparseTexel");
+                                            else
+                                                s.append("sparseTexture");
+                                        } else {
+                                            if (fetch)
+                                                s.append("texel");
+                                            else
+                                                s.append("texture");
+                                        }
+                                        if (proj)
+                                            s.append("Proj");
+                                        if (lod)
+                                            s.append("Lod");
+                                        if (grad)
+                                            s.append("Grad");
+                                        if (fetch)
+                                            s.append("Fetch");
+                                        if (offset)
+                                            s.append("Offset");
+                                        if (lodClamp)
+                                            s.append("Clamp");
+                                        if (lodClamp || sparse)
+                                            s.append("ARB");
+                                        s.append("(");
+
+                                        // sampler type
+                                        s.append(typeName);
+
+                                        // P coordinate
+                                        if (extraProj)
+                                            s.append(",vec4");
+                                        else {
+                                            s.append(",");
+                                            TBasicType t = fetch ? EbtInt : EbtFloat;
+                                            if (totalDims == 1)
+                                                s.append(TType::getBasicString(t));
+                                            else {
+                                                s.append(prefixes[t]);
+                                                s.append("vec");
+                                                s.append(postfixes[totalDims]);
+                                            }
+                                        }
+
+                                        if (bias && compare)
+                                            continue;
+
+                                        // non-optional lod argument (lod that's not driven by lod loop) or sample
+                                        if ((fetch && sampler.dim != EsdBuffer && sampler.dim != EsdRect && !sampler.ms) ||
+                                            (sampler.ms && fetch))
+                                            s.append(",int");
+
+                                        // non-optional lod
+                                        if (lod)
+                                            s.append(",float");
+
+                                        // gradient arguments
+                                        if (grad) {
+                                            if (dimMap[sampler.dim] == 1)
+                                                s.append(",float,float");
+                                            else {
+                                                s.append(",vec");
+                                                s.append(postfixes[dimMap[sampler.dim]]);
+                                                s.append(",vec");
+                                                s.append(postfixes[dimMap[sampler.dim]]);
+                                            }
+                                        }
+
+                                        // offset
+                                        if (offset) {
+                                            if (dimMap[sampler.dim] == 1)
+                                                s.append(",int");
+                                            else {
+                                                s.append(",ivec");
+                                                s.append(postfixes[dimMap[sampler.dim]]);
+                                            }
+                                        }
+
+                                        // non-optional compare
+                                        if (compare)
+                                            s.append(",float");
+
+                                        // lod clamp
+                                        if (lodClamp)
+                                            s.append(",float");
+
+                                        // texel out (for sparse texture)
+                                        if (sparse) {
+                                            s.append(",out ");
+                                            if (sampler.shadow)
+                                                s.append("float ");
+                                            else {
+                                                s.append(prefixes[sampler.type]);
+                                                s.append("vec4 ");
+                                            }
+                                        }
+
+                                        // optional bias
+                                        if (bias)
+                                            s.append(",float");
+
+                                        s.append(");\n");
+
+                                        // Add to the per-language set of built-ins
+
+                                        if (bias || lodClamp)
+                                            stageBuiltins[EShLangFragment].append(s);
+                                        else
+                                            commonBuiltins.append(s);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+//
+// Helper function for add2ndGenerationSamplingImaging(),
+// when adding context-independent built-in functions.
+//
+// Add all the texture gather functions for the given type.
+//
+void TBuiltIns::addGatherFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile)
+{
+    switch (sampler.dim) {
+    case Esd2D:
+    case EsdRect:
+    case EsdCube:
+        break;
+    default:
+        return;
+    }
+
+    if (sampler.ms)
+        return;
+
+    if (version < 140 && sampler.dim == EsdRect && sampler.type != EbtFloat)
+        return;
+
+    for (int offset = 0; offset < 3; ++offset) { // loop over three forms of offset in the call name:  none, Offset, and Offsets
+
+        for (int comp = 0; comp < 2; ++comp) { // loop over presence of comp argument
+
+            if (comp > 0 && sampler.shadow)
+                continue;
+
+            if (offset > 0 && sampler.dim == EsdCube)
+                continue;
+
+            for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not
+                if (sparse && (profile == EEsProfile || version < 450))
+                    continue;
+
+                TString s;
+
+                // return type
+                if (sparse)
+                    s.append("int ");
+                else {
+                    s.append(prefixes[sampler.type]);
+                    s.append("vec4 ");
+                }
+
+                // name
+                if (sparse)
+                    s.append("sparseTextureGather");
+                else
+                    s.append("textureGather");
+                switch (offset) {
+                case 1:
+                    s.append("Offset");
+                    break;
+                case 2:
+                    s.append("Offsets");
+                default:
+                    break;
+                }
+
+                if (sparse)
+                    s.append("ARB");
+                s.append("(");
+
+                // sampler type argument
+                s.append(typeName);
+
+                // P coordinate argument
+                s.append(",vec");
+                int totalDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0);
+                s.append(postfixes[totalDims]);
+
+                // refZ argument
+                if (sampler.shadow)
+                    s.append(",float");
+
+                // offset argument
+                if (offset > 0) {
+                    s.append(",ivec2");
+                    if (offset == 2)
+                        s.append("[4]");
+                }
+
+                // texel out (for sparse texture)
+                if (sparse) {
+                    s.append(",out ");
+                    s.append(prefixes[sampler.type]);
+                    s.append("vec4 ");
+                }
+
+                // comp argument
+                if (comp)
+                    s.append(",int");
+
+                s.append(");\n");
+                commonBuiltins.append(s);
+            }
+        }
+    }
+
+#ifdef AMD_EXTENSIONS
+    if (sampler.dim == EsdRect || sampler.shadow)
+        return;
+
+    if (profile == EEsProfile || version < 450)
+        return;
+
+    for (int bias = 0; bias < 2; ++bias) { // loop over presence of bias argument
+
+        for (int lod = 0; lod < 2; ++lod) { // loop over presence of lod argument
+
+            if ((lod && bias) || (lod == 0 && bias == 0))
+                continue;
+
+            for (int offset = 0; offset < 3; ++offset) { // loop over three forms of offset in the call name:  none, Offset, and Offsets
+
+                for (int comp = 0; comp < 2; ++comp) { // loop over presence of comp argument
+
+                    if (comp == 0 && bias)
+                        continue;
+
+                    if (offset > 0 && sampler.dim == EsdCube)
+                        continue;
+
+                    for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not
+                        if (sparse && (profile == EEsProfile || version < 450))
+                            continue;
+
+                        TString s;
+
+                        // return type
+                        if (sparse)
+                            s.append("int ");
+                        else {
+                            s.append(prefixes[sampler.type]);
+                            s.append("vec4 ");
+                        }
+
+                        // name
+                        if (sparse)
+                            s.append("sparseTextureGather");
+                        else
+                            s.append("textureGather");
+
+                        if (lod)
+                            s.append("Lod");
+
+                        switch (offset) {
+                        case 1:
+                            s.append("Offset");
+                            break;
+                        case 2:
+                            s.append("Offsets");
+                        default:
+                            break;
+                        }
+
+                        if (lod)
+                            s.append("AMD");
+                        else if (sparse)
+                            s.append("ARB");
+
+                        s.append("(");
+
+                        // sampler type argument
+                        s.append(typeName);
+
+                        // P coordinate argument
+                        s.append(",vec");
+                        int totalDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0);
+                        s.append(postfixes[totalDims]);
+
+                        // lod argument
+                        if (lod)
+                            s.append(",float");
+
+                        // offset argument
+                        if (offset > 0) {
+                            s.append(",ivec2");
+                            if (offset == 2)
+                                s.append("[4]");
+                        }
+
+                        // texel out (for sparse texture)
+                        if (sparse) {
+                            s.append(",out ");
+                            s.append(prefixes[sampler.type]);
+                            s.append("vec4 ");
+                        }
+
+                        // comp argument
+                        if (comp)
+                            s.append(",int");
+
+                        // bias argument
+                        if (bias)
+                            s.append(",float");
+
+                        s.append(");\n");
+                        if (bias)
+                            stageBuiltins[EShLangFragment].append(s);
+                        else
+                            commonBuiltins.append(s);
+                    }
+                }
+            }
+        }
+    }
+#endif
+}
+
+//
+// Add context-dependent built-in functions and variables that are present
+// for the given version and profile.  All the results are put into just the
+// commonBuiltins, because it is called for just a specific stage.  So,
+// add stage-specific entries to the commonBuiltins, and only if that stage
+// was requested.
+//
+void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language)
+{
+    //
+    // Initialize the context-dependent (resource-dependent) built-in strings for parsing.
+    //
+
+    //============================================================================
+    //
+    // Standard Uniforms
+    //
+    //============================================================================
+
+    TString& s = commonBuiltins;
+    const int maxSize = 80;
+    char builtInConstant[maxSize];
+
+    //
+    // Build string of implementation dependent constants.
+    //
+
+    if (profile == EEsProfile) {
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVertexUniformVectors = %d;", resources.maxVertexUniformVectors);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVertexTextureImageUnits = %d;", resources.maxVertexTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxCombinedTextureImageUnits = %d;", resources.maxCombinedTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxTextureImageUnits = %d;", resources.maxTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxFragmentUniformVectors = %d;", resources.maxFragmentUniformVectors);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxDrawBuffers = %d;", resources.maxDrawBuffers);
+        s.append(builtInConstant);
+
+        if (version == 100) {
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVaryingVectors = %d;", resources.maxVaryingVectors);
+            s.append(builtInConstant);
+        } else {
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVertexOutputVectors = %d;", resources.maxVertexOutputVectors);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxFragmentInputVectors = %d;", resources.maxFragmentInputVectors);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MinProgramTexelOffset = %d;", resources.minProgramTexelOffset);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxProgramTexelOffset = %d;", resources.maxProgramTexelOffset);
+            s.append(builtInConstant);
+        }
+
+        if (version >= 310) {
+            // geometry
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryInputComponents = %d;", resources.maxGeometryInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryOutputComponents = %d;", resources.maxGeometryOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryImageUniforms = %d;", resources.maxGeometryImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTextureImageUnits = %d;", resources.maxGeometryTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryOutputVertices = %d;", resources.maxGeometryOutputVertices);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTotalOutputComponents = %d;", resources.maxGeometryTotalOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryUniformComponents = %d;", resources.maxGeometryUniformComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryAtomicCounters = %d;", resources.maxGeometryAtomicCounters);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryAtomicCounterBuffers = %d;", resources.maxGeometryAtomicCounterBuffers);
+            s.append(builtInConstant);
+
+            // tessellation
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlInputComponents = %d;", resources.maxTessControlInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlOutputComponents = %d;", resources.maxTessControlOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTextureImageUnits = %d;", resources.maxTessControlTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlUniformComponents = %d;", resources.maxTessControlUniformComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTotalOutputComponents = %d;", resources.maxTessControlTotalOutputComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationInputComponents = %d;", resources.maxTessEvaluationInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationOutputComponents = %d;", resources.maxTessEvaluationOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationTextureImageUnits = %d;", resources.maxTessEvaluationTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationUniformComponents = %d;", resources.maxTessEvaluationUniformComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessPatchComponents = %d;", resources.maxTessPatchComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxPatchVertices = %d;", resources.maxPatchVertices);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessGenLevel = %d;", resources.maxTessGenLevel);
+            s.append(builtInConstant);
+
+            // this is here instead of with the others in initialize(version, profile) due to the dependence on gl_MaxPatchVertices
+            if (language == EShLangTessControl || language == EShLangTessEvaluation) {
+                s.append(
+                    "in gl_PerVertex {"
+                        "highp vec4 gl_Position;"
+                        "highp float gl_PointSize;"
+#ifdef NV_EXTENSIONS
+                        "highp vec4 gl_SecondaryPositionNV;"  // GL_NV_stereo_view_rendering
+                        "highp vec4 gl_PositionPerViewNV[];"  // GL_NVX_multiview_per_view_attributes
+#endif
+                    "} gl_in[gl_MaxPatchVertices];"
+                    "\n");
+            }
+        }
+
+    } else {
+        // non-ES profile
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxVertexTextureImageUnits = %d;", resources.maxVertexTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxCombinedTextureImageUnits = %d;", resources.maxCombinedTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxTextureImageUnits = %d;", resources.maxTextureImageUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxDrawBuffers = %d;", resources.maxDrawBuffers);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxLights = %d;", resources.maxLights);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxClipPlanes = %d;", resources.maxClipPlanes);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxTextureUnits = %d;", resources.maxTextureUnits);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxTextureCoords = %d;", resources.maxTextureCoords);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxVertexUniformComponents = %d;", resources.maxVertexUniformComponents);
+        s.append(builtInConstant);
+
+        if (version < 150 || ARBCompatibility) {
+            snprintf(builtInConstant, maxSize, "const int  gl_MaxVaryingFloats = %d;", resources.maxVaryingFloats);
+            s.append(builtInConstant);
+        }
+
+        snprintf(builtInConstant, maxSize, "const int  gl_MaxFragmentUniformComponents = %d;", resources.maxFragmentUniformComponents);
+        s.append(builtInConstant);
+
+        if (spvVersion.spv == 0 && IncludeLegacy(version, profile, spvVersion)) {
+            //
+            // OpenGL'uniform' state.  Page numbers are in reference to version
+            // 1.4 of the OpenGL specification.
+            //
+
+            //
+            // Matrix state. p. 31, 32, 37, 39, 40.
+            //
+            s.append("uniform mat4  gl_TextureMatrix[gl_MaxTextureCoords];"
+
+            //
+            // Derived matrix state that provides inverse and transposed versions
+            // of the matrices above.
+            //
+                        "uniform mat4  gl_TextureMatrixInverse[gl_MaxTextureCoords];"
+
+                        "uniform mat4  gl_TextureMatrixTranspose[gl_MaxTextureCoords];"
+
+                        "uniform mat4  gl_TextureMatrixInverseTranspose[gl_MaxTextureCoords];"
+
+            //
+            // Clip planes p. 42.
+            //
+                        "uniform vec4  gl_ClipPlane[gl_MaxClipPlanes];"
+
+            //
+            // Light State p 50, 53, 55.
+            //
+                        "uniform gl_LightSourceParameters  gl_LightSource[gl_MaxLights];"
+
+            //
+            // Derived state from products of light.
+            //
+                        "uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights];"
+                        "uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights];"
+
+            //
+            // Texture Environment and Generation, p. 152, p. 40-42.
+            //
+                        "uniform vec4  gl_TextureEnvColor[gl_MaxTextureImageUnits];"
+                        "uniform vec4  gl_EyePlaneS[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_EyePlaneT[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_EyePlaneR[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_EyePlaneQ[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_ObjectPlaneS[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_ObjectPlaneT[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_ObjectPlaneR[gl_MaxTextureCoords];"
+                        "uniform vec4  gl_ObjectPlaneQ[gl_MaxTextureCoords];");
+        }
+
+        if (version >= 130) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxClipDistances = %d;", resources.maxClipDistances);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxVaryingComponents = %d;", resources.maxVaryingComponents);
+            s.append(builtInConstant);
+
+            // GL_ARB_shading_language_420pack
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MinProgramTexelOffset = %d;", resources.minProgramTexelOffset);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxProgramTexelOffset = %d;", resources.maxProgramTexelOffset);
+            s.append(builtInConstant);
+        }
+
+        // geometry
+        if (version >= 150) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryInputComponents = %d;", resources.maxGeometryInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryOutputComponents = %d;", resources.maxGeometryOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTextureImageUnits = %d;", resources.maxGeometryTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryOutputVertices = %d;", resources.maxGeometryOutputVertices);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTotalOutputComponents = %d;", resources.maxGeometryTotalOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryUniformComponents = %d;", resources.maxGeometryUniformComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryVaryingComponents = %d;", resources.maxGeometryVaryingComponents);
+            s.append(builtInConstant);
+
+        }
+
+        if (version >= 150) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxVertexOutputComponents = %d;", resources.maxVertexOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentInputComponents = %d;", resources.maxFragmentInputComponents);
+            s.append(builtInConstant);
+        }
+
+        // tessellation
+        if (version >= 150) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlInputComponents = %d;", resources.maxTessControlInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlOutputComponents = %d;", resources.maxTessControlOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTextureImageUnits = %d;", resources.maxTessControlTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlUniformComponents = %d;", resources.maxTessControlUniformComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlTotalOutputComponents = %d;", resources.maxTessControlTotalOutputComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationInputComponents = %d;", resources.maxTessEvaluationInputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationOutputComponents = %d;", resources.maxTessEvaluationOutputComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationTextureImageUnits = %d;", resources.maxTessEvaluationTextureImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationUniformComponents = %d;", resources.maxTessEvaluationUniformComponents);
+            s.append(builtInConstant);
+
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessPatchComponents = %d;", resources.maxTessPatchComponents);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessGenLevel = %d;", resources.maxTessGenLevel);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxPatchVertices = %d;", resources.maxPatchVertices);
+            s.append(builtInConstant);
+
+            // this is here instead of with the others in initialize(version, profile) due to the dependence on gl_MaxPatchVertices
+            if (language == EShLangTessControl || language == EShLangTessEvaluation) {
+                s.append(
+                    "in gl_PerVertex {"
+                        "vec4 gl_Position;"
+                        "float gl_PointSize;"
+                        "float gl_ClipDistance[];"
+                    );
+                if (profile == ECompatibilityProfile)
+                    s.append(
+                        "vec4 gl_ClipVertex;"
+                        "vec4 gl_FrontColor;"
+                        "vec4 gl_BackColor;"
+                        "vec4 gl_FrontSecondaryColor;"
+                        "vec4 gl_BackSecondaryColor;"
+                        "vec4 gl_TexCoord[];"
+                        "float gl_FogFragCoord;"
+                        );
+                if (profile != EEsProfile && version >= 450)
+                    s.append(
+                        "float gl_CullDistance[];"
+#ifdef NV_EXTENSIONS
+                        "vec4 gl_SecondaryPositionNV;"  // GL_NV_stereo_view_rendering
+                        "vec4 gl_PositionPerViewNV[];"  // GL_NVX_multiview_per_view_attributes
+#endif
+                       );
+                s.append(
+                    "} gl_in[gl_MaxPatchVertices];"
+                    "\n");
+            }
+        }
+
+        if (version >= 150) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxViewports = %d;", resources.maxViewports);
+            s.append(builtInConstant);
+        }
+
+        // images
+        if (version >= 130) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUnitsAndFragmentOutputs = %d;", resources.maxCombinedImageUnitsAndFragmentOutputs);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxImageSamples = %d;", resources.maxImageSamples);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlImageUniforms = %d;", resources.maxTessControlImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationImageUniforms = %d;", resources.maxTessEvaluationImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryImageUniforms = %d;", resources.maxGeometryImageUniforms);
+            s.append(builtInConstant);
+        }
+
+        // enhanced layouts
+        if (version >= 430) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTransformFeedbackBuffers = %d;", resources.maxTransformFeedbackBuffers);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTransformFeedbackInterleavedComponents = %d;", resources.maxTransformFeedbackInterleavedComponents);
+            s.append(builtInConstant);
+        }
+    }
+
+    // images (some in compute below)
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 130)) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxImageUnits = %d;", resources.maxImageUnits);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedShaderOutputResources = %d;", resources.maxCombinedShaderOutputResources);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxVertexImageUniforms = %d;", resources.maxVertexImageUniforms);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentImageUniforms = %d;", resources.maxFragmentImageUniforms);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUniforms = %d;", resources.maxCombinedImageUniforms);
+        s.append(builtInConstant);
+    }
+
+    // atomic counters (some in compute below)
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 420)) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxVertexAtomicCounters = %d;", resources.               maxVertexAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentAtomicCounters = %d;", resources.             maxFragmentAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedAtomicCounters = %d;", resources.             maxCombinedAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxAtomicCounterBindings = %d;", resources.              maxAtomicCounterBindings);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxVertexAtomicCounterBuffers = %d;", resources.         maxVertexAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentAtomicCounterBuffers = %d;", resources.       maxFragmentAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedAtomicCounterBuffers = %d;", resources.       maxCombinedAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxAtomicCounterBufferSize = %d;", resources.            maxAtomicCounterBufferSize);
+        s.append(builtInConstant);
+    }
+    if (profile != EEsProfile && version >= 420) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlAtomicCounters = %d;", resources.          maxTessControlAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationAtomicCounters = %d;", resources.       maxTessEvaluationAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryAtomicCounters = %d;", resources.             maxGeometryAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlAtomicCounterBuffers = %d;", resources.    maxTessControlAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationAtomicCounterBuffers = %d;", resources. maxTessEvaluationAtomicCounterBuffers);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryAtomicCounterBuffers = %d;", resources.       maxGeometryAtomicCounterBuffers);
+        s.append(builtInConstant);
+
+        s.append("\n");
+    }
+
+    // compute
+    if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 420)) {
+        snprintf(builtInConstant, maxSize, "const ivec3 gl_MaxComputeWorkGroupCount = ivec3(%d,%d,%d);", resources.maxComputeWorkGroupCountX,
+                                                                                                         resources.maxComputeWorkGroupCountY,
+                                                                                                         resources.maxComputeWorkGroupCountZ);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const ivec3 gl_MaxComputeWorkGroupSize = ivec3(%d,%d,%d);", resources.maxComputeWorkGroupSizeX,
+                                                                                                        resources.maxComputeWorkGroupSizeY,
+                                                                                                        resources.maxComputeWorkGroupSizeZ);
+        s.append(builtInConstant);
+
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeUniformComponents = %d;", resources.maxComputeUniformComponents);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeTextureImageUnits = %d;", resources.maxComputeTextureImageUnits);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeImageUniforms = %d;", resources.maxComputeImageUniforms);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeAtomicCounters = %d;", resources.maxComputeAtomicCounters);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxComputeAtomicCounterBuffers = %d;", resources.maxComputeAtomicCounterBuffers);
+        s.append(builtInConstant);
+
+        s.append("\n");
+    }
+
+    // GL_ARB_cull_distance
+    if (profile != EEsProfile && version >= 450) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCullDistances = %d;",                resources.maxCullDistances);
+        s.append(builtInConstant);
+        snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedClipAndCullDistances = %d;", resources.maxCombinedClipAndCullDistances);
+        s.append(builtInConstant);
+    }
+
+    // GL_ARB_ES3_1_compatibility
+    if ((profile != EEsProfile && version >= 450) ||
+        (profile == EEsProfile && version >= 310)) {
+        snprintf(builtInConstant, maxSize, "const int gl_MaxSamples = %d;", resources.maxSamples);
+        s.append(builtInConstant);
+    }
+
+#ifdef AMD_EXTENSIONS
+    // GL_AMD_gcn_shader
+    if (profile != EEsProfile && version >= 450) {
+        snprintf(builtInConstant, maxSize, "const int gl_SIMDGroupSizeAMD = 64;");
+        s.append(builtInConstant);
+    }
+#endif
+
+    s.append("\n");
+}
+
+//
+// To support special built-ins that have a special qualifier that cannot be declared textually
+// in a shader, like gl_Position.
+//
+// This lets the type of the built-in be declared textually, and then have just its qualifier be
+// updated afterward.
+//
+// Safe to call even if name is not present.
+//
+// Only use this for built-in variables that have a special qualifier in TStorageQualifier.
+// New built-in variables should use a generic (textually declarable) qualifier in
+// TStoraregQualifier and only call BuiltInVariable().
+//
+static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
+{
+    TSymbol* symbol = symbolTable.find(name);
+    if (symbol) {
+        TQualifier& symQualifier = symbol->getWritableType().getQualifier();
+        symQualifier.storage = qualifier;
+        symQualifier.builtIn = builtIn;
+    }
+}
+
+//
+// To tag built-in variables with their TBuiltInVariable enum.  Use this when the
+// normal declaration text already gets the qualifier right, and all that's needed
+// is setting the builtIn field.  This should be the normal way for all new
+// built-in variables.
+//
+// If SpecialQualifier() was called, this does not need to be called.
+//
+// Safe to call even if name is not present.
+//
+static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
+{
+    TSymbol* symbol = symbolTable.find(name);
+    if (! symbol)
+        return;
+
+    TQualifier& symQualifier = symbol->getWritableType().getQualifier();
+    symQualifier.builtIn = builtIn;
+}
+
+//
+// For built-in variables inside a named block.
+// SpecialQualifier() won't ever go inside a block; their member's qualifier come
+// from the qualification of the block.
+//
+// See comments above for other detail.
+//
+static void BuiltInVariable(const char* blockName, const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
+{
+    TSymbol* symbol = symbolTable.find(blockName);
+    if (! symbol)
+        return;
+
+    TTypeList& structure = *symbol->getWritableType().getWritableStruct();
+    for (int i = 0; i < (int)structure.size(); ++i) {
+        if (structure[i].type->getFieldName().compare(name) == 0) {
+            structure[i].type->getQualifier().builtIn = builtIn;
+            return;
+        }
+    }
+}
+
+//
+// Finish adding/processing context-independent built-in symbols.
+// 1) Programmatically add symbols that could not be added by simple text strings above.
+// 2) Map built-in functions to operators, for those that will turn into an operation node
+//    instead of remaining a function call.
+// 3) Tag extension-related symbols added to their base version with their extensions, so
+//    that if an early version has the extension turned off, there is an error reported on use.
+//
+void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable)
+{
+    //
+    // Tag built-in variables and functions with additional qualifier and extension information
+    // that cannot be declared with the text strings.
+    //
+
+    // N.B.: a symbol should only be tagged once, and this function is called multiple times, once
+    // per stage that's used for this profile.  So
+    //  - generally, stick common ones in the fragment stage to ensure they are tagged exactly once
+    //  - for ES, which has different precisions for different stages, the coarsest-grained tagging
+    //    for a built-in used in many stages needs to be once for the fragment stage and once for
+    //    the vertex stage
+
+    switch(language) {
+    case EShLangVertex:
+        if (profile != EEsProfile) {
+            symbolTable.setVariableExtensions("gl_BaseVertexARB",   1, &E_GL_ARB_shader_draw_parameters);
+            symbolTable.setVariableExtensions("gl_BaseInstanceARB", 1, &E_GL_ARB_shader_draw_parameters);
+            symbolTable.setVariableExtensions("gl_DrawIDARB",       1, &E_GL_ARB_shader_draw_parameters);
+
+            BuiltInVariable("gl_BaseVertexARB",   EbvBaseVertex,   symbolTable);
+            BuiltInVariable("gl_BaseInstanceARB", EbvBaseInstance, symbolTable);
+            BuiltInVariable("gl_DrawIDARB",       EbvDrawId,       symbolTable);
+        }
+
+        if (profile != EEsProfile) {
+            symbolTable.setVariableExtensions("gl_SubGroupSizeARB",       1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupInvocationARB", 1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupEqMaskARB",     1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupGeMaskARB",     1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupGtMaskARB",     1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupLeMaskARB",     1, &E_GL_ARB_shader_ballot);
+            symbolTable.setVariableExtensions("gl_SubGroupLtMaskARB",     1, &E_GL_ARB_shader_ballot);
+
+            symbolTable.setFunctionExtensions("ballotARB",              1, &E_GL_ARB_shader_ballot);
+            symbolTable.setFunctionExtensions("readInvocationARB",      1, &E_GL_ARB_shader_ballot);
+            symbolTable.setFunctionExtensions("readFirstInvocationARB", 1, &E_GL_ARB_shader_ballot);
+
+            BuiltInVariable("gl_SubGroupInvocationARB", EbvSubGroupInvocation, symbolTable);
+            BuiltInVariable("gl_SubGroupEqMaskARB",     EbvSubGroupEqMask,     symbolTable);
+            BuiltInVariable("gl_SubGroupGeMaskARB",     EbvSubGroupGeMask,     symbolTable);
+            BuiltInVariable("gl_SubGroupGtMaskARB",     EbvSubGroupGtMask,     symbolTable);
+            BuiltInVariable("gl_SubGroupLeMaskARB",     EbvSubGroupLeMask,     symbolTable);
+            BuiltInVariable("gl_SubGroupLtMaskARB",     EbvSubGroupLtMask,     symbolTable);
+
+            if (spvVersion.vulkan >= 100)
+                // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan
+                SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable);
+
+            symbolTable.setFunctionExtensions("anyInvocationARB",       1, &E_GL_ARB_shader_group_vote);
+            symbolTable.setFunctionExtensions("allInvocationsARB",      1, &E_GL_ARB_shader_group_vote);
+            symbolTable.setFunctionExtensions("allInvocationsEqualARB", 1, &E_GL_ARB_shader_group_vote);
+        }
+
+#ifdef AMD_EXTENSIONS
+        if (profile != EEsProfile) {
+            symbolTable.setFunctionExtensions("minInvocationsAMD",                1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsAMD",                1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsAMD",                1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("minInvocationsNonUniformAMD",      1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsNonUniformAMD",      1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsNonUniformAMD",      1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("swizzleInvocationsAMD",            1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("swizzleInvocationsWithPatternAMD", 1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("writeInvocationAMD",               1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("mbcntAMD",                         1, &E_GL_AMD_shader_ballot);
+
+            symbolTable.setFunctionExtensions("minInvocationsInclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsInclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsInclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("minInvocationsInclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsInclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsInclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("minInvocationsExclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsExclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsExclusiveScanAMD",             1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("minInvocationsExclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("maxInvocationsExclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+            symbolTable.setFunctionExtensions("addInvocationsExclusiveScanNonUniformAMD",   1, &E_GL_AMD_shader_ballot);
+        }
+
+        if (profile != EEsProfile) {
+            symbolTable.setFunctionExtensions("min3", 1, &E_GL_AMD_shader_trinary_minmax);
+            symbolTable.setFunctionExtensions("max3", 1, &E_GL_AMD_shader_trinary_minmax);
+            symbolTable.setFunctionExtensions("mid3", 1, &E_GL_AMD_shader_trinary_minmax);
+        }
+
+        if (profile != EEsProfile) {
+            symbolTable.setFunctionExtensions("cubeFaceIndexAMD", 1, &E_GL_AMD_gcn_shader);
+            symbolTable.setFunctionExtensions("cubeFaceCoordAMD", 1, &E_GL_AMD_gcn_shader);
+            symbolTable.setFunctionExtensions("timeAMD",          1, &E_GL_AMD_gcn_shader);
+        }
+#endif
+
+        // Compatibility variables, vertex only
+        if (spvVersion.spv == 0) {
+            BuiltInVariable("gl_Color",          EbvColor,          symbolTable);
+            BuiltInVariable("gl_SecondaryColor", EbvSecondaryColor, symbolTable);
+            BuiltInVariable("gl_Normal",         EbvNormal,         symbolTable);
+            BuiltInVariable("gl_Vertex",         EbvVertex,         symbolTable);
+            BuiltInVariable("gl_MultiTexCoord0", EbvMultiTexCoord0, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord1", EbvMultiTexCoord1, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord2", EbvMultiTexCoord2, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord3", EbvMultiTexCoord3, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord4", EbvMultiTexCoord4, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord5", EbvMultiTexCoord5, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord6", EbvMultiTexCoord6, symbolTable);
+            BuiltInVariable("gl_MultiTexCoord7", EbvMultiTexCoord7, symbolTable);
+            BuiltInVariable("gl_FogCoord",       EbvFogFragCoord,   symbolTable);
+        }
+
+        if (profile == EEsProfile) {
+            if (spvVersion.spv == 0) {
+                symbolTable.setFunctionExtensions("texture2DGradEXT",     1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DProjGradEXT", 1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureCubeGradEXT",   1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5);
+            }
+            if (version >= 310)
+                symbolTable.setFunctionExtensions("fma", Num_AEP_gpu_shader5, AEP_gpu_shader5);
+        }
+
+        if (profile == EEsProfile) {
+            symbolTable.setFunctionExtensions("imageAtomicAdd",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicMin",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicMax",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicAnd",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicOr",       1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicXor",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicExchange", 1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicCompSwap", 1, &E_GL_OES_shader_image_atomic);
+        }
+
+        if (spvVersion.vulkan == 0) {
+            SpecialQualifier("gl_VertexID",   EvqVertexId,   EbvVertexId,   symbolTable);
+            SpecialQualifier("gl_InstanceID", EvqInstanceId, EbvInstanceId, symbolTable);
+        }
+
+        if (spvVersion.vulkan >= 100) {
+            BuiltInVariable("gl_VertexIndex",   EbvVertexIndex,   symbolTable);
+            BuiltInVariable("gl_InstanceIndex", EbvInstanceIndex, symbolTable);
+        }
+
+        // Fall through
+
+    case EShLangTessControl:
+        if (profile == EEsProfile && version >= 310) {
+            symbolTable.setVariableExtensions("gl_BoundingBoxOES", Num_AEP_primitive_bounding_box, AEP_primitive_bounding_box);
+            BuiltInVariable("gl_BoundingBoxOES", EbvBoundingBox, symbolTable);
+        }
+
+        // Fall through
+
+    case EShLangTessEvaluation:
+    case EShLangGeometry:
+        SpecialQualifier("gl_Position",   EvqPosition,   EbvPosition,   symbolTable);
+        SpecialQualifier("gl_PointSize",  EvqPointSize,  EbvPointSize,  symbolTable);
+        SpecialQualifier("gl_ClipVertex", EvqClipVertex, EbvClipVertex, symbolTable);
+
+        BuiltInVariable("gl_in",  "gl_Position",     EbvPosition,     symbolTable);
+        BuiltInVariable("gl_in",  "gl_PointSize",    EbvPointSize,    symbolTable);
+        BuiltInVariable("gl_in",  "gl_ClipDistance", EbvClipDistance, symbolTable);
+        BuiltInVariable("gl_in",  "gl_CullDistance", EbvCullDistance, symbolTable);
+
+        BuiltInVariable("gl_out", "gl_Position",     EbvPosition,     symbolTable);
+        BuiltInVariable("gl_out", "gl_PointSize",    EbvPointSize,    symbolTable);
+        BuiltInVariable("gl_out", "gl_ClipDistance", EbvClipDistance, symbolTable);
+        BuiltInVariable("gl_out", "gl_CullDistance", EbvCullDistance, symbolTable);
+
+        BuiltInVariable("gl_ClipDistance",    EbvClipDistance,   symbolTable);
+        BuiltInVariable("gl_CullDistance",    EbvCullDistance,   symbolTable);
+        BuiltInVariable("gl_PrimitiveIDIn",   EbvPrimitiveId,    symbolTable);
+        BuiltInVariable("gl_PrimitiveID",     EbvPrimitiveId,    symbolTable);
+        BuiltInVariable("gl_InvocationID",    EbvInvocationId,   symbolTable);
+        BuiltInVariable("gl_Layer",           EbvLayer,          symbolTable);
+        BuiltInVariable("gl_ViewportIndex",   EbvViewportIndex,  symbolTable);
+
+#ifdef NV_EXTENSIONS
+        if (language != EShLangGeometry) {
+            symbolTable.setVariableExtensions("gl_Layer",         Num_viewportEXTs, viewportEXTs);
+            symbolTable.setVariableExtensions("gl_ViewportIndex", Num_viewportEXTs, viewportEXTs);
+        }
+        symbolTable.setVariableExtensions("gl_ViewportMask",            1, &E_GL_NV_viewport_array2);
+        symbolTable.setVariableExtensions("gl_SecondaryPositionNV",     1, &E_GL_NV_stereo_view_rendering);
+        symbolTable.setVariableExtensions("gl_SecondaryViewportMaskNV", 1, &E_GL_NV_stereo_view_rendering);
+        symbolTable.setVariableExtensions("gl_PositionPerViewNV",       1, &E_GL_NVX_multiview_per_view_attributes);
+        symbolTable.setVariableExtensions("gl_ViewportMaskPerViewNV",   1, &E_GL_NVX_multiview_per_view_attributes);
+
+        BuiltInVariable("gl_ViewportMask",              EbvViewportMaskNV,          symbolTable);
+        BuiltInVariable("gl_SecondaryPositionNV",       EbvSecondaryPositionNV,     symbolTable);
+        BuiltInVariable("gl_SecondaryViewportMaskNV",   EbvSecondaryViewportMaskNV, symbolTable);
+        BuiltInVariable("gl_PositionPerViewNV",         EbvPositionPerViewNV,       symbolTable);
+        BuiltInVariable("gl_ViewportMaskPerViewNV",     EbvViewportMaskPerViewNV,   symbolTable);
+
+        if (language != EShLangVertex) {
+            BuiltInVariable("gl_in", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
+            BuiltInVariable("gl_in", "gl_PositionPerViewNV",   EbvPositionPerViewNV,   symbolTable);
+        }
+        BuiltInVariable("gl_out", "gl_Layer",                   EbvLayer,                   symbolTable);
+        BuiltInVariable("gl_out", "gl_ViewportIndex",           EbvViewportIndex,           symbolTable);
+        BuiltInVariable("gl_out", "gl_ViewportMask",            EbvViewportMaskNV,          symbolTable);
+        BuiltInVariable("gl_out", "gl_SecondaryPositionNV",     EbvSecondaryPositionNV,     symbolTable);
+        BuiltInVariable("gl_out", "gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable);
+        BuiltInVariable("gl_out", "gl_PositionPerViewNV",       EbvPositionPerViewNV,       symbolTable);
+        BuiltInVariable("gl_out", "gl_ViewportMaskPerViewNV",   EbvViewportMaskPerViewNV,   symbolTable);
+#endif
+
+        BuiltInVariable("gl_PatchVerticesIn", EbvPatchVertices,  symbolTable);
+        BuiltInVariable("gl_TessLevelOuter",  EbvTessLevelOuter, symbolTable);
+        BuiltInVariable("gl_TessLevelInner",  EbvTessLevelInner, symbolTable);
+        BuiltInVariable("gl_TessCoord",       EbvTessCoord,      symbolTable);
+
+        if (version < 410)
+            symbolTable.setVariableExtensions("gl_ViewportIndex", 1, &E_GL_ARB_viewport_array);
+
+        // Compatibility variables
+
+        BuiltInVariable("gl_in", "gl_ClipVertex",          EbvClipVertex,          symbolTable);
+        BuiltInVariable("gl_in", "gl_FrontColor",          EbvFrontColor,          symbolTable);
+        BuiltInVariable("gl_in", "gl_BackColor",           EbvBackColor,           symbolTable);
+        BuiltInVariable("gl_in", "gl_FrontSecondaryColor", EbvFrontSecondaryColor, symbolTable);
+        BuiltInVariable("gl_in", "gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
+        BuiltInVariable("gl_in", "gl_TexCoord",            EbvTexCoord,            symbolTable);
+        BuiltInVariable("gl_in", "gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
+
+        BuiltInVariable("gl_out", "gl_ClipVertex",          EbvClipVertex,          symbolTable);
+        BuiltInVariable("gl_out", "gl_FrontColor",          EbvFrontColor,          symbolTable);
+        BuiltInVariable("gl_out", "gl_BackColor",           EbvBackColor,           symbolTable);
+        BuiltInVariable("gl_out", "gl_FrontSecondaryColor", EbvFrontSecondaryColor, symbolTable);
+        BuiltInVariable("gl_out", "gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
+        BuiltInVariable("gl_out", "gl_TexCoord",            EbvTexCoord,            symbolTable);
+        BuiltInVariable("gl_out", "gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
+
+        BuiltInVariable("gl_ClipVertex",          EbvClipVertex,          symbolTable);
+        BuiltInVariable("gl_FrontColor",          EbvFrontColor,          symbolTable);
+        BuiltInVariable("gl_BackColor",           EbvBackColor,           symbolTable);
+        BuiltInVariable("gl_FrontSecondaryColor", EbvFrontSecondaryColor, symbolTable);
+        BuiltInVariable("gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
+        BuiltInVariable("gl_TexCoord",            EbvTexCoord,            symbolTable);
+        BuiltInVariable("gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
+
+        // gl_PointSize, when it needs to be tied to an extension, is always a member of a block.
+        // (Sometimes with an instance name, sometimes anonymous).
+        // However, the current automatic extension scheme does not work per block member,
+        // so for now check when parsing.
+        //
+        // if (profile == EEsProfile) {
+        //    if (language == EShLangGeometry)
+        //        symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
+        //    else if (language == EShLangTessEvaluation || language == EShLangTessControl)
+        //        symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
+        //}
+
+        if ((profile != EEsProfile && version >= 140) ||
+            (profile == EEsProfile && version >= 310)) {
+            symbolTable.setVariableExtensions("gl_DeviceIndex",  1, &E_GL_EXT_device_group);
+            BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable);
+            symbolTable.setVariableExtensions("gl_ViewIndex", 1, &E_GL_EXT_multiview);
+            BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable);
+        }
+
+        break;
+
+    case EShLangFragment:
+        SpecialQualifier("gl_FrontFacing",      EvqFace,       EbvFace,             symbolTable);
+        SpecialQualifier("gl_FragCoord",        EvqFragCoord,  EbvFragCoord,        symbolTable);
+        SpecialQualifier("gl_PointCoord",       EvqPointCoord, EbvPointCoord,       symbolTable);
+        if (spvVersion.spv == 0)
+            SpecialQualifier("gl_FragColor",    EvqFragColor,  EbvFragColor,        symbolTable);
+        else {
+            TSymbol* symbol = symbolTable.find("gl_FragColor");
+            if (symbol) {
+                symbol->getWritableType().getQualifier().storage = EvqVaryingOut;
+                symbol->getWritableType().getQualifier().layoutLocation = 0;
+            }
+        }
+        SpecialQualifier("gl_FragDepth",        EvqFragDepth,  EbvFragDepth,        symbolTable);
+        SpecialQualifier("gl_FragDepthEXT",     EvqFragDepth,  EbvFragDepth,        symbolTable);
+        SpecialQualifier("gl_HelperInvocation", EvqVaryingIn,  EbvHelperInvocation, symbolTable);
+
+        BuiltInVariable("gl_ClipDistance",    EbvClipDistance,   symbolTable);
+        BuiltInVariable("gl_CullDistance",    EbvCullDistance,   symbolTable);
+        BuiltInVariable("gl_PrimitiveID",     EbvPrimitiveId,    symbolTable);
+
+        if ((profile != EEsProfile && version >= 400) ||
+            (profile == EEsProfile && version >= 310)) {
+            BuiltInVariable("gl_SampleID",        EbvSampleId,       symbolTable);
+            BuiltInVariable("gl_SamplePosition",  EbvSamplePosition, symbolTable);
+            BuiltInVariable("gl_SampleMaskIn",    EbvSampleMask,     symbolTable);
+            BuiltInVariable("gl_SampleMask",      EbvSampleMask,     symbolTable);
+            if (profile == EEsProfile) {
+                symbolTable.setVariableExtensions("gl_SampleID",       1, &E_GL_OES_sample_variables);
+                symbolTable.setVariableExtensions("gl_SamplePosition", 1, &E_GL_OES_sample_variables);
+                symbolTable.setVariableExtensions("gl_SampleMaskIn",   1, &E_GL_OES_sample_variables);
+                symbolTable.setVariableExtensions("gl_SampleMask",     1, &E_GL_OES_sample_variables);
+                symbolTable.setVariableExtensions("gl_NumSamples",     1, &E_GL_OES_sample_variables);
+            }
+        }
+
+        BuiltInVariable("gl_Layer",           EbvLayer,          symbolTable);
+        BuiltInVariable("gl_ViewportIndex",   EbvViewportIndex,  symbolTable);
+
+        // Compatibility variables
+
+        BuiltInVariable("gl_in", "gl_FogFragCoord",   EbvFogFragCoord,   symbolTable);
+        BuiltInVariable("gl_in", "gl_TexCoord",       EbvTexCoord,       symbolTable);
+        BuiltInVariable("gl_in", "gl_Color",          EbvColor,          symbolTable);
+        BuiltInVariable("gl_in", "gl_SecondaryColor", EbvSecondaryColor, symbolTable);
+
+        BuiltInVariable("gl_FogFragCoord",   EbvFogFragCoord,   symbolTable);
+        BuiltInVariable("gl_TexCoord",       EbvTexCoord,       symbolTable);
+        BuiltInVariable("gl_Color",          EbvColor,          symbolTable);
+        BuiltInVariable("gl_SecondaryColor", EbvSecondaryColor, symbolTable);
+
+        // built-in functions
+
+        if (profile == EEsProfile) {
+            if (spvVersion.spv == 0) {
+                symbolTable.setFunctionExtensions("texture2DLodEXT",      1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DProjLodEXT",  1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureCubeLodEXT",    1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DGradEXT",     1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DProjGradEXT", 1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureCubeGradEXT",   1, &E_GL_EXT_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5);
+            }
+            if (version == 100) {
+                symbolTable.setFunctionExtensions("dFdx",   1, &E_GL_OES_standard_derivatives);
+                symbolTable.setFunctionExtensions("dFdy",   1, &E_GL_OES_standard_derivatives);
+                symbolTable.setFunctionExtensions("fwidth", 1, &E_GL_OES_standard_derivatives);
+            }
+            if (version >= 310) {
+                symbolTable.setFunctionExtensions("fma", Num_AEP_gpu_shader5, AEP_gpu_shader5);
+                symbolTable.setFunctionExtensions("interpolateAtCentroid", 1, &E_GL_OES_shader_multisample_interpolation);
+                symbolTable.setFunctionExtensions("interpolateAtSample",   1, &E_GL_OES_shader_multisample_interpolation);
+                symbolTable.setFunctionExtensions("interpolateAtOffset",   1, &E_GL_OES_shader_multisample_interpolation);
+            }
+        } else if (version < 130) {
+            if (spvVersion.spv == 0) {
+                symbolTable.setFunctionExtensions("texture1DLod",        1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DLod",        1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture3DLod",        1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("textureCubeLod",      1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture1DProjLod",    1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture2DProjLod",    1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("texture3DProjLod",    1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("shadow1DLod",         1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("shadow2DLod",         1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("shadow1DProjLod",     1, &E_GL_ARB_shader_texture_lod);
+                symbolTable.setFunctionExtensions("shadow2DProjLod",     1, &E_GL_ARB_shader_texture_lod);
+            }
+        }
+
+        // E_GL_ARB_shader_texture_lod functions usable only with the extension enabled
+        if (profile != EEsProfile && spvVersion.spv == 0) {
+            symbolTable.setFunctionExtensions("texture1DGradARB",         1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture1DProjGradARB",     1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture2DGradARB",         1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture2DProjGradARB",     1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture3DGradARB",         1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture3DProjGradARB",     1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("textureCubeGradARB",       1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow1DGradARB",          1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow1DProjGradARB",      1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow2DGradARB",          1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow2DProjGradARB",      1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture2DRectGradARB",     1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("texture2DRectProjGradARB", 1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow2DRectGradARB",      1, &E_GL_ARB_shader_texture_lod);
+            symbolTable.setFunctionExtensions("shadow2DRectProjGradARB",  1, &E_GL_ARB_shader_texture_lod);
+        }
+
+		// E_GL_EXT_texture_array
+        if (spvVersion.spv == 0) {
+            symbolTable.setFunctionExtensions("texture2DArray",    1, &E_GL_EXT_texture_array);
+        }
+        if (profile != EEsProfile && spvVersion.spv == 0) {
+            int nLodExtensions = 2;
+            const char *lodExtensions[] = {E_GL_EXT_texture_array, E_GL_ARB_shader_texture_lod};
+
+            if (version >= 130)
+                nLodExtensions = 1;
+
+            symbolTable.setFunctionExtensions("texture1DArray",    1, &E_GL_EXT_texture_array);
+            symbolTable.setFunctionExtensions("shadow1DArray",     1, &E_GL_EXT_texture_array);
+            symbolTable.setFunctionExtensions("shadow2DArray",     1, &E_GL_EXT_texture_array);
+
+            symbolTable.setFunctionExtensions("texture1DArrayLod", nLodExtensions, lodExtensions);
+            symbolTable.setFunctionExtensions("texture2DArrayLod", nLodExtensions, lodExtensions);
+            symbolTable.setFunctionExtensions("shadow1DArrayLod",  nLodExtensions, lodExtensions);
+            symbolTable.setFunctionExtensions("shadow2DArrayLod",  nLodExtensions, lodExtensions);
+        }
+
+        // E_GL_ARB_shader_image_load_store
+        if (profile != EEsProfile && version < 420)
+            symbolTable.setFunctionExtensions("memoryBarrier", 1, &E_GL_ARB_shader_image_load_store);
+        // All the image access functions are protected by checks on the type of the first argument.
+
+        // E_GL_ARB_shader_atomic_counters
+        if (profile != EEsProfile && version < 420) {
+            symbolTable.setFunctionExtensions("atomicCounterIncrement", 1, &E_GL_ARB_shader_atomic_counters);
+            symbolTable.setFunctionExtensions("atomicCounterDecrement", 1, &E_GL_ARB_shader_atomic_counters);
+            symbolTable.setFunctionExtensions("atomicCounter"         , 1, &E_GL_ARB_shader_atomic_counters);
+        }
+
+        // E_GL_ARB_derivative_control
+        if (profile != EEsProfile && version < 450) {
+            symbolTable.setFunctionExtensions("dFdxFine",     1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("dFdyFine",     1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("fwidthFine",   1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("dFdxCoarse",   1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("dFdyCoarse",   1, &E_GL_ARB_derivative_control);
+            symbolTable.setFunctionExtensions("fwidthCoarse", 1, &E_GL_ARB_derivative_control);
+        }
+
+        // E_GL_ARB_sparse_texture2
+        if (profile != EEsProfile)
+        {
+            symbolTable.setFunctionExtensions("sparseTextureARB",              1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureLodARB",           1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureOffsetARB",        1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTexelFetchARB",           1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTexelFetchOffsetARB",     1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureLodOffsetARB",     1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGradARB",          1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGradOffsetARB",    1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGatherARB",        1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGatherOffsetARB",  1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTextureGatherOffsetsARB", 1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseImageLoadARB",            1, &E_GL_ARB_sparse_texture2);
+            symbolTable.setFunctionExtensions("sparseTexelsResident",          1, &E_GL_ARB_sparse_texture2);
+        }
+
+        // E_GL_ARB_sparse_texture_clamp
+        if (profile != EEsProfile)
+        {
+            symbolTable.setFunctionExtensions("sparseTextureClampARB",              1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("sparseTextureOffsetClampARB",        1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("sparseTextureGradClampARB",          1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("sparseTextureGradOffsetClampARB",    1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("textureClampARB",                    1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("textureOffsetClampARB",              1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("textureGradClampARB",                1, &E_GL_ARB_sparse_texture_clamp);
+            symbolTable.setFunctionExtensions("textureGradOffsetClampARB",          1, &E_GL_ARB_sparse_texture_clamp);
+        }
+
+#ifdef AMD_EXTENSIONS
+        // E_GL_AMD_shader_explicit_vertex_parameter
+        if (profile != EEsProfile) {
+            symbolTable.setVariableExtensions("gl_BaryCoordNoPerspAMD",         1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordNoPerspCentroidAMD", 1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordNoPerspSampleAMD",   1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordSmoothAMD",          1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordSmoothCentroidAMD",  1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordSmoothSampleAMD",    1, &E_GL_AMD_shader_explicit_vertex_parameter);
+            symbolTable.setVariableExtensions("gl_BaryCoordPullModelAMD",       1, &E_GL_AMD_shader_explicit_vertex_parameter);
+
+            symbolTable.setFunctionExtensions("interpolateAtVertexAMD",         1, &E_GL_AMD_shader_explicit_vertex_parameter);
+
+            BuiltInVariable("gl_BaryCoordNoPerspAMD",           EbvBaryCoordNoPersp,         symbolTable);
+            BuiltInVariable("gl_BaryCoordNoPerspCentroidAMD",   EbvBaryCoordNoPerspCentroid, symbolTable);
+            BuiltInVariable("gl_BaryCoordNoPerspSampleAMD",     EbvBaryCoordNoPerspSample,   symbolTable);
+            BuiltInVariable("gl_BaryCoordSmoothAMD",            EbvBaryCoordSmooth,          symbolTable);
+            BuiltInVariable("gl_BaryCoordSmoothCentroidAMD",    EbvBaryCoordSmoothCentroid,  symbolTable);
+            BuiltInVariable("gl_BaryCoordSmoothSampleAMD",      EbvBaryCoordSmoothSample,    symbolTable);
+            BuiltInVariable("gl_BaryCoordPullModelAMD",         EbvBaryCoordPullModel,       symbolTable);
+        }
+
+        // E_GL_AMD_texture_gather_bias_lod
+        if (profile != EEsProfile) {
+            symbolTable.setFunctionExtensions("textureGatherLodAMD",                1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("textureGatherLodOffsetAMD",          1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("textureGatherLodOffsetsAMD",         1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("sparseTextureGatherLodAMD",          1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("sparseTextureGatherLodOffsetAMD",    1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("sparseTextureGatherLodOffsetsAMD",   1, &E_GL_AMD_texture_gather_bias_lod);
+        }
+#endif
+
+        symbolTable.setVariableExtensions("gl_FragDepthEXT", 1, &E_GL_EXT_frag_depth);
+
+        if (profile == EEsProfile) {
+            symbolTable.setVariableExtensions("gl_PrimitiveID",  Num_AEP_geometry_shader, AEP_geometry_shader);
+            symbolTable.setVariableExtensions("gl_Layer",        Num_AEP_geometry_shader, AEP_geometry_shader);
+        }
+
+        if (profile == EEsProfile) {
+            symbolTable.setFunctionExtensions("imageAtomicAdd",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicMin",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicMax",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicAnd",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicOr",       1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicXor",      1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicExchange", 1, &E_GL_OES_shader_image_atomic);
+            symbolTable.setFunctionExtensions("imageAtomicCompSwap", 1, &E_GL_OES_shader_image_atomic);
+        }
+
+        symbolTable.setVariableExtensions("gl_DeviceIndex",  1, &E_GL_EXT_device_group);
+        BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable);
+        symbolTable.setVariableExtensions("gl_ViewIndex", 1, &E_GL_EXT_multiview);
+        BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable);
+        break;
+
+    case EShLangCompute:
+        BuiltInVariable("gl_NumWorkGroups",         EbvNumWorkGroups,        symbolTable);
+        BuiltInVariable("gl_WorkGroupSize",         EbvWorkGroupSize,        symbolTable);
+        BuiltInVariable("gl_WorkGroupID",           EbvWorkGroupId,          symbolTable);
+        BuiltInVariable("gl_LocalInvocationID",     EbvLocalInvocationId,    symbolTable);
+        BuiltInVariable("gl_GlobalInvocationID",    EbvGlobalInvocationId,   symbolTable);
+        BuiltInVariable("gl_LocalInvocationIndex",  EbvLocalInvocationIndex, symbolTable);
+
+        if (profile != EEsProfile && version < 430) {
+            symbolTable.setVariableExtensions("gl_NumWorkGroups",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_WorkGroupSize",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_WorkGroupID",          1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_LocalInvocationID",    1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_GlobalInvocationID",   1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_LocalInvocationIndex", 1, &E_GL_ARB_compute_shader);
+
+            symbolTable.setVariableExtensions("gl_MaxComputeWorkGroupCount",       1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeWorkGroupSize",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeUniformComponents",    1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeTextureImageUnits",    1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeImageUniforms",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeAtomicCounters",       1, &E_GL_ARB_compute_shader);
+            symbolTable.setVariableExtensions("gl_MaxComputeAtomicCounterBuffers", 1, &E_GL_ARB_compute_shader);
+
+            symbolTable.setFunctionExtensions("barrier",                    1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("memoryBarrierAtomicCounter", 1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("memoryBarrierBuffer",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("memoryBarrierImage",         1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("memoryBarrierShared",        1, &E_GL_ARB_compute_shader);
+            symbolTable.setFunctionExtensions("groupMemoryBarrier",         1, &E_GL_ARB_compute_shader);
+        }
+
+        if ((profile != EEsProfile && version >= 140) ||
+            (profile == EEsProfile && version >= 310)) {
+            symbolTable.setVariableExtensions("gl_DeviceIndex",  1, &E_GL_EXT_device_group);
+            BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable);
+            symbolTable.setVariableExtensions("gl_ViewIndex", 1, &E_GL_EXT_multiview);
+            BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable);
+        }
+
+        break;
+
+    default:
+        assert(false && "Language not supported");
+        break;
+    }
+
+    //
+    // Next, identify which built-ins have a mapping to an operator.
+    // If PureOperatorBuiltins is false, those that are not identified as such are
+    // expected to be resolved through a library of functions, versus as
+    // operations.
+    //
+    symbolTable.relateToOperator("not",              EOpVectorLogicalNot);
+
+    symbolTable.relateToOperator("matrixCompMult",   EOpMul);
+    // 120 and 150 are correct for both ES and desktop
+    if (version >= 120) {
+        symbolTable.relateToOperator("outerProduct", EOpOuterProduct);
+        symbolTable.relateToOperator("transpose", EOpTranspose);
+        if (version >= 150) {
+            symbolTable.relateToOperator("determinant", EOpDeterminant);
+            symbolTable.relateToOperator("inverse", EOpMatrixInverse);
+        }
+    }
+
+    symbolTable.relateToOperator("mod",              EOpMod);
+    symbolTable.relateToOperator("modf",             EOpModf);
+
+    symbolTable.relateToOperator("equal",            EOpVectorEqual);
+    symbolTable.relateToOperator("notEqual",         EOpVectorNotEqual);
+    symbolTable.relateToOperator("lessThan",         EOpLessThan);
+    symbolTable.relateToOperator("greaterThan",      EOpGreaterThan);
+    symbolTable.relateToOperator("lessThanEqual",    EOpLessThanEqual);
+    symbolTable.relateToOperator("greaterThanEqual", EOpGreaterThanEqual);
+
+    symbolTable.relateToOperator("radians",      EOpRadians);
+    symbolTable.relateToOperator("degrees",      EOpDegrees);
+    symbolTable.relateToOperator("sin",          EOpSin);
+    symbolTable.relateToOperator("cos",          EOpCos);
+    symbolTable.relateToOperator("tan",          EOpTan);
+    symbolTable.relateToOperator("asin",         EOpAsin);
+    symbolTable.relateToOperator("acos",         EOpAcos);
+    symbolTable.relateToOperator("atan",         EOpAtan);
+    symbolTable.relateToOperator("sinh",         EOpSinh);
+    symbolTable.relateToOperator("cosh",         EOpCosh);
+    symbolTable.relateToOperator("tanh",         EOpTanh);
+    symbolTable.relateToOperator("asinh",        EOpAsinh);
+    symbolTable.relateToOperator("acosh",        EOpAcosh);
+    symbolTable.relateToOperator("atanh",        EOpAtanh);
+
+    symbolTable.relateToOperator("pow",          EOpPow);
+    symbolTable.relateToOperator("exp2",         EOpExp2);
+    symbolTable.relateToOperator("log",          EOpLog);
+    symbolTable.relateToOperator("exp",          EOpExp);
+    symbolTable.relateToOperator("log2",         EOpLog2);
+    symbolTable.relateToOperator("sqrt",         EOpSqrt);
+    symbolTable.relateToOperator("inversesqrt",  EOpInverseSqrt);
+
+    symbolTable.relateToOperator("abs",          EOpAbs);
+    symbolTable.relateToOperator("sign",         EOpSign);
+    symbolTable.relateToOperator("floor",        EOpFloor);
+    symbolTable.relateToOperator("trunc",        EOpTrunc);
+    symbolTable.relateToOperator("round",        EOpRound);
+    symbolTable.relateToOperator("roundEven",    EOpRoundEven);
+    symbolTable.relateToOperator("ceil",         EOpCeil);
+    symbolTable.relateToOperator("fract",        EOpFract);
+    symbolTable.relateToOperator("min",          EOpMin);
+    symbolTable.relateToOperator("max",          EOpMax);
+    symbolTable.relateToOperator("clamp",        EOpClamp);
+    symbolTable.relateToOperator("mix",          EOpMix);
+    symbolTable.relateToOperator("step",         EOpStep);
+    symbolTable.relateToOperator("smoothstep",   EOpSmoothStep);
+
+    symbolTable.relateToOperator("isnan",  EOpIsNan);
+    symbolTable.relateToOperator("isinf",  EOpIsInf);
+
+    symbolTable.relateToOperator("floatBitsToInt",  EOpFloatBitsToInt);
+    symbolTable.relateToOperator("floatBitsToUint", EOpFloatBitsToUint);
+    symbolTable.relateToOperator("intBitsToFloat",  EOpIntBitsToFloat);
+    symbolTable.relateToOperator("uintBitsToFloat", EOpUintBitsToFloat);
+    symbolTable.relateToOperator("doubleBitsToInt64",  EOpDoubleBitsToInt64);
+    symbolTable.relateToOperator("doubleBitsToUint64", EOpDoubleBitsToUint64);
+    symbolTable.relateToOperator("int64BitsToDouble",  EOpInt64BitsToDouble);
+    symbolTable.relateToOperator("uint64BitsToDouble", EOpUint64BitsToDouble);
+#ifdef AMD_EXTENSIONS
+    symbolTable.relateToOperator("float16BitsToInt16",  EOpFloat16BitsToInt16);
+    symbolTable.relateToOperator("float16BitsToUint16", EOpFloat16BitsToUint16);
+    symbolTable.relateToOperator("int16BitsToFloat16",  EOpInt16BitsToFloat16);
+    symbolTable.relateToOperator("uint16BitsToFloat16", EOpUint16BitsToFloat16);
+#endif
+
+    symbolTable.relateToOperator("packSnorm2x16",   EOpPackSnorm2x16);
+    symbolTable.relateToOperator("unpackSnorm2x16", EOpUnpackSnorm2x16);
+    symbolTable.relateToOperator("packUnorm2x16",   EOpPackUnorm2x16);
+    symbolTable.relateToOperator("unpackUnorm2x16", EOpUnpackUnorm2x16);
+
+    symbolTable.relateToOperator("packSnorm4x8",    EOpPackSnorm4x8);
+    symbolTable.relateToOperator("unpackSnorm4x8",  EOpUnpackSnorm4x8);
+    symbolTable.relateToOperator("packUnorm4x8",    EOpPackUnorm4x8);
+    symbolTable.relateToOperator("unpackUnorm4x8",  EOpUnpackUnorm4x8);
+
+    symbolTable.relateToOperator("packDouble2x32",    EOpPackDouble2x32);
+    symbolTable.relateToOperator("unpackDouble2x32",  EOpUnpackDouble2x32);
+
+    symbolTable.relateToOperator("packHalf2x16",    EOpPackHalf2x16);
+    symbolTable.relateToOperator("unpackHalf2x16",  EOpUnpackHalf2x16);
+
+    symbolTable.relateToOperator("packInt2x32",     EOpPackInt2x32);
+    symbolTable.relateToOperator("unpackInt2x32",   EOpUnpackInt2x32);
+    symbolTable.relateToOperator("packUint2x32",    EOpPackUint2x32);
+    symbolTable.relateToOperator("unpackUint2x32",  EOpUnpackUint2x32);
+
+#ifdef AMD_EXTENSIONS
+    symbolTable.relateToOperator("packInt2x16",     EOpPackInt2x16);
+    symbolTable.relateToOperator("unpackInt2x16",   EOpUnpackInt2x16);
+    symbolTable.relateToOperator("packUint2x16",    EOpPackUint2x16);
+    symbolTable.relateToOperator("unpackUint2x16",  EOpUnpackUint2x16);
+
+    symbolTable.relateToOperator("packInt4x16",     EOpPackInt4x16);
+    symbolTable.relateToOperator("unpackInt4x16",   EOpUnpackInt4x16);
+    symbolTable.relateToOperator("packUint4x16",    EOpPackUint4x16);
+    symbolTable.relateToOperator("unpackUint4x16",  EOpUnpackUint4x16);
+
+    symbolTable.relateToOperator("packFloat2x16",   EOpPackFloat2x16);
+    symbolTable.relateToOperator("unpackFloat2x16", EOpUnpackFloat2x16);
+#endif
+
+    symbolTable.relateToOperator("length",       EOpLength);
+    symbolTable.relateToOperator("distance",     EOpDistance);
+    symbolTable.relateToOperator("dot",          EOpDot);
+    symbolTable.relateToOperator("cross",        EOpCross);
+    symbolTable.relateToOperator("normalize",    EOpNormalize);
+    symbolTable.relateToOperator("faceforward",  EOpFaceForward);
+    symbolTable.relateToOperator("reflect",      EOpReflect);
+    symbolTable.relateToOperator("refract",      EOpRefract);
+
+    symbolTable.relateToOperator("any",          EOpAny);
+    symbolTable.relateToOperator("all",          EOpAll);
+
+    symbolTable.relateToOperator("barrier",                    EOpBarrier);
+    symbolTable.relateToOperator("memoryBarrier",              EOpMemoryBarrier);
+    symbolTable.relateToOperator("memoryBarrierAtomicCounter", EOpMemoryBarrierAtomicCounter);
+    symbolTable.relateToOperator("memoryBarrierBuffer",        EOpMemoryBarrierBuffer);
+    symbolTable.relateToOperator("memoryBarrierImage",         EOpMemoryBarrierImage);
+
+    symbolTable.relateToOperator("atomicAdd",      EOpAtomicAdd);
+    symbolTable.relateToOperator("atomicMin",      EOpAtomicMin);
+    symbolTable.relateToOperator("atomicMax",      EOpAtomicMax);
+    symbolTable.relateToOperator("atomicAnd",      EOpAtomicAnd);
+    symbolTable.relateToOperator("atomicOr",       EOpAtomicOr);
+    symbolTable.relateToOperator("atomicXor",      EOpAtomicXor);
+    symbolTable.relateToOperator("atomicExchange", EOpAtomicExchange);
+    symbolTable.relateToOperator("atomicCompSwap", EOpAtomicCompSwap);
+
+    symbolTable.relateToOperator("atomicCounterIncrement", EOpAtomicCounterIncrement);
+    symbolTable.relateToOperator("atomicCounterDecrement", EOpAtomicCounterDecrement);
+    symbolTable.relateToOperator("atomicCounter",          EOpAtomicCounter);
+
+    symbolTable.relateToOperator("fma",               EOpFma);
+    symbolTable.relateToOperator("frexp",             EOpFrexp);
+    symbolTable.relateToOperator("ldexp",             EOpLdexp);
+    symbolTable.relateToOperator("uaddCarry",         EOpAddCarry);
+    symbolTable.relateToOperator("usubBorrow",        EOpSubBorrow);
+    symbolTable.relateToOperator("umulExtended",      EOpUMulExtended);
+    symbolTable.relateToOperator("imulExtended",      EOpIMulExtended);
+    symbolTable.relateToOperator("bitfieldExtract",   EOpBitfieldExtract);
+    symbolTable.relateToOperator("bitfieldInsert",    EOpBitfieldInsert);
+    symbolTable.relateToOperator("bitfieldReverse",   EOpBitFieldReverse);
+    symbolTable.relateToOperator("bitCount",          EOpBitCount);
+    symbolTable.relateToOperator("findLSB",           EOpFindLSB);
+    symbolTable.relateToOperator("findMSB",           EOpFindMSB);
+
+    if (PureOperatorBuiltins) {
+        symbolTable.relateToOperator("imageSize",               EOpImageQuerySize);
+        symbolTable.relateToOperator("imageSamples",            EOpImageQuerySamples);
+        symbolTable.relateToOperator("imageLoad",               EOpImageLoad);
+        symbolTable.relateToOperator("imageStore",              EOpImageStore);
+        symbolTable.relateToOperator("imageAtomicAdd",          EOpImageAtomicAdd);
+        symbolTable.relateToOperator("imageAtomicMin",          EOpImageAtomicMin);
+        symbolTable.relateToOperator("imageAtomicMax",          EOpImageAtomicMax);
+        symbolTable.relateToOperator("imageAtomicAnd",          EOpImageAtomicAnd);
+        symbolTable.relateToOperator("imageAtomicOr",           EOpImageAtomicOr);
+        symbolTable.relateToOperator("imageAtomicXor",          EOpImageAtomicXor);
+        symbolTable.relateToOperator("imageAtomicExchange",     EOpImageAtomicExchange);
+        symbolTable.relateToOperator("imageAtomicCompSwap",     EOpImageAtomicCompSwap);
+
+        symbolTable.relateToOperator("subpassLoad",             EOpSubpassLoad);
+        symbolTable.relateToOperator("subpassLoadMS",           EOpSubpassLoadMS);
+
+        symbolTable.relateToOperator("textureSize",             EOpTextureQuerySize);
+        symbolTable.relateToOperator("textureQueryLod",         EOpTextureQueryLod);
+        symbolTable.relateToOperator("textureQueryLevels",      EOpTextureQueryLevels);
+        symbolTable.relateToOperator("textureSamples",          EOpTextureQuerySamples);
+        symbolTable.relateToOperator("texture",                 EOpTexture);
+        symbolTable.relateToOperator("textureProj",             EOpTextureProj);
+        symbolTable.relateToOperator("textureLod",              EOpTextureLod);
+        symbolTable.relateToOperator("textureOffset",           EOpTextureOffset);
+        symbolTable.relateToOperator("texelFetch",              EOpTextureFetch);
+        symbolTable.relateToOperator("texelFetchOffset",        EOpTextureFetchOffset);
+        symbolTable.relateToOperator("textureProjOffset",       EOpTextureProjOffset);
+        symbolTable.relateToOperator("textureLodOffset",        EOpTextureLodOffset);
+        symbolTable.relateToOperator("textureProjLod",          EOpTextureProjLod);
+        symbolTable.relateToOperator("textureProjLodOffset",    EOpTextureProjLodOffset);
+        symbolTable.relateToOperator("textureGrad",             EOpTextureGrad);
+        symbolTable.relateToOperator("textureGradOffset",       EOpTextureGradOffset);
+        symbolTable.relateToOperator("textureProjGrad",         EOpTextureProjGrad);
+        symbolTable.relateToOperator("textureProjGradOffset",   EOpTextureProjGradOffset);
+        symbolTable.relateToOperator("textureGather",           EOpTextureGather);
+        symbolTable.relateToOperator("textureGatherOffset",     EOpTextureGatherOffset);
+        symbolTable.relateToOperator("textureGatherOffsets",    EOpTextureGatherOffsets);
+
+        symbolTable.relateToOperator("noise1", EOpNoise);
+        symbolTable.relateToOperator("noise2", EOpNoise);
+        symbolTable.relateToOperator("noise3", EOpNoise);
+        symbolTable.relateToOperator("noise4", EOpNoise);
+
+        if (spvVersion.spv == 0 && (IncludeLegacy(version, profile, spvVersion) ||
+            (profile == EEsProfile && version == 100))) {
+            symbolTable.relateToOperator("ftransform",               EOpFtransform);
+
+            symbolTable.relateToOperator("texture1D",                EOpTexture);
+            symbolTable.relateToOperator("texture1DGradARB",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture1DProj",            EOpTextureProj);
+            symbolTable.relateToOperator("texture1DProjGradARB",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture1DLod",             EOpTextureLod);
+            symbolTable.relateToOperator("texture1DProjLod",         EOpTextureProjLod);
+
+            symbolTable.relateToOperator("texture2DRect",            EOpTexture);
+            symbolTable.relateToOperator("texture2DRectProj",        EOpTextureProj);
+            symbolTable.relateToOperator("texture2DRectGradARB",     EOpTextureGrad);
+            symbolTable.relateToOperator("texture2DRectProjGradARB", EOpTextureProjGrad);
+            symbolTable.relateToOperator("shadow2DRect",             EOpTexture);
+            symbolTable.relateToOperator("shadow2DRectProj",         EOpTextureProj);
+            symbolTable.relateToOperator("shadow2DRectGradARB",      EOpTextureGrad);
+            symbolTable.relateToOperator("shadow2DRectProjGradARB",  EOpTextureProjGrad);
+
+            symbolTable.relateToOperator("texture2D",                EOpTexture);
+            symbolTable.relateToOperator("texture2DProj",            EOpTextureProj);
+            symbolTable.relateToOperator("texture2DGradEXT",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture2DGradARB",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture2DProjGradEXT",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture2DProjGradARB",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture2DLod",             EOpTextureLod);
+            symbolTable.relateToOperator("texture2DLodEXT",          EOpTextureLod);
+            symbolTable.relateToOperator("texture2DProjLod",         EOpTextureProjLod);
+            symbolTable.relateToOperator("texture2DProjLodEXT",      EOpTextureProjLod);
+
+            symbolTable.relateToOperator("texture1DArray",           EOpTexture);
+            symbolTable.relateToOperator("texture2DArray",           EOpTexture);
+            symbolTable.relateToOperator("shadow1DArray",            EOpTexture);
+            symbolTable.relateToOperator("shadow2DArray",            EOpTexture);
+            symbolTable.relateToOperator("texture1DArrayLod",        EOpTextureLod);
+            symbolTable.relateToOperator("texture2DArrayLod",        EOpTextureLod);
+            symbolTable.relateToOperator("shadow1DArrayLod",         EOpTextureLod);
+            symbolTable.relateToOperator("shadow2DArrayLod",         EOpTextureLod);
+
+            symbolTable.relateToOperator("texture3D",                EOpTexture);
+            symbolTable.relateToOperator("texture3DGradARB",         EOpTextureGrad);
+            symbolTable.relateToOperator("texture3DProj",            EOpTextureProj);
+            symbolTable.relateToOperator("texture3DProjGradARB",     EOpTextureProjGrad);
+            symbolTable.relateToOperator("texture3DLod",             EOpTextureLod);
+            symbolTable.relateToOperator("texture3DProjLod",         EOpTextureProjLod);
+            symbolTable.relateToOperator("textureCube",              EOpTexture);
+            symbolTable.relateToOperator("textureCubeGradEXT",       EOpTextureGrad);
+            symbolTable.relateToOperator("textureCubeGradARB",       EOpTextureGrad);
+            symbolTable.relateToOperator("textureCubeLod",           EOpTextureLod);
+            symbolTable.relateToOperator("textureCubeLodEXT",        EOpTextureLod);
+            symbolTable.relateToOperator("shadow1D",                 EOpTexture);
+            symbolTable.relateToOperator("shadow1DGradARB",          EOpTextureGrad);
+            symbolTable.relateToOperator("shadow2D",                 EOpTexture);
+            symbolTable.relateToOperator("shadow2DGradARB",          EOpTextureGrad);
+            symbolTable.relateToOperator("shadow1DProj",             EOpTextureProj);
+            symbolTable.relateToOperator("shadow2DProj",             EOpTextureProj);
+            symbolTable.relateToOperator("shadow1DProjGradARB",      EOpTextureProjGrad);
+            symbolTable.relateToOperator("shadow2DProjGradARB",      EOpTextureProjGrad);
+            symbolTable.relateToOperator("shadow1DLod",              EOpTextureLod);
+            symbolTable.relateToOperator("shadow2DLod",              EOpTextureLod);
+            symbolTable.relateToOperator("shadow1DProjLod",          EOpTextureProjLod);
+            symbolTable.relateToOperator("shadow2DProjLod",          EOpTextureProjLod);
+        }
+
+        if (profile != EEsProfile) {
+            symbolTable.relateToOperator("sparseTextureARB",                EOpSparseTexture);
+            symbolTable.relateToOperator("sparseTextureLodARB",             EOpSparseTextureLod);
+            symbolTable.relateToOperator("sparseTextureOffsetARB",          EOpSparseTextureOffset);
+            symbolTable.relateToOperator("sparseTexelFetchARB",             EOpSparseTextureFetch);
+            symbolTable.relateToOperator("sparseTexelFetchOffsetARB",       EOpSparseTextureFetchOffset);
+            symbolTable.relateToOperator("sparseTextureLodOffsetARB",       EOpSparseTextureLodOffset);
+            symbolTable.relateToOperator("sparseTextureGradARB",            EOpSparseTextureGrad);
+            symbolTable.relateToOperator("sparseTextureGradOffsetARB",      EOpSparseTextureGradOffset);
+            symbolTable.relateToOperator("sparseTextureGatherARB",          EOpSparseTextureGather);
+            symbolTable.relateToOperator("sparseTextureGatherOffsetARB",    EOpSparseTextureGatherOffset);
+            symbolTable.relateToOperator("sparseTextureGatherOffsetsARB",   EOpSparseTextureGatherOffsets);
+            symbolTable.relateToOperator("sparseImageLoadARB",              EOpSparseImageLoad);
+            symbolTable.relateToOperator("sparseTexelsResidentARB",         EOpSparseTexelsResident);
+
+            symbolTable.relateToOperator("sparseTextureClampARB",           EOpSparseTextureClamp);
+            symbolTable.relateToOperator("sparseTextureOffsetClampARB",     EOpSparseTextureOffsetClamp);
+            symbolTable.relateToOperator("sparseTextureGradClampARB",       EOpSparseTextureGradClamp);
+            symbolTable.relateToOperator("sparseTextureGradOffsetClampARB", EOpSparseTextureGradOffsetClamp);
+            symbolTable.relateToOperator("textureClampARB",                 EOpTextureClamp);
+            symbolTable.relateToOperator("textureOffsetClampARB",           EOpTextureOffsetClamp);
+            symbolTable.relateToOperator("textureGradClampARB",             EOpTextureGradClamp);
+            symbolTable.relateToOperator("textureGradOffsetClampARB",       EOpTextureGradOffsetClamp);
+
+            symbolTable.relateToOperator("ballotARB",                       EOpBallot);
+            symbolTable.relateToOperator("readInvocationARB",               EOpReadInvocation);
+            symbolTable.relateToOperator("readFirstInvocationARB",          EOpReadFirstInvocation);
+
+            symbolTable.relateToOperator("anyInvocationARB",                EOpAnyInvocation);
+            symbolTable.relateToOperator("allInvocationsARB",               EOpAllInvocations);
+            symbolTable.relateToOperator("allInvocationsEqualARB",          EOpAllInvocationsEqual);
+
+#ifdef AMD_EXTENSIONS
+            symbolTable.relateToOperator("minInvocationsAMD",                           EOpMinInvocations);
+            symbolTable.relateToOperator("maxInvocationsAMD",                           EOpMaxInvocations);
+            symbolTable.relateToOperator("addInvocationsAMD",                           EOpAddInvocations);
+            symbolTable.relateToOperator("minInvocationsNonUniformAMD",                 EOpMinInvocationsNonUniform);
+            symbolTable.relateToOperator("maxInvocationsNonUniformAMD",                 EOpMaxInvocationsNonUniform);
+            symbolTable.relateToOperator("addInvocationsNonUniformAMD",                 EOpAddInvocationsNonUniform);
+            symbolTable.relateToOperator("minInvocationsInclusiveScanAMD",              EOpMinInvocationsInclusiveScan);
+            symbolTable.relateToOperator("maxInvocationsInclusiveScanAMD",              EOpMaxInvocationsInclusiveScan);
+            symbolTable.relateToOperator("addInvocationsInclusiveScanAMD",              EOpAddInvocationsInclusiveScan);
+            symbolTable.relateToOperator("minInvocationsInclusiveScanNonUniformAMD",    EOpMinInvocationsInclusiveScanNonUniform);
+            symbolTable.relateToOperator("maxInvocationsInclusiveScanNonUniformAMD",    EOpMaxInvocationsInclusiveScanNonUniform);
+            symbolTable.relateToOperator("addInvocationsInclusiveScanNonUniformAMD",    EOpAddInvocationsInclusiveScanNonUniform);
+            symbolTable.relateToOperator("minInvocationsExclusiveScanAMD",              EOpMinInvocationsExclusiveScan);
+            symbolTable.relateToOperator("maxInvocationsExclusiveScanAMD",              EOpMaxInvocationsExclusiveScan);
+            symbolTable.relateToOperator("addInvocationsExclusiveScanAMD",              EOpAddInvocationsExclusiveScan);
+            symbolTable.relateToOperator("minInvocationsExclusiveScanNonUniformAMD",    EOpMinInvocationsExclusiveScanNonUniform);
+            symbolTable.relateToOperator("maxInvocationsExclusiveScanNonUniformAMD",    EOpMaxInvocationsExclusiveScanNonUniform);
+            symbolTable.relateToOperator("addInvocationsExclusiveScanNonUniformAMD",    EOpAddInvocationsExclusiveScanNonUniform);
+            symbolTable.relateToOperator("swizzleInvocationsAMD",                       EOpSwizzleInvocations);
+            symbolTable.relateToOperator("swizzleInvocationsMaskedAMD",                 EOpSwizzleInvocationsMasked);
+            symbolTable.relateToOperator("writeInvocationAMD",                          EOpWriteInvocation);
+            symbolTable.relateToOperator("mbcntAMD",                                    EOpMbcnt);
+
+            symbolTable.relateToOperator("min3",    EOpMin3);
+            symbolTable.relateToOperator("max3",    EOpMax3);
+            symbolTable.relateToOperator("mid3",    EOpMid3);
+
+            symbolTable.relateToOperator("cubeFaceIndexAMD",    EOpCubeFaceIndex);
+            symbolTable.relateToOperator("cubeFaceCoordAMD",    EOpCubeFaceCoord);
+            symbolTable.relateToOperator("timeAMD",             EOpTime);
+
+            symbolTable.relateToOperator("textureGatherLodAMD",                 EOpTextureGatherLod);
+            symbolTable.relateToOperator("textureGatherLodOffsetAMD",           EOpTextureGatherLodOffset);
+            symbolTable.relateToOperator("textureGatherLodOffsetsAMD",          EOpTextureGatherLodOffsets);
+            symbolTable.relateToOperator("sparseTextureGatherLodAMD",           EOpSparseTextureGatherLod);
+            symbolTable.relateToOperator("sparseTextureGatherLodOffsetAMD",     EOpSparseTextureGatherLodOffset);
+            symbolTable.relateToOperator("sparseTextureGatherLodOffsetsAMD",    EOpSparseTextureGatherLodOffsets);
+#endif
+        }
+    }
+
+    switch(language) {
+    case EShLangVertex:
+        break;
+
+    case EShLangTessControl:
+    case EShLangTessEvaluation:
+        break;
+
+    case EShLangGeometry:
+        symbolTable.relateToOperator("EmitStreamVertex",   EOpEmitStreamVertex);
+        symbolTable.relateToOperator("EndStreamPrimitive", EOpEndStreamPrimitive);
+        symbolTable.relateToOperator("EmitVertex",         EOpEmitVertex);
+        symbolTable.relateToOperator("EndPrimitive",       EOpEndPrimitive);
+        break;
+
+    case EShLangFragment:
+        symbolTable.relateToOperator("dFdx",         EOpDPdx);
+        symbolTable.relateToOperator("dFdy",         EOpDPdy);
+        symbolTable.relateToOperator("fwidth",       EOpFwidth);
+        if (profile != EEsProfile && version >= 400) {
+            symbolTable.relateToOperator("dFdxFine",     EOpDPdxFine);
+            symbolTable.relateToOperator("dFdyFine",     EOpDPdyFine);
+            symbolTable.relateToOperator("fwidthFine",   EOpFwidthFine);
+            symbolTable.relateToOperator("dFdxCoarse",   EOpDPdxCoarse);
+            symbolTable.relateToOperator("dFdyCoarse",   EOpDPdyCoarse);
+            symbolTable.relateToOperator("fwidthCoarse", EOpFwidthCoarse);
+        }
+        symbolTable.relateToOperator("interpolateAtCentroid", EOpInterpolateAtCentroid);
+        symbolTable.relateToOperator("interpolateAtSample",   EOpInterpolateAtSample);
+        symbolTable.relateToOperator("interpolateAtOffset",   EOpInterpolateAtOffset);
+
+#ifdef AMD_EXTENSIONS
+        if (profile != EEsProfile)
+            symbolTable.relateToOperator("interpolateAtVertexAMD", EOpInterpolateAtVertex);
+        break;
+#endif
+
+    case EShLangCompute:
+        symbolTable.relateToOperator("memoryBarrierShared",     EOpMemoryBarrierShared);
+        symbolTable.relateToOperator("groupMemoryBarrier",      EOpGroupMemoryBarrier);
+        break;
+
+    default:
+        assert(false && "Language not supported");
+    }
+}
+
+//
+// Add context-dependent (resource-specific) built-ins not handled by the above.  These
+// would be ones that need to be programmatically added because they cannot
+// be added by simple text strings.  For these, also
+// 1) Map built-in functions to operators, for those that will turn into an operation node
+//    instead of remaining a function call.
+// 2) Tag extension-related symbols added to their base version with their extensions, so
+//    that if an early version has the extension turned off, there is an error reported on use.
+//
+void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources)
+{
+    if (profile != EEsProfile && version >= 430 && version < 440) {
+        symbolTable.setVariableExtensions("gl_MaxTransformFeedbackBuffers", 1, &E_GL_ARB_enhanced_layouts);
+        symbolTable.setVariableExtensions("gl_MaxTransformFeedbackInterleavedComponents", 1, &E_GL_ARB_enhanced_layouts);
+    }
+    if (profile != EEsProfile && version >= 130 && version < 420) {
+        symbolTable.setVariableExtensions("gl_MinProgramTexelOffset", 1, &E_GL_ARB_shading_language_420pack);
+        symbolTable.setVariableExtensions("gl_MaxProgramTexelOffset", 1, &E_GL_ARB_shading_language_420pack);
+    }
+    if (profile != EEsProfile && version >= 150 && version < 410)
+        symbolTable.setVariableExtensions("gl_MaxViewports", 1, &E_GL_ARB_viewport_array);
+
+    switch(language) {
+    case EShLangFragment:
+        // Set up gl_FragData based on current array size.
+        if (version == 100 || IncludeLegacy(version, profile, spvVersion) || (! ForwardCompatibility && profile != EEsProfile && version < 420)) {
+            TPrecisionQualifier pq = profile == EEsProfile ? EpqMedium : EpqNone;
+            TType fragData(EbtFloat, EvqFragColor, pq, 4);
+            TArraySizes& arraySizes = *new TArraySizes;
+            arraySizes.addInnerSize(resources.maxDrawBuffers);
+            fragData.newArraySizes(arraySizes);
+            symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData));
+            SpecialQualifier("gl_FragData", EvqFragColor, EbvFragData, symbolTable);
+        }
+        break;
+
+    case EShLangTessControl:
+    case EShLangTessEvaluation:
+        // Because of the context-dependent array size (gl_MaxPatchVertices),
+        // these variables were added later than the others and need to be mapped now.
+
+        // standard members
+        BuiltInVariable("gl_in", "gl_Position",     EbvPosition,     symbolTable);
+        BuiltInVariable("gl_in", "gl_PointSize",    EbvPointSize,    symbolTable);
+        BuiltInVariable("gl_in", "gl_ClipDistance", EbvClipDistance, symbolTable);
+        BuiltInVariable("gl_in", "gl_CullDistance", EbvCullDistance, symbolTable);
+
+        // compatibility members
+        BuiltInVariable("gl_in", "gl_ClipVertex",          EbvClipVertex,          symbolTable);
+        BuiltInVariable("gl_in", "gl_FrontColor",          EbvFrontColor,          symbolTable);
+        BuiltInVariable("gl_in", "gl_BackColor",           EbvBackColor,           symbolTable);
+        BuiltInVariable("gl_in", "gl_FrontSecondaryColor", EbvFrontSecondaryColor, symbolTable);
+        BuiltInVariable("gl_in", "gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
+        BuiltInVariable("gl_in", "gl_TexCoord",            EbvTexCoord,            symbolTable);
+        BuiltInVariable("gl_in", "gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
+        break;
+
+    default:
+        break;
+    }
+}
+
+} // end namespace glslang

+ 112 - 0
src/libraries/glslang/glslang/MachineIndependent/Initialize.h

@@ -0,0 +1,112 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013-2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _INITIALIZE_INCLUDED_
+#define _INITIALIZE_INCLUDED_
+
+#include "../Include/ResourceLimits.h"
+#include "../Include/Common.h"
+#include "../Include/ShHandle.h"
+#include "SymbolTable.h"
+#include "Versions.h"
+
+namespace glslang {
+
+//
+// This is made to hold parseable strings for almost all the built-in
+// functions and variables for one specific combination of version
+// and profile.  (Some still need to be added programmatically.)
+// This is a base class for language-specific derivations, which
+// can be used for language independent builtins.
+//
+// The strings are organized by
+//    commonBuiltins:  intersection of all stages' built-ins, processed just once
+//    stageBuiltins[]: anything a stage needs that's not in commonBuiltins
+//
+class TBuiltInParseables {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+    TBuiltInParseables();
+    virtual ~TBuiltInParseables();
+    virtual void initialize(int version, EProfile, const SpvVersion& spvVersion) = 0;
+    virtual void initialize(const TBuiltInResource& resources, int version, EProfile, const SpvVersion& spvVersion, EShLanguage) = 0;
+    virtual const TString& getCommonString() const { return commonBuiltins; }
+    virtual const TString& getStageString(EShLanguage language) const { return stageBuiltins[language]; }
+
+    virtual void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable) = 0;
+
+    virtual void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources) = 0;
+
+protected:
+    TString commonBuiltins;
+    TString stageBuiltins[EShLangCount];
+};
+
+//
+// This is a GLSL specific derivation of TBuiltInParseables.  To present a stable
+// interface and match other similar code, it is called TBuiltIns, rather
+// than TBuiltInParseablesGlsl.
+//
+class TBuiltIns : public TBuiltInParseables {
+public:
+    POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+    TBuiltIns();
+    virtual ~TBuiltIns();
+    void initialize(int version, EProfile, const SpvVersion& spvVersion);
+    void initialize(const TBuiltInResource& resources, int version, EProfile, const SpvVersion& spvVersion, EShLanguage);
+
+    void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable);
+
+    void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources);
+
+protected:
+    void add2ndGenerationSamplingImaging(int version, EProfile profile, const SpvVersion& spvVersion);
+    void addSubpassSampling(TSampler, const TString& typeName, int version, EProfile profile);
+    void addQueryFunctions(TSampler, const TString& typeName, int version, EProfile profile);
+    void addImageFunctions(TSampler, const TString& typeName, int version, EProfile profile);
+    void addSamplingFunctions(TSampler, const TString& typeName, int version, EProfile profile);
+    void addGatherFunctions(TSampler, const TString& typeName, int version, EProfile profile);
+
+    // Helpers for making textual representations of the permutations
+    // of texturing/imaging functions.
+    const char* postfixes[5];
+    const char* prefixes[EbtNumTypes];
+    int dimMap[EsdNumDims];
+};
+
+} // end namespace glslang
+
+#endif // _INITIALIZE_INCLUDED_

+ 302 - 0
src/libraries/glslang/glslang/MachineIndependent/IntermTraverse.cpp

@@ -0,0 +1,302 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// Copyright (c) 2002-2010 The ANGLE Project Authors.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "../Include/intermediate.h"
+
+namespace glslang {
+
+//
+// Traverse the intermediate representation tree, and
+// call a node type specific function for each node.
+// Done recursively through the member function Traverse().
+// Node types can be skipped if their function to call is 0,
+// but their subtree will still be traversed.
+// Nodes with children can have their whole subtree skipped
+// if preVisit is turned on and the type specific function
+// returns false.
+//
+// preVisit, postVisit, and rightToLeft control what order
+// nodes are visited in.
+//
+
+//
+// Traversal functions for terminals are straightforward....
+//
+void TIntermMethod::traverse(TIntermTraverser*)
+{
+    // Tree should always resolve all methods as a non-method.
+}
+
+void TIntermSymbol::traverse(TIntermTraverser *it)
+{
+    it->visitSymbol(this);
+}
+
+void TIntermConstantUnion::traverse(TIntermTraverser *it)
+{
+    it->visitConstantUnion(this);
+}
+
+//
+// Traverse a binary node.
+//
+void TIntermBinary::traverse(TIntermTraverser *it)
+{
+    bool visit = true;
+
+    //
+    // visit the node before children if pre-visiting.
+    //
+    if (it->preVisit)
+        visit = it->visitBinary(EvPreVisit, this);
+
+    //
+    // Visit the children, in the right order.
+    //
+    if (visit) {
+        it->incrementDepth(this);
+
+        if (it->rightToLeft) {
+            if (right)
+                right->traverse(it);
+
+            if (it->inVisit)
+                visit = it->visitBinary(EvInVisit, this);
+
+            if (visit && left)
+                left->traverse(it);
+        } else {
+            if (left)
+                left->traverse(it);
+
+            if (it->inVisit)
+                visit = it->visitBinary(EvInVisit, this);
+
+            if (visit && right)
+                right->traverse(it);
+        }
+
+        it->decrementDepth();
+    }
+
+    //
+    // Visit the node after the children, if requested and the traversal
+    // hasn't been canceled yet.
+    //
+    if (visit && it->postVisit)
+        it->visitBinary(EvPostVisit, this);
+}
+
+//
+// Traverse a unary node.  Same comments in binary node apply here.
+//
+void TIntermUnary::traverse(TIntermTraverser *it)
+{
+    bool visit = true;
+
+    if (it->preVisit)
+        visit = it->visitUnary(EvPreVisit, this);
+
+    if (visit) {
+        it->incrementDepth(this);
+        operand->traverse(it);
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitUnary(EvPostVisit, this);
+}
+
+//
+// Traverse an aggregate node.  Same comments in binary node apply here.
+//
+void TIntermAggregate::traverse(TIntermTraverser *it)
+{
+    bool visit = true;
+
+    if (it->preVisit)
+        visit = it->visitAggregate(EvPreVisit, this);
+
+    if (visit) {
+        it->incrementDepth(this);
+
+        if (it->rightToLeft) {
+            for (TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++) {
+                (*sit)->traverse(it);
+
+                if (visit && it->inVisit) {
+                    if (*sit != sequence.front())
+                        visit = it->visitAggregate(EvInVisit, this);
+                }
+            }
+        } else {
+            for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) {
+                (*sit)->traverse(it);
+
+                if (visit && it->inVisit) {
+                    if (*sit != sequence.back())
+                        visit = it->visitAggregate(EvInVisit, this);
+                }
+            }
+        }
+
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitAggregate(EvPostVisit, this);
+}
+
+//
+// Traverse a selection node.  Same comments in binary node apply here.
+//
+void TIntermSelection::traverse(TIntermTraverser *it)
+{
+    bool visit = true;
+
+    if (it->preVisit)
+        visit = it->visitSelection(EvPreVisit, this);
+
+    if (visit) {
+        it->incrementDepth(this);
+        if (it->rightToLeft) {
+            if (falseBlock)
+                falseBlock->traverse(it);
+            if (trueBlock)
+                trueBlock->traverse(it);
+            condition->traverse(it);
+        } else {
+            condition->traverse(it);
+            if (trueBlock)
+                trueBlock->traverse(it);
+            if (falseBlock)
+                falseBlock->traverse(it);
+        }
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitSelection(EvPostVisit, this);
+}
+
+//
+// Traverse a loop node.  Same comments in binary node apply here.
+//
+void TIntermLoop::traverse(TIntermTraverser *it)
+{
+    bool visit = true;
+
+    if (it->preVisit)
+        visit = it->visitLoop(EvPreVisit, this);
+
+    if (visit) {
+        it->incrementDepth(this);
+
+        if (it->rightToLeft) {
+            if (terminal)
+                terminal->traverse(it);
+
+            if (body)
+                body->traverse(it);
+
+            if (test)
+                test->traverse(it);
+        } else {
+            if (test)
+                test->traverse(it);
+
+            if (body)
+                body->traverse(it);
+
+            if (terminal)
+                terminal->traverse(it);
+        }
+
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitLoop(EvPostVisit, this);
+}
+
+//
+// Traverse a branch node.  Same comments in binary node apply here.
+//
+void TIntermBranch::traverse(TIntermTraverser *it)
+{
+    bool visit = true;
+
+    if (it->preVisit)
+        visit = it->visitBranch(EvPreVisit, this);
+
+    if (visit && expression) {
+        it->incrementDepth(this);
+        expression->traverse(it);
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitBranch(EvPostVisit, this);
+}
+
+//
+// Traverse a switch node.
+//
+void TIntermSwitch::traverse(TIntermTraverser* it)
+{
+    bool visit = true;
+
+    if (it->preVisit)
+        visit = it->visitSwitch(EvPreVisit, this);
+
+    if (visit) {
+        it->incrementDepth(this);
+        if (it->rightToLeft) {
+            body->traverse(it);
+            condition->traverse(it);
+        } else {
+            condition->traverse(it);
+            body->traverse(it);
+        }
+        it->decrementDepth();
+    }
+
+    if (visit && it->postVisit)
+        it->visitSwitch(EvPostVisit, this);
+}
+
+} // end namespace glslang

+ 3199 - 0
src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp

@@ -0,0 +1,3199 @@
+//
+// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
+// Copyright (C) 2012-2015 LunarG, Inc.
+// Copyright (C) 2015-2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// Build the intermediate representation.
+//
+
+#include "localintermediate.h"
+#include "RemoveTree.h"
+#include "SymbolTable.h"
+#include "propagateNoContraction.h"
+
+#include <cfloat>
+#include <utility>
+
+namespace glslang {
+
+////////////////////////////////////////////////////////////////////////////
+//
+// First set of functions are to help build the intermediate representation.
+// These functions are not member functions of the nodes.
+// They are called from parser productions.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+//
+// Add a terminal node for an identifier in an expression.
+//
+// Returns the added node.
+//
+
+TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TConstUnionArray& constArray,
+                                        TIntermTyped* constSubtree, const TSourceLoc& loc)
+{
+    TIntermSymbol* node = new TIntermSymbol(id, name, type);
+    node->setLoc(loc);
+    node->setConstArray(constArray);
+    node->setConstSubtree(constSubtree);
+
+    return node;
+}
+
+TIntermSymbol* TIntermediate::addSymbol(const TIntermSymbol& intermSymbol)
+{
+    return addSymbol(intermSymbol.getId(),
+                     intermSymbol.getName(),
+                     intermSymbol.getType(),
+                     intermSymbol.getConstArray(),
+                     intermSymbol.getConstSubtree(),
+                     intermSymbol.getLoc());
+}
+
+TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable)
+{
+    glslang::TSourceLoc loc; // just a null location
+    loc.init();
+
+    return addSymbol(variable, loc);
+}
+
+TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc)
+{
+    return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), variable.getConstSubtree(), loc);
+}
+
+TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc)
+{
+    TConstUnionArray unionArray;  // just a null constant
+
+    return addSymbol(0, "", type, unionArray, nullptr, loc);
+}
+
+//
+// Connect two nodes with a new parent that does a binary operation on the nodes.
+//
+// Returns the added node.
+//
+// Returns nullptr if the working conversions and promotions could not be found.
+//
+TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc)
+{
+    // No operations work on blocks
+    if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
+        return nullptr;
+
+    // Try converting the children's base types to compatible types.
+    TIntermTyped* child = addConversion(op, left->getType(), right);
+    if (child)
+        right = child;
+    else {
+        child = addConversion(op, right->getType(), left);
+        if (child)
+            left = child;
+        else
+            return nullptr;
+    }
+
+    // Convert the children's type shape to be compatible.
+    addBiShapeConversion(op, left, right);
+    if (left == nullptr || right == nullptr)
+        return nullptr;
+
+    //
+    // Need a new node holding things together.  Make
+    // one and promote it to the right type.
+    //
+    TIntermBinary* node = addBinaryNode(op, left, right, loc);
+    if (! promote(node))
+        return nullptr;
+
+    node->updatePrecision();
+
+    //
+    // If they are both (non-specialization) constants, they must be folded.
+    // (Unless it's the sequence (comma) operator, but that's handled in addComma().)
+    //
+    TIntermConstantUnion *leftTempConstant = node->getLeft()->getAsConstantUnion();
+    TIntermConstantUnion *rightTempConstant = node->getRight()->getAsConstantUnion();
+    if (leftTempConstant && rightTempConstant) {
+        TIntermTyped* folded = leftTempConstant->fold(node->getOp(), rightTempConstant);
+        if (folded)
+            return folded;
+    }
+
+    // If can propagate spec-constantness and if the operation is an allowed
+    // specialization-constant operation, make a spec-constant.
+    if (specConstantPropagates(*node->getLeft(), *node->getRight()) && isSpecializationOperation(*node))
+        node->getWritableType().getQualifier().makeSpecConstant();
+
+    return node;
+}
+
+//
+// Low level: add binary node (no promotions or other argument modifications)
+//
+TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc) const
+{
+    // build the node
+    TIntermBinary* node = new TIntermBinary(op);
+    if (loc.line == 0)
+        loc = left->getLoc();
+    node->setLoc(loc);
+    node->setLeft(left);
+    node->setRight(right);
+
+    return node;
+}
+
+//
+// like non-type form, but sets node's type.
+//
+TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc, const TType& type) const
+{
+    TIntermBinary* node = addBinaryNode(op, left, right, loc);
+    node->setType(type);
+    return node;
+}
+
+//
+// Low level: add unary node (no promotions or other argument modifications)
+//
+TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc loc) const
+{
+    TIntermUnary* node = new TIntermUnary(op);
+    if (loc.line == 0)
+        loc = child->getLoc();
+    node->setLoc(loc);
+    node->setOperand(child);
+
+    return node;
+}
+
+//
+// like non-type form, but sets node's type.
+//
+TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc loc, const TType& type) const
+{
+    TIntermUnary* node = addUnaryNode(op, child, loc);
+    node->setType(type);
+    return node;
+}
+
+//
+// Connect two nodes through an assignment.
+//
+// Returns the added node.
+//
+// Returns nullptr if the 'right' type could not be converted to match the 'left' type,
+// or the resulting operation cannot be properly promoted.
+//
+TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc)
+{
+    // No block assignment
+    if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
+        return nullptr;
+
+    //
+    // Like adding binary math, except the conversion can only go
+    // from right to left.
+    //
+
+    // convert base types, nullptr return means not possible
+    right = addConversion(op, left->getType(), right);
+    if (right == nullptr)
+        return nullptr;
+
+    // convert shape
+    right = addUniShapeConversion(op, left->getType(), right);
+
+    // build the node
+    TIntermBinary* node = addBinaryNode(op, left, right, loc);
+
+    if (! promote(node))
+        return nullptr;
+
+    node->updatePrecision();
+
+    return node;
+}
+
+//
+// Connect two nodes through an index operator, where the left node is the base
+// of an array or struct, and the right node is a direct or indirect offset.
+//
+// Returns the added node.
+// The caller should set the type of the returned node.
+//
+TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc loc)
+{
+    // caller should set the type
+    return addBinaryNode(op, base, index, loc);
+}
+
+//
+// Add one node as the parent of another that it operates on.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSourceLoc loc)
+{
+    if (child == 0)
+        return nullptr;
+
+    if (child->getType().getBasicType() == EbtBlock)
+        return nullptr;
+
+    switch (op) {
+    case EOpLogicalNot:
+        if (source == EShSourceHlsl) {
+            break; // HLSL can promote logical not
+        }
+
+        if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
+            return nullptr;
+        }
+        break;
+
+    case EOpPostIncrement:
+    case EOpPreIncrement:
+    case EOpPostDecrement:
+    case EOpPreDecrement:
+    case EOpNegative:
+        if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
+            return nullptr;
+    default: break; // some compilers want this
+    }
+
+    //
+    // Do we need to promote the operand?
+    //
+    TBasicType newType = EbtVoid;
+    switch (op) {
+    case EOpConstructInt:    newType = EbtInt;    break;
+    case EOpConstructUint:   newType = EbtUint;   break;
+    case EOpConstructInt64:  newType = EbtInt64;  break;
+    case EOpConstructUint64: newType = EbtUint64; break;
+#ifdef AMD_EXTENSIONS
+    case EOpConstructInt16:  newType = EbtInt16;  break;
+    case EOpConstructUint16: newType = EbtUint16; break;
+#endif
+    case EOpConstructBool:   newType = EbtBool;   break;
+    case EOpConstructFloat:  newType = EbtFloat;  break;
+    case EOpConstructDouble: newType = EbtDouble; break;
+#ifdef AMD_EXTENSIONS
+    case EOpConstructFloat16: newType = EbtFloat16; break;
+#endif
+    default: break; // some compilers want this
+    }
+
+    if (newType != EbtVoid) {
+        child = addConversion(op, TType(newType, EvqTemporary, child->getVectorSize(),
+                                                               child->getMatrixCols(),
+                                                               child->getMatrixRows(),
+                                                               child->isVector()),
+                              child);
+        if (child == nullptr)
+            return nullptr;
+    }
+
+    //
+    // For constructors, we are now done, it was all in the conversion.
+    // TODO: but, did this bypass constant folding?
+    //
+    switch (op) {
+    case EOpConstructInt:
+    case EOpConstructUint:
+    case EOpConstructInt64:
+    case EOpConstructUint64:
+#ifdef AMD_EXTENSIONS
+    case EOpConstructInt16:
+    case EOpConstructUint16:
+#endif
+    case EOpConstructBool:
+    case EOpConstructFloat:
+    case EOpConstructDouble:
+#ifdef AMD_EXTENSIONS
+    case EOpConstructFloat16:
+#endif
+        return child;
+    default: break; // some compilers want this
+    }
+
+    //
+    // Make a new node for the operator.
+    //
+    TIntermUnary* node = addUnaryNode(op, child, loc);
+
+    if (! promote(node))
+        return nullptr;
+
+    node->updatePrecision();
+
+    // If it's a (non-specialization) constant, it must be folded.
+    if (node->getOperand()->getAsConstantUnion())
+        return node->getOperand()->getAsConstantUnion()->fold(op, node->getType());
+
+    // If it's a specialization constant, the result is too,
+    // if the operation is allowed for specialization constants.
+    if (node->getOperand()->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*node))
+        node->getWritableType().getQualifier().makeSpecConstant();
+
+    return node;
+}
+
+TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOperator op, bool unary, TIntermNode* childNode, const TType& returnType)
+{
+    if (unary) {
+        //
+        // Treat it like a unary operator.
+        // addUnaryMath() should get the type correct on its own;
+        // including constness (which would differ from the prototype).
+        //
+        TIntermTyped* child = childNode->getAsTyped();
+        if (child == nullptr)
+            return nullptr;
+
+        if (child->getAsConstantUnion()) {
+            TIntermTyped* folded = child->getAsConstantUnion()->fold(op, returnType);
+            if (folded)
+                return folded;
+        }
+
+        return addUnaryNode(op, child, child->getLoc(), returnType);
+    } else {
+        // setAggregateOperater() calls fold() for constant folding
+        TIntermTyped* node = setAggregateOperator(childNode, op, returnType, loc);
+
+        return node;
+    }
+}
+
+//
+// This is the safe way to change the operator on an aggregate, as it
+// does lots of error checking and fixing.  Especially for establishing
+// a function call's operation on it's set of parameters.  Sequences
+// of instructions are also aggregates, but they just directly set
+// their operator to EOpSequence.
+//
+// Returns an aggregate node, which could be the one passed in if
+// it was already an aggregate.
+//
+TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TType& type, TSourceLoc loc)
+{
+    TIntermAggregate* aggNode;
+
+    //
+    // Make sure we have an aggregate.  If not turn it into one.
+    //
+    if (node) {
+        aggNode = node->getAsAggregate();
+        if (aggNode == nullptr || aggNode->getOp() != EOpNull) {
+            //
+            // Make an aggregate containing this node.
+            //
+            aggNode = new TIntermAggregate();
+            aggNode->getSequence().push_back(node);
+            if (loc.line == 0)
+                loc = node->getLoc();
+        }
+    } else
+        aggNode = new TIntermAggregate();
+
+    //
+    // Set the operator.
+    //
+    aggNode->setOperator(op);
+    if (loc.line != 0)
+        aggNode->setLoc(loc);
+
+    aggNode->setType(type);
+
+    return fold(aggNode);
+}
+
+//
+// Convert the node's type to the given type, as allowed by the operation involved: 'op'.
+// For implicit conversions, 'op' is not the requested conversion, it is the explicit
+// operation requiring the implicit conversion.
+//
+// Returns a node representing the conversion, which could be the same
+// node passed in if no conversion was needed.
+//
+// Generally, this is focused on basic type conversion, not shape conversion.
+// See addShapeConversion().
+//
+// Return nullptr if a conversion can't be done.
+//
+TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const
+{
+    //
+    // Does the base type even allow the operation?
+    //
+    switch (node->getBasicType()) {
+    case EbtVoid:
+        return nullptr;
+    case EbtAtomicUint:
+    case EbtSampler:
+        // opaque types can be passed to functions
+        if (op == EOpFunction)
+            break;
+
+        // HLSL can assign samplers directly (no constructor)
+        if (source == EShSourceHlsl && node->getBasicType() == EbtSampler)
+            break;
+
+        // samplers can get assigned via a sampler constructor
+        // (well, not yet, but code in the rest of this function is ready for it)
+        if (node->getBasicType() == EbtSampler && op == EOpAssign &&
+            node->getAsOperator() != nullptr && node->getAsOperator()->getOp() == EOpConstructTextureSampler)
+            break;
+
+        // otherwise, opaque types can't even be operated on, let alone converted
+        return nullptr;
+    default:
+        break;
+    }
+
+    // Otherwise, if types are identical, no problem
+    if (type == node->getType())
+        return node;
+
+    // If one's a structure, then no conversions.
+    if (type.isStruct() || node->isStruct())
+        return nullptr;
+
+    // If one's an array, then no conversions.
+    if (type.isArray() || node->getType().isArray())
+        return nullptr;
+
+    // Note: callers are responsible for other aspects of shape,
+    // like vector and matrix sizes.
+
+    TBasicType promoteTo;
+
+    switch (op) {
+    //
+    // Explicit conversions (unary operations)
+    //
+    case EOpConstructBool:
+        promoteTo = EbtBool;
+        break;
+    case EOpConstructFloat:
+        promoteTo = EbtFloat;
+        break;
+    case EOpConstructDouble:
+        promoteTo = EbtDouble;
+        break;
+#ifdef AMD_EXTENSIONS
+    case EOpConstructFloat16:
+        promoteTo = EbtFloat16;
+        break;
+#endif
+    case EOpConstructInt:
+        promoteTo = EbtInt;
+        break;
+    case EOpConstructUint:
+        promoteTo = EbtUint;
+        break;
+    case EOpConstructInt64:
+        promoteTo = EbtInt64;
+        break;
+    case EOpConstructUint64:
+        promoteTo = EbtUint64;
+        break;
+#ifdef AMD_EXTENSIONS
+    case EOpConstructInt16:
+        promoteTo = EbtInt16;
+        break;
+    case EOpConstructUint16:
+        promoteTo = EbtUint16;
+        break;
+#endif
+
+    //
+    // List all the binary ops that can implicitly convert one operand to the other's type;
+    // This implements the 'policy' for implicit type conversion.
+    //
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+    case EOpEqual:
+    case EOpNotEqual:
+
+    case EOpAdd:
+    case EOpSub:
+    case EOpMul:
+    case EOpDiv:
+    case EOpMod:
+
+    case EOpVectorTimesScalar:
+    case EOpVectorTimesMatrix:
+    case EOpMatrixTimesVector:
+    case EOpMatrixTimesScalar:
+
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+    case EOpLogicalNot:
+    case EOpLogicalAnd:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+
+    case EOpFunctionCall:
+    case EOpReturn:
+    case EOpAssign:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpMulAssign:
+    case EOpVectorTimesScalarAssign:
+    case EOpMatrixTimesScalarAssign:
+    case EOpDivAssign:
+    case EOpModAssign:
+
+    case EOpAtan:
+    case EOpClamp:
+    case EOpCross:
+    case EOpDistance:
+    case EOpDot:
+    case EOpDst:
+    case EOpFaceForward:
+    case EOpFma:
+    case EOpFrexp:
+    case EOpLdexp:
+    case EOpMix:
+    case EOpLit:
+    case EOpMax:
+    case EOpMin:
+    case EOpModf:
+    case EOpPow:
+    case EOpReflect:
+    case EOpRefract:
+    case EOpSmoothStep:
+    case EOpStep:
+
+    case EOpSequence:
+    case EOpConstructStruct:
+
+        if (type.getBasicType() == node->getType().getBasicType())
+            return node;
+
+        if (canImplicitlyPromote(node->getType().getBasicType(), type.getBasicType(), op))
+            promoteTo = type.getBasicType();
+        else
+            return nullptr;
+
+        break;
+
+    // Shifts can have mixed types as long as they are integer, without converting.
+    // It's the left operand's type that determines the resulting type, so no issue
+    // with assign shift ops either.
+    case EOpLeftShift:
+    case EOpRightShift:
+    case EOpLeftShiftAssign:
+    case EOpRightShiftAssign:
+        if ((type.getBasicType() == EbtInt ||
+             type.getBasicType() == EbtUint ||
+#ifdef AMD_EXTENSIONS
+             type.getBasicType() == EbtInt16 ||
+             type.getBasicType() == EbtUint16 ||
+#endif
+             type.getBasicType() == EbtInt64 ||
+             type.getBasicType() == EbtUint64) &&
+            (node->getType().getBasicType() == EbtInt ||
+             node->getType().getBasicType() == EbtUint ||
+#ifdef AMD_EXTENSIONS
+             node->getType().getBasicType() == EbtInt16 ||
+             node->getType().getBasicType() == EbtUint16 ||
+#endif
+             node->getType().getBasicType() == EbtInt64 ||
+             node->getType().getBasicType() == EbtUint64))
+
+            return node;
+        else if (source == EShSourceHlsl && node->getType().getBasicType() == EbtBool) {
+            promoteTo = type.getBasicType();
+            break;
+        } else
+            return nullptr;
+
+    default:
+        // default is to require a match; all exceptions should have case statements above
+
+        if (type.getBasicType() == node->getType().getBasicType())
+            return node;
+        else
+            return nullptr;
+    }
+
+    if (node->getAsConstantUnion())
+        return promoteConstantUnion(promoteTo, node->getAsConstantUnion());
+
+    //
+    // Add a new newNode for the conversion.
+    //
+    TIntermUnary* newNode = nullptr;
+
+    TOperator newOp = EOpNull;
+
+    // This is 'mechanism' here, it does any conversion told.  The policy comes
+    // from the shader or the above code.
+    switch (promoteTo) {
+    case EbtDouble:
+        switch (node->getBasicType()) {
+        case EbtInt:   newOp = EOpConvIntToDouble;   break;
+        case EbtUint:  newOp = EOpConvUintToDouble;  break;
+        case EbtBool:  newOp = EOpConvBoolToDouble;  break;
+        case EbtFloat: newOp = EOpConvFloatToDouble; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToDouble; break;
+#endif
+        case EbtInt64: newOp = EOpConvInt64ToDouble; break;
+        case EbtUint64: newOp = EOpConvUint64ToDouble; break;
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:  newOp = EOpConvInt16ToDouble;  break;
+        case EbtUint16: newOp = EOpConvUint16ToDouble; break;
+#endif
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtFloat:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToFloat;    break;
+        case EbtUint:   newOp = EOpConvUintToFloat;   break;
+        case EbtBool:   newOp = EOpConvBoolToFloat;   break;
+        case EbtDouble: newOp = EOpConvDoubleToFloat; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToFloat; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToFloat;  break;
+        case EbtUint64: newOp = EOpConvUint64ToFloat; break;
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:  newOp = EOpConvInt16ToFloat;  break;
+        case EbtUint16: newOp = EOpConvUint16ToFloat; break;
+#endif
+        default:
+            return nullptr;
+        }
+        break;
+#ifdef AMD_EXTENSIONS
+    case EbtFloat16:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToFloat16;    break;
+        case EbtUint:   newOp = EOpConvUintToFloat16;   break;
+        case EbtBool:   newOp = EOpConvBoolToFloat16;   break;
+        case EbtFloat:  newOp = EOpConvFloatToFloat16;  break;
+        case EbtDouble: newOp = EOpConvDoubleToFloat16; break;
+        case EbtInt64:  newOp = EOpConvInt64ToFloat16;  break;
+        case EbtUint64: newOp = EOpConvUint64ToFloat16; break;
+        case EbtInt16:  newOp = EOpConvInt16ToFloat16;  break;
+        case EbtUint16: newOp = EOpConvUint16ToFloat16; break;
+        default:
+            return nullptr;
+        }
+        break;
+#endif
+    case EbtBool:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToBool;    break;
+        case EbtUint:   newOp = EOpConvUintToBool;   break;
+        case EbtFloat:  newOp = EOpConvFloatToBool;  break;
+        case EbtDouble: newOp = EOpConvDoubleToBool; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToBool; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToBool;  break;
+        case EbtUint64: newOp = EOpConvUint64ToBool; break;
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:  newOp = EOpConvInt16ToBool;  break;
+        case EbtUint16: newOp = EOpConvUint16ToBool; break;
+#endif
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtInt:
+        switch (node->getBasicType()) {
+        case EbtUint:   newOp = EOpConvUintToInt;   break;
+        case EbtBool:   newOp = EOpConvBoolToInt;   break;
+        case EbtFloat:  newOp = EOpConvFloatToInt;  break;
+        case EbtDouble: newOp = EOpConvDoubleToInt; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToInt; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToInt;  break;
+        case EbtUint64: newOp = EOpConvUint64ToInt; break;
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:  newOp = EOpConvInt16ToInt;  break;
+        case EbtUint16: newOp = EOpConvUint16ToInt; break;
+#endif
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtUint:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToUint;    break;
+        case EbtBool:   newOp = EOpConvBoolToUint;   break;
+        case EbtFloat:  newOp = EOpConvFloatToUint;  break;
+        case EbtDouble: newOp = EOpConvDoubleToUint; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToUint; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToUint;  break;
+        case EbtUint64: newOp = EOpConvUint64ToUint; break;
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:  newOp = EOpConvInt16ToUint;  break;
+        case EbtUint16: newOp = EOpConvUint16ToUint; break;
+#endif
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtInt64:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToInt64;    break;
+        case EbtUint:   newOp = EOpConvUintToInt64;   break;
+        case EbtBool:   newOp = EOpConvBoolToInt64;   break;
+        case EbtFloat:  newOp = EOpConvFloatToInt64;  break;
+        case EbtDouble: newOp = EOpConvDoubleToInt64; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToInt64; break;
+#endif
+        case EbtUint64: newOp = EOpConvUint64ToInt64; break;
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:  newOp = EOpConvInt16ToInt64;  break;
+        case EbtUint16: newOp = EOpConvUint16ToInt64; break;
+#endif
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtUint64:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToUint64;    break;
+        case EbtUint:   newOp = EOpConvUintToUint64;   break;
+        case EbtBool:   newOp = EOpConvBoolToUint64;   break;
+        case EbtFloat:  newOp = EOpConvFloatToUint64;  break;
+        case EbtDouble: newOp = EOpConvDoubleToUint64; break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16: newOp = EOpConvFloat16ToUint64; break;
+#endif
+        case EbtInt64:  newOp = EOpConvInt64ToUint64;  break;
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:  newOp = EOpConvInt16ToUint64;  break;
+        case EbtUint16: newOp = EOpConvUint16ToUint64; break;
+#endif
+        default:
+            return nullptr;
+        }
+        break;
+#ifdef AMD_EXTENSIONS
+    case EbtInt16:
+        switch (node->getBasicType()) {
+        case EbtInt:     newOp = EOpConvIntToInt16;     break;
+        case EbtUint:    newOp = EOpConvUintToInt16;    break;
+        case EbtBool:    newOp = EOpConvBoolToInt16;    break;
+        case EbtFloat:   newOp = EOpConvFloatToInt16;   break;
+        case EbtDouble:  newOp = EOpConvDoubleToInt16;  break;
+        case EbtFloat16: newOp = EOpConvFloat16ToInt16; break;
+        case EbtInt64:   newOp = EOpConvInt64ToInt16;   break;
+        case EbtUint64:  newOp = EOpConvUint64ToInt16;  break;
+        case EbtUint16:  newOp = EOpConvUint16ToInt16;  break;
+        default:
+            return nullptr;
+        }
+        break;
+    case EbtUint16:
+        switch (node->getBasicType()) {
+        case EbtInt:     newOp = EOpConvIntToUint16;     break;
+        case EbtUint:    newOp = EOpConvUintToUint16;    break;
+        case EbtBool:    newOp = EOpConvBoolToUint16;    break;
+        case EbtFloat:   newOp = EOpConvFloatToUint16;   break;
+        case EbtDouble:  newOp = EOpConvDoubleToUint16;  break;
+        case EbtFloat16: newOp = EOpConvFloat16ToUint16; break;
+        case EbtInt64:   newOp = EOpConvInt64ToUint16;   break;
+        case EbtUint64:  newOp = EOpConvUint64ToUint16;  break;
+        case EbtInt16:   newOp = EOpConvInt16ToUint16;   break;
+        default:
+            return nullptr;
+        }
+        break;
+#endif
+    default:
+        return nullptr;
+    }
+
+    TType newType(promoteTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows());
+    newNode = addUnaryNode(newOp, node, node->getLoc(), newType);
+
+    // TODO: it seems that some unary folding operations should occur here, but are not
+
+    // Propagate specialization-constant-ness, if allowed
+    if (node->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*newNode))
+        newNode->getWritableType().getQualifier().makeSpecConstant();
+
+    return newNode;
+}
+
+// Convert the node's shape of type for the given type, as allowed by the
+// operation involved: 'op'.  This is for situations where there is only one
+// direction to consider doing the shape conversion.
+//
+// This implements policy, it call addShapeConversion() for the mechanism.
+//
+// Generally, the AST represents allowed GLSL shapes, so this isn't needed
+// for GLSL.  Bad shapes are caught in conversion or promotion.
+//
+// Return 'node' if no conversion was done. Promotion handles final shape
+// checking.
+//
+TIntermTyped* TIntermediate::addUniShapeConversion(TOperator op, const TType& type, TIntermTyped* node)
+{
+    // some source languages don't do this
+    switch (source) {
+    case EShSourceHlsl:
+        break;
+    case EShSourceGlsl:
+    default:
+        return node;
+    }
+
+    // some operations don't do this
+    switch (op) {
+    case EOpFunctionCall:
+    case EOpReturn:
+        break;
+
+    case EOpMulAssign:
+        // want to support vector *= scalar native ops in AST and lower, not smear, similarly for
+        // matrix *= scalar, etc.
+
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpDivAssign:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+    case EOpRightShiftAssign:
+    case EOpLeftShiftAssign:
+        if (node->getVectorSize() == 1)
+            return node;
+        break;
+
+    case EOpAssign:
+        break;
+
+    case EOpMix:
+        break;
+
+    default:
+        return node;
+    }
+
+    return addShapeConversion(type, node);
+}
+
+// Convert the nodes' shapes to be compatible for the operation 'op'.
+//
+// This implements policy, it call addShapeConversion() for the mechanism.
+//
+// Generally, the AST represents allowed GLSL shapes, so this isn't needed
+// for GLSL.  Bad shapes are caught in conversion or promotion.
+//
+void TIntermediate::addBiShapeConversion(TOperator op, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode)
+{
+    // some source languages don't do this
+    switch (source) {
+    case EShSourceHlsl:
+        break;
+    case EShSourceGlsl:
+    default:
+        return;
+    }
+
+    // some operations don't do this
+    // 'break' will mean attempt bidirectional conversion
+    switch (op) {
+    case EOpMulAssign:
+    case EOpAssign:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpDivAssign:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+    case EOpRightShiftAssign:
+    case EOpLeftShiftAssign:
+        // switch to unidirectional conversion (the lhs can't change)
+        rhsNode = addUniShapeConversion(op, lhsNode->getType(), rhsNode);
+        return;
+
+    case EOpAdd:
+    case EOpSub:
+    case EOpMul:
+    case EOpDiv:
+        // want to support vector * scalar native ops in AST and lower, not smear, similarly for
+        // matrix * vector, etc.
+        if (lhsNode->getVectorSize() == 1 || rhsNode->getVectorSize() == 1)
+            return;
+        break;
+
+    case EOpRightShift:
+    case EOpLeftShift:
+        // can natively support the right operand being a scalar and the left a vector,
+        // but not the reverse
+        if (rhsNode->getVectorSize() == 1)
+            return;
+        break;
+
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+
+    case EOpEqual:
+    case EOpNotEqual:
+
+    case EOpLogicalAnd:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+
+    case EOpMix:
+        break;
+
+    default:
+        return;
+    }
+
+    // Do bidirectional conversions
+    if (lhsNode->getType().isScalarOrVec1() || rhsNode->getType().isScalarOrVec1()) {
+        if (lhsNode->getType().isScalarOrVec1())
+            lhsNode = addShapeConversion(rhsNode->getType(), lhsNode);
+        else
+            rhsNode = addShapeConversion(lhsNode->getType(), rhsNode);
+    }
+    lhsNode = addShapeConversion(rhsNode->getType(), lhsNode);
+    rhsNode = addShapeConversion(lhsNode->getType(), rhsNode);
+}
+
+// Convert the node's shape of type for the given type. It's not necessarily
+// an error if they are different and not converted, as some operations accept
+// mixed types.  Promotion will do final shape checking.
+//
+// If there is a chance of two nodes, with conversions possible in each direction,
+// the policy for what to ask for must be in the caller; this will do what is asked.
+//
+// Return 'node' if no conversion was done. Promotion handles final shape
+// checking.
+//
+TIntermTyped* TIntermediate::addShapeConversion(const TType& type, TIntermTyped* node)
+{
+    // no conversion needed
+    if (node->getType() == type)
+        return node;
+
+    // structures and arrays don't change shape, either to or from
+    if (node->getType().isStruct() || node->getType().isArray() ||
+        type.isStruct() || type.isArray())
+        return node;
+
+    // The new node that handles the conversion
+    TOperator constructorOp = mapTypeToConstructorOp(type);
+
+    // scalar -> vector or vec1 -> vector or
+    // vector -> scalar or
+    // bigger vector -> smaller vector
+    if ((node->getType().isScalarOrVec1() && type.isVector()) ||
+        (node->getType().isVector() && type.isScalar()) ||
+        (node->isVector() && type.isVector() && node->getVectorSize() > type.getVectorSize()))
+        return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
+
+    return node;
+}
+
+//
+// See if the 'from' type is allowed to be implicitly converted to the
+// 'to' type.  This is not about vector/array/struct, only about basic type.
+//
+bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op) const
+{
+    if (profile == EEsProfile || version == 110)
+        return false;
+
+    if (from == to)
+        return true;
+
+    // TODO: Move more policies into language-specific handlers.
+    // Some languages allow more general (or potentially, more specific) conversions under some conditions.
+    if (source == EShSourceHlsl) {
+        const bool fromConvertable = (from == EbtFloat || from == EbtDouble || from == EbtInt || from == EbtUint || from == EbtBool);
+        const bool toConvertable = (to == EbtFloat || to == EbtDouble || to == EbtInt || to == EbtUint || to == EbtBool);
+
+        if (fromConvertable && toConvertable) {
+            switch (op) {
+            case EOpAndAssign:               // assignments can perform arbitrary conversions
+            case EOpInclusiveOrAssign:       // ...
+            case EOpExclusiveOrAssign:       // ...
+            case EOpAssign:                  // ...
+            case EOpAddAssign:               // ...
+            case EOpSubAssign:               // ...
+            case EOpMulAssign:               // ...
+            case EOpVectorTimesScalarAssign: // ...
+            case EOpMatrixTimesScalarAssign: // ...
+            case EOpDivAssign:               // ...
+            case EOpModAssign:               // ...
+            case EOpReturn:                  // function returns can also perform arbitrary conversions
+            case EOpFunctionCall:            // conversion of a calling parameter
+            case EOpLogicalNot:
+            case EOpLogicalAnd:
+            case EOpLogicalOr:
+            case EOpLogicalXor:
+            case EOpConstructStruct:
+                return true;
+            default:
+                break;
+            }
+        }
+    }
+
+    switch (to) {
+    case EbtDouble:
+        switch (from) {
+        case EbtInt:
+        case EbtUint:
+        case EbtInt64:
+        case EbtUint64:
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:
+        case EbtUint16:
+#endif
+        case EbtFloat:
+        case EbtDouble:
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:
+#endif
+            return true;
+        default:
+            return false;
+        }
+    case EbtFloat:
+        switch (from) {
+        case EbtInt:
+        case EbtUint:
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:
+        case EbtUint16:
+#endif
+        case EbtFloat:
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:
+#endif
+            return true;
+        case EbtBool:
+            return (source == EShSourceHlsl);
+        default:
+            return false;
+        }
+    case EbtUint:
+        switch (from) {
+        case EbtInt:
+            return version >= 400 || (source == EShSourceHlsl);
+        case EbtUint:
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:
+        case EbtUint16:
+#endif
+            return true;
+        case EbtBool:
+            return (source == EShSourceHlsl);
+        default:
+            return false;
+        }
+    case EbtInt:
+        switch (from) {
+        case EbtInt:
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:
+#endif
+            return true;
+        case EbtBool:
+            return (source == EShSourceHlsl);
+        default:
+            return false;
+        }
+    case EbtUint64:
+        switch (from) {
+        case EbtInt:
+        case EbtUint:
+        case EbtInt64:
+        case EbtUint64:
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:
+        case EbtUint16:
+#endif
+            return true;
+        default:
+            return false;
+        }
+    case EbtInt64:
+        switch (from) {
+        case EbtInt:
+        case EbtInt64:
+#ifdef AMD_EXTENSIONS
+        case EbtInt16:
+#endif
+            return true;
+        default:
+            return false;
+        }
+#ifdef AMD_EXTENSIONS
+    case EbtFloat16:
+        switch (from) {
+        case EbtInt16:
+        case EbtUint16:
+        case EbtFloat16:
+            return true;
+        default:
+            return false;
+        }
+    case EbtUint16:
+        switch (from) {
+        case EbtInt16:
+        case EbtUint16:
+            return true;
+        default:
+            return false;
+        }
+#endif
+    default:
+        return false;
+    }
+}
+
+//
+// Given a type, find what operation would fully construct it.
+//
+TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
+{
+    TOperator op = EOpNull;
+
+    switch (type.getBasicType()) {
+    case EbtStruct:
+        op = EOpConstructStruct;
+        break;
+    case EbtSampler:
+        if (type.getSampler().combined)
+            op = EOpConstructTextureSampler;
+        break;
+    case EbtFloat:
+        if (type.isMatrix()) {
+            switch (type.getMatrixCols()) {
+            case 2:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructMat2x2; break;
+                case 3: op = EOpConstructMat2x3; break;
+                case 4: op = EOpConstructMat2x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 3:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructMat3x2; break;
+                case 3: op = EOpConstructMat3x3; break;
+                case 4: op = EOpConstructMat3x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 4:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructMat4x2; break;
+                case 3: op = EOpConstructMat4x3; break;
+                case 4: op = EOpConstructMat4x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            default: break; // some compilers want this
+            }
+        } else {
+            switch(type.getVectorSize()) {
+            case 1: op = EOpConstructFloat; break;
+            case 2: op = EOpConstructVec2;  break;
+            case 3: op = EOpConstructVec3;  break;
+            case 4: op = EOpConstructVec4;  break;
+            default: break; // some compilers want this
+            }
+        }
+        break;
+    case EbtDouble:
+        if (type.getMatrixCols()) {
+            switch (type.getMatrixCols()) {
+            case 2:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructDMat2x2; break;
+                case 3: op = EOpConstructDMat2x3; break;
+                case 4: op = EOpConstructDMat2x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 3:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructDMat3x2; break;
+                case 3: op = EOpConstructDMat3x3; break;
+                case 4: op = EOpConstructDMat3x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 4:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructDMat4x2; break;
+                case 3: op = EOpConstructDMat4x3; break;
+                case 4: op = EOpConstructDMat4x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            }
+        } else {
+            switch(type.getVectorSize()) {
+            case 1: op = EOpConstructDouble; break;
+            case 2: op = EOpConstructDVec2;  break;
+            case 3: op = EOpConstructDVec3;  break;
+            case 4: op = EOpConstructDVec4;  break;
+            default: break; // some compilers want this
+            }
+        }
+        break;
+#ifdef AMD_EXTENSIONS
+    case EbtFloat16:
+        if (type.getMatrixCols()) {
+            switch (type.getMatrixCols()) {
+            case 2:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructF16Mat2x2; break;
+                case 3: op = EOpConstructF16Mat2x3; break;
+                case 4: op = EOpConstructF16Mat2x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 3:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructF16Mat3x2; break;
+                case 3: op = EOpConstructF16Mat3x3; break;
+                case 4: op = EOpConstructF16Mat3x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 4:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructF16Mat4x2; break;
+                case 3: op = EOpConstructF16Mat4x3; break;
+                case 4: op = EOpConstructF16Mat4x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            }
+        }
+        else {
+            switch (type.getVectorSize()) {
+            case 1: op = EOpConstructFloat16;  break;
+            case 2: op = EOpConstructF16Vec2;  break;
+            case 3: op = EOpConstructF16Vec3;  break;
+            case 4: op = EOpConstructF16Vec4;  break;
+            default: break; // some compilers want this
+            }
+        }
+        break;
+#endif
+    case EbtInt:
+        if (type.getMatrixCols()) {
+            switch (type.getMatrixCols()) {
+            case 2:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructIMat2x2; break;
+                case 3: op = EOpConstructIMat2x3; break;
+                case 4: op = EOpConstructIMat2x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 3:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructIMat3x2; break;
+                case 3: op = EOpConstructIMat3x3; break;
+                case 4: op = EOpConstructIMat3x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 4:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructIMat4x2; break;
+                case 3: op = EOpConstructIMat4x3; break;
+                case 4: op = EOpConstructIMat4x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            }
+        } else {
+            switch(type.getVectorSize()) {
+            case 1: op = EOpConstructInt;   break;
+            case 2: op = EOpConstructIVec2; break;
+            case 3: op = EOpConstructIVec3; break;
+            case 4: op = EOpConstructIVec4; break;
+            default: break; // some compilers want this
+            }
+        }
+        break;
+    case EbtUint:
+        if (type.getMatrixCols()) {
+            switch (type.getMatrixCols()) {
+            case 2:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructUMat2x2; break;
+                case 3: op = EOpConstructUMat2x3; break;
+                case 4: op = EOpConstructUMat2x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 3:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructUMat3x2; break;
+                case 3: op = EOpConstructUMat3x3; break;
+                case 4: op = EOpConstructUMat3x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 4:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructUMat4x2; break;
+                case 3: op = EOpConstructUMat4x3; break;
+                case 4: op = EOpConstructUMat4x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            }
+        } else {
+            switch(type.getVectorSize()) {
+            case 1: op = EOpConstructUint;  break;
+            case 2: op = EOpConstructUVec2; break;
+            case 3: op = EOpConstructUVec3; break;
+            case 4: op = EOpConstructUVec4; break;
+            default: break; // some compilers want this
+            }
+        }
+        break;
+    case EbtInt64:
+        switch(type.getVectorSize()) {
+        case 1: op = EOpConstructInt64;   break;
+        case 2: op = EOpConstructI64Vec2; break;
+        case 3: op = EOpConstructI64Vec3; break;
+        case 4: op = EOpConstructI64Vec4; break;
+        default: break; // some compilers want this
+        }
+        break;
+    case EbtUint64:
+        switch(type.getVectorSize()) {
+        case 1: op = EOpConstructUint64;  break;
+        case 2: op = EOpConstructU64Vec2; break;
+        case 3: op = EOpConstructU64Vec3; break;
+        case 4: op = EOpConstructU64Vec4; break;
+        default: break; // some compilers want this
+        }
+        break;
+#ifdef AMD_EXTENSIONS
+    case EbtInt16:
+        switch(type.getVectorSize()) {
+        case 1: op = EOpConstructInt16;   break;
+        case 2: op = EOpConstructI16Vec2; break;
+        case 3: op = EOpConstructI16Vec3; break;
+        case 4: op = EOpConstructI16Vec4; break;
+        default: break; // some compilers want this
+        }
+        break;
+    case EbtUint16:
+        switch(type.getVectorSize()) {
+        case 1: op = EOpConstructUint16;  break;
+        case 2: op = EOpConstructU16Vec2; break;
+        case 3: op = EOpConstructU16Vec3; break;
+        case 4: op = EOpConstructU16Vec4; break;
+        default: break; // some compilers want this
+        }
+        break;
+#endif
+    case EbtBool:
+        if (type.getMatrixCols()) {
+            switch (type.getMatrixCols()) {
+            case 2:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructBMat2x2; break;
+                case 3: op = EOpConstructBMat2x3; break;
+                case 4: op = EOpConstructBMat2x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 3:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructBMat3x2; break;
+                case 3: op = EOpConstructBMat3x3; break;
+                case 4: op = EOpConstructBMat3x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            case 4:
+                switch (type.getMatrixRows()) {
+                case 2: op = EOpConstructBMat4x2; break;
+                case 3: op = EOpConstructBMat4x3; break;
+                case 4: op = EOpConstructBMat4x4; break;
+                default: break; // some compilers want this
+                }
+                break;
+            }
+        } else {
+            switch(type.getVectorSize()) {
+            case 1:  op = EOpConstructBool;  break;
+            case 2:  op = EOpConstructBVec2; break;
+            case 3:  op = EOpConstructBVec3; break;
+            case 4:  op = EOpConstructBVec4; break;
+            default: break; // some compilers want this
+            }
+        }
+        break;
+    default:
+        break;
+    }
+
+    return op;
+}
+
+//
+// Safe way to combine two nodes into an aggregate.  Works with null pointers,
+// a node that's not a aggregate yet, etc.
+//
+// Returns the resulting aggregate, unless nullptr was passed in for
+// both existing nodes.
+//
+TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right)
+{
+    if (left == nullptr && right == nullptr)
+        return nullptr;
+
+    TIntermAggregate* aggNode = nullptr;
+    if (left != nullptr)
+        aggNode = left->getAsAggregate();
+    if (aggNode == nullptr || aggNode->getOp() != EOpNull) {
+        aggNode = new TIntermAggregate;
+        if (left != nullptr)
+            aggNode->getSequence().push_back(left);
+    }
+
+    if (right != nullptr)
+        aggNode->getSequence().push_back(right);
+
+    return aggNode;
+}
+
+TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& loc)
+{
+    TIntermAggregate* aggNode = growAggregate(left, right);
+    if (aggNode)
+        aggNode->setLoc(loc);
+
+    return aggNode;
+}
+
+//
+// Turn an existing node into an aggregate.
+//
+// Returns an aggregate, unless nullptr was passed in for the existing node.
+//
+TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node)
+{
+    if (node == nullptr)
+        return nullptr;
+
+    TIntermAggregate* aggNode = new TIntermAggregate;
+    aggNode->getSequence().push_back(node);
+    aggNode->setLoc(node->getLoc());
+
+    return aggNode;
+}
+
+TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& loc)
+{
+    if (node == nullptr)
+        return nullptr;
+
+    TIntermAggregate* aggNode = new TIntermAggregate;
+    aggNode->getSequence().push_back(node);
+    aggNode->setLoc(loc);
+
+    return aggNode;
+}
+
+//
+// Make an aggregate with an empty sequence.
+//
+TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
+{
+    TIntermAggregate* aggNode = new TIntermAggregate;
+    aggNode->setLoc(loc);
+
+    return aggNode;
+}
+
+//
+// For "if" test nodes.  There are three children; a condition,
+// a true path, and a false path.  The two paths are in the
+// nodePair.
+//
+// Returns the selection node created.
+//
+TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc)
+{
+    //
+    // Don't prune the false path for compile-time constants; it's needed
+    // for static access analysis.
+    //
+
+    TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
+    node->setLoc(loc);
+
+    return node;
+}
+
+TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& loc)
+{
+    // However, the lowest precedence operators of the sequence operator ( , ) and the assignment operators
+    // ... are not included in the operators that can create a constant expression.
+    //
+    // if (left->getType().getQualifier().storage == EvqConst &&
+    //    right->getType().getQualifier().storage == EvqConst) {
+
+    //    return right;
+    //}
+
+    TIntermTyped *commaAggregate = growAggregate(left, right, loc);
+    commaAggregate->getAsAggregate()->setOperator(EOpComma);
+    commaAggregate->setType(right->getType());
+    commaAggregate->getWritableType().getQualifier().makeTemporary();
+
+    return commaAggregate;
+}
+
+TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type, const TString* name, const TSourceLoc& loc)
+{
+    TIntermMethod* method = new TIntermMethod(object, type, *name);
+    method->setLoc(loc);
+
+    return method;
+}
+
+//
+// For "?:" test nodes.  There are three children; a condition,
+// a true path, and a false path.  The two paths are specified
+// as separate parameters. For vector 'cond', the true and false
+// are not paths, but vectors to mix.
+//
+// Specialization constant operations include
+//     - The ternary operator ( ? : )
+//
+// Returns the selection node created, or nullptr if one could not be.
+//
+TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc)
+{
+    // If it's void, go to the if-then-else selection()
+    if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
+        TIntermNodePair pair = { trueBlock, falseBlock };
+        return addSelection(cond, pair, loc);
+    }
+
+    //
+    // Get compatible types.
+    //
+    TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
+    if (child)
+        falseBlock = child;
+    else {
+        child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
+        if (child)
+            trueBlock = child;
+        else
+            return nullptr;
+    }
+
+    // Handle a vector condition as a mix
+    if (!cond->getType().isScalarOrVec1()) {
+        TType targetVectorType(trueBlock->getType().getBasicType(), EvqTemporary,
+                               cond->getType().getVectorSize());
+        // smear true/false operands as needed
+        trueBlock = addUniShapeConversion(EOpMix, targetVectorType, trueBlock);
+        falseBlock = addUniShapeConversion(EOpMix, targetVectorType, falseBlock);
+
+        // After conversion, types have to match.
+        if (falseBlock->getType() != trueBlock->getType())
+            return nullptr;
+
+        // make the mix operation
+        TIntermAggregate* mix = makeAggregate(loc);
+        mix = growAggregate(mix, falseBlock);
+        mix = growAggregate(mix, trueBlock);
+        mix = growAggregate(mix, cond);
+        mix->setType(targetVectorType);
+        mix->setOp(EOpMix);
+
+        return mix;
+    }
+
+    // Now have a scalar condition...
+
+    // Convert true and false expressions to matching types
+    addBiShapeConversion(EOpMix, trueBlock, falseBlock);
+
+    // After conversion, types have to match.
+    if (falseBlock->getType() != trueBlock->getType())
+        return nullptr;
+
+    // Eliminate the selection when the condition is a scalar and all operands are constant.
+    if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
+        if (cond->getAsConstantUnion()->getConstArray()[0].getBConst())
+            return trueBlock;
+        else
+            return falseBlock;
+    }
+
+    //
+    // Make a selection node.
+    //
+    TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
+    node->setLoc(loc);
+    node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision);
+
+    if ((cond->getQualifier().isConstant() && specConstantPropagates(*trueBlock, *falseBlock)) ||
+        (cond->getQualifier().isSpecConstant() && trueBlock->getQualifier().isConstant() &&
+                                                 falseBlock->getQualifier().isConstant()))
+        node->getQualifier().makeSpecConstant();
+    else
+        node->getQualifier().makeTemporary();
+
+    return node;
+}
+
+//
+// Constant terminal nodes.  Has a union that contains bool, float or int constants
+//
+// Returns the constant union node created.
+//
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(const TConstUnionArray& unionArray, const TType& t, const TSourceLoc& loc, bool literal) const
+{
+    TIntermConstantUnion* node = new TIntermConstantUnion(unionArray, t);
+    node->getQualifier().storage = EvqConst;
+    node->setLoc(loc);
+    if (literal)
+        node->setLiteral();
+
+    return node;
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(int i, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setIConst(i);
+
+    return addConstantUnion(unionArray, TType(EbtInt, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned int u, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setUConst(u);
+
+    return addConstantUnion(unionArray, TType(EbtUint, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(long long i64, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setI64Const(i64);
+
+    return addConstantUnion(unionArray, TType(EbtInt64, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned long long u64, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setU64Const(u64);
+
+    return addConstantUnion(unionArray, TType(EbtUint64, EvqConst), loc, literal);
+}
+
+#ifdef AMD_EXTENSIONS
+TIntermConstantUnion* TIntermediate::addConstantUnion(short i16, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setIConst(i16);
+
+    return addConstantUnion(unionArray, TType(EbtInt16, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned short u16, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setUConst(u16);
+
+    return addConstantUnion(unionArray, TType(EbtUint16, EvqConst), loc, literal);
+}
+#endif
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(bool b, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setBConst(b);
+
+    return addConstantUnion(unionArray, TType(EbtBool, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseType, const TSourceLoc& loc, bool literal) const
+{
+#ifdef AMD_EXTENSIONS
+    assert(baseType == EbtFloat || baseType == EbtDouble || baseType == EbtFloat16);
+#else
+    assert(baseType == EbtFloat || baseType == EbtDouble);
+#endif
+
+    TConstUnionArray unionArray(1);
+    unionArray[0].setDConst(d);
+
+    return addConstantUnion(unionArray, TType(baseType, EvqConst), loc, literal);
+}
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(const TString* s, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setSConst(s);
+
+    return addConstantUnion(unionArray, TType(EbtString, EvqConst), loc, literal);
+}
+
+// Put vector swizzle selectors onto the given sequence
+void TIntermediate::pushSelector(TIntermSequence& sequence, const TVectorSelector& selector, const TSourceLoc& loc)
+{
+    TIntermConstantUnion* constIntNode = addConstantUnion(selector, loc);
+    sequence.push_back(constIntNode);
+}
+
+// Put matrix swizzle selectors onto the given sequence
+void TIntermediate::pushSelector(TIntermSequence& sequence, const TMatrixSelector& selector, const TSourceLoc& loc)
+{
+    TIntermConstantUnion* constIntNode = addConstantUnion(selector.coord1, loc);
+    sequence.push_back(constIntNode);
+    constIntNode = addConstantUnion(selector.coord2, loc);
+    sequence.push_back(constIntNode);
+}
+
+// Make an aggregate node that has a sequence of all selectors.
+template TIntermTyped* TIntermediate::addSwizzle<TVectorSelector>(TSwizzleSelectors<TVectorSelector>& selector, const TSourceLoc& loc);
+template TIntermTyped* TIntermediate::addSwizzle<TMatrixSelector>(TSwizzleSelectors<TMatrixSelector>& selector, const TSourceLoc& loc);
+template<typename selectorType>
+TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors<selectorType>& selector, const TSourceLoc& loc)
+{
+    TIntermAggregate* node = new TIntermAggregate(EOpSequence);
+
+    node->setLoc(loc);
+    TIntermSequence &sequenceVector = node->getSequence();
+
+    for (int i = 0; i < selector.size(); i++)
+        pushSelector(sequenceVector, selector[i], loc);
+
+    return node;
+}
+
+//
+// Follow the left branches down to the root of an l-value
+// expression (just "." and []).
+//
+// Return the base of the l-value (where following indexing quits working).
+// Return nullptr if a chain following dereferences cannot be followed.
+//
+// 'swizzleOkay' says whether or not it is okay to consider a swizzle
+// a valid part of the dereference chain.
+//
+const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool swizzleOkay)
+{
+    do {
+        const TIntermBinary* binary = node->getAsBinaryNode();
+        if (binary == nullptr)
+            return node;
+        TOperator op = binary->getOp();
+        if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle && op != EOpMatrixSwizzle)
+            return nullptr;
+        if (! swizzleOkay) {
+            if (op == EOpVectorSwizzle || op == EOpMatrixSwizzle)
+                return nullptr;
+            if ((op == EOpIndexDirect || op == EOpIndexIndirect) &&
+                (binary->getLeft()->getType().isVector() || binary->getLeft()->getType().isScalar()) &&
+                ! binary->getLeft()->getType().isArray())
+                return nullptr;
+        }
+        node = node->getAsBinaryNode()->getLeft();
+    } while (true);
+}
+
+//
+// Create while and do-while loop nodes.
+//
+TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
+{
+    TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
+    node->setLoc(loc);
+    node->setLoopControl(control);
+
+    return node;
+}
+
+//
+// Create a for-loop sequence.
+//
+TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
+{
+    TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
+    node->setLoc(loc);
+    node->setLoopControl(control);
+
+    // make a sequence of the initializer and statement, but try to reuse the
+    // aggregate already created for whatever is in the initializer, if there is one
+    TIntermAggregate* loopSequence = (initializer == nullptr ||
+                                      initializer->getAsAggregate() == nullptr) ? makeAggregate(initializer, loc)
+                                                                                : initializer->getAsAggregate();
+    if (loopSequence != nullptr && loopSequence->getOp() == EOpSequence)
+        loopSequence->setOp(EOpNull);
+    loopSequence = growAggregate(loopSequence, node);
+    loopSequence->setOperator(EOpSequence);
+
+    return loopSequence;
+}
+
+//
+// Add branches.
+//
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& loc)
+{
+    return addBranch(branchOp, nullptr, loc);
+}
+
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& loc)
+{
+    TIntermBranch* node = new TIntermBranch(branchOp, expression);
+    node->setLoc(loc);
+
+    return node;
+}
+
+//
+// This is to be executed after the final root is put on top by the parsing
+// process.
+//
+bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/)
+{
+    if (root == nullptr)
+        return true;
+
+    // Finish off the top-level sequence
+    TIntermAggregate* aggRoot = root->getAsAggregate();
+    if (aggRoot && aggRoot->getOp() == EOpNull)
+        aggRoot->setOperator(EOpSequence);
+
+    // Propagate 'noContraction' label in backward from 'precise' variables.
+    glslang::PropagateNoContraction(*this);
+
+    switch (textureSamplerTransformMode) {
+    case EShTexSampTransKeep:
+        break;
+    case EShTexSampTransUpgradeTextureRemoveSampler:
+        performTextureUpgradeAndSamplerRemovalTransformation(root);
+        break;
+    }
+
+    return true;
+}
+
+void TIntermediate::addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage language, TSymbolTable& symbolTable)
+{
+    // Add top-level nodes for declarations that must be checked cross
+    // compilation unit by a linker, yet might not have been referenced
+    // by the AST.
+    //
+    // Almost entirely, translation of symbols is driven by what's present
+    // in the AST traversal, not by translating the symbol table.
+    //
+    // However, there are some special cases:
+    //  - From the specification: "Special built-in inputs gl_VertexID and
+    //    gl_InstanceID are also considered active vertex attributes."
+    //  - Linker-based type mismatch error reporting needs to see all
+    //    uniforms/ins/outs variables and blocks.
+    //  - ftransform() can make gl_Vertex and gl_ModelViewProjectionMatrix active.
+    //
+
+    // if (ftransformUsed) {
+        // TODO: 1.1 lowering functionality: track ftransform() usage
+    //    addSymbolLinkageNode(root, symbolTable, "gl_Vertex");
+    //    addSymbolLinkageNode(root, symbolTable, "gl_ModelViewProjectionMatrix");
+    //}
+
+    if (language == EShLangVertex) {
+        // the names won't be found in the symbol table unless the versions are right,
+        // so version logic does not need to be repeated here
+        addSymbolLinkageNode(linkage, symbolTable, "gl_VertexID");
+        addSymbolLinkageNode(linkage, symbolTable, "gl_InstanceID");
+    }
+
+    // Add a child to the root node for the linker objects
+    linkage->setOperator(EOpLinkerObjects);
+    treeRoot = growAggregate(treeRoot, linkage);
+}
+
+//
+// Add the given name or symbol to the list of nodes at the end of the tree used
+// for link-time checking and external linkage.
+//
+
+void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name)
+{
+    TSymbol* symbol = symbolTable.find(name);
+    if (symbol)
+        addSymbolLinkageNode(linkage, *symbol->getAsVariable());
+}
+
+void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol& symbol)
+{
+    const TVariable* variable = symbol.getAsVariable();
+    if (! variable) {
+        // This must be a member of an anonymous block, and we need to add the whole block
+        const TAnonMember* anon = symbol.getAsAnonMember();
+        variable = &anon->getAnonContainer();
+    }
+    TIntermSymbol* node = addSymbol(*variable);
+    linkage = growAggregate(linkage, node);
+}
+
+//
+// Add a caller->callee relationship to the call graph.
+// Assumes the strings are unique per signature.
+//
+void TIntermediate::addToCallGraph(TInfoSink& /*infoSink*/, const TString& caller, const TString& callee)
+{
+    // Duplicates are okay, but faster to not keep them, and they come grouped by caller,
+    // as long as new ones are push on the same end we check on for duplicates
+    for (TGraph::const_iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
+        if (call->caller != caller)
+            break;
+        if (call->callee == callee)
+            return;
+    }
+
+    callGraph.push_front(TCall(caller, callee));
+}
+
+//
+// This deletes the tree.
+//
+void TIntermediate::removeTree()
+{
+    if (treeRoot)
+        RemoveAllTreeNodes(treeRoot);
+}
+
+//
+// Implement the part of KHR_vulkan_glsl that lists the set of operations
+// that can result in a specialization constant operation.
+//
+// "5.x Specialization Constant Operations"
+//
+//    Only some operations discussed in this section may be applied to a
+//    specialization constant and still yield a result that is as
+//    specialization constant.  The operations allowed are listed below.
+//    When a specialization constant is operated on with one of these
+//    operators and with another constant or specialization constant, the
+//    result is implicitly a specialization constant.
+//
+//     - int(), uint(), and bool() constructors for type conversions
+//       from any of the following types to any of the following types:
+//         * int
+//         * uint
+//         * bool
+//     - vector versions of the above conversion constructors
+//     - allowed implicit conversions of the above
+//     - swizzles (e.g., foo.yx)
+//     - The following when applied to integer or unsigned integer types:
+//         * unary negative ( - )
+//         * binary operations ( + , - , * , / , % )
+//         * shift ( <<, >> )
+//         * bitwise operations ( & , | , ^ )
+//     - The following when applied to integer or unsigned integer scalar types:
+//         * comparison ( == , != , > , >= , < , <= )
+//     - The following when applied to the Boolean scalar type:
+//         * not ( ! )
+//         * logical operations ( && , || , ^^ )
+//         * comparison ( == , != )"
+//
+// This function just handles binary and unary nodes.  Construction
+// rules are handled in construction paths that are not covered by the unary
+// and binary paths, while required conversions will still show up here
+// as unary converters in the from a construction operator.
+//
+bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const
+{
+    // The operations resulting in floating point are quite limited
+    // (However, some floating-point operations result in bool, like ">",
+    // so are handled later.)
+    if (node.getType().isFloatingDomain()) {
+        switch (node.getOp()) {
+        case EOpIndexDirect:
+        case EOpIndexIndirect:
+        case EOpIndexDirectStruct:
+        case EOpVectorSwizzle:
+        case EOpConvFloatToDouble:
+        case EOpConvDoubleToFloat:
+#ifdef AMD_EXTENSIONS
+        case EOpConvFloat16ToFloat:
+        case EOpConvFloatToFloat16:
+        case EOpConvFloat16ToDouble:
+        case EOpConvDoubleToFloat16:
+#endif
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    // Check for floating-point arguments
+    if (const TIntermBinary* bin = node.getAsBinaryNode())
+        if (bin->getLeft() ->getType().isFloatingDomain() ||
+            bin->getRight()->getType().isFloatingDomain())
+            return false;
+
+    // So, for now, we can assume everything left is non-floating-point...
+
+    // Now check for integer/bool-based operations
+    switch (node.getOp()) {
+
+    // dereference/swizzle
+    case EOpIndexDirect:
+    case EOpIndexIndirect:
+    case EOpIndexDirectStruct:
+    case EOpVectorSwizzle:
+
+    // conversion constructors
+    case EOpConvIntToBool:
+    case EOpConvUintToBool:
+    case EOpConvUintToInt:
+    case EOpConvBoolToInt:
+    case EOpConvIntToUint:
+    case EOpConvBoolToUint:
+    case EOpConvInt64ToBool:
+    case EOpConvBoolToInt64:
+    case EOpConvUint64ToBool:
+    case EOpConvBoolToUint64:
+    case EOpConvInt64ToInt:
+    case EOpConvIntToInt64:
+    case EOpConvUint64ToUint:
+    case EOpConvUintToUint64:
+    case EOpConvInt64ToUint64:
+    case EOpConvUint64ToInt64:
+    case EOpConvInt64ToUint:
+    case EOpConvUintToInt64:
+    case EOpConvUint64ToInt:
+    case EOpConvIntToUint64:
+#ifdef AMD_EXTENSIONS
+    case EOpConvInt16ToBool:
+    case EOpConvBoolToInt16:
+    case EOpConvInt16ToInt:
+    case EOpConvIntToInt16:
+    case EOpConvInt16ToUint:
+    case EOpConvUintToInt16:
+    case EOpConvInt16ToInt64:
+    case EOpConvInt64ToInt16:
+    case EOpConvInt16ToUint64:
+    case EOpConvUint64ToInt16:
+    case EOpConvUint16ToBool:
+    case EOpConvBoolToUint16:
+    case EOpConvUint16ToInt:
+    case EOpConvIntToUint16:
+    case EOpConvUint16ToUint:
+    case EOpConvUintToUint16:
+    case EOpConvUint16ToInt64:
+    case EOpConvInt64ToUint16:
+    case EOpConvUint16ToUint64:
+    case EOpConvUint64ToUint16:
+    case EOpConvInt16ToUint16:
+    case EOpConvUint16ToInt16:
+#endif
+
+    // unary operations
+    case EOpNegative:
+    case EOpLogicalNot:
+    case EOpBitwiseNot:
+
+    // binary operations
+    case EOpAdd:
+    case EOpSub:
+    case EOpMul:
+    case EOpVectorTimesScalar:
+    case EOpDiv:
+    case EOpMod:
+    case EOpRightShift:
+    case EOpLeftShift:
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+    case EOpLogicalAnd:
+    case EOpEqual:
+    case EOpNotEqual:
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+        return true;
+    default:
+        return false;
+    }
+}
+
+////////////////////////////////////////////////////////////////
+//
+// Member functions of the nodes used for building the tree.
+//
+////////////////////////////////////////////////////////////////
+
+//
+// Say whether or not an operation node changes the value of a variable.
+//
+// Returns true if state is modified.
+//
+bool TIntermOperator::modifiesState() const
+{
+    switch (op) {
+    case EOpPostIncrement:
+    case EOpPostDecrement:
+    case EOpPreIncrement:
+    case EOpPreDecrement:
+    case EOpAssign:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpMulAssign:
+    case EOpVectorTimesMatrixAssign:
+    case EOpVectorTimesScalarAssign:
+    case EOpMatrixTimesScalarAssign:
+    case EOpMatrixTimesMatrixAssign:
+    case EOpDivAssign:
+    case EOpModAssign:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+    case EOpLeftShiftAssign:
+    case EOpRightShiftAssign:
+        return true;
+    default:
+        return false;
+    }
+}
+
+//
+// returns true if the operator is for one of the constructors
+//
+bool TIntermOperator::isConstructor() const
+{
+    return op > EOpConstructGuardStart && op < EOpConstructGuardEnd;
+}
+
+//
+// Make sure the type of an operator is appropriate for its
+// combination of operation and operand type.  This will invoke
+// promoteUnary, promoteBinary, etc as needed.
+//
+// Returns false if nothing makes sense.
+//
+bool TIntermediate::promote(TIntermOperator* node)
+{
+    if (node == nullptr)
+        return false;
+
+    if (node->getAsUnaryNode())
+        return promoteUnary(*node->getAsUnaryNode());
+
+    if (node->getAsBinaryNode())
+        return promoteBinary(*node->getAsBinaryNode());
+
+    if (node->getAsAggregate())
+        return promoteAggregate(*node->getAsAggregate());
+
+    return false;
+}
+
+//
+// See TIntermediate::promote
+//
+bool TIntermediate::promoteUnary(TIntermUnary& node)
+{
+    const TOperator op    = node.getOp();
+    TIntermTyped* operand = node.getOperand();
+
+    switch (op) {
+    case EOpLogicalNot:
+        // Convert operand to a boolean type
+        if (operand->getBasicType() != EbtBool) {
+            // Add constructor to boolean type. If that fails, we can't do it, so return false.
+            TIntermTyped* converted = convertToBasicType(op, EbtBool, operand);
+            if (converted == nullptr)
+                return false;
+
+            // Use the result of converting the node to a bool.
+            node.setOperand(operand = converted); // also updates stack variable
+        }
+        break;
+    case EOpBitwiseNot:
+        if (operand->getBasicType() != EbtInt &&
+            operand->getBasicType() != EbtUint &&
+#ifdef AMD_EXTENSIONS
+            operand->getBasicType() != EbtInt16 &&
+            operand->getBasicType() != EbtUint16 &&
+#endif
+            operand->getBasicType() != EbtInt64 &&
+            operand->getBasicType() != EbtUint64)
+
+            return false;
+        break;
+    case EOpNegative:
+    case EOpPostIncrement:
+    case EOpPostDecrement:
+    case EOpPreIncrement:
+    case EOpPreDecrement:
+        if (operand->getBasicType() != EbtInt &&
+            operand->getBasicType() != EbtUint &&
+            operand->getBasicType() != EbtInt64 &&
+            operand->getBasicType() != EbtUint64 &&
+#ifdef AMD_EXTENSIONS
+            operand->getBasicType() != EbtInt16 &&
+            operand->getBasicType() != EbtUint16 &&
+#endif
+            operand->getBasicType() != EbtFloat &&
+#ifdef AMD_EXTENSIONS
+            operand->getBasicType() != EbtFloat16 &&
+#endif
+            operand->getBasicType() != EbtDouble)
+
+            return false;
+        break;
+
+    default:
+        if (operand->getBasicType() != EbtFloat)
+
+            return false;
+    }
+
+    node.setType(operand->getType());
+    node.getWritableType().getQualifier().makeTemporary();
+
+    return true;
+}
+
+void TIntermUnary::updatePrecision()
+{
+#ifdef AMD_EXTENSIONS
+    if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
+#else
+    if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat) {
+#endif
+        if (operand->getQualifier().precision > getQualifier().precision)
+            getQualifier().precision = operand->getQualifier().precision;
+    }
+}
+
+// If it is not already, convert this node to the given basic type.
+TIntermTyped* TIntermediate::convertToBasicType(TOperator op, TBasicType basicType, TIntermTyped* node) const
+{
+    if (node == nullptr)
+        return nullptr;
+
+    // It's already this basic type: nothing needs to be done, so use the node directly.
+    if (node->getBasicType() == basicType)
+        return node;
+
+    const TType& type = node->getType();
+    const TType newType(basicType, type.getQualifier().storage,
+                        type.getVectorSize(), type.getMatrixCols(), type.getMatrixRows(), type.isVector());
+
+    // Add constructor to the right vectorness of the right type. If that fails, we can't do it, so return nullptr.
+    return addConversion(op, newType, node);
+}
+
+//
+// See TIntermediate::promote
+//
+bool TIntermediate::promoteBinary(TIntermBinary& node)
+{
+    TOperator     op    = node.getOp();
+    TIntermTyped* left  = node.getLeft();
+    TIntermTyped* right = node.getRight();
+
+    // Arrays and structures have to be exact matches.
+    if ((left->isArray() || right->isArray() || left->getBasicType() == EbtStruct || right->getBasicType() == EbtStruct)
+        && left->getType() != right->getType())
+        return false;
+
+    // Base assumption:  just make the type the same as the left
+    // operand.  Only deviations from this will be coded.
+    node.setType(left->getType());
+    node.getWritableType().getQualifier().clear();
+
+    // Composite and opaque types don't having pending operator changes, e.g.,
+    // array, structure, and samplers.  Just establish final type and correctness.
+    if (left->isArray() || left->getBasicType() == EbtStruct || left->getBasicType() == EbtSampler) {
+        switch (op) {
+        case EOpEqual:
+        case EOpNotEqual:
+            if (left->getBasicType() == EbtSampler) {
+                // can't compare samplers
+                return false;
+            } else {
+                // Promote to conditional
+                node.setType(TType(EbtBool));
+            }
+
+            return true;
+
+        case EOpAssign:
+            // Keep type from above
+
+            return true;
+
+        default:
+            return false;
+        }
+    }
+
+    //
+    // We now have only scalars, vectors, and matrices to worry about.
+    //
+
+    // HLSL implicitly promotes bool -> int for numeric operations.
+    // (Implicit conversions to make the operands match each other's types were already done.)
+    if (getSource() == EShSourceHlsl &&
+        (left->getBasicType() == EbtBool || right->getBasicType() == EbtBool)) {
+        switch (op) {
+        case EOpLessThan:
+        case EOpGreaterThan:
+        case EOpLessThanEqual:
+        case EOpGreaterThanEqual:
+
+        case EOpRightShift:
+        case EOpLeftShift:
+
+        case EOpMod:
+
+        case EOpAnd:
+        case EOpInclusiveOr:
+        case EOpExclusiveOr:
+
+        case EOpAdd:
+        case EOpSub:
+        case EOpDiv:
+        case EOpMul:
+            left = addConversion(op, TType(EbtInt, EvqTemporary, left->getVectorSize()), left);
+            right = addConversion(op, TType(EbtInt, EvqTemporary, right->getVectorSize()), right);
+            if (left == nullptr || right == nullptr)
+                return false;
+            node.setLeft(left);
+            node.setRight(right);
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    // Do general type checks against individual operands (comparing left and right is coming up, checking mixed shapes after that)
+    switch (op) {
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+        // Relational comparisons need numeric types and will promote to scalar Boolean.
+        if (left->getBasicType() == EbtBool)
+            return false;
+
+        node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize()));
+        break;
+
+    case EOpEqual:
+    case EOpNotEqual:
+        if (getSource() == EShSourceHlsl) {
+            const int resultWidth = std::max(left->getVectorSize(), right->getVectorSize());
+
+            // In HLSL, == or != on vectors means component-wise comparison.
+            if (resultWidth > 1) {
+                op = (op == EOpEqual) ? EOpVectorEqual : EOpVectorNotEqual;
+                node.setOp(op);
+            }
+
+            node.setType(TType(EbtBool, EvqTemporary, resultWidth));
+        } else {
+            // All the above comparisons result in a bool (but not the vector compares)
+            node.setType(TType(EbtBool));
+        }
+        break;
+
+    case EOpLogicalAnd:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+        if (getSource() == EShSourceHlsl) {
+            TIntermTyped* convertedL = convertToBasicType(op, EbtBool, left);
+            TIntermTyped* convertedR = convertToBasicType(op, EbtBool, right);
+            if (convertedL == nullptr || convertedR == nullptr)
+                return false;
+            node.setLeft(left = convertedL);   // also updates stack variable
+            node.setRight(right = convertedR); // also updates stack variable
+        } else {
+            // logical ops operate only on scalar Booleans and will promote to scalar Boolean.
+            if (left->getBasicType() != EbtBool || left->isVector() || left->isMatrix())
+                return false;
+        }
+
+        node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize()));
+
+        break;
+
+    case EOpRightShift:
+    case EOpLeftShift:
+    case EOpRightShiftAssign:
+    case EOpLeftShiftAssign:
+
+    case EOpMod:
+    case EOpModAssign:
+
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+        if (getSource() == EShSourceHlsl)
+            break;
+
+        // Check for integer-only operands.
+        if ((left->getBasicType() != EbtInt &&  left->getBasicType() != EbtUint &&
+#ifdef AMD_EXTENSIONS
+             left->getBasicType() != EbtInt16 && left->getBasicType() != EbtUint16 &&
+#endif
+             left->getBasicType() != EbtInt64 && left->getBasicType() != EbtUint64) ||
+            (right->getBasicType() != EbtInt && right->getBasicType() != EbtUint &&
+#ifdef AMD_EXTENSIONS
+             right->getBasicType() != EbtInt16 && right->getBasicType() != EbtUint16 &&
+#endif
+             right->getBasicType() != EbtInt64 && right->getBasicType() != EbtUint64))
+            return false;
+        if (left->isMatrix() || right->isMatrix())
+            return false;
+
+        break;
+
+    case EOpAdd:
+    case EOpSub:
+    case EOpDiv:
+    case EOpMul:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpMulAssign:
+    case EOpDivAssign:
+        // check for non-Boolean operands
+        if (left->getBasicType() == EbtBool || right->getBasicType() == EbtBool)
+            return false;
+
+    default:
+        break;
+    }
+
+    // Compare left and right, and finish with the cases where the operand types must match
+    switch (op) {
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+
+    case EOpEqual:
+    case EOpNotEqual:
+    case EOpVectorEqual:
+    case EOpVectorNotEqual:
+
+    case EOpLogicalAnd:
+    case EOpLogicalOr:
+    case EOpLogicalXor:
+        return left->getType() == right->getType();
+
+    case EOpMod:
+    case EOpModAssign:
+
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+
+    case EOpAdd:
+    case EOpSub:
+    case EOpDiv:
+
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpDivAssign:
+        // Quick out in case the types do match
+        if (left->getType() == right->getType())
+            return true;
+
+        // Fall through
+
+    case EOpMul:
+    case EOpMulAssign:
+        // At least the basic type has to match
+        if (left->getBasicType() != right->getBasicType())
+            return false;
+
+    default:
+        break;
+    }
+
+    // Finish handling the case, for all ops, where both operands are scalars.
+    if (left->isScalar() && right->isScalar())
+        return true;
+
+    // Finish handling the case, for all ops, where there are two vectors of different sizes
+    if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize() && right->getVectorSize() > 1)
+        return false;
+
+    //
+    // We now have a mix of scalars, vectors, or matrices, for non-relational operations.
+    //
+
+    // Can these two operands be combined, what is the resulting type?
+    TBasicType basicType = left->getBasicType();
+    switch (op) {
+    case EOpMul:
+        if (!left->isMatrix() && right->isMatrix()) {
+            if (left->isVector()) {
+                if (left->getVectorSize() != right->getMatrixRows())
+                    return false;
+                node.setOp(op = EOpVectorTimesMatrix);
+                node.setType(TType(basicType, EvqTemporary, right->getMatrixCols()));
+            } else {
+                node.setOp(op = EOpMatrixTimesScalar);
+                node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), right->getMatrixRows()));
+            }
+        } else if (left->isMatrix() && !right->isMatrix()) {
+            if (right->isVector()) {
+                if (left->getMatrixCols() != right->getVectorSize())
+                    return false;
+                node.setOp(op = EOpMatrixTimesVector);
+                node.setType(TType(basicType, EvqTemporary, left->getMatrixRows()));
+            } else {
+                node.setOp(op = EOpMatrixTimesScalar);
+            }
+        } else if (left->isMatrix() && right->isMatrix()) {
+            if (left->getMatrixCols() != right->getMatrixRows())
+                return false;
+            node.setOp(op = EOpMatrixTimesMatrix);
+            node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), left->getMatrixRows()));
+        } else if (! left->isMatrix() && ! right->isMatrix()) {
+            if (left->isVector() && right->isVector()) {
+                ; // leave as component product
+            } else if (left->isVector() || right->isVector()) {
+                node.setOp(op = EOpVectorTimesScalar);
+                if (right->isVector())
+                    node.setType(TType(basicType, EvqTemporary, right->getVectorSize()));
+            }
+        } else {
+            return false;
+        }
+        break;
+    case EOpMulAssign:
+        if (! left->isMatrix() && right->isMatrix()) {
+            if (left->isVector()) {
+                if (left->getVectorSize() != right->getMatrixRows() || left->getVectorSize() != right->getMatrixCols())
+                    return false;
+                node.setOp(op = EOpVectorTimesMatrixAssign);
+            } else {
+                return false;
+            }
+        } else if (left->isMatrix() && !right->isMatrix()) {
+            if (right->isVector()) {
+                return false;
+            } else {
+                node.setOp(op = EOpMatrixTimesScalarAssign);
+            }
+        } else if (left->isMatrix() && right->isMatrix()) {
+            if (left->getMatrixCols() != left->getMatrixRows() || left->getMatrixCols() != right->getMatrixCols() || left->getMatrixCols() != right->getMatrixRows())
+                return false;
+            node.setOp(op = EOpMatrixTimesMatrixAssign);
+        } else if (!left->isMatrix() && !right->isMatrix()) {
+            if (left->isVector() && right->isVector()) {
+                // leave as component product
+            } else if (left->isVector() || right->isVector()) {
+                if (! left->isVector())
+                    return false;
+                node.setOp(op = EOpVectorTimesScalarAssign);
+            }
+        } else {
+            return false;
+        }
+        break;
+
+    case EOpRightShift:
+    case EOpLeftShift:
+    case EOpRightShiftAssign:
+    case EOpLeftShiftAssign:
+        if (right->isVector() && (! left->isVector() || right->getVectorSize() != left->getVectorSize()))
+            return false;
+        break;
+
+    case EOpAssign:
+        if (left->getVectorSize() != right->getVectorSize() || left->getMatrixCols() != right->getMatrixCols() || left->getMatrixRows() != right->getMatrixRows())
+            return false;
+        // fall through
+
+    case EOpAdd:
+    case EOpSub:
+    case EOpDiv:
+    case EOpMod:
+    case EOpAnd:
+    case EOpInclusiveOr:
+    case EOpExclusiveOr:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpDivAssign:
+    case EOpModAssign:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+
+        if ((left->isMatrix() && right->isVector()) ||
+            (left->isVector() && right->isMatrix()) ||
+            left->getBasicType() != right->getBasicType())
+            return false;
+        if (left->isMatrix() && right->isMatrix() && (left->getMatrixCols() != right->getMatrixCols() || left->getMatrixRows() != right->getMatrixRows()))
+            return false;
+        if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize())
+            return false;
+        if (right->isVector() || right->isMatrix()) {
+            node.getWritableType().shallowCopy(right->getType());
+            node.getWritableType().getQualifier().makeTemporary();
+        }
+        break;
+
+    default:
+        return false;
+    }
+
+    //
+    // One more check for assignment.
+    //
+    switch (op) {
+    // The resulting type has to match the left operand.
+    case EOpAssign:
+    case EOpAddAssign:
+    case EOpSubAssign:
+    case EOpMulAssign:
+    case EOpDivAssign:
+    case EOpModAssign:
+    case EOpAndAssign:
+    case EOpInclusiveOrAssign:
+    case EOpExclusiveOrAssign:
+    case EOpLeftShiftAssign:
+    case EOpRightShiftAssign:
+        if (node.getType() != left->getType())
+            return false;
+        break;
+    default:
+        break;
+    }
+
+    return true;
+}
+
+//
+// See TIntermediate::promote
+//
+bool TIntermediate::promoteAggregate(TIntermAggregate& node)
+{
+    TOperator op = node.getOp();
+    TIntermSequence& args = node.getSequence();
+    const int numArgs = static_cast<int>(args.size());
+
+    // Presently, only hlsl does intrinsic promotions.
+    if (getSource() != EShSourceHlsl)
+        return true;
+
+    // set of opcodes that can be promoted in this manner.
+    switch (op) {
+    case EOpAtan:
+    case EOpClamp:
+    case EOpCross:
+    case EOpDistance:
+    case EOpDot:
+    case EOpDst:
+    case EOpFaceForward:
+    // case EOpFindMSB: TODO:
+    // case EOpFindLSB: TODO:
+    case EOpFma:
+    case EOpMod:
+    case EOpFrexp:
+    case EOpLdexp:
+    case EOpMix:
+    case EOpLit:
+    case EOpMax:
+    case EOpMin:
+    case EOpModf:
+    // case EOpGenMul: TODO:
+    case EOpPow:
+    case EOpReflect:
+    case EOpRefract:
+    // case EOpSinCos: TODO:
+    case EOpSmoothStep:
+    case EOpStep:
+        break;
+    default:
+        return true;
+    }
+
+    // TODO: array and struct behavior
+
+    // Try converting all nodes to the given node's type
+    TIntermSequence convertedArgs(numArgs, nullptr);
+
+    // Try to convert all types to the nonConvArg type.
+    for (int nonConvArg = 0; nonConvArg < numArgs; ++nonConvArg) {
+        // Try converting all args to this arg's type
+        for (int convArg = 0; convArg < numArgs; ++convArg) {
+            convertedArgs[convArg] = addConversion(op, args[nonConvArg]->getAsTyped()->getType(),
+                                                   args[convArg]->getAsTyped());
+        }
+
+        // If we successfully converted all the args, use the result.
+        if (std::all_of(convertedArgs.begin(), convertedArgs.end(),
+                        [](const TIntermNode* node) { return node != nullptr; })) {
+
+            std::swap(args, convertedArgs);
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void TIntermBinary::updatePrecision()
+{
+#ifdef AMD_EXTENSIONS
+    if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
+#else
+    if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat) {
+#endif
+        getQualifier().precision = std::max(right->getQualifier().precision, left->getQualifier().precision);
+        if (getQualifier().precision != EpqNone) {
+            left->propagatePrecision(getQualifier().precision);
+            right->propagatePrecision(getQualifier().precision);
+        }
+    }
+}
+
+void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision)
+{
+#ifdef AMD_EXTENSIONS
+    if (getQualifier().precision != EpqNone || (getBasicType() != EbtInt && getBasicType() != EbtUint && getBasicType() != EbtFloat && getBasicType() != EbtFloat16))
+#else
+    if (getQualifier().precision != EpqNone || (getBasicType() != EbtInt && getBasicType() != EbtUint && getBasicType() != EbtFloat))
+#endif
+        return;
+
+    getQualifier().precision = newPrecision;
+
+    TIntermBinary* binaryNode = getAsBinaryNode();
+    if (binaryNode) {
+        binaryNode->getLeft()->propagatePrecision(newPrecision);
+        binaryNode->getRight()->propagatePrecision(newPrecision);
+
+        return;
+    }
+
+    TIntermUnary* unaryNode = getAsUnaryNode();
+    if (unaryNode) {
+        unaryNode->getOperand()->propagatePrecision(newPrecision);
+
+        return;
+    }
+
+    TIntermAggregate* aggregateNode = getAsAggregate();
+    if (aggregateNode) {
+        TIntermSequence operands = aggregateNode->getSequence();
+        for (unsigned int i = 0; i < operands.size(); ++i) {
+            TIntermTyped* typedNode = operands[i]->getAsTyped();
+            if (! typedNode)
+                break;
+            typedNode->propagatePrecision(newPrecision);
+        }
+
+        return;
+    }
+
+    TIntermSelection* selectionNode = getAsSelectionNode();
+    if (selectionNode) {
+        TIntermTyped* typedNode = selectionNode->getTrueBlock()->getAsTyped();
+        if (typedNode) {
+            typedNode->propagatePrecision(newPrecision);
+            typedNode = selectionNode->getFalseBlock()->getAsTyped();
+            if (typedNode)
+                typedNode->propagatePrecision(newPrecision);
+        }
+
+        return;
+    }
+}
+
+TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) const
+{
+    const TConstUnionArray& rightUnionArray = node->getConstArray();
+    int size = node->getType().computeNumComponents();
+
+    TConstUnionArray leftUnionArray(size);
+
+    for (int i=0; i < size; i++) {
+        switch (promoteTo) {
+        case EbtFloat:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtDouble:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            default:
+                return node;
+            }
+            break;
+#ifdef AMD_EXTENSIONS
+        case EbtFloat16:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setDConst(static_cast<double>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+            case EbtFloat16:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            default:
+                return node;
+            }
+            break;
+#endif
+        case EbtInt:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtUint:
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getDConst()));
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtUint:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setUConst(static_cast<unsigned int>(rightUnionArray[i].getDConst()));
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtBool:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0);
+                break;
+            case EbtUint:
+                leftUnionArray[i].setBConst(rightUnionArray[i].getUConst() != 0);
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setBConst(rightUnionArray[i].getI64Const() != 0);
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setBConst(rightUnionArray[i].getU64Const() != 0);
+                break;
+            case EbtBool:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setBConst(rightUnionArray[i].getDConst() != 0.0);
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtInt64:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtUint64:
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getU64Const()));
+                break;
+            case EbtBool:
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setI64Const(static_cast<long long>(rightUnionArray[i].getDConst()));
+                break;
+            default:
+                return node;
+            }
+            break;
+        case EbtUint64:
+            switch (node->getType().getBasicType()) {
+            case EbtInt:
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getIConst()));
+                break;
+            case EbtUint:
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getUConst()));
+                break;
+            case EbtInt64:
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getI64Const()));
+                break;
+            case EbtUint64:
+                leftUnionArray[i] = rightUnionArray[i];
+                break;
+            case EbtBool:
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getBConst()));
+                break;
+            case EbtFloat:
+            case EbtDouble:
+#ifdef AMD_EXTENSIONS
+            case EbtFloat16:
+#endif
+                leftUnionArray[i].setU64Const(static_cast<unsigned long long>(rightUnionArray[i].getDConst()));
+                break;
+            default:
+                return node;
+            }
+            break;
+        default:
+            return node;
+        }
+    }
+
+    const TType& t = node->getType();
+
+    return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier().storage, t.getVectorSize(), t.getMatrixCols(), t.getMatrixRows()),
+                            node->getLoc());
+}
+
+void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
+{
+    assert(!pragmaTable);
+    pragmaTable = new TPragmaTable();
+    *pragmaTable = pTable;
+}
+
+// If either node is a specialization constant, while the other is
+// a constant (or specialization constant), the result is still
+// a specialization constant.
+bool TIntermediate::specConstantPropagates(const TIntermTyped& node1, const TIntermTyped& node2)
+{
+    return (node1.getType().getQualifier().isSpecConstant() && node2.getType().getQualifier().isConstant()) ||
+           (node2.getType().getQualifier().isSpecConstant() && node1.getType().getQualifier().isConstant());
+}
+
+struct TextureUpgradeAndSamplerRemovalTransform : public TIntermTraverser {
+    bool visitAggregate(TVisit, TIntermAggregate* ag) override {
+        using namespace std;
+        TIntermSequence& seq = ag->getSequence();
+        // remove pure sampler variables
+        TIntermSequence::iterator newEnd = remove_if(seq.begin(), seq.end(), [](TIntermNode* node) {
+            TIntermSymbol* symbol = node->getAsSymbolNode();
+            if (!symbol)
+                return false;
+
+            return (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isPureSampler());
+        });
+        seq.erase(newEnd, seq.end());
+        // replace constructors with sampler/textures
+        // update textures into sampled textures
+        for_each(seq.begin(), seq.end(), [](TIntermNode*& node) {
+            TIntermSymbol* symbol = node->getAsSymbolNode();
+            if (!symbol) {
+                TIntermAggregate *constructor = node->getAsAggregate();
+                if (constructor && constructor->getOp() == EOpConstructTextureSampler) {
+                    if (!constructor->getSequence().empty())
+                        node = constructor->getSequence()[0];
+                }
+            } else if (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isTexture()) {
+                symbol->getWritableType().getSampler().combined = true;
+            }
+        });
+        return true;
+    }
+};
+
+void TIntermediate::performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root)
+{
+    TextureUpgradeAndSamplerRemovalTransform transform;
+    root->traverse(&transform);
+}
+
+} // end namespace glslang

+ 138 - 0
src/libraries/glslang/glslang/MachineIndependent/LiveTraverser.h

@@ -0,0 +1,138 @@
+//
+// Copyright (C) 2016 LunarG, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#pragma once
+
+#include "../Include/Common.h"
+#include "reflection.h"
+#include "localintermediate.h"
+
+#include "gl_types.h"
+
+#include <list>
+#include <unordered_set>
+
+namespace glslang {
+
+//
+// The traverser: mostly pass through, except
+//  - processing function-call nodes to push live functions onto the stack of functions to process
+//  - processing selection nodes to trim semantically dead code
+//
+// This is in the glslang namespace directly so it can be a friend of TReflection.
+// This can be derived from to implement reflection database traversers or
+// binding mappers: anything that wants to traverse the live subset of the tree.
+//
+
+class TLiveTraverser : public TIntermTraverser {
+public:
+    TLiveTraverser(const TIntermediate& i, bool traverseAll = false,
+                   bool preVisit = true, bool inVisit = false, bool postVisit = false) :
+        TIntermTraverser(preVisit, inVisit, postVisit),
+        intermediate(i), traverseAll(traverseAll)
+    { }
+
+    //
+    // Given a function name, find its subroot in the tree, and push it onto the stack of
+    // functions left to process.
+    //
+    void pushFunction(const TString& name)
+    {
+        TIntermSequence& globals = intermediate.getTreeRoot()->getAsAggregate()->getSequence();
+        for (unsigned int f = 0; f < globals.size(); ++f) {
+            TIntermAggregate* candidate = globals[f]->getAsAggregate();
+            if (candidate && candidate->getOp() == EOpFunction && candidate->getName() == name) {
+                functions.push_back(candidate);
+                break;
+            }
+        }
+    }
+
+    typedef std::list<TIntermAggregate*> TFunctionStack;
+    TFunctionStack functions;
+
+protected:
+    // To catch which function calls are not dead, and hence which functions must be visited.
+    virtual bool visitAggregate(TVisit, TIntermAggregate* node)
+    {
+        if (!traverseAll)
+            if (node->getOp() == EOpFunctionCall)
+                addFunctionCall(node);
+
+        return true; // traverse this subtree
+    }
+
+    // To prune semantically dead paths.
+    virtual bool visitSelection(TVisit /* visit */,  TIntermSelection* node)
+    {
+        if (traverseAll)
+            return true; // traverse all code
+
+        TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion();
+        if (constant) {
+            // cull the path that is dead
+            if (constant->getConstArray()[0].getBConst() == true && node->getTrueBlock())
+                node->getTrueBlock()->traverse(this);
+            if (constant->getConstArray()[0].getBConst() == false && node->getFalseBlock())
+                node->getFalseBlock()->traverse(this);
+
+            return false; // don't traverse any more, we did it all above
+        } else
+            return true; // traverse the whole subtree
+    }
+
+    // Track live functions as well as uniforms, so that we don't visit dead functions
+    // and only visit each function once.
+    void addFunctionCall(TIntermAggregate* call)
+    {
+        // // just use the map to ensure we process each function at most once
+        if (liveFunctions.find(call->getName()) == liveFunctions.end()) {
+            liveFunctions.insert(call->getName());
+            pushFunction(call->getName());
+        }
+    }
+
+    const TIntermediate& intermediate;
+    typedef std::unordered_set<TString> TLiveFunctions;
+    TLiveFunctions liveFunctions;
+    bool traverseAll;
+
+private:
+    // prevent copy & copy construct
+    TLiveTraverser(TLiveTraverser&);
+    TLiveTraverser& operator=(TLiveTraverser&);
+};
+
+} // namespace glslang

Some files were not shown because too many files changed in this diff