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
 # warranty.  In no event will the authors be held liable for any damages
@@ -255,27 +255,41 @@ endfunction()
 set(LOVE_SRC_COMMON
 	src/common/b64.cpp
 	src/common/b64.h
+	src/common/Color.h
 	src/common/config.h
+	src/common/Data.cpp
 	src/common/Data.h
 	src/common/delay.cpp
 	src/common/delay.h
+	src/common/deprecation.cpp
+	src/common/deprecation.h
 	src/common/EnumMap.h
 	src/common/Exception.cpp
 	src/common/Exception.h
+	src/common/halffloat.cpp
+	src/common/halffloat.h
 	src/common/int.h
 	src/common/math.h
 	src/common/Matrix.cpp
 	src/common/Matrix.h
 	src/common/Memoizer.cpp
 	src/common/Memoizer.h
+	src/common/memory.cpp
+	src/common/memory.h
 	src/common/Module.cpp
 	src/common/Module.h
 	src/common/Object.cpp
 	src/common/Object.h
+	src/common/Optional.h
+	src/common/pixelformat.cpp
+	src/common/pixelformat.h
 	src/common/Reference.cpp
 	src/common/Reference.h
 	src/common/runtime.cpp
 	src/common/runtime.h
+	src/common/Stream.cpp
+	src/common/Stream.h
+	src/common/StringMap.cpp
 	src/common/StringMap.h
 	src/common/types.cpp
 	src/common/types.h
@@ -286,8 +300,6 @@ set(LOVE_SRC_COMMON
 	#src/common/Vector.cpp # Vector.cpp is empty.
 	src/common/Vector.h
 	src/common/version.h
-	src/common/wrap_Data.cpp
-	src/common/wrap_Data.h
 )
 
 if (APPLE)
@@ -307,10 +319,18 @@ set(LOVE_SRC_MODULE_AUDIO_ROOT
 	src/modules/audio/Audio.h
 	src/modules/audio/Source.cpp
 	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.h
 	src/modules/audio/wrap_Source.cpp
 	src/modules/audio/wrap_Source.h
+	src/modules/audio/wrap_RecordingDevice.cpp
+	src/modules/audio/wrap_RecordingDevice.h
 )
 
 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/Source.cpp
 	src/modules/audio/null/Source.h
+	src/modules/audio/null/RecordingDevice.cpp
+	src/modules/audio/null/RecordingDevice.h
 )
 
 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/Source.cpp
 	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
@@ -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\\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
 #
@@ -446,71 +505,94 @@ source_group("modules\\font\\freetype" FILES ${LOVE_SRC_MODULE_FONT_FREETYPE})
 #
 
 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/Font.cpp
+	src/modules/graphics/Font.h
 	src/modules/graphics/Graphics.cpp
 	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.h
+	src/modules/graphics/Polyline.cpp
+	src/modules/graphics/Polyline.h
 	src/modules/graphics/Quad.cpp
 	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.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.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.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.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
+	src/modules/graphics/opengl/Buffer.cpp
+	src/modules/graphics/opengl/Buffer.h
 	src/modules/graphics/opengl/Canvas.cpp
 	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.h
 	src/modules/graphics/opengl/Image.cpp
 	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.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.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
@@ -528,9 +610,16 @@ source_group("modules\\graphics\\opengl" FILES ${LOVE_SRC_MODULE_GRAPHICS_OPENGL
 set(LOVE_SRC_MODULE_IMAGE_ROOT
 	src/modules/image/CompressedImageData.cpp
 	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/ImageData.cpp
 	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.h
 	src/modules/image/wrap_Image.cpp
@@ -542,17 +631,10 @@ set(LOVE_SRC_MODULE_IMAGE_ROOT
 set(LOVE_SRC_MODULE_IMAGE_MAGPIE
 	src/modules/image/magpie/ASTCHandler.cpp
 	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.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.h
 	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
 	src/modules/math/BezierCurve.cpp
 	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.h
 	src/modules/math/RandomGenerator.cpp
 	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.h
-	src/modules/math/wrap_CompressedData.cpp
-	src/modules/math/wrap_CompressedData.h
 	src/modules/math/wrap_Math.cpp
 	src/modules/math/wrap_Math.h
 	src/modules/math/wrap_RandomGenerator.cpp
 	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})
@@ -809,6 +889,7 @@ source_group("modules\\physics\\box2d" FILES ${LOVE_SRC_MODULE_PHYSICS_BOX2D})
 #
 
 set(LOVE_SRC_MODULE_SOUND_ROOT
+	src/modules/sound/Decoder.cpp
 	src/modules/sound/Decoder.h
 	src/modules/sound/Sound.cpp
 	src/modules/sound/Sound.h
@@ -823,8 +904,6 @@ set(LOVE_SRC_MODULE_SOUND_ROOT
 )
 
 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.h
 	src/modules/sound/lullaby/GmeDecoder.cpp
@@ -920,25 +999,14 @@ source_group("modules\\thread\\sdl" FILES ${LOVE_SRC_MODULE_THREAD_SDL})
 # love.timer
 #
 
-set(LOVE_SRC_MODULE_TIMER_ROOT
+set(LOVE_SRC_MODULE_TIMER
 	src/modules/timer/Timer.cpp
 	src/modules/timer/Timer.h
 	src/modules/timer/wrap_Timer.cpp
 	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
@@ -980,8 +1048,10 @@ set(LOVE_SRC_MODULE_VIDEO_ROOT
 set(LOVE_SRC_MODULE_VIDEO_THEORA
 	src/modules/video/theora/Video.cpp
 	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
@@ -1220,6 +1290,121 @@ set(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
 #
@@ -1245,23 +1430,27 @@ set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET
 	src/libraries/luasocket/libluasocket/auxiliar.h
 	src/libraries/luasocket/libluasocket/buffer.c
 	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.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/inet.c
 	src/libraries/luasocket/libluasocket/inet.h
 	src/libraries/luasocket/libluasocket/io.c
 	src/libraries/luasocket/libluasocket/io.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.h
+	src/libraries/luasocket/libluasocket/mbox.lua.h
 	src/libraries/luasocket/libluasocket/mime.c
 	src/libraries/luasocket/libluasocket/mime.h
 	src/libraries/luasocket/libluasocket/mime.lua.h
 	src/libraries/luasocket/libluasocket/options.c
 	src/libraries/luasocket/libluasocket/options.h
+	src/libraries/luasocket/libluasocket/pierror.h
 	src/libraries/luasocket/libluasocket/select.c
 	src/libraries/luasocket/libluasocket/select.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
 )
 
+set(LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET)
+
 if(MSVC)
 	set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET
 		${LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET}
 		src/libraries/luasocket/libluasocket/wsocket.c
 		src/libraries/luasocket/libluasocket/wsocket.h
 	)
+
+	set(LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET
+		${LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET}
+		ws2_32.lib
+	)
 else()
 	set(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.h
 	)
@@ -1297,20 +1500,22 @@ set(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
@@ -1348,6 +1553,16 @@ set(LOVE_SRC_3P_STB
 
 # 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
 #
@@ -1385,17 +1600,30 @@ set(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
 	love_3p_box2d
 	love_3p_ddsparse
 	love_3p_enet
 	love_3p_glad
+	love_3p_glslang
 	love_3p_lodepng
 	love_3p_luasocket
-	love_3p_luautf8
+	love_3p_lua53
 	love_3p_lz4
 	love_3p_noise1234
 	love_3p_wuff
+	love_3p_xxhash
 )
 
 love_disable_warnings(love_3p_box2d love_3p_enet love_3p_luasocket)
@@ -1407,6 +1635,7 @@ set(LOVE_LIB_SRC
 	${LOVE_SRC_COMMON}
 	# Modules
 	${LOVE_SRC_MODULE_AUDIO}
+	${LOVE_SRC_MODULE_DATA}
 	${LOVE_SRC_MODULE_EVENT}
 	${LOVE_SRC_MODULE_FILESYSTEM}
 	${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
 
+  * 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 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 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 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 love.filesystem.setRequirePath to support multiple template '?' characters in each path.
+  * Updated luasocket to version 3.0rc1.
 
 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
 
 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:
 # 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:
 # We need to install NSIS to create the packaged installer executable.
@@ -26,7 +35,7 @@ install:
 - move love libs\love
 
 before_build:
-- cmake -G "Visual Studio 12" -H. -Bbuild
+- cmake -G "%GENERATOR%" -H. -Bbuild
 
 build_script:
 - cmake --build build --target PACKAGE --config Release

BIN
extra/windows/love.rc


+ 246 - 7
license.txt

@@ -1,6 +1,6 @@
 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
 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
 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
 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
 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:
 
 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,
 and Android:
 
  - libmpg123
      Website: http://www.mpg123.de/
      Source download: http://sourceforge.net/projects/mpg123/files/latest/download
+
  - OpenAL Soft
      Website: http://kcat.strangesoft.net/openal.html
      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 ${AUTOMAKE} ]]   || die "Could not find automake."
 
+print_errors() {
+	local output
+	output="$("$@" 2>&1)" && return 0
+	printf "%s\n" "$output"
+	return 1
+}
+
 automagic() {
-	log "Copying files..." >&2
+	log "Copying files..."
 	cp platform/unix/configure.ac .
 	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."
 		exit 1
 	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
 	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)"
 	exit 1
 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_AUX_DIR([platform/unix])
 AC_CONFIG_MACRO_DIR([platform/unix/m4])
@@ -19,6 +19,7 @@ AC_LANG([C++])
 
 dnl Workaround for old aclocal versions
 m4_include([platform/unix/cpp11.m4])
+m4_include([platform/unix/deps.m4])
 
 includes=
 
@@ -44,70 +45,68 @@ AS_VAR_IF([enable_stbi_sse2_override], [no], [], #else
 
 # --with-lua and --with-luaversion
 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])],
-			[], [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'`
-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([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],
 	  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
-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)
 AC_ARG_ENABLE([exe],
@@ -128,8 +127,6 @@ AS_VAR_IF([LUA_EXECUTABLE], [:],
 # Set our includes as automake variable
 AC_SUBST([LOVE_INCLUDES], ["$includes"])
 
-m4_include([configure-modules.ac])
-
 AC_CONFIG_FILES([
 	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/
 
 Files: *
-Copyright: 2006-2015 LOVE Development Team
+Copyright: 2006-2017 LOVE Development Team
 License: zlib
  This software is provided 'as-is', without any express or implied
  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
 \./modules/sound/lullaby/Mpg123Decoder\.cpp
 \./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_amsuffix="$(echo "$love_suffix" | sed 's/\-/_/g' | sed 's/\./_/g')"
 
-flags=""
+flags=()
 upper()
 {
 	echo "$@" | tr '[:lower:]' '[:upper:]'
 }
 
-implfind()
-{
-	find "$1" -maxdepth 1 -type d -exec basename '{}' \; | grep -v "^\." | tail -n +2
-}
-
 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()
@@ -26,82 +21,90 @@ handlemodule()
 	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()
 {
 	LOVEROOT="$(pwd)"
-	cd src
+	cd ./src
 
 	printf "liblove${love_amsuffix}_la_SOURCES = \\\\\n"
 	sourcefind "common" | sed "s/^/    /"
 	FILES="$(sourcefind "scripts" | sed "s/^/    /")"
 	printf "${FILES:0:${#FILES}-2}\n\n"
 
-	cd modules
+	local -a modulelist=()
+	local -a liblist=()
+
+	cd ./modules
 	prefix="modules/"
 	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
-			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
 
-		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
 
 	cd ../libraries
 	prefix="libraries/"
 	for library in *; do
-		NAME="LOVE_LIBRARY_$(upper "$library")"
-		flags="$flags library-$library"
+		flags+=("library-$library")
 		FILES="$(sourcefind "$library" | sed "s/^/    /")"
 
 		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
 	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 ../..
 }
 
 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'))"
-		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
 }
 
@@ -137,33 +140,26 @@ endif
 
 # Compile scripts
 .lua.lua.h:
-	cd scripts; \
+	cd ./scripts; \
 	\$(LUA_EXECUTABLE) auto.lua \$<
 
 # libLÖVE
 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 = \
 	\$(SDL_LIBS) \$(freetype2_LIBS) \$(lua_LIBS)\
 	\$(openal_LIBS) \$(zlib_LIBS) \$(libmodplug_LIBS)\
 	\$(vorbisfile_LIBS) \$(theora_LIBS)
+
 EOF
 
 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 "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}])
 EOF
 echo "configure-modules.ac is updated! ^.^"

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

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

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

@@ -40,7 +40,7 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>0.10.2</string>
+	<string>0.11.0</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<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 */; };
 		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 */; };
+		FA15DFB41F9B8D9E0042AB22 /* libbz2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = FA15DFB31F9B8D9E0042AB22 /* libbz2.tbd */; };
 		FA27B3CB1B498696008A9DCE /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA27B3CA1B498696008A9DCE /* Theora.framework */; };
 		FA5933751C6D625B000EC779 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FA5D249A1A96CF4300C6FC8F /* Images.xcassets */; };
 		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; };
 		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; };
+		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>"; };
 		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; };
@@ -151,6 +153,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				FA15DFB41F9B8D9E0042AB22 /* libbz2.tbd in Frameworks */,
 				CE73F8001EEB64150052DAB3 /* AVFoundation.framework in Frameworks */,
 				FA5D24D11A96E73300C6FC8F /* liblove.a in Frameworks */,
 				FA5D24C21A96D78000C6FC8F /* Foundation.framework in Frameworks */,
@@ -172,6 +175,7 @@
 		1058C7A0FEA54F0111CA2CBB /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				FA15DFB31F9B8D9E0042AB22 /* libbz2.tbd */,
 				CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */,
 				FA5D24801A96C97900C6FC8F /* ios */,
 				FA0B7EEC1A959249000E1D17 /* macosx */,
@@ -322,7 +326,7 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0700;
+				LastUpgradeCheck = 0920;
 				TargetAttributes = {
 					FA0B7F051A95AAF3000E1D17 = {
 						CreatedOnToolsVersion = 6.1.1;
@@ -434,6 +438,7 @@
 				COMBINE_HIDPI_IMAGES = YES;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks",
 					/Library/Frameworks,
 					"\"$(SRCROOT)/build/Release\"",
 					"\"$(SRCROOT)/build/Debug\"",
@@ -443,6 +448,8 @@
 				GCC_OPTIMIZATION_LEVEL = 0;
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
+					"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
 					/Library/Frameworks/Lua.framework/Headers,
 					/Library/Frameworks/SDL2.framework/Headers,
 				);
@@ -462,6 +469,7 @@
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks",
 					/Library/Frameworks,
 					"\"$(SRCROOT)/build/Release\"",
 					"\"$(SRCROOT)/build/Debug\"",
@@ -469,6 +477,8 @@
 				);
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
+					"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
 					/Library/Frameworks/Lua.framework/Headers,
 					/Library/Frameworks/SDL2.framework/Headers,
 				);
@@ -484,16 +494,35 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = 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;
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = LOVE_APPLE_USE_FRAMEWORKS;
 				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_PROTOTYPES = NO;
 				GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
@@ -508,6 +537,9 @@
 				GCC_WARN_SHADOW = NO;
 				GCC_WARN_SIGN_COMPARE = YES;
 				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;
 				HEADER_SEARCH_PATHS = (
 					"\"$(SRCROOT)/../../src\"",
@@ -539,16 +571,35 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = 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;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_INPUT_FILETYPE = automatic;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 3;
 				GCC_PREPROCESSOR_DEFINITIONS = LOVE_APPLE_USE_FRAMEWORKS;
 				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_PROTOTYPES = NO;
 				GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
@@ -563,6 +614,9 @@
 				GCC_WARN_SHADOW = NO;
 				GCC_WARN_SIGN_COMPARE = YES;
 				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_VALUE = NO;
 				GCC_WARN_UNUSED_VARIABLE = YES;
@@ -734,16 +788,35 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = 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;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_INPUT_FILETYPE = automatic;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 3;
 				GCC_PREPROCESSOR_DEFINITIONS = LOVE_APPLE_USE_FRAMEWORKS;
 				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_PROTOTYPES = NO;
 				GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
@@ -758,6 +831,9 @@
 				GCC_WARN_SHADOW = NO;
 				GCC_WARN_SIGN_COMPARE = YES;
 				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_VALUE = NO;
 				GCC_WARN_UNUSED_VARIABLE = YES;
@@ -797,6 +873,7 @@
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks",
 					/Library/Frameworks,
 					"\"$(SRCROOT)/build/Release\"",
 					"\"$(SRCROOT)/build/Debug\"",
@@ -804,6 +881,8 @@
 				);
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
+					"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
+					"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
 					/Library/Frameworks/Lua.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>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>0.10.1</string>
+	<string>0.11.0</string>
 	<key>CFBundleSignature</key>
 	<string>LoVe</string>
 	<key>NSPrincipalClass</key>

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

@@ -62,7 +62,7 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>0.10.2</string>
+	<string>0.11.0</string>
 	<key>CFBundleSignature</key>
 	<string>LoVe</string>
 	<key>LSApplicationCategoryType</key>
@@ -70,9 +70,11 @@
 	<key>NSHighResolutionCapable</key>
 	<true/>
 	<key>NSHumanReadableCopyright</key>
-	<string>© 2006-2016 LÖVE Development Team</string>
+	<string>© 2006-2017 LÖVE Development Team</string>
 	<key>NSPrincipalClass</key>
 	<string>NSApplication</string>
+	<key>NSSupportsAutomaticGraphicsSwitching</key>
+	<false/>
 	<key>UTExportedTypeDeclarations</key>
 	<array>
 		<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
  * 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.
  **/
 
-#ifndef LOVE_GRAPHICS_COLOR_H
-#define LOVE_GRAPHICS_COLOR_H
+#ifndef LOVE_COLOR_H
+#define LOVE_COLOR_H
 
 namespace love
 {
-namespace graphics
-{
 
 template <typename T>
 struct ColorT
@@ -48,6 +46,7 @@ struct ColorT
 	bool operator!=(const ColorT<T> &other) const;
 
 	ColorT<T> operator+=(const ColorT<T> &other);
+	ColorT<T> operator*=(const ColorT<T> &other);
 	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;
 }
 
+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>
 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;
 }
 
+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>
 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<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
 
-#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
  * warranty.  In no event will the authors be held liable for any damages
@@ -38,11 +38,17 @@ class Data : public Object
 {
 public:
 
+	static love::Type type;
+
 	/**
 	 * Destructor.
 	 **/
 	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
 	 * 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
  * 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
  * 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
  * 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -19,14 +19,87 @@
  **/
 
 #include "Matrix.h"
+#include "common/config.h"
 
 // STD
 #include <cstring> // memcpy
 #include <cmath>
 
+#if defined(LOVE_SIMD_SSE)
+#include <xmmintrin.h>
+#endif
+
 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 |
 // | e1 e5 e9  e13 |
 // | e2 e6 e10 e14 |
@@ -36,61 +109,38 @@ Matrix4::Matrix4()
 {
 	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)
 {
 	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 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)
 {
-	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
@@ -101,7 +151,7 @@ const float *Matrix4::getElements() const
 void Matrix4::setIdentity()
 {
 	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)
@@ -134,6 +184,12 @@ void Matrix4::setShear(float kx, float ky)
 	e[1] = ky;
 	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)
 {
@@ -194,16 +250,149 @@ void Matrix4::shear(float kx, float ky)
 	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;
 
 	m.e[0] = 2.0f / (right - left);
 	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[13] = -(top + bottom) / (top - bottom);
+	m.e[14] = -(far + near) / (far - near);
 
 	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
  * warranty.  In no event will the authors be held liable for any damages
@@ -34,8 +34,14 @@ namespace love
  **/
 class Matrix4
 {
+private:
+
+	static void multiply(const Matrix4 &a, const Matrix4 &b, float t[16]);
+
 public:
 
+	static void multiply(const Matrix4 &a, const Matrix4 &b, Matrix4 &result);
+
 	/**
 	 * Creates a new identity matrix.
 	 **/
@@ -47,14 +53,21 @@ public:
 	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.
@@ -106,6 +119,12 @@ public:
 	 * @param ky Shear along y-axis.
 	 **/
 	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,
@@ -166,21 +185,42 @@ public:
 	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:
 
@@ -249,8 +289,8 @@ public:
 	/**
 	 * 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:
 
@@ -272,8 +312,8 @@ private:
 // | e2 e6 e10 e14 |
 // | 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++)
 	{
@@ -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 |
 //            | y |
 //            | 1 |
 // | e0 e3 e6 |
 // | e1 e4 e7 |
 // | 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++)
 	{

+ 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
  * 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
  * 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -21,6 +21,7 @@
 // LOVE
 #include "Module.h"
 #include "Exception.h"
+#include "deprecation.h"
 
 // std
 #include <map>
@@ -58,8 +59,14 @@ namespace
 namespace love
 {
 
+love::Type Module::type("Module", &Object::type);
 Module *Module::instances[] = {};
 
+Module::Module()
+{
+	initDeprecation();
+}
+
 Module::~Module()
 {
 	ModuleRegistry &registry = registryInstance();
@@ -82,6 +89,8 @@ Module::~Module()
 	}
 
 	freeEmptyRegistry();
+
+	deinitDeprecation();
 }
 
 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -34,9 +34,12 @@ class Module : public Object
 {
 public:
 
+	static love::Type type;
+
 	enum ModuleType
 	{
 		M_AUDIO,
+		M_DATA,
 		M_EVENT,
 		M_FILESYSTEM,
 		M_FONT,
@@ -52,11 +55,12 @@ public:
 		M_THREAD,
 		M_TIMER,
 		M_TOUCH,
-		M_WINDOW,
 		M_VIDEO,
+		M_WINDOW,
 		M_MAX_ENUM
 	};
 
+	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
  * warranty.  In no event will the authors be held liable for any damages
@@ -24,6 +24,8 @@
 namespace love
 {
 
+love::Type Object::type("Object", nullptr);
+
 Object::Object()
 	: 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -22,6 +22,7 @@
 #define LOVE_OBJECT_H
 
 #include <atomic>
+#include "types.h"
 
 namespace love
 {
@@ -38,6 +39,8 @@ class Object
 {
 public:
 
+	static love::Type type;
+
 	/**
 	 * 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
  * 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
  * 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
 {
 public:
+	static love::Type type;
+
 	virtual ~Stream() {}
 
 	// 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -23,6 +23,15 @@
 
 #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
 {
 
@@ -145,6 +154,18 @@ public:
 		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:
 
 	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
  * 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.
  **/
 
+#include <memory>
+
 #include "Variant.h"
 #include "common/StringMap.h"
 
 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);
 
-	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
 	// be less safe...
 	if (dynamic_cast<Object *>(u->object) != nullptr)
-		return u->type;
+		return u;
 
-	return INVALID_ID;
+	return nullptr;
 }
 
 Variant::Variant()
@@ -71,24 +73,20 @@ Variant::Variant(const char *string, size_t len)
 	}
 }
 
-Variant::Variant(void *userdata)
+Variant::Variant(void *lightuserdata)
 	: 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.
@@ -100,20 +98,18 @@ Variant::Variant(std::vector<std::pair<Variant, Variant>> *table)
 
 Variant::Variant(const Variant &v)
 	: type(v.type)
-	, udatatype(v.udatatype)
 	, data(v.data)
 {
 	if (type == STRING)
 		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)
 		data.table->retain();
 }
 
 Variant::Variant(Variant &&v)
 	: type(std::move(v.type))
-	, udatatype(std::move(v.udatatype))
 	, data(std::move(v.data))
 {
 	v.type = NIL;
@@ -121,49 +117,41 @@ Variant::Variant(Variant &&v)
 
 Variant::~Variant()
 {
-	switch (type)
-	{
-	case STRING:
+	if (type == STRING)
 		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();
-		break;
-	default:
-		break;
-	}
 }
 
 Variant &Variant::operator = (const Variant &v)
 {
 	if (v.type == STRING)
 		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)
 		v.data.table->retain();
 
 	if (type == STRING)
 		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)
 		data.table->release();
 
 	type = v.type;
 	data = v.data;
-	udatatype = v.udatatype;
 
 	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;
 	const char *str;
+	Proxy *p = nullptr;
 
 	if (n < 0) // Fix the stack position, we might modify it later
 		n += lua_gettop(L) + 1;
@@ -180,15 +168,34 @@ Variant Variant::fromLua(lua_State *L, int n, bool allowTables)
 	case LUA_TLIGHTUSERDATA:
 		return Variant(lua_touserdata(L, n));
 	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:
 		return Variant();
 	case LUA_TTABLE:
-		if (allowTables)
 		{
 			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>>();
 
+			// 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);
 			if (len > 0)
 				table->reserve(len);
@@ -197,7 +204,7 @@ Variant Variant::fromLua(lua_State *L, int n, bool allowTables)
 
 			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);
 
 				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)
 				return Variant(table);
 			else
@@ -240,14 +250,8 @@ void Variant::toLua(lua_State *L) const
 	case LUSERDATA:
 		lua_pushlightuserdata(L, data.userdata);
 		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;
 	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
  * warranty.  In no event will the authors be held liable for any damages
@@ -27,6 +27,7 @@
 
 #include <cstring>
 #include <vector>
+#include <set>
 
 namespace love
 {
@@ -43,7 +44,7 @@ public:
 		STRING,
 		SMALLSTRING,
 		LUSERDATA,
-		FUSERDATA,
+		LOVEOBJECT,
 		NIL,
 		TABLE
 	};
@@ -52,8 +53,8 @@ public:
 	Variant(bool boolean);
 	Variant(double number);
 	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(const Variant &v);
 	Variant(Variant &&v);
@@ -63,7 +64,7 @@ public:
 
 	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;
 
 private:
@@ -101,7 +102,6 @@ private:
 	static const int MAX_SMALL_STRING_LENGTH = 15;
 
 	Type type;
-	love::Type udatatype;
 
 	union Data
 	{
@@ -109,6 +109,7 @@ private:
 		double number;
 		SharedString *string;
 		void *userdata;
+		Proxy objectproxy;
 		SharedTable *table;
 		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
  * 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -24,45 +24,26 @@
 // STD
 #include <cmath>
 
-// LOVE
-#include "Matrix.h"
-
 namespace love
 {
 
-/**
- * 2D Vector class.
- *
- * @author Anders Ruud
- * @date 2006-05-13
- **/
-class Vector
+struct Vector2
 {
-public:
-
-	// The components.
 	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.
-	 * @return The length of the Vector.
-	 *
-	 * This method requires sqrtf() and should be used
-	 * carefully.
 	 **/
 	float getLength() const;
+	float getLengthSquare() const;
 
 	/**
 	 * Normalizes the Vector.
@@ -76,7 +57,7 @@ public:
 	 * To get the true (normalized) normal, use v.getNormal(1.0f / v.getLength())
 	 * @return A normal to the Vector.
 	 **/
-	Vector getNormal() const;
+	Vector2 getNormal() const;
 
 	/**
 	 * Gets a vector perpendicular to the Vector.
@@ -84,125 +65,177 @@ public:
 	 * @param scale factor to apply.
 	 * @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.
-	 * @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.
-	 * @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.
-	 * @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.
-	 * @param s The scalar by which we want to resize the Vector.
 	 **/
 	void operator *= (float s);
 
 	/**
 	 * 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);
 
+	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);
 }
 
-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();
 
 	if (length_current > 0)
@@ -211,113 +244,161 @@ inline float Vector::normalize(float length)
 	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

+ 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
  * 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
  * 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -19,12 +19,98 @@
  **/
 
 #include "b64.h"
+#include "Exception.h"
+
+#include <limits>
+#include <stdio.h>
 
 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";
 
+/**
+ * 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])
 {
 	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]);
 }
 
-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 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]);
-				if (v)
+				if (v != 0)
 					v = (char)((v == '$') ? 0 : v - 61);
 			}
 
-			if (pos <= slen)
+			if (srcpos <= srclen)
 			{
 				len++;
-				if (v)
+				if (v != 0)
 					in[i] = (char)(v - 1);
 			}
 			else
@@ -72,12 +166,11 @@ char *b64_decode(const char *src, int slen, int &size)
 		{
 			b64_decode_block(in, out);
 			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;
 }
 

+ 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -20,21 +20,35 @@
 
 #include "config.h"
 
+#include <stddef.h>
+
 #ifndef LOVE_B64_H
 #define LOVE_B64_H
 
 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.
  *
  * @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[]).
  */
-char *b64_decode(const char *src, int slen, int &size);
+char *b64_decode(const char *src, size_t srclen, size_t &dstlen);
 
 } // 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -26,7 +26,7 @@
 #	define LOVE_WINDOWS 1
 	// If _USING_V110_SDK71_ is defined it means we are using the xp toolset.
 #	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)
 #			define LOVE_WINDOWS_UWP 1
 #			define LOVE_NO_MODPLUG 1
@@ -60,6 +60,22 @@
 #	define LOVE_LITTLE_ENDIAN 1
 #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.
 #ifndef _CRT_SECURE_NO_WARNINGS
 #	define _CRT_SECURE_NO_WARNINGS
@@ -70,6 +86,16 @@
 #	define LOVE_UNUSED(x) (void)sizeof(x)
 #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
 #	define LOVE_BUILD
 #	define LOVE_BUILD_STANDALONE
@@ -111,51 +137,30 @@
 #		define LOVE_LITTLE_ENDIAN 1
 #	endif
 #else
+#	define LOVE_ENABLE_LOVE
 #	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_SDL
 #	define LOVE_ENABLE_FILESYSTEM
-#	define LOVE_ENABLE_FILESYSTEM_PHYSFS
 #	define LOVE_ENABLE_FONT
-#	define LOVE_ENABLE_FONT_FREETYPE
 #	define LOVE_ENABLE_GRAPHICS
-#	define LOVE_ENABLE_GRAPHICS_OPENGL
 #	define LOVE_ENABLE_IMAGE
-#	define LOVE_ENABLE_IMAGE_MAGPIE
 #	define LOVE_ENABLE_JOYSTICK
-#	define LOVE_ENABLE_JOYSTICK_SDL
 #	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_MOUSE
-#	define LOVE_ENABLE_MOUSE_SDL
-#	define LOVE_ENABLE_NOISE1234
 #	define LOVE_ENABLE_PHYSICS
-#	define LOVE_ENABLE_PHYSICS_BOX2D
 #	define LOVE_ENABLE_SOUND
-#	define LOVE_ENABLE_SOUND_LULLABY
 #	define LOVE_ENABLE_SYSTEM
-#	define LOVE_ENABLE_SYSTEM_SDL
 #	define LOVE_ENABLE_THREAD
-#	define LOVE_ENABLE_THREAD_SDL
 #	define LOVE_ENABLE_TIMER
-#	define LOVE_ENABLE_TIMER_SDL
 #	define LOVE_ENABLE_TOUCH
-#	define LOVE_ENABLE_TOUCH_SDL
-#	define LOVE_ENABLE_UTF8
 #	define LOVE_ENABLE_VIDEO
-#	define LOVE_ENABLE_VIDEO_THEORA
 #	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
 
 // 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -27,6 +27,8 @@ namespace love
 
 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);
 }
 

+ 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
  * 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
  * 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
  * 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
  * 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
  * 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
  * 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -61,11 +61,15 @@
 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)

+ 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -31,6 +31,7 @@
 #include <algorithm>
 #include <iostream>
 #include <cstdio>
+#include <sstream>
 
 namespace love
 {
@@ -42,7 +43,11 @@ namespace love
 static int w__gc(lua_State *L)
 {
 	Proxy *p = (Proxy *) lua_touserdata(L, 1);
-	p->object->release();
+	if (p->object != nullptr)
+	{
+		p->object->release();
+		p->object = nullptr;
+	}
 	return 0;
 }
 
@@ -63,8 +68,11 @@ static int w__type(lua_State *L)
 static int w__typeOf(lua_State *L)
 {
 	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;
 }
 
@@ -72,7 +80,35 @@ static int w__eq(lua_State *L)
 {
 	Proxy *p1 = (Proxy *)lua_touserdata(L, 1);
 	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;
 }
 
@@ -95,11 +131,53 @@ void luax_printstack(lua_State *L)
 		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)
 {
 	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)
 {
 	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;
 }
 
+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 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)
 {
-	love::addTypeName(m.type, m.name);
+	m.type->init();
 
 	// Put a reference to the C++ module in Lua.
 	luax_insistregistry(L, REGISTRY_MODULES);
@@ -272,9 +381,9 @@ int luax_preload(lua_State *L, lua_CFunction f, const char *name)
 	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.
 	luax_getregistry(L, REGISTRY_OBJECTS);
@@ -301,7 +410,7 @@ int luax_register_type(lua_State *L, love::Type type, const char *name, ...)
 	else
 		lua_pop(L, 1);
 
-	luaL_newmetatable(L, name);
+	luaL_newmetatable(L, type->getName());
 
 	// m.__index = m
 	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");
 
 	// Add tostring function.
-	lua_pushstring(L, name);
+	lua_pushstring(L, type->getName());
 	lua_pushcclosure(L, w__tostring, 1);
 	lua_setfield(L, -2, "__tostring");
 
 	// Add type
-	lua_pushstring(L, name);
+	lua_pushstring(L, type->getName());
 	lua_pushcclosure(L, w__type, 1);
 	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_setfield(L, -2, "typeOf");
 
+	// Add release
+	lua_pushcfunction(L, w__release);
+	lua_setfield(L, -2, "release");
+
 	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 *))
 		luax_setfuncs(L, f);
 	va_end(fs);
@@ -339,13 +452,10 @@ int luax_register_type(lua_State *L, love::Type type, const char *name, ...)
 	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)
@@ -401,23 +511,34 @@ int luax_register_searcher(lua_State *L, lua_CFunction f, int pos)
 	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));
 
 	object->retain();
 
 	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);
+
+	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);
 }
 
-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)
 	{
@@ -459,15 +580,15 @@ void luax_pushtype(lua_State *L, love::Type type, love::Object *object)
 	// 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)
 		return false;
 
 	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
 		return false;
 }
@@ -666,10 +787,29 @@ lua_State *luax_getpinnedthread(lua_State *L)
 	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)
 {
 	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.
 	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
 			// 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);
 
 	const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, argtname);
 	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)
 {
 #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

+ 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -22,7 +22,9 @@
 #define LOVE_RUNTIME_H
 
 // LOVE
+#include "config.h"
 #include "types.h"
+#include "deprecation.h"
 
 // Lua
 extern "C" {
@@ -34,6 +36,7 @@ extern "C" {
 
 // C++
 #include <exception>
+#include <algorithm>
 
 namespace love
 {
@@ -43,6 +46,9 @@ class Object;
 class Module;
 class Reference;
 
+template<typename T>
+class StrongRef;
+
 /**
  * Registries represent special tables which can be accessed with
  * luax_insistregistry and luax_getregistry.
@@ -62,7 +68,7 @@ enum Registry
 struct Proxy
 {
 	// Holds type information (see types.h).
-	Type type;
+	love::Type *type;
 
 	// Pointer to the actual object.
 	Object *object;
@@ -80,7 +86,7 @@ struct WrappedModule
 	const char *name;
 
 	// The type of this module.
-	love::Type type;
+	love::Type *type;
 
 	// The functions of the module (last element {0,0}).
 	const luaL_Reg *functions;
@@ -103,6 +109,16 @@ Reference *luax_refif(lua_State *L, int type);
  **/
 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
  * 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);
 
+/**
+ * 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,
  * 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);
 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
@@ -181,6 +206,16 @@ inline float luax_checkfloat(lua_State *L, int 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.
  * @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.
+ * 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 name The type's human-readable name
  * @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.
 **/
-void luax_gettypemetatable(lua_State *L, love::Type type);
+void luax_gettypemetatable(lua_State *L, love::Type &type);
 
 /**
  * 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 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
@@ -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 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.
@@ -305,7 +353,7 @@ void luax_rawnewtype(lua_State *L, love::Type type, love::Object *object);
  * @param type The type to check for.
  * @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
@@ -412,10 +460,20 @@ lua_State *luax_insistpinnedthread(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
 	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
  **/
@@ -434,32 +492,38 @@ extern "C" { // Called by enet and luasocket
  * @param type The type bit.
  **/
 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)
 	{
-		const char *name = "Invalid";
-		getTypeName(type, name);
+		const char *name = type.getName();
 		luax_typerror(L, idx, name);
 	}
 
 	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);
 	}
 
+	if (u->object == nullptr)
+		luaL_error(L, "Cannot use object after it has been released.");
+
 	return (T *)u->object;
 }
 
 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);
 	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);
 
-	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);
 
 	lua_pop(L, 2);
@@ -478,10 +542,15 @@ T *luax_getmodule(lua_State *L, love::Type type)
 }
 
 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);
 	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);
 
-	if (!typeFlags[u->type][type])
+	if (!u->type->isa(type))
 		luaL_error(L, "Incorrect module %s", name);
 
 	lua_pop(L, 2);
@@ -502,6 +571,12 @@ T *luax_optmodule(lua_State *L, love::Type type)
 	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
  * 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.
  **/
 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.

+ 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
  * 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.
  **/
 
+// STL
+#include <unordered_map>
+
 #include "types.h"
-#include "StringMap.h"
 
 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

+ 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -21,117 +21,54 @@
 #ifndef LOVE_TYPES_H
 #define LOVE_TYPES_H
 
+#include "int.h"
+
 // STD
 #include <bitset>
+#include <vector>
 
 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
 
 #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
  * 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
  * 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
  * warranty.  In no event will the authors be held liable for any damages
@@ -25,13 +25,13 @@ namespace love
 {
 
 // 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_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_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
 

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

@@ -1,25 +1,23 @@
 /**
  * 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.

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

@@ -1,25 +1,23 @@
 /**
  * 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"

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

@@ -1,25 +1,23 @@
 /**
  * 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

+ 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
 	// naming conventions the same as the rest of the lib.
 	{"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!
 	{"destroy", host_gc},
 
@@ -803,7 +800,7 @@ int luaopen_enet(lua_State *l) {
 
 	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 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
 * 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