Bug 1225280. Update ANGLE to chromium/2572.
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Mon, 30 Nov 2015 10:31:12 -0500
changeset 313363 5e7184c74b8244015e6bc3dbe070778232f9aa4b
parent 313362 a68e4f331402e35aa076aa57169ce0486e8b82a2
child 313364 8c813f2aeb7aa183373c828a56611969fd2e29f9
push id8073
push userdmitchell@mozilla.com
push dateWed, 02 Dec 2015 16:15:39 +0000
bugs1225280
milestone45.0a1
Bug 1225280. Update ANGLE to chromium/2572.
gfx/angle/AUTHORS
gfx/angle/BUILD.gn
gfx/angle/README.md
gfx/angle/include/GLSLANG/ShaderLang.h
gfx/angle/include/platform/Platform.h
gfx/angle/moz.build
gfx/angle/src/commit.h
gfx/angle/src/common/angleutils.h
gfx/angle/src/common/utilities.cpp
gfx/angle/src/compiler.gypi
gfx/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
gfx/angle/src/compiler/translator/Compiler.cpp
gfx/angle/src/compiler/translator/ExtensionGLSL.cpp
gfx/angle/src/compiler/translator/ExtensionGLSL.h
gfx/angle/src/compiler/translator/IntermNode.cpp
gfx/angle/src/compiler/translator/IntermNode.h
gfx/angle/src/compiler/translator/Intermediate.cpp
gfx/angle/src/compiler/translator/Intermediate.h
gfx/angle/src/compiler/translator/OutputGLSLBase.cpp
gfx/angle/src/compiler/translator/OutputGLSLBase.h
gfx/angle/src/compiler/translator/OutputHLSL.cpp
gfx/angle/src/compiler/translator/OutputHLSL.h
gfx/angle/src/compiler/translator/ParseContext.cpp
gfx/angle/src/compiler/translator/ParseContext.h
gfx/angle/src/compiler/translator/RemoveDynamicIndexing.cpp
gfx/angle/src/compiler/translator/SeparateArrayInitialization.cpp
gfx/angle/src/compiler/translator/SeparateArrayInitialization.h
gfx/angle/src/compiler/translator/SymbolTable.h
gfx/angle/src/compiler/translator/TranslatorGLSL.cpp
gfx/angle/src/compiler/translator/TranslatorGLSL.h
gfx/angle/src/compiler/translator/Types.h
gfx/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp
gfx/angle/src/compiler/translator/VariableInfo.cpp
gfx/angle/src/compiler/translator/glslang.l
gfx/angle/src/compiler/translator/glslang.y
gfx/angle/src/compiler/translator/glslang_lex.cpp
gfx/angle/src/compiler/translator/glslang_tab.cpp
gfx/angle/src/compiler/translator/parseConst.cpp
gfx/angle/src/compiler/translator/util.cpp
gfx/angle/src/compiler/translator/util.h
gfx/angle/src/libANGLE/Caps.cpp
gfx/angle/src/libANGLE/Caps.h
gfx/angle/src/libANGLE/Context.cpp
gfx/angle/src/libANGLE/Context.h
gfx/angle/src/libANGLE/Data.cpp
gfx/angle/src/libANGLE/Data.h
gfx/angle/src/libANGLE/Device.cpp
gfx/angle/src/libANGLE/Error.cpp
gfx/angle/src/libANGLE/Error.h
gfx/angle/src/libANGLE/Platform.cpp
gfx/angle/src/libANGLE/Program.cpp
gfx/angle/src/libANGLE/Program.h
gfx/angle/src/libANGLE/RefCountObject.h
gfx/angle/src/libANGLE/Shader.cpp
gfx/angle/src/libANGLE/Shader.h
gfx/angle/src/libANGLE/State.cpp
gfx/angle/src/libANGLE/Surface_unittest.cpp
gfx/angle/src/libANGLE/VertexArray.cpp
gfx/angle/src/libANGLE/angletypes.cpp
gfx/angle/src/libANGLE/angletypes.h
gfx/angle/src/libANGLE/features.h
gfx/angle/src/libANGLE/formatutils.cpp
gfx/angle/src/libANGLE/formatutils.h
gfx/angle/src/libANGLE/moz.build
gfx/angle/src/libANGLE/queryconversions.cpp
gfx/angle/src/libANGLE/renderer/DeviceImpl.h
gfx/angle/src/libANGLE/renderer/FramebufferImpl_mock.h
gfx/angle/src/libANGLE/renderer/ProgramImpl_mock.h
gfx/angle/src/libANGLE/renderer/ShaderImpl.h
gfx/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp
gfx/angle/src/libANGLE/renderer/d3d/BufferD3D.h
gfx/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp
gfx/angle/src/libANGLE/renderer/d3d/DeviceD3D.h
gfx/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp
gfx/angle/src/libANGLE/renderer/d3d/DisplayD3D.h
gfx/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
gfx/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h
gfx/angle/src/libANGLE/renderer/d3d/DynamicHLSL_unittest.cpp
gfx/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp
gfx/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp
gfx/angle/src/libANGLE/renderer/d3d/IndexDataManager.h
gfx/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp
gfx/angle/src/libANGLE/renderer/d3d/ProgramD3D.h
gfx/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp
gfx/angle/src/libANGLE/renderer/d3d/RendererD3D.h
gfx/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp
gfx/angle/src/libANGLE/renderer/d3d/ShaderD3D.h
gfx/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp
gfx/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp
gfx/angle/src/libANGLE/renderer/d3d/VaryingPacking.h
gfx/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp
gfx/angle/src/libANGLE/renderer/d3d/VertexBuffer.h
gfx/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp
gfx/angle/src/libANGLE/renderer/d3d/VertexDataManager.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.py
gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_swizzle_format_table.py
gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_texture_format_table.py
gfx/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json
gfx/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json
gfx/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json
gfx/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_util.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_util.h
gfx/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
gfx/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
gfx/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp
gfx/angle/src/libANGLE/renderer/d3d/loadimage_etc.h
gfx/angle/src/libANGLE/renderer/gl/BlitGL.cpp
gfx/angle/src/libANGLE/renderer/gl/BlitGL.h
gfx/angle/src/libANGLE/renderer/gl/FunctionsGL.cpp
gfx/angle/src/libANGLE/renderer/gl/ProgramGL.cpp
gfx/angle/src/libANGLE/renderer/gl/RendererGL.cpp
gfx/angle/src/libANGLE/renderer/gl/ShaderGL.cpp
gfx/angle/src/libANGLE/renderer/gl/ShaderGL.h
gfx/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp
gfx/angle/src/libANGLE/renderer/gl/StateManagerGL.h
gfx/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp
gfx/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.h
gfx/angle/src/libANGLE/renderer/gl/VertexArrayGL.cpp
gfx/angle/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm
gfx/angle/src/libANGLE/renderer/gl/formatutilsgl.cpp
gfx/angle/src/libANGLE/renderer/gl/glx/DisplayGLX.cpp
gfx/angle/src/libANGLE/renderer/gl/glx/DisplayGLX.h
gfx/angle/src/libANGLE/renderer/gl/glx/FBConfigCompatibility.md
gfx/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp
gfx/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.h
gfx/angle/src/libANGLE/renderer/gl/glx/PbufferSurfaceGLX.cpp
gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp
gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.h
gfx/angle/src/libANGLE/renderer/gl/glx/functionsglx_typedefs.h
gfx/angle/src/libANGLE/renderer/gl/glx/platform_glx.h
gfx/angle/src/libANGLE/renderer/gl/renderergl_utils.cpp
gfx/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp
gfx/angle/src/libANGLE/renderer/gl/wgl/FunctionsWGL.cpp
gfx/angle/src/libANGLE/renderer/gl/wgl/wgl_utils.cpp
gfx/angle/src/libANGLE/validationES.cpp
gfx/angle/src/libANGLE/validationES.h
gfx/angle/src/libANGLE/validationES2.cpp
gfx/angle/src/libANGLE/validationES2.h
gfx/angle/src/libANGLE/validationES3.cpp
gfx/angle/src/libANGLE/validationES3.h
gfx/angle/src/libANGLE/validationES_unittest.cpp
gfx/angle/src/libEGL/moz.build
gfx/angle/src/libGLESv2.gypi
gfx/angle/src/libGLESv2/entry_points_egl.cpp
gfx/angle/src/libGLESv2/entry_points_egl_ext.cpp
gfx/angle/src/libGLESv2/entry_points_gles_2_0.cpp
gfx/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp
gfx/angle/src/libGLESv2/entry_points_gles_2_0_ext.h
gfx/angle/src/libGLESv2/entry_points_gles_3_0.cpp
gfx/angle/src/libGLESv2/global_state.cpp
gfx/angle/src/libGLESv2/libGLESv2.cpp
gfx/angle/src/libGLESv2/libGLESv2.def
gfx/angle/src/libGLESv2/moz.build
gfx/angle/src/tests/BUILD.gn
gfx/angle/src/tests/WebGL-CTS-known-failures.txt
gfx/angle/src/tests/angle_end2end_tests.gypi
gfx/angle/src/tests/angle_perftests.gypi
gfx/angle/src/tests/angle_unittests.gypi
gfx/angle/src/tests/compiler_tests/ConstantFolding_test.cpp
gfx/angle/src/tests/compiler_tests/MalformedShader_test.cpp
gfx/angle/src/tests/deqp_support/angle_deqp_gtest.cpp
gfx/angle/src/tests/deqp_support/angle_deqp_libtester_main.cpp
gfx/angle/src/tests/deqp_support/deqp_egl_test_expectations.txt
gfx/angle/src/tests/deqp_support/deqp_gles2_test_expectations.txt
gfx/angle/src/tests/deqp_support/deqp_gles3_test_expectations.txt
gfx/angle/src/tests/egl_tests/EGLSurfaceTest.cpp
gfx/angle/src/tests/gl_tests/D3D11EmulatedIndexedBufferTest.cpp
gfx/angle/src/tests/gl_tests/DifferentStencilMasksTest.cpp
gfx/angle/src/tests/gl_tests/DiscardFramebufferEXTTest.cpp
gfx/angle/src/tests/gl_tests/GLSLTest.cpp
gfx/angle/src/tests/gl_tests/ProgramBinaryTest.cpp
gfx/angle/src/tests/gl_tests/ProvokingVertexTest.cpp
gfx/angle/src/tests/gl_tests/TransformFeedbackTest.cpp
gfx/angle/src/tests/gl_tests/UniformTest.cpp
gfx/angle/src/tests/perf_tests/BufferSubData.cpp
gfx/angle/src/tests/perf_tests/DrawCallPerf.cpp
gfx/angle/src/tests/perf_tests/IndexDataManagerTest.cpp
gfx/angle/src/tests/perf_tests/InterleavedAttributeData.cpp
gfx/angle/src/tests/perf_tests/PointSprites.cpp
gfx/angle/src/tests/perf_tests/TexSubImage.cpp
gfx/angle/src/tests/test_utils/ANGLETest.cpp
gfx/angle/src/tests/test_utils/ANGLETest.h
gfx/angle/src/tests/test_utils/compiler_test.cpp
--- a/gfx/angle/AUTHORS
+++ b/gfx/angle/AUTHORS
@@ -36,8 +36,9 @@ James Hauxwell
 Sam Hocevar
 Pierre Leveille
 Jonathan Liu
 Boying Lu
 Aitor Moreno
 Yuri O'Donnell
 Josh Soref
 Maks Naumov
+Jinyoung Hur
--- a/gfx/angle/BUILD.gn
+++ b/gfx/angle/BUILD.gn
@@ -374,16 +374,17 @@ static_library("angle_util") {
   sources = rebase_path(util_gypi.util_sources, ".", "util")
 
   if (is_win) {
     sources += rebase_path(util_gypi.util_win32_sources, ".", "util")
   }
 
   if (is_linux) {
     sources += rebase_path(util_gypi.util_linux_sources, ".", "util")
+    libs = [ "rt" ]
   }
 
   if (is_mac) {
     sources += rebase_path(util_gypi.util_osx_sources, ".", "util")
   }
 
   if (use_x11) {
     sources += rebase_path(util_gypi.util_x11_sources, ".", "util")
--- a/gfx/angle/README.md
+++ b/gfx/angle/README.md
@@ -1,22 +1,39 @@
 #ANGLE
-The goal of ANGLE is to allow Windows users to seamlessly run WebGL and other OpenGL ES content by translating OpenGL ES API calls to DirectX 9 or DirectX 11 API calls.
+The goal of ANGLE is to allow users of multiple operating systems to seamlessly run WebGL and other OpenGL ES content by translating OpenGL ES API calls to one of the hardware-supported APIs available for that platform. ANGLE currently provides translation from OpenGL ES 2.0 to desktop OpenGL, Direct3D 9, and Direct3D 11. Support for translation from OpenGL ES 3.0 to all of these APIs is nearing completion, and future plans include enabling validated ES-to-ES support.
+
+|                |  Direct3D 9   |    Direct3D 11      |    Desktop GL      |    GL ES  |
+|----------------|:-------------:|:-------------------:|:------------------:|:---------:|
+| OpenGL ES 2.0  |    complete   |      complete       |     complete       |   planned |
+| OpenGL ES 3.0  |               |  nearing completion | nearing completion |   planned |
+[Level of OpenGL ES support via backing renderers]
 
-ANGLE is a conformant implementation of the OpenGL ES 2.0 specification that is hardware‐accelerated via Direct3D. ANGLE v1.0.772 was certified compliant by passing the ES 2.0.3 conformance tests in October 2011. ANGLE also provides an implementation of the EGL 1.4 specification. Work on ANGLE's OpenGL ES 3.0 implementation is currently in progress, but should not be considered stable.
+|             |    Direct3D 9  |   Direct3D 11  |   Desktop GL  |
+|------------:|:--------------:|:--------------:|:-------------:|
+| Windows     |        *       |        *       |       *       |
+| Linux       |                |                |       *       |
+| Mac OS X    |                |                |   in progress |
+[Platform support via backing renderers]
+
+ANGLE v1.0.772 was certified compliant by passing the ES 2.0.3 conformance tests in October 2011. ANGLE also provides an implementation of the EGL 1.4 specification.
 
 ANGLE is used as the default WebGL backend for both Google Chrome and Mozilla Firefox on Windows platforms. Chrome uses ANGLE for all graphics rendering on Windows, including the accelerated Canvas2D implementation and the Native Client sandbox environment.
 
 Portions of the ANGLE shader compiler are used as a shader validator and translator by WebGL implementations across multiple platforms. It is used on Mac OS X, Linux, and in mobile variants of the browsers. Having one shader validator helps to ensure that a consistent set of GLSL ES shaders are accepted across browsers and platforms. The shader translator can be used to translate shaders to other shading languages, and to optionally apply shader modifications to work around bugs or quirks in the native graphics drivers. The translator targets Desktop GLSL, Direct3D HLSL, and even ESSL for native GLES2 platforms.
 
 ##Building
 View the [Dev setup instructions](doc/DevSetup.md).
 
 ##Contributing
 * Join our [Google group](https://groups.google.com/group/angleproject) to keep up to date.
 * Join us on IRC in the #ANGLEproject channel on FreeNode.
 * Read about ANGLE development in our [documentation](doc).
 * Become a [code contributor](doc/ContributingCode.md).
+* Refer to ANGLE's [coding standard](doc/CodingStandard.md).
+* Learn how to [build ANGLE for Chromium development](doc/BuildingAngleForChromiumDevelopment.md).
+* [Choose an ANGLE branch](doc/ChoosingANGLEBranch.md) to track in your own project.
 * File bugs in the [issue tracker](http://code.google.com/p/angleproject/issues/list) (preferably with an isolated test-case).
 * Read about WebGL on the [Khronos WebGL Wiki](http://khronos.org/webgl/wiki/Main_Page).
 * Learn about implementation details in the [OpenGL Insights chapter on ANGLE](http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-ANGLE.pdf) and this [ANGLE presentation](https://code.google.com/p/angleproject/downloads/detail?name=ANGLE%20and%20Cross-Platform%20WebGL%20Support.pdf&can=2&q=).
 * Learn about the past, present, and future of the ANGLE implementation in [this recent presentation](https://docs.google.com/presentation/d/1CucIsdGVDmdTWRUbg68IxLE5jXwCb2y1E9YVhQo0thg/pub?start=false&loop=false).
-* If you use ANGLE in your own project, we'd love to hear about it!
\ No newline at end of file
+* If you use ANGLE in your own project, we'd love to hear about it!
+
--- a/gfx/angle/include/GLSLANG/ShaderLang.h
+++ b/gfx/angle/include/GLSLANG/ShaderLang.h
@@ -261,17 +261,19 @@ typedef struct
     int ARM_shader_framebuffer_fetch;
 
     // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives
     // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate
     // EXT_draw_buffers by using it in combination with GLES3.0 glDrawBuffers
     // function. This applies to Tegra K1 devices.
     int NV_draw_buffers;
 
-    // Set to 1 if highp precision is supported in the fragment language.
+    // Set to 1 if highp precision is supported in the ESSL 1.00 version of the
+    // fragment language. Does not affect versions of the language where highp
+    // support is mandatory.
     // Default is 0.
     int FragmentPrecisionHigh;
 
     // GLSL ES 3.0 constants.
     int MaxVertexOutputVectors;
     int MaxFragmentInputVectors;
     int MinProgramTexelOffset;
     int MaxProgramTexelOffset;
--- a/gfx/angle/include/platform/Platform.h
+++ b/gfx/angle/include/platform/Platform.h
@@ -6,17 +6,34 @@
 // Platform.h: The public interface ANGLE exposes to the API layer, for
 //   doing platform-specific tasks like gathering data, or for tracing.
 
 #ifndef ANGLE_PLATFORM_H
 #define ANGLE_PLATFORM_H
 
 #include <stdint.h>
 
-#include "../export.h"
+#if defined(_WIN32)
+#   if !defined(LIBANGLE_IMPLEMENTATION)
+#       define ANGLE_PLATFORM_EXPORT __declspec(dllimport)
+#   endif
+#elif defined(__GNUC__)
+#   if defined(LIBANGLE_IMPLEMENTATION)
+#       define ANGLE_PLATFORM_EXPORT __attribute__((visibility ("default")))
+#   endif
+#endif
+#if !defined(ANGLE_PLATFORM_EXPORT)
+#   define ANGLE_PLATFORM_EXPORT
+#endif
+
+#if defined(_WIN32)
+#   define ANGLE_APIENTRY __stdcall
+#else
+#   define ANGLE_APIENTRY
+#endif
 
 namespace angle
 {
 
 class Platform
 {
   public:
 
@@ -129,18 +146,23 @@ class Platform
     virtual void histogramBoolean(const char *name, bool sample) { }
 
   protected:
     virtual ~Platform() { }
 };
 
 }
 
-typedef void(*ANGLEPlatformInitializeFunc)(angle::Platform*);
-ANGLE_EXPORT void ANGLEPlatformInitialize(angle::Platform*);
+extern "C"
+{
+
+typedef void (ANGLE_APIENTRY *ANGLEPlatformInitializeFunc)(angle::Platform*);
+ANGLE_PLATFORM_EXPORT void ANGLE_APIENTRY ANGLEPlatformInitialize(angle::Platform*);
 
-typedef void (*ANGLEPlatformShutdownFunc)();
-ANGLE_EXPORT void ANGLEPlatformShutdown();
+typedef void (ANGLE_APIENTRY *ANGLEPlatformShutdownFunc)();
+ANGLE_PLATFORM_EXPORT void ANGLE_APIENTRY ANGLEPlatformShutdown();
 
-typedef angle::Platform *(*ANGLEPlatformCurrentFunc)();
-ANGLE_EXPORT angle::Platform *ANGLEPlatformCurrent();
+typedef angle::Platform *(ANGLE_APIENTRY *ANGLEPlatformCurrentFunc)();
+ANGLE_PLATFORM_EXPORT angle::Platform *ANGLE_APIENTRY ANGLEPlatformCurrent();
+
+}
 
 #endif // ANGLE_PLATFORM_H
--- a/gfx/angle/moz.build
+++ b/gfx/angle/moz.build
@@ -41,16 +41,17 @@ UNIFIED_SOURCES += [
     'src/compiler/translator/Compiler.cpp',
     'src/compiler/translator/depgraph/DependencyGraph.cpp',
     'src/compiler/translator/depgraph/DependencyGraphBuilder.cpp',
     'src/compiler/translator/depgraph/DependencyGraphOutput.cpp',
     'src/compiler/translator/depgraph/DependencyGraphTraverse.cpp',
     'src/compiler/translator/Diagnostics.cpp',
     'src/compiler/translator/DirectiveHandler.cpp',
     'src/compiler/translator/EmulatePrecision.cpp',
+    'src/compiler/translator/ExtensionGLSL.cpp',
     'src/compiler/translator/FlagStd140Structs.cpp',
     'src/compiler/translator/ForLoopUnroll.cpp',
     'src/compiler/translator/InfoSink.cpp',
     'src/compiler/translator/Initialize.cpp',
     'src/compiler/translator/InitializeDll.cpp',
     'src/compiler/translator/InitializeParseContext.cpp',
     'src/compiler/translator/InitializeVariables.cpp',
     'src/compiler/translator/Intermediate.cpp',
@@ -58,17 +59,16 @@ UNIFIED_SOURCES += [
     'src/compiler/translator/intermOut.cpp',
     'src/compiler/translator/IntermTraverse.cpp',
     'src/compiler/translator/LoopInfo.cpp',
     'src/compiler/translator/Operator.cpp',
     'src/compiler/translator/OutputESSL.cpp',
     'src/compiler/translator/OutputGLSL.cpp',
     'src/compiler/translator/OutputGLSLBase.cpp',
     'src/compiler/translator/OutputHLSL.cpp',
-    'src/compiler/translator/parseConst.cpp',
     'src/compiler/translator/ParseContext.cpp',
     'src/compiler/translator/PoolAlloc.cpp',
     'src/compiler/translator/PruneEmptyDeclarations.cpp',
     'src/compiler/translator/RecordConstantPrecision.cpp',
     'src/compiler/translator/RegenerateStructNames.cpp',
     'src/compiler/translator/RemoveDynamicIndexing.cpp',
     'src/compiler/translator/RemovePow.cpp',
     'src/compiler/translator/RemoveSwitchFallThrough.cpp',
--- a/gfx/angle/src/commit.h
+++ b/gfx/angle/src/commit.h
@@ -1,3 +1,3 @@
-#define ANGLE_COMMIT_HASH "c7fc1b46df29"
+#define ANGLE_COMMIT_HASH "2eb89424cc6d"
 #define ANGLE_COMMIT_HASH_SIZE 12
-#define ANGLE_COMMIT_DATE "2015-11-09 16:31:17 -0500"
+#define ANGLE_COMMIT_DATE "2015-11-28 17:17:38 -0500"
--- a/gfx/angle/src/common/angleutils.h
+++ b/gfx/angle/src/common/angleutils.h
@@ -65,19 +65,19 @@ void SafeDelete(T*& resource)
 {
     delete resource;
     resource = NULL;
 }
 
 template <typename T>
 void SafeDeleteContainer(T& resource)
 {
-    for (typename T::iterator i = resource.begin(); i != resource.end(); i++)
+    for (auto &element : resource)
     {
-        SafeDelete(*i);
+        SafeDelete(element);
     }
     resource.clear();
 }
 
 template <typename T>
 void SafeDeleteArray(T*& resource)
 {
     delete[] resource;
--- a/gfx/angle/src/common/utilities.cpp
+++ b/gfx/angle/src/common/utilities.cpp
@@ -792,37 +792,12 @@ void writeFile(const char* path, const v
 
 #if defined (ANGLE_PLATFORM_WINDOWS)
 
 // Causes the thread to relinquish the remainder of its time slice to any
 // other thread that is ready to run.If there are no other threads ready
 // to run, the function returns immediately, and the thread continues execution.
 void ScheduleYield()
 {
-#if defined(ANGLE_ENABLE_WINDOWS_STORE)
-    // This implementation of Sleep exists because it is not available prior to Update 4.
-    static HANDLE singletonEvent = nullptr;
-    HANDLE sleepEvent = singletonEvent;
-    if (!sleepEvent)
-    {
-        sleepEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
-
-        if (!sleepEvent)
-            return;
-
-        HANDLE previousEvent = InterlockedCompareExchangePointerRelease(&singletonEvent, sleepEvent, nullptr);
-
-        if (previousEvent)
-        {
-            // Back out if multiple threads try to demand create at the same time.
-            CloseHandle(sleepEvent);
-            sleepEvent = previousEvent;
-        }
-    }
-
-    // Emulate sleep by waiting with timeout on an event that is never signalled.
-    WaitForSingleObjectEx(sleepEvent, 0, false);
-#else
     Sleep(0);
-#endif
 }
 
 #endif
--- a/gfx/angle/src/compiler.gypi
+++ b/gfx/angle/src/compiler.gypi
@@ -38,16 +38,18 @@
             'compiler/translator/ConstantUnion.h',
             'compiler/translator/Diagnostics.cpp',
             'compiler/translator/Diagnostics.h',
             'compiler/translator/DirectiveHandler.cpp',
             'compiler/translator/DirectiveHandler.h',
             'compiler/translator/EmulatePrecision.cpp',
             'compiler/translator/EmulatePrecision.h',
             'compiler/translator/ExtensionBehavior.h',
+            'compiler/translator/ExtensionGLSL.cpp',
+            'compiler/translator/ExtensionGLSL.h',
             'compiler/translator/FlagStd140Structs.cpp',
             'compiler/translator/FlagStd140Structs.h',
             'compiler/translator/ForLoopUnroll.cpp',
             'compiler/translator/ForLoopUnroll.h',
             'compiler/translator/HashNames.h',
             'compiler/translator/InfoSink.cpp',
             'compiler/translator/InfoSink.h',
             'compiler/translator/Initialize.cpp',
@@ -132,17 +134,16 @@
             'compiler/translator/glslang.h',
             'compiler/translator/glslang.l',
             'compiler/translator/glslang.y',
             'compiler/translator/glslang_lex.cpp',
             'compiler/translator/glslang_tab.cpp',
             'compiler/translator/glslang_tab.h',
             'compiler/translator/intermOut.cpp',
             'compiler/translator/length_limits.h',
-            'compiler/translator/parseConst.cpp',
             'compiler/translator/timing/RestrictFragmentShaderTiming.cpp',
             'compiler/translator/timing/RestrictFragmentShaderTiming.h',
             'compiler/translator/timing/RestrictVertexShaderTiming.cpp',
             'compiler/translator/timing/RestrictVertexShaderTiming.h',
             'compiler/translator/util.cpp',
             'compiler/translator/util.h',
             'third_party/compiler/ArrayBoundsClamper.cpp',
             'third_party/compiler/ArrayBoundsClamper.h',
--- a/gfx/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
+++ b/gfx/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -45,122 +45,146 @@ void InitBuiltInFunctionEmulatorForGLSLM
 {
     // Emulate packSnorm2x16, packHalf2x16, unpackSnorm2x16, and unpackHalf2x16 (GLSL 4.20)
     // by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30).
     if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420)
     {
         const TType *float2 = TCache::getType(EbtFloat, 2);
         const TType *uint1 = TCache::getType(EbtUInt);
 
+        // clang-format off
         emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
             "uint webgl_packSnorm2x16_emu(vec2 v)\n"
             "{\n"
-            "    int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
-            "    int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
-            "    return uint((y << 16) | (x & 0xFFFF));\n"
+            "    #if defined(GL_ARB_shading_language_packing)\n"
+            "        return packSnorm2x16(v);\n"
+            "    #else\n"
+            "        int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
+            "        int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
+            "        return uint((y << 16) | (x & 0xFFFF));\n"
+            "    #endif\n"
             "}\n");
         emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
-            "float webgl_fromSnorm(uint x)\n"
-            "{\n"
-            "    int xi = (int(x) & 0x7FFF) - (int(x) & 0x8000);\n"
-            "    return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
-            "}\n"
+            "#if !defined(GL_ARB_shading_language_packing)\n"
+            "    float webgl_fromSnorm(uint x)\n"
+            "    {\n"
+            "        int xi = (int(x) & 0x7FFF) - (int(x) & 0x8000);\n"
+            "        return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
+            "    }\n"
+            "#endif\n"
             "\n"
             "vec2 webgl_unpackSnorm2x16_emu(uint u)\n"
             "{\n"
-            "    uint y = (u >> 16);\n"
-            "    uint x = u;\n"
-            "    return vec2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
+            "    #if defined(GL_ARB_shading_language_packing)\n"
+            "        return unpackSnorm2x16(u);\n"
+            "    #else\n"
+            "        uint y = (u >> 16);\n"
+            "        uint x = u;\n"
+            "        return vec2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
+            "    #endif\n"
             "}\n");
         // Functions uint webgl_f32tof16(float val) and float webgl_f16tof32(uint val) are
         // based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
         emu->addEmulatedFunction(EOpPackHalf2x16, float2,
-            "uint webgl_f32tof16(float val)\n"
-            "{\n"
-            "    uint f32 = floatBitsToUint(val);\n"
-            "    uint f16 = 0u;\n"
-            "    uint sign = (f32 >> 16) & 0x8000u;\n"
-            "    int exponent = int((f32 >> 23) & 0xFFu) - 127;\n"
-            "    uint mantissa = f32 & 0x007FFFFFu;\n"
-            "    if (exponent == 128)\n"
-            "    {\n"
-            "        // Infinity or NaN\n"
-            "        // NaN bits that are masked out by 0x3FF get discarded.\n"
-            "        // This can turn some NaNs to infinity, but this is allowed by the spec.\n"
-            "        f16 = sign | (0x1Fu << 10);\n"
-            "        f16 |= (mantissa & 0x3FFu);\n"
-            "    }\n"
-            "    else if (exponent > 15)\n"
+            "#if !defined(GL_ARB_shading_language_packing)\n"
+            "    uint webgl_f32tof16(float val)\n"
             "    {\n"
-            "        // Overflow - flush to Infinity\n"
-            "        f16 = sign | (0x1Fu << 10);\n"
+            "        uint f32 = floatBitsToUint(val);\n"
+            "        uint f16 = 0u;\n"
+            "        uint sign = (f32 >> 16) & 0x8000u;\n"
+            "        int exponent = int((f32 >> 23) & 0xFFu) - 127;\n"
+            "        uint mantissa = f32 & 0x007FFFFFu;\n"
+            "        if (exponent == 128)\n"
+            "        {\n"
+            "            // Infinity or NaN\n"
+            "            // NaN bits that are masked out by 0x3FF get discarded.\n"
+            "            // This can turn some NaNs to infinity, but this is allowed by the spec.\n"
+            "            f16 = sign | (0x1Fu << 10);\n"
+            "            f16 |= (mantissa & 0x3FFu);\n"
+            "        }\n"
+            "        else if (exponent > 15)\n"
+            "        {\n"
+            "            // Overflow - flush to Infinity\n"
+            "            f16 = sign | (0x1Fu << 10);\n"
+            "        }\n"
+            "        else if (exponent > -15)\n"
+            "        {\n"
+            "            // Representable value\n"
+            "            exponent += 15;\n"
+            "            mantissa >>= 13;\n"
+            "            f16 = sign | uint(exponent << 10) | mantissa;\n"
+            "        }\n"
+            "        else\n"
+            "        {\n"
+            "            f16 = sign;\n"
+            "        }\n"
+            "        return f16;\n"
             "    }\n"
-            "    else if (exponent > -15)\n"
-            "    {\n"
-            "        // Representable value\n"
-            "        exponent += 15;\n"
-            "        mantissa >>= 13;\n"
-            "        f16 = sign | uint(exponent << 10) | mantissa;\n"
-            "    }\n"
-            "    else\n"
-            "    {\n"
-            "        f16 = sign;\n"
-            "    }\n"
-            "    return f16;\n"
-            "}\n"
+            "#endif\n"
             "\n"
             "uint webgl_packHalf2x16_emu(vec2 v)\n"
             "{\n"
-            "    uint x = webgl_f32tof16(v.x);\n"
-            "    uint y = webgl_f32tof16(v.y);\n"
-            "    return (y << 16) | x;\n"
+            "    #if defined(GL_ARB_shading_language_packing)\n"
+            "        return packHalf2x16(v);\n"
+            "    #else\n"
+            "        uint x = webgl_f32tof16(v.x);\n"
+            "        uint y = webgl_f32tof16(v.y);\n"
+            "        return (y << 16) | x;\n"
+            "    #endif\n"
             "}\n");
         emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
-            "float webgl_f16tof32(uint val)\n"
-            "{\n"
-            "    uint sign = (val & 0x8000u) << 16;\n"
-            "    int exponent = int((val & 0x7C00u) >> 10);\n"
-            "    uint mantissa = val & 0x03FFu;\n"
-            "    float f32 = 0.0;\n"
-            "    if(exponent == 0)\n"
-            "    {\n"
-            "        if (mantissa != 0u)\n"
-            "        {\n"
-            "            const float scale = 1.0 / (1 << 24);\n"
-            "            f32 = scale * mantissa;\n"
-            "        }\n"
-            "    }\n"
-            "    else if (exponent == 31)\n"
-            "    {\n"
-            "        return uintBitsToFloat(sign | 0x7F800000u | mantissa);\n"
-            "    }\n"
-            "    else\n"
+            "#if !defined(GL_ARB_shading_language_packing)\n"
+            "    float webgl_f16tof32(uint val)\n"
             "    {\n"
-            "         exponent -= 15;\n"
-            "         float scale;\n"
-            "         if(exponent < 0)\n"
-            "         {\n"
-            "             scale = 1.0 / (1 << -exponent);\n"
-            "         }\n"
-            "         else\n"
-            "         {\n"
-            "             scale = 1 << exponent;\n"
-            "         }\n"
-            "         float decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
-            "         f32 = scale * decimal;\n"
+            "        uint sign = (val & 0x8000u) << 16;\n"
+            "        int exponent = int((val & 0x7C00u) >> 10);\n"
+            "        uint mantissa = val & 0x03FFu;\n"
+            "        float f32 = 0.0;\n"
+            "        if(exponent == 0)\n"
+            "        {\n"
+            "            if (mantissa != 0u)\n"
+            "            {\n"
+            "                const float scale = 1.0 / (1 << 24);\n"
+            "                f32 = scale * mantissa;\n"
+            "            }\n"
+            "        }\n"
+            "        else if (exponent == 31)\n"
+            "        {\n"
+            "            return uintBitsToFloat(sign | 0x7F800000u | mantissa);\n"
+            "        }\n"
+            "        else\n"
+            "        {\n"
+            "            exponent -= 15;\n"
+            "            float scale;\n"
+            "            if(exponent < 0)\n"
+            "            {\n"
+            "                scale = 1.0 / (1 << -exponent);\n"
+            "            }\n"
+            "            else\n"
+            "            {\n"
+            "                scale = 1 << exponent;\n"
+            "            }\n"
+            "            float decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
+            "            f32 = scale * decimal;\n"
+            "        }\n"
+            "\n"
+            "        if (sign != 0u)\n"
+            "        {\n"
+            "            f32 = -f32;\n"
+            "        }\n"
+            "\n"
+            "        return f32;\n"
             "    }\n"
-            "\n"
-            "    if (sign != 0u)\n"
-            "    {\n"
-            "        f32 = -f32;\n"
-            "    }\n"
-            "\n"
-            "    return f32;\n"
-            "}\n"
+            "#endif\n"
             "\n"
             "vec2 webgl_unpackHalf2x16_emu(uint u)\n"
             "{\n"
-            "    uint y = (u >> 16);\n"
-            "    uint x = u & 0xFFFFu;\n"
-            "    return vec2(webgl_f16tof32(x), webgl_f16tof32(y));\n"
+            "    #if defined(GL_ARB_shading_language_packing)\n"
+            "        return unpackHalf2x16(u);\n"
+            "    #else\n"
+            "        uint y = (u >> 16);\n"
+            "        uint x = u & 0xFFFFu;\n"
+            "        return vec2(webgl_f16tof32(x), webgl_f16tof32(y));\n"
+            "    #endif\n"
             "}\n");
+        // clang-format on
     }
 }
--- a/gfx/angle/src/compiler/translator/Compiler.cpp
+++ b/gfx/angle/src/compiler/translator/Compiler.cpp
@@ -208,23 +208,21 @@ TIntermNode *TCompiler::compileTreeImpl(
     // First string is path of source file if flag is set. The actual source follows.
     size_t firstSource = 0;
     if (compileOptions & SH_SOURCE_PATH)
     {
         mSourcePath = shaderStrings[0];
         ++firstSource;
     }
 
-    bool debugShaderPrecision = getResources().WEBGL_debug_shader_precision == 1;
     TIntermediate intermediate(infoSink);
-    TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
-                               shaderType, shaderSpec, compileOptions, true,
-                               infoSink, debugShaderPrecision);
+    TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec,
+                               compileOptions, true, infoSink, getResources());
 
-    parseContext.setFragmentPrecisionHigh(fragmentPrecisionHigh);
+    parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
     SetGlobalParseContext(&parseContext);
 
     // We preserve symbols at the built-in level from compile-to-compile.
     // Start pushing the user-defined symbols at global level.
     TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
 
     // Parse shader.
     bool success =
@@ -247,16 +245,19 @@ TIntermNode *TCompiler::compileTreeImpl(
         if (mPragma.stdgl.invariantAll)
         {
             symbolTable.setGlobalInvariant();
         }
 
         root = parseContext.getTreeRoot();
         root = intermediate.postProcess(root);
 
+        // Highp might have been auto-enabled based on shader version
+        fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
+
         // Disallow expressions deemed too complex.
         if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
             success = limitExpressionComplexity(root);
 
         // Create the function DAG and check there is no recursion
         if (success)
             success = initCallDag(root);
 
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/ExtensionGLSL.cpp
@@ -0,0 +1,100 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ExtensionGLSL.cpp: Implements the TExtensionGLSL class that tracks GLSL extension requirements
+// of shaders.
+
+#include "compiler/translator/ExtensionGLSL.h"
+
+#include "compiler/translator/VersionGLSL.h"
+
+TExtensionGLSL::TExtensionGLSL(ShShaderOutput output)
+    : TIntermTraverser(true, false, false), mTargetVersion(ShaderOutputTypeToGLSLVersion(output))
+{
+}
+
+const std::set<std::string> &TExtensionGLSL::getEnabledExtensions() const
+{
+    return mEnabledExtensions;
+}
+
+const std::set<std::string> &TExtensionGLSL::getRequiredExtensions() const
+{
+    return mRequiredExtensions;
+}
+
+bool TExtensionGLSL::visitUnary(Visit, TIntermUnary *node)
+{
+    checkOperator(node);
+
+    return true;
+}
+
+bool TExtensionGLSL::visitAggregate(Visit, TIntermAggregate *node)
+{
+    checkOperator(node);
+
+    return true;
+}
+
+void TExtensionGLSL::checkOperator(TIntermOperator *node)
+{
+    if (mTargetVersion < GLSL_VERSION_130)
+    {
+        return;
+    }
+
+    switch (node->getOp())
+    {
+        case EOpAbs:
+            break;
+
+        case EOpSign:
+            break;
+
+        case EOpMix:
+            break;
+
+        case EOpFloatBitsToInt:
+        case EOpFloatBitsToUint:
+        case EOpIntBitsToFloat:
+        case EOpUintBitsToFloat:
+            if (mTargetVersion < GLSL_VERSION_330)
+            {
+                // Bit conversion functions cannot be emulated.
+                mRequiredExtensions.insert("GL_ARB_shader_bit_encoding");
+            }
+            break;
+
+        case EOpPackSnorm2x16:
+        case EOpPackHalf2x16:
+        case EOpUnpackSnorm2x16:
+        case EOpUnpackHalf2x16:
+            if (mTargetVersion < GLSL_VERSION_420)
+            {
+                mEnabledExtensions.insert("GL_ARB_shading_language_packing");
+
+                if (mTargetVersion < GLSL_VERSION_330)
+                {
+                    // floatBitsToUint and uintBitsToFloat are needed to emulate
+                    // packHalf2x16 and unpackHalf2x16 respectively and cannot be
+                    // emulated themselves.
+                    mRequiredExtensions.insert("GL_ARB_shader_bit_encoding");
+                }
+            }
+            break;
+
+        case EOpPackUnorm2x16:
+        case EOpUnpackUnorm2x16:
+            if (mTargetVersion < GLSL_VERSION_410)
+            {
+                mEnabledExtensions.insert("GL_ARB_shading_language_packing");
+            }
+            break;
+
+        default:
+            break;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/ExtensionGLSL.h
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ExtensionGLSL.h: Defines the TExtensionGLSL class that tracks GLSL extension requirements of
+// shaders.
+
+#ifndef COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
+#define COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
+
+#include <set>
+#include <string>
+
+#include "compiler/translator/IntermNode.h"
+
+// Traverses the intermediate tree to determine which GLSL extensions are required
+// to support the shader.
+class TExtensionGLSL : public TIntermTraverser
+{
+  public:
+    TExtensionGLSL(ShShaderOutput output);
+
+    const std::set<std::string> &getEnabledExtensions() const;
+    const std::set<std::string> &getRequiredExtensions() const;
+
+    bool visitUnary(Visit visit, TIntermUnary *node) override;
+    bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+  private:
+    void checkOperator(TIntermOperator *node);
+
+    int mTargetVersion;
+
+    std::set<std::string> mEnabledExtensions;
+    std::set<std::string> mRequiredExtensions;
+};
+
+#endif  // COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
--- a/gfx/angle/src/compiler/translator/IntermNode.cpp
+++ b/gfx/angle/src/compiler/translator/IntermNode.cpp
@@ -61,83 +61,16 @@ bool ValidateMultiplication(TOperator op
                left.getRows() == right.getRows();
 
       default:
         UNREACHABLE();
         return false;
     }
 }
 
-bool CompareStructure(const TType& leftNodeType,
-                      const TConstantUnion *rightUnionArray,
-                      const TConstantUnion *leftUnionArray);
-
-bool CompareStruct(const TType &leftNodeType,
-                   const TConstantUnion *rightUnionArray,
-                   const TConstantUnion *leftUnionArray)
-{
-    const TFieldList &fields = leftNodeType.getStruct()->fields();
-
-    size_t structSize = fields.size();
-    size_t index = 0;
-
-    for (size_t j = 0; j < structSize; j++)
-    {
-        size_t size = fields[j]->type()->getObjectSize();
-        for (size_t i = 0; i < size; i++)
-        {
-            if (fields[j]->type()->getBasicType() == EbtStruct)
-            {
-                if (!CompareStructure(*fields[j]->type(),
-                                      &rightUnionArray[index],
-                                      &leftUnionArray[index]))
-                {
-                    return false;
-                }
-            }
-            else
-            {
-                if (leftUnionArray[index] != rightUnionArray[index])
-                    return false;
-                index++;
-            }
-        }
-    }
-    return true;
-}
-
-bool CompareStructure(const TType &leftNodeType,
-                      const TConstantUnion *rightUnionArray,
-                      const TConstantUnion *leftUnionArray)
-{
-    if (leftNodeType.isArray())
-    {
-        TType typeWithoutArrayness = leftNodeType;
-        typeWithoutArrayness.clearArrayness();
-
-        size_t arraySize = leftNodeType.getArraySize();
-
-        for (size_t i = 0; i < arraySize; ++i)
-        {
-            size_t offset = typeWithoutArrayness.getObjectSize() * i;
-            if (!CompareStruct(typeWithoutArrayness,
-                               &rightUnionArray[offset],
-                               &leftUnionArray[offset]))
-            {
-                return false;
-            }
-        }
-    }
-    else
-    {
-        return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
-    }
-    return true;
-}
-
 TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
 {
     TConstantUnion *constUnion = new TConstantUnion[size];
     for (unsigned int i = 0; i < size; ++i)
         constUnion[i] = constant;
 
     return constUnion;
 }
@@ -164,58 +97,64 @@ void UndefinedConstantFoldingError(const
       case EbtBool:
         result->setBConst(false);
         break;
       default:
         break;
     }
 }
 
-float VectorLength(TConstantUnion *paramArray, size_t paramArraySize)
+float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
 {
     float result = 0.0f;
     for (size_t i = 0; i < paramArraySize; i++)
     {
         float f = paramArray[i].getFConst();
         result += f * f;
     }
     return sqrtf(result);
 }
 
-float VectorDotProduct(TConstantUnion *paramArray1, TConstantUnion *paramArray2, size_t paramArraySize)
+float VectorDotProduct(const TConstantUnion *paramArray1,
+                       const TConstantUnion *paramArray2,
+                       size_t paramArraySize)
 {
     float result = 0.0f;
     for (size_t i = 0; i < paramArraySize; i++)
         result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
     return result;
 }
 
-TIntermTyped *CreateFoldedNode(TConstantUnion *constArray, const TIntermTyped *originalNode)
+TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
+                               const TIntermTyped *originalNode,
+                               TQualifier qualifier)
 {
     if (constArray == nullptr)
     {
         return nullptr;
     }
     TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
-    folded->getTypePointer()->setQualifier(EvqConst);
+    folded->getTypePointer()->setQualifier(qualifier);
     folded->setLine(originalNode->getLine());
     return folded;
 }
 
-angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &rows, const unsigned int &cols)
+angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
+                               const unsigned int &rows,
+                               const unsigned int &cols)
 {
     std::vector<float> elements;
     for (size_t i = 0; i < rows * cols; i++)
         elements.push_back(paramArray[i].getFConst());
     // Transpose is used since the Matrix constructor expects arguments in row-major order,
     // whereas the paramArray is in column-major order.
     return angle::Matrix<float>(elements, rows, cols).transpose();
 }
 
-angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &size)
+angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
 {
     std::vector<float> elements;
     for (size_t i = 0; i < size * size; i++)
         elements.push_back(paramArray[i].getFConst());
     // Transpose is used since the Matrix constructor expects arguments in row-major order,
     // whereas the paramArray is in column-major order.
     return angle::Matrix<float>(elements, size).transpose();
 }
@@ -254,17 +193,17 @@ void TIntermTyped::setTypePreservePrecis
     }
 
 bool TIntermLoop::replaceChildNode(
     TIntermNode *original, TIntermNode *replacement)
 {
     REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
     REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
     REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
-    REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
+    REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
     return false;
 }
 
 bool TIntermBranch::replaceChildNode(
     TIntermNode *original, TIntermNode *replacement)
 {
     REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
     return false;
@@ -315,16 +254,29 @@ bool TIntermAggregate::insertChildNodes(
     {
         return false;
     }
     auto it = mSequence.begin() + position;
     mSequence.insert(it, insertions.begin(), insertions.end());
     return true;
 }
 
+bool TIntermAggregate::areChildrenConstQualified()
+{
+    for (TIntermNode *&child : mSequence)
+    {
+        TIntermTyped *typed = child->getAsTyped();
+        if (typed && typed->getQualifier() != EvqConst)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
 void TIntermAggregate::setPrecisionFromChildren()
 {
     mGotPrecisionFromChildren = true;
     if (getBasicType() == EbtBool)
     {
         mType.setPrecision(EbpUndefined);
         return;
     }
@@ -396,22 +348,17 @@ TIntermTyped::TIntermTyped(const TInterm
     // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
     // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
     // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
     mLine = node.mLine;
 }
 
 TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
 {
-    size_t arraySize   = mType.getObjectSize();
-    mUnionArrayPointer = new TConstantUnion[arraySize];
-    for (size_t i = 0u; i < arraySize; ++i)
-    {
-        mUnionArrayPointer[i] = node.mUnionArrayPointer[i];
-    }
+    mUnionArrayPointer = node.mUnionArrayPointer;
 }
 
 TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
     : TIntermOperator(node),
       mName(node.mName),
       mUserDefined(node.mUserDefined),
       mFunctionId(node.mFunctionId),
       mUseEmulatedFunction(node.mUseEmulatedFunction),
@@ -582,17 +529,20 @@ void TIntermUnary::promote(const TType *
         }
         else
         {
             // Precision of the node has been set based on the operand.
             setTypePreservePrecision(*funcReturnType);
         }
     }
 
-    mType.setQualifier(EvqTemporary);
+    if (mOperand->getQualifier() == EvqConst)
+        mType.setQualifier(EvqConst);
+    else
+        mType.setQualifier(EvqTemporary);
 }
 
 //
 // Establishes the type of the resultant operation, as well as
 // makes the operator the correct one for the operands.
 //
 // For lots of operations it should already be established that the operand
 // combination is valid, but returns false if operator can't work on operands.
@@ -607,20 +557,22 @@ bool TIntermBinary::promote(TInfoSink &i
     //
     setType(mLeft->getType());
 
     // The result gets promoted to the highest precision.
     TPrecision higherPrecision = GetHigherPrecision(
         mLeft->getPrecision(), mRight->getPrecision());
     getTypePointer()->setPrecision(higherPrecision);
 
+    TQualifier resultQualifier = EvqConst;
     // Binary operations results in temporary variables unless both
     // operands are const.
     if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
     {
+        resultQualifier = EvqTemporary;
         getTypePointer()->setQualifier(EvqTemporary);
     }
 
     const int nominalSize =
         std::max(mLeft->getNominalSize(), mRight->getNominalSize());
 
     //
     // All scalars or structs. Code after this test assumes this case is removed!
@@ -665,55 +617,57 @@ bool TIntermBinary::promote(TInfoSink &i
     switch (mOp)
     {
       case EOpMul:
         if (!mLeft->isMatrix() && mRight->isMatrix())
         {
             if (mLeft->isVector())
             {
                 mOp = EOpVectorTimesMatrix;
-                setType(TType(basicType, higherPrecision, EvqTemporary,
+                setType(TType(basicType, higherPrecision, resultQualifier,
                               static_cast<unsigned char>(mRight->getCols()), 1));
             }
             else
             {
                 mOp = EOpMatrixTimesScalar;
-                setType(TType(basicType, higherPrecision, EvqTemporary,
-                              static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
+                setType(TType(basicType, higherPrecision, resultQualifier,
+                              static_cast<unsigned char>(mRight->getCols()),
+                              static_cast<unsigned char>(mRight->getRows())));
             }
         }
         else if (mLeft->isMatrix() && !mRight->isMatrix())
         {
             if (mRight->isVector())
             {
                 mOp = EOpMatrixTimesVector;
-                setType(TType(basicType, higherPrecision, EvqTemporary,
+                setType(TType(basicType, higherPrecision, resultQualifier,
                               static_cast<unsigned char>(mLeft->getRows()), 1));
             }
             else
             {
                 mOp = EOpMatrixTimesScalar;
             }
         }
         else if (mLeft->isMatrix() && mRight->isMatrix())
         {
             mOp = EOpMatrixTimesMatrix;
-            setType(TType(basicType, higherPrecision, EvqTemporary,
-                          static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
+            setType(TType(basicType, higherPrecision, resultQualifier,
+                          static_cast<unsigned char>(mRight->getCols()),
+                          static_cast<unsigned char>(mLeft->getRows())));
         }
         else if (!mLeft->isMatrix() && !mRight->isMatrix())
         {
             if (mLeft->isVector() && mRight->isVector())
             {
                 // leave as component product
             }
             else if (mLeft->isVector() || mRight->isVector())
             {
                 mOp = EOpVectorTimesScalar;
-                setType(TType(basicType, higherPrecision, EvqTemporary,
+                setType(TType(basicType, higherPrecision, resultQualifier,
                               static_cast<unsigned char>(nominalSize), 1));
             }
         }
         else
         {
             infoSink.info.message(EPrefixInternalError, getLine(),
                                   "Missing elses");
             return false;
@@ -746,31 +700,32 @@ bool TIntermBinary::promote(TInfoSink &i
             else
             {
                 mOp = EOpMatrixTimesScalarAssign;
             }
         }
         else if (mLeft->isMatrix() && mRight->isMatrix())
         {
             mOp = EOpMatrixTimesMatrixAssign;
-            setType(TType(basicType, higherPrecision, EvqTemporary,
-                          static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
+            setType(TType(basicType, higherPrecision, resultQualifier,
+                          static_cast<unsigned char>(mRight->getCols()),
+                          static_cast<unsigned char>(mLeft->getRows())));
         }
         else if (!mLeft->isMatrix() && !mRight->isMatrix())
         {
             if (mLeft->isVector() && mRight->isVector())
             {
                 // leave as component product
             }
             else if (mLeft->isVector() || mRight->isVector())
             {
                 if (!mLeft->isVector())
                     return false;
                 mOp = EOpVectorTimesScalarAssign;
-                setType(TType(basicType, higherPrecision, EvqTemporary,
+                setType(TType(basicType, higherPrecision, resultQualifier,
                               static_cast<unsigned char>(mLeft->getNominalSize()), 1));
             }
         }
         else
         {
             infoSink.info.message(EPrefixInternalError, getLine(),
                                   "Missing elses");
             return false;
@@ -830,18 +785,19 @@ bool TIntermBinary::promote(TInfoSink &i
                 mOp == EOpBitShiftLeft ||
                 mOp == EOpBitShiftRight))
                 return false;
         }
 
         {
             const int secondarySize = std::max(
                 mLeft->getSecondarySize(), mRight->getSecondarySize());
-            setType(TType(basicType, higherPrecision, EvqTemporary,
-                          static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
+            setType(TType(basicType, higherPrecision, resultQualifier,
+                          static_cast<unsigned char>(nominalSize),
+                          static_cast<unsigned char>(secondarySize)));
             if (mLeft->isArray())
             {
                 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
                 mType.setArraySize(mLeft->getArraySize());
             }
         }
         break;
 
@@ -866,17 +822,24 @@ TIntermTyped *TIntermBinary::fold(TInfoS
 {
     TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
     TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
     if (leftConstant == nullptr || rightConstant == nullptr)
     {
         return nullptr;
     }
     TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
-    return CreateFoldedNode(constArray, this);
+
+    // Nodes may be constant folded without being qualified as constant.
+    TQualifier resultQualifier = EvqConst;
+    if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
+    {
+        resultQualifier = EvqTemporary;
+    }
+    return CreateFoldedNode(constArray, this, resultQualifier);
 }
 
 TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
 {
     TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
     if (operandConstant == nullptr)
     {
         return nullptr;
@@ -898,43 +861,53 @@ TIntermTyped *TIntermUnary::fold(TInfoSi
       case EOpPackHalf2x16:
       case EOpUnpackHalf2x16:
         constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
         break;
       default:
         constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
         break;
     }
-    return CreateFoldedNode(constArray, this);
+
+    // Nodes may be constant folded without being qualified as constant.
+    TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
+    return CreateFoldedNode(constArray, this, resultQualifier);
 }
 
 TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
 {
     // Make sure that all params are constant before actual constant folding.
     for (auto *param : *getSequence())
     {
         if (param->getAsConstantUnion() == nullptr)
         {
             return nullptr;
         }
     }
-    TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
-    return CreateFoldedNode(constArray, this);
+    TConstantUnion *constArray = nullptr;
+    if (isConstructor())
+        constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
+    else
+        constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
+
+    // Nodes may be constant folded without being qualified as constant.
+    TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
+    return CreateFoldedNode(constArray, this, resultQualifier);
 }
 
 //
 // The fold functions see if an operation on a constant can be done in place,
 // without generating run-time code.
 //
 // Returns the constant value to keep using or nullptr.
 //
 TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
 {
-    TConstantUnion *leftArray = getUnionArrayPointer();
-    TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
+    const TConstantUnion *leftArray  = getUnionArrayPointer();
+    const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
 
     if (!leftArray)
         return nullptr;
     if (!rightArray)
         return nullptr;
 
     size_t objectSize = getType().getObjectSize();
 
@@ -1224,29 +1197,22 @@ TConstantUnion *TIntermConstantUnion::fo
         resultArray->setBConst(!(*leftArray < *rightArray));
         break;
 
       case EOpEqual:
       case EOpNotEqual:
         {
             resultArray = new TConstantUnion[1];
             bool equal = true;
-            if (getType().getBasicType() == EbtStruct)
-            {
-                equal = CompareStructure(getType(), rightArray, leftArray);
-            }
-            else
+            for (size_t i = 0; i < objectSize; i++)
             {
-                for (size_t i = 0; i < objectSize; i++)
+                if (leftArray[i] != rightArray[i])
                 {
-                    if (leftArray[i] != rightArray[i])
-                    {
-                        equal = false;
-                        break;  // break out of for loop
-                    }
+                    equal = false;
+                    break;  // break out of for loop
                 }
             }
             if (op == EOpEqual)
             {
                 resultArray->setBConst(equal);
             }
             else
             {
@@ -1271,17 +1237,17 @@ TConstantUnion *TIntermConstantUnion::fo
 // Returns the constant value to keep using or nullptr.
 //
 TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
 {
     //
     // Do operations where the return type has a different number of components compared to the operand type.
     //
 
-    TConstantUnion *operandArray = getUnionArrayPointer();
+    const TConstantUnion *operandArray = getUnionArrayPointer();
     if (!operandArray)
         return nullptr;
 
     size_t objectSize = getType().getObjectSize();
     TConstantUnion *resultArray = nullptr;
     switch (op)
     {
       case EOpAny:
@@ -1484,17 +1450,17 @@ TConstantUnion *TIntermConstantUnion::fo
 }
 
 TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
 {
     //
     // Do unary operations where the return type is the same as operand type.
     //
 
-    TConstantUnion *operandArray = getUnionArrayPointer();
+    const TConstantUnion *operandArray = getUnionArrayPointer();
     if (!operandArray)
         return nullptr;
 
     size_t objectSize = getType().getObjectSize();
 
     TConstantUnion *resultArray = new TConstantUnion[objectSize];
     for (size_t i = 0; i < objectSize; i++)
     {
@@ -1931,22 +1897,122 @@ bool TIntermConstantUnion::foldFloatType
 
     infoSink.info.message(
         EPrefixInternalError, getLine(),
         "Unary operation not folded into constant");
     return false;
 }
 
 // static
+TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
+                                                               TInfoSink &infoSink)
+{
+    ASSERT(aggregate->getSequence()->size() > 0u);
+    size_t resultSize           = aggregate->getType().getObjectSize();
+    TConstantUnion *resultArray = new TConstantUnion[resultSize];
+    TBasicType basicType        = aggregate->getBasicType();
+
+    size_t resultIndex = 0u;
+
+    if (aggregate->getSequence()->size() == 1u)
+    {
+        TIntermNode *argument                    = aggregate->getSequence()->front();
+        TIntermConstantUnion *argumentConstant   = argument->getAsConstantUnion();
+        const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
+        // Check the special case of constructing a matrix diagonal from a single scalar,
+        // or a vector from a single scalar.
+        if (argumentConstant->getType().getObjectSize() == 1u)
+        {
+            if (aggregate->isMatrix())
+            {
+                int resultCols = aggregate->getType().getCols();
+                int resultRows = aggregate->getType().getRows();
+                for (int col = 0; col < resultCols; ++col)
+                {
+                    for (int row = 0; row < resultRows; ++row)
+                    {
+                        if (col == row)
+                        {
+                            resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
+                        }
+                        else
+                        {
+                            resultArray[resultIndex].setFConst(0.0f);
+                        }
+                        ++resultIndex;
+                    }
+                }
+            }
+            else
+            {
+                while (resultIndex < resultSize)
+                {
+                    resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
+                    ++resultIndex;
+                }
+            }
+            ASSERT(resultIndex == resultSize);
+            return resultArray;
+        }
+        else if (aggregate->isMatrix() && argumentConstant->isMatrix())
+        {
+            // The special case of constructing a matrix from a matrix.
+            int argumentCols = argumentConstant->getType().getCols();
+            int argumentRows = argumentConstant->getType().getRows();
+            int resultCols   = aggregate->getType().getCols();
+            int resultRows = aggregate->getType().getRows();
+            for (int col = 0; col < resultCols; ++col)
+            {
+                for (int row = 0; row < resultRows; ++row)
+                {
+                    if (col < argumentCols && row < argumentRows)
+                    {
+                        resultArray[resultIndex].cast(basicType,
+                                                      argumentUnionArray[col * argumentRows + row]);
+                    }
+                    else if (col == row)
+                    {
+                        resultArray[resultIndex].setFConst(1.0f);
+                    }
+                    else
+                    {
+                        resultArray[resultIndex].setFConst(0.0f);
+                    }
+                    ++resultIndex;
+                }
+            }
+            ASSERT(resultIndex == resultSize);
+            return resultArray;
+        }
+    }
+
+    for (TIntermNode *&argument : *aggregate->getSequence())
+    {
+        TIntermConstantUnion *argumentConstant   = argument->getAsConstantUnion();
+        size_t argumentSize                      = argumentConstant->getType().getObjectSize();
+        const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
+        for (size_t i = 0u; i < argumentSize; ++i)
+        {
+            if (resultIndex >= resultSize)
+                break;
+            resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
+            ++resultIndex;
+        }
+    }
+    ASSERT(resultIndex == resultSize);
+    return resultArray;
+}
+
+// static
 TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
 {
     TOperator op = aggregate->getOp();
     TIntermSequence *sequence = aggregate->getSequence();
     unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
-    std::vector<TConstantUnion *> unionArrays(paramsCount);
+    std::vector<const TConstantUnion *> unionArrays(paramsCount);
     std::vector<size_t> objectSizes(paramsCount);
     size_t maxObjectSize = 0;
     TBasicType basicType = EbtVoid;
     TSourceLoc loc;
     for (unsigned int i = 0; i < paramsCount; i++)
     {
         TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
         ASSERT(paramConstant != nullptr); // Should be checked already.
--- a/gfx/angle/src/compiler/translator/IntermNode.h
+++ b/gfx/angle/src/compiler/translator/IntermNode.h
@@ -168,44 +168,43 @@ enum TLoopType
     ELoopWhile,
     ELoopDoWhile
 };
 
 class TIntermLoop : public TIntermNode
 {
   public:
     TIntermLoop(TLoopType type,
-                TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
-                TIntermNode *body)
-        : mType(type),
-          mInit(init),
-          mCond(cond),
-          mExpr(expr),
-          mBody(body),
-          mUnrollFlag(false) { }
+                TIntermNode *init,
+                TIntermTyped *cond,
+                TIntermTyped *expr,
+                TIntermAggregate *body)
+        : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body), mUnrollFlag(false)
+    {
+    }
 
     TIntermLoop *getAsLoopNode() override { return this; }
     void traverse(TIntermTraverser *it) override;
     bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
 
     TLoopType getType() const { return mType; }
     TIntermNode *getInit() { return mInit; }
     TIntermTyped *getCondition() { return mCond; }
     TIntermTyped *getExpression() { return mExpr; }
-    TIntermNode *getBody() { return mBody; }
+    TIntermAggregate *getBody() { return mBody; }
 
     void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
     bool getUnrollFlag() const { return mUnrollFlag; }
 
   protected:
     TLoopType mType;
     TIntermNode *mInit;  // for-loop initialization
     TIntermTyped *mCond; // loop exit condition
     TIntermTyped *mExpr; // for-loop expression
-    TIntermNode *mBody;  // loop body
+    TIntermAggregate *mBody;  // loop body
 
     bool mUnrollFlag; // Whether the loop should be unrolled or not.
 };
 
 //
 // Handle break, continue, return, and kill.
 //
 class TIntermBranch : public TIntermNode
@@ -289,29 +288,35 @@ class TIntermRaw : public TIntermTyped
 
     TIntermRaw *getAsRawNode() override { return this; }
     bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
 
   protected:
     TString mRawText;
 };
 
+// Constant folded node.
+// Note that nodes may be constant folded and not be constant expressions with the EvqConst
+// qualifier. This happens for example when the following expression is processed:
+// "true ? 1.0 : non_constant"
+// Other nodes than TIntermConstantUnion may also be constant expressions.
+//
 class TIntermConstantUnion : public TIntermTyped
 {
   public:
-    TIntermConstantUnion(TConstantUnion *unionPointer, const TType &type)
-        : TIntermTyped(type),
-          mUnionArrayPointer(unionPointer) { }
+    TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
+        : TIntermTyped(type), mUnionArrayPointer(unionPointer)
+    {
+    }
 
     TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
 
     bool hasSideEffects() const override { return false; }
 
     const TConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; }
-    TConstantUnion *getUnionArrayPointer() { return mUnionArrayPointer; }
 
     int getIConst(size_t index) const
     {
         return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0;
     }
     unsigned int getUConst(size_t index) const
     {
         return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0;
@@ -320,34 +325,37 @@ class TIntermConstantUnion : public TInt
     {
         return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f;
     }
     bool getBConst(size_t index) const
     {
         return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false;
     }
 
-    void replaceConstantUnion(TConstantUnion *safeConstantUnion)
+    void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
     {
         // Previous union pointer freed on pool deallocation.
         mUnionArrayPointer = safeConstantUnion;
     }
 
     TIntermConstantUnion *getAsConstantUnion() override { return this; }
     void traverse(TIntermTraverser *it) override;
     bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
 
     TConstantUnion *foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink);
     TConstantUnion *foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink);
     TConstantUnion *foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink);
 
+    static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate,
+                                                    TInfoSink &infoSink);
     static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink);
 
   protected:
-    TConstantUnion *mUnionArrayPointer;
+    // Same data may be shared between multiple constant unions, so it can't be modified.
+    const TConstantUnion *mUnionArrayPointer;
 
   private:
     typedef float(*FloatTypeUnaryFunc) (float);
     bool foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const;
 
     TIntermConstantUnion(const TIntermConstantUnion &node);  // Note: not deleted, just private!
 };
 
@@ -511,16 +519,17 @@ class TIntermAggregate : public TIntermO
     bool isUserDefined() const { return mUserDefined; }
 
     void setFunctionId(int functionId) { mFunctionId = functionId; }
     int getFunctionId() const { return mFunctionId; }
 
     void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
     bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
 
+    bool areChildrenConstQualified();
     void setPrecisionFromChildren();
     void setBuiltInFunctionPrecision();
 
     // Returns true if changing parameter precision may affect the return value.
     bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; }
 
   protected:
     TIntermSequence mSequence;
--- a/gfx/angle/src/compiler/translator/Intermediate.cpp
+++ b/gfx/angle/src/compiler/translator/Intermediate.cpp
@@ -255,17 +255,17 @@ TIntermAggregate *TIntermediate::ensureS
 TIntermNode *TIntermediate::addSelection(
     TIntermTyped *cond, TIntermNodePair nodePair, const TSourceLoc &line)
 {
     //
     // For compile time constant selections, prune the code and
     // test now.
     //
 
-    if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion())
+    if (cond->getAsConstantUnion())
     {
         if (cond->getAsConstantUnion()->getBConst(0) == true)
         {
             return nodePair.node1 ? setAggregateOperator(
                 nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
         }
         else
         {
@@ -276,65 +276,81 @@ TIntermNode *TIntermediate::addSelection
 
     TIntermSelection *node = new TIntermSelection(
         cond, ensureSequence(nodePair.node1), ensureSequence(nodePair.node2));
     node->setLine(line);
 
     return node;
 }
 
-TIntermTyped *TIntermediate::addComma(
-    TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
+TIntermTyped *TIntermediate::addComma(TIntermTyped *left,
+                                      TIntermTyped *right,
+                                      const TSourceLoc &line,
+                                      int shaderVersion)
 {
-    if (left->getType().getQualifier() == EvqConst &&
-        right->getType().getQualifier() == EvqConst)
+    TQualifier resultQualifier = EvqConst;
+    // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
+    if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
+        right->getQualifier() != EvqConst)
     {
-        return right;
+        resultQualifier = EvqTemporary;
+    }
+
+    TIntermTyped *commaNode = nullptr;
+    if (!left->hasSideEffects())
+    {
+        commaNode = right;
     }
     else
     {
-        TIntermTyped *commaAggregate = growAggregate(left, right, line);
-        commaAggregate->getAsAggregate()->setOp(EOpComma);
-        commaAggregate->setType(right->getType());
-        commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
-        return commaAggregate;
+        commaNode = growAggregate(left, right, line);
+        commaNode->getAsAggregate()->setOp(EOpComma);
+        commaNode->setType(right->getType());
     }
+    commaNode->getTypePointer()->setQualifier(resultQualifier);
+    return commaNode;
 }
 
 //
 // For "?:" test nodes.  There are three children; a condition,
 // a true path, and a false path.  The two paths are specified
 // as separate parameters.
 //
 // Returns the selection node created, or one of trueBlock and falseBlock if the expression could be folded.
 //
 TIntermTyped *TIntermediate::addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
                                           const TSourceLoc &line)
 {
-    // Right now it's safe to fold ternary operators only when all operands
-    // are constant. If only the condition is constant, it's theoretically
-    // possible to fold the ternary operator, but that requires making sure
-    // that the node returned from here won't be treated as a constant
-    // expression in case the node that gets eliminated was not a constant
-    // expression.
-    if (cond->getAsConstantUnion() &&
-        trueBlock->getAsConstantUnion() &&
-        falseBlock->getAsConstantUnion())
+    TQualifier resultQualifier = EvqTemporary;
+    if (cond->getQualifier() == EvqConst && trueBlock->getQualifier() == EvqConst &&
+        falseBlock->getQualifier() == EvqConst)
+    {
+        resultQualifier = EvqConst;
+    }
+    // Note that the node resulting from here can be a constant union without being qualified as
+    // constant.
+    if (cond->getAsConstantUnion())
     {
         if (cond->getAsConstantUnion()->getBConst(0))
+        {
+            trueBlock->getTypePointer()->setQualifier(resultQualifier);
             return trueBlock;
+        }
         else
+        {
+            falseBlock->getTypePointer()->setQualifier(resultQualifier);
             return falseBlock;
+        }
     }
 
     //
     // Make a selection node.
     //
     TIntermSelection *node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
-    node->getTypePointer()->setQualifier(EvqTemporary);
+    node->getTypePointer()->setQualifier(resultQualifier);
     node->setLine(line);
 
     return node;
 }
 
 TIntermSwitch *TIntermediate::addSwitch(
     TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line)
 {
@@ -354,18 +370,19 @@ TIntermCase *TIntermediate::addCase(
 }
 
 //
 // Constant terminal nodes.  Has a union that contains bool, float or int constants
 //
 // Returns the constant union node created.
 //
 
-TIntermConstantUnion *TIntermediate::addConstantUnion(
-    TConstantUnion *constantUnion, const TType &type, const TSourceLoc &line)
+TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *constantUnion,
+                                                      const TType &type,
+                                                      const TSourceLoc &line)
 {
     TIntermConstantUnion *node = new TIntermConstantUnion(constantUnion, type);
     node->setLine(line);
 
     return node;
 }
 
 TIntermTyped *TIntermediate::addSwizzle(
@@ -448,39 +465,44 @@ TIntermAggregate *TIntermediate::postPro
 
     return aggRoot;
 }
 
 TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
 {
     switch (aggregate->getOp())
     {
-      case EOpAtan:
-      case EOpPow:
-      case EOpMod:
-      case EOpMin:
-      case EOpMax:
-      case EOpClamp:
-      case EOpMix:
-      case EOpStep:
-      case EOpSmoothStep:
-      case EOpMul:
-      case EOpOuterProduct:
-      case EOpLessThan:
-      case EOpLessThanEqual:
-      case EOpGreaterThan:
-      case EOpGreaterThanEqual:
-      case EOpVectorEqual:
-      case EOpVectorNotEqual:
-      case EOpDistance:
-      case EOpDot:
-      case EOpCross:
-      case EOpFaceForward:
-      case EOpReflect:
-      case EOpRefract:
-        return aggregate->fold(mInfoSink);
-      default:
-        // Constant folding not supported for the built-in.
-        return nullptr;
+        case EOpAtan:
+        case EOpPow:
+        case EOpMod:
+        case EOpMin:
+        case EOpMax:
+        case EOpClamp:
+        case EOpMix:
+        case EOpStep:
+        case EOpSmoothStep:
+        case EOpMul:
+        case EOpOuterProduct:
+        case EOpLessThan:
+        case EOpLessThanEqual:
+        case EOpGreaterThan:
+        case EOpGreaterThanEqual:
+        case EOpVectorEqual:
+        case EOpVectorNotEqual:
+        case EOpDistance:
+        case EOpDot:
+        case EOpCross:
+        case EOpFaceForward:
+        case EOpReflect:
+        case EOpRefract:
+            return aggregate->fold(mInfoSink);
+        default:
+            // TODO: Add support for folding array constructors
+            if (aggregate->isConstructor() && !aggregate->isArray())
+            {
+                return aggregate->fold(mInfoSink);
+            }
+            // Constant folding not supported for the built-in.
+            return nullptr;
     }
 
     return nullptr;
 }
--- a/gfx/angle/src/compiler/translator/Intermediate.h
+++ b/gfx/angle/src/compiler/translator/Intermediate.h
@@ -43,23 +43,23 @@ class TIntermediate
     TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &);
     TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &);
     TIntermTyped *addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
                                const TSourceLoc &line);
     TIntermSwitch *addSwitch(
         TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line);
     TIntermCase *addCase(
         TIntermTyped *condition, const TSourceLoc &line);
-    TIntermTyped *addComma(
-        TIntermTyped *left, TIntermTyped *right, const TSourceLoc &);
-    TIntermConstantUnion *addConstantUnion(
-        TConstantUnion *constantUnion, const TType &type, const TSourceLoc &line);
-    // TODO(zmo): Get rid of default value.
-    bool parseConstTree(const TSourceLoc &, TIntermNode *, TConstantUnion *,
-                        TOperator, TType, bool singleConstantParam = false);
+    TIntermTyped *addComma(TIntermTyped *left,
+                           TIntermTyped *right,
+                           const TSourceLoc &line,
+                           int shaderVersion);
+    TIntermConstantUnion *addConstantUnion(const TConstantUnion *constantUnion,
+                                           const TType &type,
+                                           const TSourceLoc &line);
     TIntermNode *addLoop(TLoopType, TIntermNode *, TIntermTyped *, TIntermTyped *,
                          TIntermNode *, const TSourceLoc &);
     TIntermBranch *addBranch(TOperator, const TSourceLoc &);
     TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
     TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &);
     TIntermAggregate *postProcess(TIntermNode *root);
 
     static void outputTree(TIntermNode *, TInfoSinkBase &);
--- a/gfx/angle/src/compiler/translator/OutputGLSLBase.cpp
+++ b/gfx/angle/src/compiler/translator/OutputGLSLBase.cpp
@@ -84,16 +84,29 @@ void TOutputGLSLBase::writeTriplet(
 void TOutputGLSLBase::writeBuiltInFunctionTriplet(
     Visit visit, const char *preStr, bool useEmulatedFunction)
 {
     TString preString = useEmulatedFunction ?
         BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
     writeTriplet(visit, preString.c_str(), ", ", ")");
 }
 
+void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
+{
+    if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
+    {
+        const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
+        if (layoutQualifier.location >= 0)
+        {
+            TInfoSinkBase &out = objSink();
+            out << "layout(location = " << layoutQualifier.location << ") ";
+        }
+    }
+}
+
 void TOutputGLSLBase::writeVariableType(const TType &type)
 {
     TInfoSinkBase &out = objSink();
     if (type.isInvariant())
     {
         out << "invariant ";
     }
     if (type.getBasicType() == EbtInterfaceBlock)
@@ -871,16 +884,17 @@ bool TOutputGLSLBase::visitAggregate(Vis
         visitChildren = false;
         break;
       case EOpDeclaration:
         // Variable declaration.
         if (visit == PreVisit)
         {
             const TIntermSequence &sequence = *(node->getSequence());
             const TIntermTyped *variable = sequence.front()->getAsTyped();
+            writeLayoutQualifier(variable->getType());
             writeVariableType(variable->getType());
             out << " ";
             mDeclaringVariables = true;
         }
         else if (visit == InVisit)
         {
             out << ", ";
             mDeclaringVariables = true;
--- a/gfx/angle/src/compiler/translator/OutputGLSLBase.h
+++ b/gfx/angle/src/compiler/translator/OutputGLSLBase.h
@@ -27,16 +27,17 @@ class TOutputGLSLBase : public TIntermTr
     ShShaderOutput getShaderOutput() const
     {
         return mOutput;
     }
 
   protected:
     TInfoSinkBase &objSink() { return mObjSink; }
     void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr);
+    void writeLayoutQualifier(const TType &type);
     void writeVariableType(const TType &type);
     virtual bool writeVariablePrecision(TPrecision precision) = 0;
     void writeFunctionParameters(const TIntermSequence &args);
     const TConstantUnion *writeConstantUnion(const TType &type, const TConstantUnion *pConstUnion);
     void writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType);
     TString getTypeName(const TType &type);
 
     void visitSymbol(TIntermSymbol *node) override;
--- a/gfx/angle/src/compiler/translator/OutputHLSL.cpp
+++ b/gfx/angle/src/compiler/translator/OutputHLSL.cpp
@@ -30,16 +30,55 @@
 namespace
 {
 
 bool IsSequence(TIntermNode *node)
 {
     return node->getAsAggregate() != nullptr && node->getAsAggregate()->getOp() == EOpSequence;
 }
 
+void WriteSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
+{
+    ASSERT(constUnion != nullptr);
+    switch (constUnion->getType())
+    {
+        case EbtFloat:
+            out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst()));
+            break;
+        case EbtInt:
+            out << constUnion->getIConst();
+            break;
+        case EbtUInt:
+            out << constUnion->getUConst();
+            break;
+        case EbtBool:
+            out << constUnion->getBConst();
+            break;
+        default:
+            UNREACHABLE();
+    }
+}
+
+const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out,
+                                              const TConstantUnion *const constUnion,
+                                              const size_t size)
+{
+    const TConstantUnion *constUnionIterated = constUnion;
+    for (size_t i = 0; i < size; i++, constUnionIterated++)
+    {
+        WriteSingleConstant(out, constUnionIterated);
+
+        if (i != size - 1)
+        {
+            out << ", ";
+        }
+    }
+    return constUnionIterated;
+}
+
 } // namespace
 
 namespace sh
 {
 
 TString OutputHLSL::TextureFunction::name() const
 {
     TString name = "gl_texture";
@@ -880,34 +919,34 @@ void OutputHLSL::header(const BuiltInFun
                             out << "    uint mip = 0;\n";
                         }
                         else if (textureFunction->method == TextureFunction::LOD0BIAS)
                         {
                             out << "    uint mip = bias;\n";
                         }
                         else
                         {
+
+                            out << "    x.GetDimensions(0, width, height, layers, levels);\n";
                             if (textureFunction->method == TextureFunction::IMPLICIT ||
                                 textureFunction->method == TextureFunction::BIAS)
                             {
-                                out << "    x.GetDimensions(0, width, height, layers, levels);\n"
-                                       "    float2 tSized = float2(t.x * width, t.y * height);\n"
+                                out << "    float2 tSized = float2(t.x * width, t.y * height);\n"
                                        "    float dx = length(ddx(tSized));\n"
                                        "    float dy = length(ddy(tSized));\n"
                                        "    float lod = log2(max(dx, dy));\n";
 
                                 if (textureFunction->method == TextureFunction::BIAS)
                                 {
                                     out << "    lod += bias;\n";
                                 }
                             }
                             else if (textureFunction->method == TextureFunction::GRAD)
                             {
-                                out << "    x.GetDimensions(0, width, height, layers, levels);\n"
-                                       "    float lod = log2(max(length(ddx), length(ddy)));\n";
+                                out << "    float lod = log2(max(length(ddx), length(ddy)));\n";
                             }
 
                             out << "    uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
                         }
 
                         out << "    x.GetDimensions(mip, width, height, layers, levels);\n";
                     }
                     else
@@ -919,38 +958,34 @@ void OutputHLSL::header(const BuiltInFun
                             out << "    uint mip = 0;\n";
                         }
                         else if (textureFunction->method == TextureFunction::LOD0BIAS)
                         {
                             out << "    uint mip = bias;\n";
                         }
                         else
                         {
+                            out << "    x.GetDimensions(0, width, height, levels);\n";
+
                             if (textureFunction->method == TextureFunction::IMPLICIT ||
                                 textureFunction->method == TextureFunction::BIAS)
                             {
-                                out << "    x.GetDimensions(0, width, height, levels);\n"
-                                       "    float2 tSized = float2(t.x * width, t.y * height);\n"
+                                out << "    float2 tSized = float2(t.x * width, t.y * height);\n"
                                        "    float dx = length(ddx(tSized));\n"
                                        "    float dy = length(ddy(tSized));\n"
                                        "    float lod = log2(max(dx, dy));\n";
 
                                 if (textureFunction->method == TextureFunction::BIAS)
                                 {
                                     out << "    lod += bias;\n";
                                 }
                             }
-                            else if (textureFunction->method == TextureFunction::LOD)
-                            {
-                                out << "    x.GetDimensions(0, width, height, levels);\n";
-                            }
                             else if (textureFunction->method == TextureFunction::GRAD)
                             {
-                                out << "    x.GetDimensions(0, width, height, levels);\n"
-                                       "    float lod = log2(max(length(ddx), length(ddy)));\n";
+                                out << "    float lod = log2(max(length(ddx), length(ddy)));\n";
                             }
 
                             out << "    uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
                         }
 
                         out << "    x.GetDimensions(mip, width, height, levels);\n";
                     }
                 }
@@ -963,34 +998,35 @@ void OutputHLSL::header(const BuiltInFun
                         out << "    uint mip = 0;\n";
                     }
                     else if (textureFunction->method == TextureFunction::LOD0BIAS)
                     {
                         out << "    uint mip = bias;\n";
                     }
                     else
                     {
+                        out << "    x.GetDimensions(0, width, height, depth, levels);\n";
+
                         if (textureFunction->method == TextureFunction::IMPLICIT ||
                             textureFunction->method == TextureFunction::BIAS)
                         {
-                            out << "    x.GetDimensions(0, width, height, depth, levels);\n"
-                                   "    float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
+                            out << "    float3 tSized = float3(t.x * width, t.y * height, t.z * "
+                                   "depth);\n"
                                    "    float dx = length(ddx(tSized));\n"
                                    "    float dy = length(ddy(tSized));\n"
                                    "    float lod = log2(max(dx, dy));\n";
 
                             if (textureFunction->method == TextureFunction::BIAS)
                             {
                                 out << "    lod += bias;\n";
                             }
                         }
                         else if (textureFunction->method == TextureFunction::GRAD)
                         {
-                            out << "    x.GetDimensions(0, width, height, depth, levels);\n"
-                                   "    float lod = log2(max(length(ddx), length(ddy)));\n";
+                            out << "    float lod = log2(max(length(ddx), length(ddy)));\n";
                         }
 
                         out << "    uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
                     }
 
                     out << "    x.GetDimensions(mip, width, height, depth, levels);\n";
                 }
                 else UNREACHABLE();
@@ -1509,16 +1545,20 @@ bool OutputHLSL::visitBinary(Visit visit
                 const TString &initString = initializer(node->getType());
                 node->setRight(new TIntermRaw(node->getType(), initString));
             }
             else if (writeSameSymbolInitializer(out, symbolNode, expression))
             {
                 // Skip initializing the rest of the expression
                 return false;
             }
+            else if (writeConstantInitialization(out, symbolNode, expression))
+            {
+                return false;
+            }
         }
         else if (visit == InVisit)
         {
             out << " = ";
         }
         break;
       case EOpAddAssign:               outputTriplet(visit, "(", " += ", ")");          break;
       case EOpSubAssign:               outputTriplet(visit, "(", " -= ", ")");          break;
@@ -1864,17 +1904,19 @@ bool OutputHLSL::visitAggregate(Visit vi
         }
       case EOpDeclaration:
         if (visit == PreVisit)
         {
             TIntermSequence *sequence = node->getSequence();
             TIntermTyped *variable = (*sequence)[0]->getAsTyped();
             ASSERT(sequence->size() == 1);
 
-            if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
+            if (variable &&
+                (variable->getQualifier() == EvqTemporary ||
+                 variable->getQualifier() == EvqGlobal || variable->getQualifier() == EvqConst))
             {
                 ensureStructDefined(variable->getType());
 
                 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "")   // Variable declaration
                 {
                     if (!mInsideFunction)
                     {
                         out << "static ";
@@ -2906,31 +2948,34 @@ void OutputHLSL::outputConstructor(Visit
         out << ", ";
     }
     else if (visit == PostVisit)
     {
         out << ")";
     }
 }
 
-const TConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const TConstantUnion *constUnion)
+const TConstantUnion *OutputHLSL::writeConstantUnion(const TType &type,
+                                                     const TConstantUnion *const constUnion)
 {
     TInfoSinkBase &out = getInfoSink();
 
+    const TConstantUnion *constUnionIterated = constUnion;
+
     const TStructure* structure = type.getStruct();
     if (structure)
     {
         out << StructNameString(*structure) + "_ctor(";
 
         const TFieldList& fields = structure->fields();
 
         for (size_t i = 0; i < fields.size(); i++)
         {
             const TType *fieldType = fields[i]->type();
-            constUnion = writeConstantUnion(*fieldType, constUnion);
+            constUnionIterated     = writeConstantUnion(*fieldType, constUnionIterated);
 
             if (i != fields.size() - 1)
             {
                 out << ", ";
             }
         }
 
         out << ")";
@@ -2939,41 +2984,24 @@ const TConstantUnion *OutputHLSL::writeC
     {
         size_t size = type.getObjectSize();
         bool writeType = size > 1;
 
         if (writeType)
         {
             out << TypeString(type) << "(";
         }
-
-        for (size_t i = 0; i < size; i++, constUnion++)
-        {
-            switch (constUnion->getType())
-            {
-              case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break;
-              case EbtInt:   out << constUnion->getIConst(); break;
-              case EbtUInt:  out << constUnion->getUConst(); break;
-              case EbtBool:  out << constUnion->getBConst(); break;
-              default: UNREACHABLE();
-            }
-
-            if (i != size - 1)
-            {
-                out << ", ";
-            }
-        }
-
+        constUnionIterated = WriteConstantUnionArray(out, constUnionIterated, size);
         if (writeType)
         {
             out << ")";
         }
     }
 
-    return constUnion;
+    return constUnionIterated;
 }
 
 void OutputHLSL::writeEmulatedFunctionTriplet(Visit visit, const char *preStr)
 {
     TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
     outputTriplet(visit, preString.c_str(), ", ", ")");
 }
 
@@ -2993,16 +3021,78 @@ bool OutputHLSL::writeSameSymbolInitiali
 
         mUniqueIndex++;
         return true;
     }
 
     return false;
 }
 
+bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
+{
+    // We support writing constant unions and constructors that only take constant unions as
+    // parameters as HLSL literals.
+    if (expression->getAsConstantUnion())
+    {
+        return true;
+    }
+    if (expression->getQualifier() != EvqConst || !expression->getAsAggregate() ||
+        !expression->getAsAggregate()->isConstructor())
+    {
+        return false;
+    }
+    TIntermAggregate *constructor = expression->getAsAggregate();
+    for (TIntermNode *&node : *constructor->getSequence())
+    {
+        if (!node->getAsConstantUnion())
+            return false;
+    }
+    return true;
+}
+
+bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
+                                             TIntermSymbol *symbolNode,
+                                             TIntermTyped *expression)
+{
+    if (canWriteAsHLSLLiteral(expression))
+    {
+        symbolNode->traverse(this);
+        if (expression->getType().isArray())
+        {
+            out << "[" << expression->getType().getArraySize() << "]";
+        }
+        out << " = {";
+        if (expression->getAsConstantUnion())
+        {
+            TIntermConstantUnion *nodeConst  = expression->getAsConstantUnion();
+            const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
+            WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
+        }
+        else
+        {
+            TIntermAggregate *constructor = expression->getAsAggregate();
+            ASSERT(constructor != nullptr);
+            for (TIntermNode *&node : *constructor->getSequence())
+            {
+                TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
+                ASSERT(nodeConst);
+                const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
+                WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
+                if (node != constructor->getSequence()->back())
+                {
+                    out << ", ";
+                }
+            }
+        }
+        out << "}";
+        return true;
+    }
+    return false;
+}
+
 void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out)
 {
     out << "#define ANGLE_USES_DEFERRED_INIT\n"
         << "\n"
         << "void initializeDeferredGlobals()\n"
         << "{\n";
 
     for (const auto &deferredGlobal : mDeferredGlobalInitializers)
--- a/gfx/angle/src/compiler/translator/OutputHLSL.h
+++ b/gfx/angle/src/compiler/translator/OutputHLSL.h
@@ -42,16 +42,18 @@ class OutputHLSL : public TIntermTravers
 
     const std::map<std::string, unsigned int> &getInterfaceBlockRegisterMap() const;
     const std::map<std::string, unsigned int> &getUniformRegisterMap() const;
 
     static TString initializer(const TType &type);
 
     TInfoSinkBase &getInfoSink() { ASSERT(!mInfoSinkStack.empty()); return *mInfoSinkStack.top(); }
 
+    static bool canWriteAsHLSLLiteral(TIntermTyped *expression);
+
   protected:
     void header(const BuiltInFunctionEmulator *builtInFunctionEmulator);
 
     // Visit AST nodes and output their code to the body stream
     void visitSymbol(TIntermSymbol*);
     void visitRaw(TIntermRaw*);
     void visitConstantUnion(TIntermConstantUnion*);
     bool visitBinary(Visit visit, TIntermBinary*);
@@ -79,16 +81,21 @@ class OutputHLSL : public TIntermTravers
 
     void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out);
 
     void writeEmulatedFunctionTriplet(Visit visit, const char *preStr);
     void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
 
     // Returns true if it found a 'same symbol' initializer (initializer that references the variable it's initting)
     bool writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression);
+    // Returns true if variable initializer could be written using literal {} notation.
+    bool writeConstantInitialization(TInfoSinkBase &out,
+                                     TIntermSymbol *symbolNode,
+                                     TIntermTyped *expression);
+
     void writeDeferredGlobalInitializers(TInfoSinkBase &out);
     void writeSelection(TIntermSelection *node);
 
     // Returns the function name
     TString addStructEqualityFunction(const TStructure &structure);
     TString addArrayEqualityFunction(const TType &type);
     TString addArrayAssignmentFunction(const TType &type);
     TString addArrayConstructIntoFunction(const TType &type);
--- a/gfx/angle/src/compiler/translator/ParseContext.cpp
+++ b/gfx/angle/src/compiler/translator/ParseContext.cpp
@@ -159,16 +159,33 @@ void TParseContext::warning(const TSourc
                             const char *extraInfo)
 {
     pp::SourceLocation srcLoc;
     srcLoc.file = loc.first_file;
     srcLoc.line = loc.first_line;
     mDiagnostics.writeInfo(pp::Diagnostics::PP_WARNING, srcLoc, reason, token, extraInfo);
 }
 
+void TParseContext::outOfRangeError(bool isError,
+                                    const TSourceLoc &loc,
+                                    const char *reason,
+                                    const char *token,
+                                    const char *extraInfo)
+{
+    if (isError)
+    {
+        error(loc, reason, token, extraInfo);
+        recover();
+    }
+    else
+    {
+        warning(loc, reason, token, extraInfo);
+    }
+}
+
 //
 // Same error message for all places assignments don't work.
 //
 void TParseContext::assignError(const TSourceLoc &line, const char *op, TString left, TString right)
 {
     std::stringstream extraInfoStream;
     extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
     std::string extraInfo = extraInfoStream.str();
@@ -471,17 +488,17 @@ bool TParseContext::reservedErrorCheck(c
 //
 // Make sure there is enough data provided to the constructor to build
 // something of the type of the constructor.  Also returns the type of
 // the constructor.
 //
 // Returns true if there was an error in construction.
 //
 bool TParseContext::constructorErrorCheck(const TSourceLoc &line,
-                                          TIntermNode *node,
+                                          TIntermNode *argumentsNode,
                                           TFunction &function,
                                           TOperator op,
                                           TType *type)
 {
     *type = function.getReturnType();
 
     bool constructingMatrix = false;
     switch (op)
@@ -582,31 +599,37 @@ bool TParseContext::constructorErrorChec
         if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
             (op == EOpConstructStruct && size < type->getObjectSize()))
         {
             error(line, "not enough data provided for construction", "constructor");
             return true;
         }
     }
 
-    TIntermTyped *typed = node ? node->getAsTyped() : 0;
-    if (typed == 0)
+    if (argumentsNode == nullptr)
     {
-        error(line, "constructor argument does not have a type", "constructor");
+        error(line, "constructor does not have any arguments", "constructor");
         return true;
     }
-    if (op != EOpConstructStruct && IsSampler(typed->getBasicType()))
+
+    TIntermAggregate *argumentsAgg = argumentsNode->getAsAggregate();
+    for (TIntermNode *&argNode : *argumentsAgg->getSequence())
     {
-        error(line, "cannot convert a sampler", "constructor");
-        return true;
-    }
-    if (typed->getBasicType() == EbtVoid)
-    {
-        error(line, "cannot convert a void", "constructor");
-        return true;
+        TIntermTyped *argTyped = argNode->getAsTyped();
+        ASSERT(argTyped != nullptr);
+        if (op != EOpConstructStruct && IsSampler(argTyped->getBasicType()))
+        {
+            error(line, "cannot convert a sampler", "constructor");
+            return true;
+        }
+        if (argTyped->getBasicType() == EbtVoid)
+        {
+            error(line, "cannot convert a void", "constructor");
+            return true;
+        }
     }
 
     return false;
 }
 
 // This function checks to see if a void variable has been declared and raise an error message for
 // such a case
 //
@@ -730,17 +753,20 @@ bool TParseContext::containsSampler(cons
 // Do size checking for an array type's size.
 //
 // Returns true if there was an error.
 //
 bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *expr, int &size)
 {
     TIntermConstantUnion *constant = expr->getAsConstantUnion();
 
-    if (constant == nullptr || !constant->isScalarInt())
+    // TODO(oetuaho@nvidia.com): Get rid of the constant == nullptr check here once all constant
+    // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
+    // fold as array size.
+    if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt())
     {
         error(line, "array size must be a constant integer expression", "");
         size = 1;
         return true;
     }
 
     unsigned int unsignedSize = 0;
 
@@ -1177,16 +1203,34 @@ const TVariable *TParseContext::getNamed
         TVariable *fakeVariable = new TVariable(name, type);
         symbolTable.declare(fakeVariable);
         variable = fakeVariable;
     }
 
     return variable;
 }
 
+TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
+                                                     const TString *name,
+                                                     const TSymbol *symbol)
+{
+    const TVariable *variable = getNamedVariable(location, name, symbol);
+
+    if (variable->getConstPointer())
+    {
+        const TConstantUnion *constArray = variable->getConstPointer();
+        return intermediate.addConstantUnion(constArray, variable->getType(), location);
+    }
+    else
+    {
+        return intermediate.addSymbol(variable->getUniqueId(), variable->getName(),
+                                      variable->getType(), location);
+    }
+}
+
 //
 // Look up a function name in the symbol table, and make sure it is a function.
 //
 // Return the function symbol if found, otherwise 0.
 //
 const TFunction *TParseContext::findFunction(const TSourceLoc &line,
                                              TFunction *call,
                                              int inputShaderVersion,
@@ -1286,80 +1330,56 @@ bool TParseContext::executeInitializer(c
         }
         if (type != initializer->getType())
         {
             error(line, " non-matching types for const initializer ",
                   variable->getType().getQualifierString());
             variable->getType().setQualifier(EvqTemporary);
             return true;
         }
+
+        // Save the constant folded value to the variable if possible. For example array
+        // initializers are not folded, since that way copying the array literal to multiple places
+        // in the shader is avoided.
+        // TODO(oetuaho@nvidia.com): Consider constant folding array initialization in cases where
+        // it would be beneficial.
         if (initializer->getAsConstantUnion())
         {
             variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
+            *intermNode = nullptr;
+            return false;
         }
         else if (initializer->getAsSymbolNode())
         {
             const TSymbol *symbol =
                 symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
             const TVariable *tVar = static_cast<const TVariable *>(symbol);
 
-            TConstantUnion *constArray = tVar->getConstPointer();
-            variable->shareConstPointer(constArray);
-        }
-        else
-        {
-            std::stringstream extraInfoStream;
-            extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
-            std::string extraInfo = extraInfoStream.str();
-            error(line, " cannot assign to", "=", extraInfo.c_str());
-            variable->getType().setQualifier(EvqTemporary);
-            return true;
+            const TConstantUnion *constArray = tVar->getConstPointer();
+            if (constArray)
+            {
+                variable->shareConstPointer(constArray);
+                *intermNode = nullptr;
+                return false;
+            }
         }
     }
 
-    if (qualifier != EvqConst)
+    TIntermSymbol *intermSymbol = intermediate.addSymbol(
+        variable->getUniqueId(), variable->getName(), variable->getType(), line);
+    *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
+    if (*intermNode == nullptr)
     {
-        TIntermSymbol *intermSymbol = intermediate.addSymbol(
-            variable->getUniqueId(), variable->getName(), variable->getType(), line);
-        *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
-        if (*intermNode == nullptr)
-        {
-            assignError(line, "=", intermSymbol->getCompleteString(),
-                        initializer->getCompleteString());
-            return true;
-        }
-    }
-    else
-    {
-        *intermNode = nullptr;
+        assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+        return true;
     }
 
     return false;
 }
 
-bool TParseContext::areAllChildConst(TIntermAggregate *aggrNode)
-{
-    ASSERT(aggrNode != NULL);
-    if (!aggrNode->isConstructor())
-        return false;
-
-    bool allConstant = true;
-
-    // check if all the child nodes are constants so that they can be inserted into
-    // the parent node
-    TIntermSequence *sequence = aggrNode->getSequence();
-    for (TIntermSequence::iterator p = sequence->begin(); p != sequence->end(); ++p)
-    {
-        if (!(*p)->getAsTyped()->getAsConstantUnion())
-            return false;
-    }
-
-    return allConstant;
-}
-
 TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier,
                                                  bool invariant,
                                                  TLayoutQualifier layoutQualifier,
                                                  const TPublicType &typeSpecifier)
 {
     TPublicType returnType     = typeSpecifier;
     returnType.qualifier       = qualifier;
     returnType.invariant       = invariant;
@@ -2068,16 +2088,23 @@ TFunction *TParseContext::parseFunctionD
     // being redeclared.  So, pass back up this declaration, not the one in the symbol table.
     //
     return function;
 }
 
 TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
 {
     TPublicType publicType = publicTypeIn;
+    if (publicType.isStructSpecifier)
+    {
+        error(publicType.line, "constructor can't be a structure definition",
+              getBasicString(publicType.type));
+        recover();
+    }
+
     TOperator op = EOpNull;
     if (publicType.userDef)
     {
         op = EOpConstructStruct;
     }
     else
     {
         switch (publicType.type)
@@ -2229,249 +2256,167 @@ TFunction *TParseContext::addConstructor
 // Returns 0 for an error or the constructed node (aggregate or typed) for no error.
 //
 TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
                                             TType *type,
                                             TOperator op,
                                             TFunction *fnCall,
                                             const TSourceLoc &line)
 {
-    TIntermAggregate *aggregateArguments = arguments->getAsAggregate();
-
-    if (!aggregateArguments)
-    {
-        aggregateArguments = new TIntermAggregate;
-        aggregateArguments->getSequence()->push_back(arguments);
-    }
+    TIntermAggregate *constructor = arguments->getAsAggregate();
+    ASSERT(constructor != nullptr);
 
     if (type->isArray())
     {
         // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
         // the array.
-        TIntermSequence *args = aggregateArguments->getSequence();
+        TIntermSequence *args = constructor->getSequence();
         for (size_t i = 0; i < args->size(); i++)
         {
             const TType &argType = (*args)[i]->getAsTyped()->getType();
             // It has already been checked that the argument is not an array.
             ASSERT(!argType.isArray());
             if (!argType.sameElementType(*type))
             {
                 error(line, "Array constructor argument has an incorrect type", "Error");
                 recover();
                 return nullptr;
             }
         }
     }
     else if (op == EOpConstructStruct)
     {
         const TFieldList &fields = type->getStruct()->fields();
-        TIntermSequence *args    = aggregateArguments->getSequence();
+        TIntermSequence *args    = constructor->getSequence();
 
         for (size_t i = 0; i < fields.size(); i++)
         {
             if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
             {
                 error(line, "Structure constructor arguments do not match structure fields",
                       "Error");
                 recover();
 
                 return 0;
             }
         }
     }
 
     // Turn the argument list itself into a constructor
-    TIntermAggregate *constructor  = intermediate.setAggregateOperator(aggregateArguments, op, line);
-    TIntermTyped *constConstructor = foldConstConstructor(constructor, *type);
-    if (constConstructor)
-    {
-        return constConstructor;
-    }
+    constructor->setOp(op);
+    constructor->setLine(line);
+    ASSERT(constructor->isConstructor());
+
+    // Need to set type before setPrecisionFromChildren() because bool doesn't have precision.
+    constructor->setType(*type);
 
     // Structs should not be precision qualified, the individual members may be.
     // Built-in types on the other hand should be precision qualified.
     if (op != EOpConstructStruct)
     {
         constructor->setPrecisionFromChildren();
         type->setPrecision(constructor->getPrecision());
     }
 
-    return constructor;
-}
-
-TIntermTyped *TParseContext::foldConstConstructor(TIntermAggregate *aggrNode, const TType &type)
-{
-    // TODO: Add support for folding array constructors
-    bool canBeFolded = areAllChildConst(aggrNode) && !type.isArray();
-    aggrNode->setType(type);
-    if (canBeFolded)
+    TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor);
+    if (constConstructor)
     {
-        bool returnVal             = false;
-        TConstantUnion *unionArray = new TConstantUnion[type.getObjectSize()];
-        if (aggrNode->getSequence()->size() == 1)
-        {
-            returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray,
-                                                    aggrNode->getOp(), type, true);
-        }
-        else
-        {
-            returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray,
-                                                    aggrNode->getOp(), type);
-        }
-        if (returnVal)
-            return 0;
-
-        return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
+        return constConstructor;
     }
 
-    return 0;
+    return constructor;
 }
 
 //
 // This function returns the tree representation for the vector field(s) being accessed from contant
 // vector.
 // If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a
 // contant node is returned, else an aggregate node is returned (for v.xy). The input to this
-// function could either
-// be the symbol node or it could be the intermediate tree representation of accessing fields in a
-// constant
-// structure or column of a constant matrix.
+// function could either be the symbol node or it could be the intermediate tree representation of
+// accessing fields in a constant structure or column of a constant matrix.
 //
 TIntermTyped *TParseContext::addConstVectorNode(TVectorFields &fields,
-                                                TIntermTyped *node,
-                                                const TSourceLoc &line)
+                                                TIntermConstantUnion *node,
+                                                const TSourceLoc &line,
+                                                bool outOfRangeIndexIsError)
 {
-    TIntermTyped *typedNode;
-    TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
-
-    const TConstantUnion *unionArray;
-    if (tempConstantNode)
-    {
-        unionArray = tempConstantNode->getUnionArrayPointer();
-
-        if (!unionArray)
-        {
-            return node;
-        }
-    }
-    else
-    {  // The node has to be either a symbol node or an aggregate node or a tempConstant node, else,
-        // its an error
-        error(line, "Cannot offset into the vector", "Error");
-        recover();
-
-        return 0;
-    }
+    const TConstantUnion *unionArray = node->getUnionArrayPointer();
+    ASSERT(unionArray);
 
     TConstantUnion *constArray = new TConstantUnion[fields.num];
 
     for (int i = 0; i < fields.num; i++)
     {
         if (fields.offsets[i] >= node->getType().getNominalSize())
         {
             std::stringstream extraInfoStream;
             extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
             std::string extraInfo = extraInfoStream.str();
-            error(line, "", "[", extraInfo.c_str());
-            recover();
-            fields.offsets[i] = 0;
+            outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str());
+            fields.offsets[i] = node->getType().getNominalSize() - 1;
         }
 
         constArray[i] = unionArray[fields.offsets[i]];
     }
-    typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
-    return typedNode;
+    return intermediate.addConstantUnion(constArray, node->getType(), line);
 }
 
 //
 // This function returns the column being accessed from a constant matrix. The values are retrieved
 // from the symbol table and parse-tree is built for a vector (each column of a matrix is a vector).
-// The
-// input to the function could either be a symbol node (m[0] where m is a constant matrix)that
-// represents
-// a constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s
-// is a constant structure)
+// The input to the function could either be a symbol node (m[0] where m is a constant matrix)that
+// represents a constant matrix or it could be the tree representation of the constant matrix
+// (s.m1[0] where s is a constant structure)
 //
 TIntermTyped *TParseContext::addConstMatrixNode(int index,
-                                                TIntermTyped *node,
-                                                const TSourceLoc &line)
+                                                TIntermConstantUnion *node,
+                                                const TSourceLoc &line,
+                                                bool outOfRangeIndexIsError)
 {
-    TIntermTyped *typedNode;
-    TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
-
     if (index >= node->getType().getCols())
     {
         std::stringstream extraInfoStream;
         extraInfoStream << "matrix field selection out of range '" << index << "'";
         std::string extraInfo = extraInfoStream.str();
-        error(line, "", "[", extraInfo.c_str());
-        recover();
-        index = 0;
+        outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str());
+        index = node->getType().getCols() - 1;
     }
 
-    if (tempConstantNode)
-    {
-        TConstantUnion *unionArray = tempConstantNode->getUnionArrayPointer();
-        int size                   = tempConstantNode->getType().getCols();
-        typedNode = intermediate.addConstantUnion(&unionArray[size * index],
-                                                  tempConstantNode->getType(), line);
-    }
-    else
-    {
-        error(line, "Cannot offset into the matrix", "Error");
-        recover();
-
-        return 0;
-    }
-
-    return typedNode;
+    const TConstantUnion *unionArray = node->getUnionArrayPointer();
+    int size = node->getType().getCols();
+    return intermediate.addConstantUnion(&unionArray[size * index], node->getType(), line);
 }
 
 //
 // This function returns an element of an array accessed from a constant array. The values are
 // retrieved from the symbol table and parse-tree is built for the type of the element. The input
 // to the function could either be a symbol node (a[0] where a is a constant array)that represents a
 // constant array or it could be the tree representation of the constant array (s.a1[0] where s is a
 // constant structure)
 //
 TIntermTyped *TParseContext::addConstArrayNode(int index,
-                                               TIntermTyped *node,
-                                               const TSourceLoc &line)
+                                               TIntermConstantUnion *node,
+                                               const TSourceLoc &line,
+                                               bool outOfRangeIndexIsError)
 {
-    TIntermTyped *typedNode;
-    TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
     TType arrayElementType = node->getType();
     arrayElementType.clearArrayness();
 
     if (index >= node->getType().getArraySize())
     {
         std::stringstream extraInfoStream;
         extraInfoStream << "array field selection out of range '" << index << "'";
         std::string extraInfo = extraInfoStream.str();
-        error(line, "", "[", extraInfo.c_str());
-        recover();
-        index = 0;
+        outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str());
+        index = node->getType().getArraySize() - 1;
     }
-
-    if (tempConstantNode)
-    {
-        size_t arrayElementSize    = arrayElementType.getObjectSize();
-        TConstantUnion *unionArray = tempConstantNode->getUnionArrayPointer();
-        typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index],
-                                                  tempConstantNode->getType(), line);
-    }
-    else
-    {
-        error(line, "Cannot offset into the array", "Error");
-        recover();
-
-        return 0;
-    }
-
-    return typedNode;
+    size_t arrayElementSize          = arrayElementType.getObjectSize();
+    const TConstantUnion *unionArray = node->getUnionArrayPointer();
+    return intermediate.addConstantUnion(&unionArray[arrayElementSize * index], node->getType(),
+                                         line);
 }
 
 //
 // This function returns the value of a particular field inside a constant structure from the symbol
 // table.
 // If there is an embedded/nested struct, it appropriately calls addConstStructNested or
 // addConstStructFromAggr function and returns the parse-tree with the values of the embedded/nested
 // struct.
@@ -2494,17 +2439,17 @@ TIntermTyped *TParseContext::addConstStr
             instanceSize += fields[index]->type()->getObjectSize();
         }
     }
 
     TIntermTyped *typedNode;
     TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
     if (tempConstantNode)
     {
-        TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer();
+        const TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer();
 
         // type will be changed in the calling function
         typedNode = intermediate.addConstantUnion(constArray + instanceSize,
                                                   tempConstantNode->getType(), line);
     }
     else
     {
         error(line, "Cannot offset into the structure", "Error");
@@ -2755,115 +2700,148 @@ TIntermTyped *TParseContext::addIndexExp
         {
             error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
         }
         recover();
     }
 
     TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
 
-    if (indexExpression->getQualifier() == EvqConst && indexConstantUnion)
-    {
-        int index = indexConstantUnion->getIConst(0);
-        if (index < 0)
-        {
-            std::stringstream infoStream;
-            infoStream << index;
-            std::string info = infoStream.str();
-            error(location, "negative index", info.c_str());
-            recover();
-            index = 0;
-        }
-        if (baseExpression->getType().getQualifier() == EvqConst)
-        {
-            if (baseExpression->isArray())
-            {
-                // constant folding for arrays
-                indexedExpression = addConstArrayNode(index, baseExpression, location);
-            }
-            else if (baseExpression->isVector())
-            {
-                // constant folding for vectors
-                TVectorFields fields;
-                fields.num = 1;
-                fields.offsets[0] =
-                    index;  // need to do it this way because v.xy sends fields integer array
-                indexedExpression = addConstVectorNode(fields, baseExpression, location);
-            }
-            else if (baseExpression->isMatrix())
-            {
-                // constant folding for matrices
-                indexedExpression = addConstMatrixNode(index, baseExpression, location);
-            }
-        }
-        else
-        {
-            int safeIndex = -1;
-
-            if (baseExpression->isArray())
-            {
-                if (index >= baseExpression->getType().getArraySize())
-                {
-                    std::stringstream extraInfoStream;
-                    extraInfoStream << "array index out of range '" << index << "'";
-                    std::string extraInfo = extraInfoStream.str();
-                    error(location, "", "[", extraInfo.c_str());
-                    recover();
-                    safeIndex = baseExpression->getType().getArraySize() - 1;
-                }
-                else if (baseExpression->getQualifier() == EvqFragData && index > 0 &&
-                         !isExtensionEnabled("GL_EXT_draw_buffers"))
-                {
-                    error(location, "", "[",
-                          "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is "
-                          "disabled");
-                    recover();
-                    safeIndex = 0;
-                }
-            }
-            else if ((baseExpression->isVector() || baseExpression->isMatrix()) &&
-                     baseExpression->getType().getNominalSize() <= index)
-            {
-                std::stringstream extraInfoStream;
-                extraInfoStream << "field selection out of range '" << index << "'";
-                std::string extraInfo = extraInfoStream.str();
-                error(location, "", "[", extraInfo.c_str());
-                recover();
-                safeIndex = baseExpression->getType().getNominalSize() - 1;
-            }
-
-            // Don't modify the data of the previous constant union, because it can point
-            // to builtins, like gl_MaxDrawBuffers. Instead use a new sanitized object.
-            if (safeIndex != -1)
-            {
-                TConstantUnion *safeConstantUnion = new TConstantUnion();
-                safeConstantUnion->setIConst(safeIndex);
-                indexConstantUnion->replaceConstantUnion(safeConstantUnion);
-            }
-
-            indexedExpression =
-                intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
-        }
-    }
-    else
+    // TODO(oetuaho@nvidia.com): Get rid of indexConstantUnion == nullptr below once ANGLE is able
+    // to constant fold all constant expressions. Right now we don't allow indexing interface blocks
+    // or fragment outputs with expressions that ANGLE is not able to constant fold, even if the
+    // index is a constant expression.
+    if (indexExpression->getQualifier() != EvqConst || indexConstantUnion == nullptr)
     {
         if (baseExpression->isInterfaceBlock())
         {
             error(
                 location, "", "[",
                 "array indexes for interface blocks arrays must be constant integral expressions");
             recover();
         }
         else if (baseExpression->getQualifier() == EvqFragmentOut)
         {
             error(location, "", "[",
                   "array indexes for fragment outputs must be constant integral expressions");
             recover();
         }
-
+        else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData)
+        {
+            error(location, "", "[", "array index for gl_FragData must be constant zero");
+            recover();
+        }
+    }
+
+    if (indexConstantUnion)
+    {
+        // If the index is not qualified as constant, the behavior in the spec is undefined. This
+        // applies even if ANGLE has been able to constant fold it (ANGLE may constant fold
+        // expressions that are not constant expressions). The most compatible way to handle this
+        // case is to report a warning instead of an error and force the index to be in the
+        // correct range.
+        bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst;
+        int index = indexConstantUnion->getIConst(0);
+        if (index < 0)
+        {
+            std::stringstream infoStream;
+            infoStream << index;
+            std::string info = infoStream.str();
+            outOfRangeError(outOfRangeIndexIsError, location, "negative index", info.c_str());
+            index = 0;
+        }
+        TIntermConstantUnion *baseConstantUnion = baseExpression->getAsConstantUnion();
+        if (baseConstantUnion)
+        {
+            if (baseExpression->isArray())
+            {
+                // constant folding for array indexing
+                indexedExpression =
+                    addConstArrayNode(index, baseConstantUnion, location, outOfRangeIndexIsError);
+            }
+            else if (baseExpression->isVector())
+            {
+                // constant folding for vector indexing
+                TVectorFields fields;
+                fields.num = 1;
+                fields.offsets[0] =
+                    index;  // need to do it this way because v.xy sends fields integer array
+                indexedExpression =
+                    addConstVectorNode(fields, baseConstantUnion, location, outOfRangeIndexIsError);
+            }
+            else if (baseExpression->isMatrix())
+            {
+                // constant folding for matrix indexing
+                indexedExpression =
+                    addConstMatrixNode(index, baseConstantUnion, location, outOfRangeIndexIsError);
+            }
+        }
+        else
+        {
+            int safeIndex = -1;
+
+            if (baseExpression->isArray())
+            {
+                if (baseExpression->getQualifier() == EvqFragData && index > 0)
+                {
+                    if (mShaderSpec == SH_WEBGL2_SPEC)
+                    {
+                        // Error has been already generated if index is not const.
+                        if (indexExpression->getQualifier() == EvqConst)
+                        {
+                            error(location, "", "[",
+                                  "array index for gl_FragData must be constant zero");
+                            recover();
+                        }
+                        safeIndex = 0;
+                    }
+                    else if (!isExtensionEnabled("GL_EXT_draw_buffers"))
+                    {
+                        outOfRangeError(outOfRangeIndexIsError, location, "", "[",
+                                        "array index for gl_FragData must be zero when "
+                                        "GL_EXT_draw_buffers is disabled");
+                        safeIndex = 0;
+                    }
+                }
+                // Only do generic out-of-range check if similar error hasn't already been reported.
+                if (safeIndex < 0 && index >= baseExpression->getType().getArraySize())
+                {
+                    std::stringstream extraInfoStream;
+                    extraInfoStream << "array index out of range '" << index << "'";
+                    std::string extraInfo = extraInfoStream.str();
+                    outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str());
+                    safeIndex = baseExpression->getType().getArraySize() - 1;
+                }
+            }
+            else if ((baseExpression->isVector() || baseExpression->isMatrix()) &&
+                     baseExpression->getType().getNominalSize() <= index)
+            {
+                std::stringstream extraInfoStream;
+                extraInfoStream << "field selection out of range '" << index << "'";
+                std::string extraInfo = extraInfoStream.str();
+                outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str());
+                safeIndex = baseExpression->getType().getNominalSize() - 1;
+            }
+
+            // Data of constant unions can't be changed, because it may be shared with other
+            // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new
+            // sanitized object.
+            if (safeIndex != -1)
+            {
+                TConstantUnion *safeConstantUnion = new TConstantUnion();
+                safeConstantUnion->setIConst(safeIndex);
+                indexConstantUnion->replaceConstantUnion(safeConstantUnion);
+            }
+
+            indexedExpression =
+                intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
+        }
+    }
+    else
+    {
         indexedExpression =
             intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
     }
 
     if (indexedExpression == 0)
     {
         TConstantUnion *unionArray = new TConstantUnion[1];
         unionArray->setFConst(0.0f);
@@ -2924,41 +2902,39 @@ TIntermTyped *TParseContext::addFieldSel
         if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
                                fieldLocation))
         {
             fields.num        = 1;
             fields.offsets[0] = 0;
             recover();
         }
 
-        if (baseExpression->getType().getQualifier() == EvqConst)
+        if (baseExpression->getAsConstantUnion())
         {
             // constant folding for vector fields
-            indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
-            if (indexedExpression == 0)
-            {
-                recover();
-                indexedExpression = baseExpression;
-            }
-            else
-            {
-                indexedExpression->setType(TType(baseExpression->getBasicType(),
-                                                 baseExpression->getPrecision(), EvqConst,
-                                                 (unsigned char)(fieldString).size()));
-            }
+            indexedExpression = addConstVectorNode(fields, baseExpression->getAsConstantUnion(),
+                                                   fieldLocation, true);
         }
         else
         {
-            TString vectorString = fieldString;
             TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation);
             indexedExpression =
                 intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
+        }
+        if (indexedExpression == nullptr)
+        {
+            recover();
+            indexedExpression = baseExpression;
+        }
+        else
+        {
+            // Note that the qualifier set here will be corrected later.
             indexedExpression->setType(TType(baseExpression->getBasicType(),
                                              baseExpression->getPrecision(), EvqTemporary,
-                                             (unsigned char)vectorString.size()));
+                                             (unsigned char)(fieldString).size()));
         }
     }
     else if (baseExpression->getBasicType() == EbtStruct)
     {
         bool fieldFound          = false;
         const TFieldList &fields = baseExpression->getType().getStruct()->fields();
         if (fields.empty())
         {
@@ -2974,30 +2950,27 @@ TIntermTyped *TParseContext::addFieldSel
                 if (fields[i]->name() == fieldString)
                 {
                     fieldFound = true;
                     break;
                 }
             }
             if (fieldFound)
             {
-                if (baseExpression->getType().getQualifier() == EvqConst)
+                if (baseExpression->getAsConstantUnion())
                 {
                     indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
                     if (indexedExpression == 0)
                     {
                         recover();
                         indexedExpression = baseExpression;
                     }
                     else
                     {
                         indexedExpression->setType(*fields[i]->type());
-                        // change the qualifier of the return type, not of the structure field
-                        // as the structure definition is shared between various structures.
-                        indexedExpression->getTypePointer()->setQualifier(EvqConst);
                     }
                 }
                 else
                 {
                     TConstantUnion *unionArray = new TConstantUnion[1];
                     unionArray->setIConst(i);
                     TIntermTyped *index = intermediate.addConstantUnion(
                         unionArray, *fields[i]->type(), fieldLocation);
@@ -3066,16 +3039,25 @@ TIntermTyped *TParseContext::addFieldSel
                   " field selection requires structure, vector, or interface block on left hand "
                   "side",
                   fieldString.c_str());
         }
         recover();
         indexedExpression = baseExpression;
     }
 
+    if (baseExpression->getQualifier() == EvqConst)
+    {
+        indexedExpression->getTypePointer()->setQualifier(EvqConst);
+    }
+    else
+    {
+        indexedExpression->getTypePointer()->setQualifier(EvqTemporary);
+    }
+
     return indexedExpression;
 }
 
 TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
                                                      const TSourceLoc &qualifierTypeLine)
 {
     TLayoutQualifier qualifier;
 
@@ -3319,16 +3301,17 @@ TPublicType TParseContext::addStructure(
                 recover();
                 break;
         }
     }
 
     TPublicType publicType;
     publicType.setBasic(EbtStruct, EvqTemporary, structLine);
     publicType.userDef = structureType;
+    publicType.isStructSpecifier = true;
     exitStructDeclaration();
 
     return publicType;
 }
 
 TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
                                         TIntermAggregate *statementList,
                                         const TSourceLoc &loc)
@@ -3378,17 +3361,20 @@ TIntermCase *TParseContext::addCase(TInt
     }
     if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
         condition->isMatrix() || condition->isArray() || condition->isVector())
     {
         error(condition->getLine(), "case label must be a scalar integer", "case");
         recover();
     }
     TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
-    if (conditionConst == nullptr)
+    // TODO(oetuaho@nvidia.com): Get rid of the conditionConst == nullptr check once all constant
+    // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
+    // fold in case labels.
+    if (condition->getQualifier() != EvqConst || conditionConst == nullptr)
     {
         error(condition->getLine(), "case label must be constant", "case");
         recover();
     }
     TIntermCase *node = intermediate.addCase(condition, loc);
     if (node == nullptr)
     {
         error(loc, "erroneous case statement", "case");
@@ -3718,16 +3704,23 @@ TIntermTyped *TParseContext::addAssign(T
     {
         assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
         recover();
         return left;
     }
     return node;
 }
 
+TIntermTyped *TParseContext::addComma(TIntermTyped *left,
+                                      TIntermTyped *right,
+                                      const TSourceLoc &loc)
+{
+    return intermediate.addComma(left, right, loc, mShaderVersion);
+}
+
 TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
 {
     switch (op)
     {
         case EOpContinue:
             if (mLoopNestingLevel <= 0)
             {
                 error(loc, "continue statement only allowed in loops", "");
@@ -3769,16 +3762,69 @@ TIntermBranch *TParseContext::addBranch(
     else if (*mCurrentFunctionType != returnValue->getType())
     {
         error(loc, "function return is not matching type:", "return");
         recover();
     }
     return intermediate.addBranch(op, returnValue, loc);
 }
 
+void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
+{
+    ASSERT(!functionCall->isUserDefined());
+    const TString &name        = functionCall->getName();
+    TIntermNode *offset        = nullptr;
+    TIntermSequence *arguments = functionCall->getSequence();
+    if (name.compare(0, 16, "texelFetchOffset") == 0 ||
+        name.compare(0, 16, "textureLodOffset") == 0 ||
+        name.compare(0, 20, "textureProjLodOffset") == 0 ||
+        name.compare(0, 17, "textureGradOffset") == 0 ||
+        name.compare(0, 21, "textureProjGradOffset") == 0)
+    {
+        offset = arguments->back();
+    }
+    else if (name.compare(0, 13, "textureOffset") == 0 ||
+             name.compare(0, 17, "textureProjOffset") == 0)
+    {
+        // A bias parameter might follow the offset parameter.
+        ASSERT(arguments->size() >= 3);
+        offset = (*arguments)[2];
+    }
+    if (offset != nullptr)
+    {
+        TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion();
+        if (offset->getAsTyped()->getQualifier() != EvqConst || !offsetConstantUnion)
+        {
+            TString unmangledName = TFunction::unmangleName(name);
+            error(functionCall->getLine(), "Texture offset must be a constant expression",
+                  unmangledName.c_str());
+            recover();
+        }
+        else
+        {
+            ASSERT(offsetConstantUnion->getBasicType() == EbtInt);
+            size_t size                  = offsetConstantUnion->getType().getObjectSize();
+            const TConstantUnion *values = offsetConstantUnion->getUnionArrayPointer();
+            for (size_t i = 0u; i < size; ++i)
+            {
+                int offsetValue = values[i].getIConst();
+                if (offsetValue > mMaxProgramTexelOffset || offsetValue < mMinProgramTexelOffset)
+                {
+                    std::stringstream tokenStream;
+                    tokenStream << offsetValue;
+                    std::string token = tokenStream.str();
+                    error(offset->getLine(), "Texture offset value out of valid range",
+                          token.c_str());
+                    recover();
+                }
+            }
+        }
+    }
+}
+
 TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
                                                      TIntermNode *paramNode,
                                                      TIntermNode *thisNode,
                                                      const TSourceLoc &loc,
                                                      bool *fatalError)
 {
     *fatalError            = false;
     TOperator op           = fnCall->getBuiltInOp();
@@ -3874,16 +3920,18 @@ TIntermTyped *TParseContext::addFunction
                 //
                 // A function call mapped to a built-in operation.
                 //
                 if (fnCandidate->getParamCount() == 1)
                 {
                     //
                     // Treat it like a built-in unary operator.
                     //
+                    TIntermAggregate *paramAgg = paramNode->getAsAggregate();
+                    paramNode                  = paramAgg->getSequence()->front();
                     callNode = createUnaryMath(op, paramNode->getAsTyped(), loc,
                                                &fnCandidate->getReturnType());
                     if (callNode == nullptr)
                     {
                         std::stringstream extraInfoStream;
                         extraInfoStream
                             << "built in unary operator function.  Type: "
                             << static_cast<TIntermTyped *>(paramNode)->getCompleteString();
@@ -3895,54 +3943,62 @@ TIntermTyped *TParseContext::addFunction
                     }
                 }
                 else
                 {
                     TIntermAggregate *aggregate =
                         intermediate.setAggregateOperator(paramNode, op, loc);
                     aggregate->setType(fnCandidate->getReturnType());
                     aggregate->setPrecisionFromChildren();
+                    if (aggregate->areChildrenConstQualified())
+                    {
+                        aggregate->getTypePointer()->setQualifier(EvqConst);
+                    }
 
                     // Some built-in functions have out parameters too.
                     functionCallLValueErrorCheck(fnCandidate, aggregate);
 
-                    // See if we can constant fold a built-in.
+                    // See if we can constant fold a built-in. Note that this may be possible even
+                    // if it is not const-qualified.
                     TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate);
                     if (foldedNode)
                     {
                         callNode = foldedNode;
                     }
                     else
                     {
                         callNode = aggregate;
                     }
                 }
             }
             else
             {
                 // This is a real function call
-
                 TIntermAggregate *aggregate =
                     intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc);
                 aggregate->setType(fnCandidate->getReturnType());
 
                 // this is how we know whether the given function is a builtIn function or a user
                 // defined function
                 // if builtIn == false, it's a userDefined -> could be an overloaded
                 // builtIn function also
                 // if builtIn == true, it's definitely a builtIn function with EOpNull
                 if (!builtIn)
                     aggregate->setUserDefined();
                 aggregate->setName(fnCandidate->getMangledName());
                 aggregate->setFunctionId(fnCandidate->getUniqueId());
 
                 // This needs to happen after the name is set
                 if (builtIn)
+                {
                     aggregate->setBuiltInFunctionPrecision();
 
+                    checkTextureOffsetConst(aggregate);
+                }
+
                 callNode = aggregate;
 
                 functionCallLValueErrorCheck(fnCandidate, aggregate);
             }
         }
         else
         {
             // error message was put out by findFunction()
--- a/gfx/angle/src/compiler/translator/ParseContext.h
+++ b/gfx/angle/src/compiler/translator/ParseContext.h
@@ -31,40 +31,45 @@ class TParseContext : angle::NonCopyable
     TParseContext(TSymbolTable &symt,
                   TExtensionBehavior &ext,
                   TIntermediate &interm,
                   sh::GLenum type,
                   ShShaderSpec spec,
                   int options,
                   bool checksPrecErrors,
                   TInfoSink &is,
-                  bool debugShaderPrecisionSupported)
+                  const ShBuiltInResources &resources)
         : intermediate(interm),
           symbolTable(symt),
           mDeferredSingleDeclarationErrorCheck(false),
           mShaderType(type),
           mShaderSpec(spec),
           mShaderVersion(100),
           mTreeRoot(nullptr),
           mLoopNestingLevel(0),
           mStructNestingLevel(0),
           mSwitchNestingLevel(0),
           mCurrentFunctionType(nullptr),
           mFunctionReturnsValue(false),
           mChecksPrecisionErrors(checksPrecErrors),
-          mFragmentPrecisionHigh(false),
+          mFragmentPrecisionHighOnESSL1(false),
           mDefaultMatrixPacking(EmpColumnMajor),
           mDefaultBlockStorage(EbsShared),
           mDiagnostics(is),
-          mDirectiveHandler(ext, mDiagnostics, mShaderVersion, debugShaderPrecisionSupported),
+          mDirectiveHandler(ext,
+                            mDiagnostics,
+                            mShaderVersion,
+                            resources.WEBGL_debug_shader_precision == 1),
           mPreprocessor(&mDiagnostics, &mDirectiveHandler),
           mScanner(nullptr),
           mUsesFragData(false),
           mUsesFragColor(false),
-          mUsesSecondaryOutputs(false)
+          mUsesSecondaryOutputs(false),
+          mMinProgramTexelOffset(resources.MinProgramTexelOffset),
+          mMaxProgramTexelOffset(resources.MaxProgramTexelOffset)
     {
     }
 
     const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
     pp::Preprocessor &getPreprocessor() { return mPreprocessor; }
     void *getScanner() const { return mScanner; }
     void setScanner(void *scanner) { mScanner = scanner; }
     int getShaderVersion() const { return mShaderVersion; }
@@ -72,24 +77,34 @@ class TParseContext : angle::NonCopyable
     ShShaderSpec getShaderSpec() const { return mShaderSpec; }
     int numErrors() const { return mDiagnostics.numErrors(); }
     TInfoSink &infoSink() { return mDiagnostics.infoSink(); }
     void error(const TSourceLoc &loc, const char *reason, const char *token,
                const char *extraInfo="");
     void warning(const TSourceLoc &loc, const char *reason, const char *token,
                  const char *extraInfo="");
 
+    // If isError is false, a warning will be reported instead.
+    void outOfRangeError(bool isError,
+                         const TSourceLoc &loc,
+                         const char *reason,
+                         const char *token,
+                         const char *extraInfo = "");
+
     void recover();
     TIntermNode *getTreeRoot() const { return mTreeRoot; }
     void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; }
 
-    bool getFragmentPrecisionHigh() const { return mFragmentPrecisionHigh; }
-    void setFragmentPrecisionHigh(bool fragmentPrecisionHigh)
+    bool getFragmentPrecisionHigh() const
     {
-        mFragmentPrecisionHigh = fragmentPrecisionHigh;
+        return mFragmentPrecisionHighOnESSL1 || mShaderVersion >= 300;
+    }
+    void setFragmentPrecisionHighOnESSL1(bool fragmentPrecisionHigh)
+    {
+        mFragmentPrecisionHighOnESSL1 = fragmentPrecisionHigh;
     }
 
     bool getFunctionReturnsValue() const { return mFunctionReturnsValue; }
     void setFunctionReturnsValue(bool functionReturnsValue)
     {
         mFunctionReturnsValue = functionReturnsValue;
     }
 
@@ -107,29 +122,36 @@ class TParseContext : angle::NonCopyable
     void incrLoopNestingLevel() { ++mLoopNestingLevel; }
     void decrLoopNestingLevel() { --mLoopNestingLevel; }
 
     void incrSwitchNestingLevel() { ++mSwitchNestingLevel; }
     void decrSwitchNestingLevel() { --mSwitchNestingLevel; }
 
     // This method is guaranteed to succeed, even if no variable with 'name' exists.
     const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
+    TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
+                                          const TString *name,
+                                          const TSymbol *symbol);
 
     bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc &line);
 
     bool reservedErrorCheck(const TSourceLoc &line, const TString &identifier);
     void assignError(const TSourceLoc &line, const char *op, TString left, TString right);
     void unaryOpError(const TSourceLoc &line, const char *op, TString operand);
     void binaryOpError(const TSourceLoc &line, const char *op, TString left, TString right);
     bool precisionErrorCheck(const TSourceLoc &line, TPrecision precision, TBasicType type);
     bool lValueErrorCheck(const TSourceLoc &line, const char *op, TIntermTyped*);
     bool constErrorCheck(TIntermTyped *node);
     bool integerErrorCheck(TIntermTyped *node, const char *token);
     bool globalErrorCheck(const TSourceLoc &line, bool global, const char *token);
-    bool constructorErrorCheck(const TSourceLoc &line, TIntermNode*, TFunction&, TOperator, TType*);
+    bool constructorErrorCheck(const TSourceLoc &line,
+                               TIntermNode *argumentsNode,
+                               TFunction &function,
+                               TOperator op,
+                               TType *type);
     bool arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *expr, int &size);
     bool arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type);
     bool arrayTypeErrorCheck(const TSourceLoc &line, const TPublicType &type);
     bool voidErrorCheck(const TSourceLoc &line, const TString &identifier, const TBasicType &type);
     bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*);
     bool boolErrorCheck(const TSourceLoc&, const TPublicType&);
     bool samplerErrorCheck(const TSourceLoc &line, const TPublicType &pType, const char *reason);
     bool locationDeclaratorListCheck(const TSourceLoc &line, const TPublicType &pType);
@@ -147,17 +169,16 @@ class TParseContext : angle::NonCopyable
     const TPragma &pragma() const { return mDirectiveHandler.pragma(); }
     const TExtensionBehavior &extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); }
     bool supportsExtension(const char *extension);
     bool isExtensionEnabled(const char *extension) const;
     void handleExtensionDirective(const TSourceLoc &loc, const char *extName, const char *behavior);
     void handlePragmaDirective(const TSourceLoc &loc, const char *name, const char *value, bool stdgl);
 
     bool containsSampler(const TType &type);
-    bool areAllChildConst(TIntermAggregate *aggrNode);
     const TFunction* findFunction(
         const TSourceLoc &line, TFunction *pfnCall, int inputShaderVersion, bool *builtIn = 0);
     bool executeInitializer(const TSourceLoc &line,
                             const TString &identifier,
                             const TPublicType &pType,
                             TIntermTyped *initializer,
                             TIntermNode **intermNode);
 
@@ -229,20 +250,28 @@ class TParseContext : angle::NonCopyable
     TFunction *parseFunctionDeclarator(const TSourceLoc &location,
                                        TFunction *function);
     TFunction *addConstructorFunc(const TPublicType &publicType);
     TIntermTyped *addConstructor(TIntermNode *arguments,
                                  TType *type,
                                  TOperator op,
                                  TFunction *fnCall,
                                  const TSourceLoc &line);
-    TIntermTyped *foldConstConstructor(TIntermAggregate *aggrNode, const TType &type);
-    TIntermTyped *addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&);
-    TIntermTyped *addConstMatrixNode(int, TIntermTyped*, const TSourceLoc&);
-    TIntermTyped *addConstArrayNode(int index, TIntermTyped *node, const TSourceLoc &line);
+    TIntermTyped *addConstVectorNode(TVectorFields &fields,
+                                     TIntermConstantUnion *node,
+                                     const TSourceLoc &line,
+                                     bool outOfRangeIndexIsError);
+    TIntermTyped *addConstMatrixNode(int index,
+                                     TIntermConstantUnion *node,
+                                     const TSourceLoc &line,
+                                     bool outOfRangeIndexIsError);
+    TIntermTyped *addConstArrayNode(int index,
+                                    TIntermConstantUnion *node,
+                                    const TSourceLoc &line,
+                                    bool outOfRangeIndexIsError);
     TIntermTyped *addConstStruct(
         const TString &identifier, TIntermTyped *node, const TSourceLoc& line);
     TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
                                      const TSourceLoc& location,
                                      TIntermTyped *indexExpression);
     TIntermTyped* addFieldSelectionExpression(TIntermTyped *baseExpression,
                                               const TSourceLoc &dotLocation,
                                               const TString &fieldString,
@@ -290,19 +319,22 @@ class TParseContext : angle::NonCopyable
     TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
     TIntermTyped *addBinaryMath(
         TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
     TIntermTyped *addBinaryMathBooleanResult(
         TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
     TIntermTyped *addAssign(
         TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
 
+    TIntermTyped *addComma(TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+
     TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
     TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
 
+    void checkTextureOffsetConst(TIntermAggregate *functionCall);
     TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall,
                                           TIntermNode *paramNode,
                                           TIntermNode *thisNode,
                                           const TSourceLoc &loc,
                                           bool *fatalError);
 
     TIntermTyped *addTernarySelection(
         TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &line);
@@ -337,26 +369,29 @@ class TParseContext : angle::NonCopyable
     int mShaderVersion;
     TIntermNode *mTreeRoot;       // root of parse tree being created
     int mLoopNestingLevel;       // 0 if outside all loops
     int mStructNestingLevel;      // incremented while parsing a struct declaration
     int mSwitchNestingLevel;     // 0 if outside all switch statements
     const TType *mCurrentFunctionType;  // the return type of the function that's currently being parsed
     bool mFunctionReturnsValue;  // true if a non-void function has a return
     bool mChecksPrecisionErrors;  // true if an error will be generated when a variable is declared without precision, explicit or implicit.
-    bool mFragmentPrecisionHigh;  // true if highp precision is supported in the fragment language.
+    bool mFragmentPrecisionHighOnESSL1;  // true if highp precision is supported when compiling
+                                         // ESSL1.
     TLayoutMatrixPacking mDefaultMatrixPacking;
     TLayoutBlockStorage mDefaultBlockStorage;
     TString mHashErrMsg;
     TDiagnostics mDiagnostics;
     TDirectiveHandler mDirectiveHandler;
     pp::Preprocessor mPreprocessor;
     void *mScanner;
     bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor
     bool mUsesFragColor;
     bool mUsesSecondaryOutputs;  // Track if we are using either gl_SecondaryFragData or
                                  // gl_Secondary FragColor or both.
+    int mMinProgramTexelOffset;
+    int mMaxProgramTexelOffset;
 };
 
 int PaParseStrings(
     size_t count, const char *const string[], const int length[], TParseContext *context);
 
 #endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_
--- a/gfx/angle/src/compiler/translator/RemoveDynamicIndexing.cpp
+++ b/gfx/angle/src/compiler/translator/RemoveDynamicIndexing.cpp
@@ -50,51 +50,56 @@ TName GetIndexFunctionName(const TType &
         nameSink << type.getNominalSize();
     }
     TString nameString = TFunction::mangleName(nameSink.c_str());
     TName name(nameString);
     name.setInternal(true);
     return name;
 }
 
-TIntermSymbol *CreateBaseSymbol(const TType &type)
+TIntermSymbol *CreateBaseSymbol(const TType &type, TQualifier qualifier)
 {
     TIntermSymbol *symbol = new TIntermSymbol(0, "base", type);
     symbol->setInternal(true);
+    symbol->getTypePointer()->setQualifier(qualifier);
     return symbol;
 }
 
 TIntermSymbol *CreateIndexSymbol()
 {
     TIntermSymbol *symbol = new TIntermSymbol(0, "index", TType(EbtInt, EbpHigh));
     symbol->setInternal(true);
+    symbol->getTypePointer()->setQualifier(EvqIn);
     return symbol;
 }
 
 TIntermSymbol *CreateValueSymbol(const TType &type)
 {
     TIntermSymbol *symbol = new TIntermSymbol(0, "value", type);
     symbol->setInternal(true);
+    symbol->getTypePointer()->setQualifier(EvqIn);
     return symbol;
 }
 
 TIntermConstantUnion *CreateIntConstantNode(int i)
 {
     TConstantUnion *constant = new TConstantUnion();
     constant->setIConst(i);
     return new TIntermConstantUnion(constant, TType(EbtInt, EbpHigh));
 }
 
 TIntermBinary *CreateIndexDirectBaseSymbolNode(const TType &indexedType,
                                                const TType &fieldType,
-                                               const int index)
+                                               const int index,
+                                               TQualifier baseQualifier)
 {
     TIntermBinary *indexNode = new TIntermBinary(EOpIndexDirect);
     indexNode->setType(fieldType);
-    indexNode->setLeft(CreateBaseSymbol(indexedType));
+    TIntermSymbol *baseSymbol = CreateBaseSymbol(indexedType, baseQualifier);
+    indexNode->setLeft(baseSymbol);
     indexNode->setRight(CreateIntConstantNode(index));
     return indexNode;
 }
 
 TIntermBinary *CreateAssignValueSymbolNode(TIntermTyped *targetNode, const TType &assignedValueType)
 {
     TIntermBinary *assignNode = new TIntermBinary(EOpAssign);
     assignNode->setType(assignedValueType);
@@ -198,40 +203,38 @@ TIntermAggregate *GetIndexFunctionDefini
         indexingFunction->setType(TType(EbtVoid));
     }
     else
     {
         indexingFunction->setType(fieldType);
     }
 
     TIntermAggregate *paramsNode = new TIntermAggregate(EOpParameters);
-    TIntermSymbol *baseParam = CreateBaseSymbol(type);
-    if (write)
-        baseParam->getTypePointer()->setQualifier(EvqInOut);
-    else
-        baseParam->getTypePointer()->setQualifier(EvqIn);
+    TQualifier baseQualifier = EvqInOut;
+    if (!write)
+        baseQualifier        = EvqIn;
+    TIntermSymbol *baseParam = CreateBaseSymbol(type, baseQualifier);
     paramsNode->getSequence()->push_back(baseParam);
     TIntermSymbol *indexParam = CreateIndexSymbol();
-    indexParam->getTypePointer()->setQualifier(EvqIn);
     paramsNode->getSequence()->push_back(indexParam);
     if (write)
     {
         TIntermSymbol *valueParam = CreateValueSymbol(fieldType);
-        valueParam->getTypePointer()->setQualifier(EvqIn);
         paramsNode->getSequence()->push_back(valueParam);
     }
     indexingFunction->getSequence()->push_back(paramsNode);
 
     TIntermAggregate *statementList = new TIntermAggregate(EOpSequence);
     for (int i = 0; i < numCases; ++i)
     {
         TIntermCase *caseNode = new TIntermCase(CreateIntConstantNode(i));
         statementList->getSequence()->push_back(caseNode);
 
-        TIntermBinary *indexNode = CreateIndexDirectBaseSymbolNode(type, fieldType, i);
+        TIntermBinary *indexNode =
+            CreateIndexDirectBaseSymbolNode(type, fieldType, i, baseQualifier);
         if (write)
         {
             TIntermBinary *assignNode = CreateAssignValueSymbolNode(indexNode, fieldType);
             statementList->getSequence()->push_back(assignNode);
             TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr);
             statementList->getSequence()->push_back(returnNode);
         }
         else
@@ -255,19 +258,21 @@ TIntermAggregate *GetIndexFunctionDefini
     TIntermBinary *cond = new TIntermBinary(EOpLessThan);
     cond->setType(TType(EbtBool, EbpUndefined));
     cond->setLeft(CreateIndexSymbol());
     cond->setRight(CreateIntConstantNode(0));
 
     // Two blocks: one accesses (either reads or writes) the first element and returns,
     // the other accesses the last element.
     TIntermAggregate *useFirstBlock = new TIntermAggregate(EOpSequence);
-    TIntermAggregate *useLastBlock  = new TIntermAggregate(EOpSequence);
-    TIntermBinary *indexFirstNode   = CreateIndexDirectBaseSymbolNode(type, fieldType, 0);
-    TIntermBinary *indexLastNode = CreateIndexDirectBaseSymbolNode(type, fieldType, numCases - 1);
+    TIntermAggregate *useLastBlock = new TIntermAggregate(EOpSequence);
+    TIntermBinary *indexFirstNode =
+        CreateIndexDirectBaseSymbolNode(type, fieldType, 0, baseQualifier);
+    TIntermBinary *indexLastNode =
+        CreateIndexDirectBaseSymbolNode(type, fieldType, numCases - 1, baseQualifier);
     if (write)
     {
         TIntermBinary *assignFirstNode = CreateAssignValueSymbolNode(indexFirstNode, fieldType);
         useFirstBlock->getSequence()->push_back(assignFirstNode);
         TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr);
         useFirstBlock->getSequence()->push_back(returnNode);
 
         TIntermBinary *assignLastNode = CreateAssignValueSymbolNode(indexLastNode, fieldType);
--- a/gfx/angle/src/compiler/translator/SeparateArrayInitialization.cpp
+++ b/gfx/angle/src/compiler/translator/SeparateArrayInitialization.cpp
@@ -4,20 +4,26 @@
 // found in the LICENSE file.
 //
 // The SeparateArrayInitialization function splits each array initialization into a declaration and an assignment.
 // Example:
 //     type[n] a = initializer;
 // will effectively become
 //     type[n] a;
 //     a = initializer;
+//
+// Note that if the array is declared as const, the initialization may still be split, making the
+// AST technically invalid. Because of that this transformation should only be used when subsequent
+// stages don't care about const qualifiers. However, the initialization will not be split if the
+// initializer can be written as a HLSL literal.
 
 #include "compiler/translator/SeparateArrayInitialization.h"
 
 #include "compiler/translator/IntermNode.h"
+#include "compiler/translator/OutputHLSL.h"
 
 namespace
 {
 
 class SeparateArrayInitTraverser : private TIntermTraverser
 {
   public:
     static void apply(TIntermNode *root);
@@ -42,17 +48,17 @@ bool SeparateArrayInitTraverser::visitAg
 {
     if (node->getOp() == EOpDeclaration)
     {
         TIntermSequence *sequence = node->getSequence();
         TIntermBinary *initNode = sequence->back()->getAsBinaryNode();
         if (initNode != nullptr && initNode->getOp() == EOpInitialize)
         {
             TIntermTyped *initializer = initNode->getRight();
-            if (initializer->isArray())
+            if (initializer->isArray() && !sh::OutputHLSL::canWriteAsHLSLLiteral(initializer))
             {
                 // We rely on that array declarations have been isolated to single declarations.
                 ASSERT(sequence->size() == 1);
                 TIntermTyped *symbol = initNode->getLeft();
                 TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
                 ASSERT(parentAgg != nullptr);
 
                 TIntermSequence replacements;
--- a/gfx/angle/src/compiler/translator/SeparateArrayInitialization.h
+++ b/gfx/angle/src/compiler/translator/SeparateArrayInitialization.h
@@ -4,16 +4,21 @@
 // found in the LICENSE file.
 //
 // The SeparateArrayInitialization function splits each array initialization into a declaration and an assignment.
 // Example:
 //     type[n] a = initializer;
 // will effectively become
 //     type[n] a;
 //     a = initializer;
+//
+// Note that if the array is declared as const, the initialization may still be split, making the
+// AST technically invalid. Because of that this transformation should only be used when subsequent
+// stages don't care about const qualifiers. However, the initialization will not be split if the
+// initializer can be written as a HLSL literal.
 
 #ifndef COMPILER_TRANSLATOR_SEPARATEARRAYINITIALIZATION_H_
 #define COMPILER_TRANSLATOR_SEPARATEARRAYINITIALIZATION_H_
 
 class TIntermNode;
 
 void SeparateArrayInitialization(TIntermNode *root);
 
--- a/gfx/angle/src/compiler/translator/SymbolTable.h
+++ b/gfx/angle/src/compiler/translator/SymbolTable.h
@@ -123,44 +123,26 @@ class TVariable : public TSymbol
     {
         return userType;
     }
     void setQualifier(TQualifier qualifier)
     {
         type.setQualifier(qualifier);
     }
 
-    TConstantUnion *getConstPointer()
-    { 
-        if (!unionArray)
-            unionArray = new TConstantUnion[type.getObjectSize()];
-
-        return unionArray;
-    }
+    const TConstantUnion *getConstPointer() const { return unionArray; }
 
-    TConstantUnion *getConstPointer() const
-    {
-        return unionArray;
-    }
-
-    void shareConstPointer(TConstantUnion *constArray)
-    {
-        if (unionArray == constArray)
-            return;
-
-        delete[] unionArray;
-        unionArray = constArray;  
-    }
+    void shareConstPointer(const TConstantUnion *constArray) { unionArray = constArray; }
 
   private:
     TType type;
     bool userType;
     // we are assuming that Pool Allocator will free the memory
     // allocated to unionArray when this object is destroyed.
-    TConstantUnion *unionArray;
+    const TConstantUnion *unionArray;
 };
 
 // Immutable version of TParameter.
 struct TConstParameter
 {
     TConstParameter()
         : name(nullptr),
           type(nullptr)
@@ -395,25 +377,29 @@ class TSymbolTable : angle::NonCopyable
         symbol->relateToExtension(ext);
         return table[level]->insert(symbol);
     }
 
     bool insertConstInt(ESymbolLevel level, const char *name, int value)
     {
         TVariable *constant = new TVariable(
             NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
-        constant->getConstPointer()->setIConst(value);
+        TConstantUnion *unionArray = new TConstantUnion[1];
+        unionArray[0].setIConst(value);
+        constant->shareConstPointer(unionArray);
         return insert(level, constant);
     }
 
     bool insertConstIntExt(ESymbolLevel level, const char *ext, const char *name, int value)
     {
         TVariable *constant =
             new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
-        constant->getConstPointer()->setIConst(value);
+        TConstantUnion *unionArray = new TConstantUnion[1];
+        unionArray[0].setIConst(value);
+        constant->shareConstPointer(unionArray);
         return insert(level, ext, constant);
     }
 
     void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, const TType *rvalue, const char *name,
                        const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0);
 
     void insertBuiltIn(ESymbolLevel level, const TType *rvalue, const char *name,
                        const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
--- a/gfx/angle/src/compiler/translator/TranslatorGLSL.cpp
+++ b/gfx/angle/src/compiler/translator/TranslatorGLSL.cpp
@@ -4,16 +4,17 @@
 // found in the LICENSE file.
 //
 
 #include "compiler/translator/TranslatorGLSL.h"
 
 #include "angle_gl.h"
 #include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
 #include "compiler/translator/EmulatePrecision.h"
+#include "compiler/translator/ExtensionGLSL.h"
 #include "compiler/translator/OutputGLSL.h"
 #include "compiler/translator/VersionGLSL.h"
 
 TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
                                ShShaderSpec spec,
                                ShShaderOutput output)
     : TCompiler(type, spec, output) {
 }
@@ -34,17 +35,17 @@ void TranslatorGLSL::translate(TIntermNo
     TInfoSinkBase& sink = getInfoSink().obj;
 
     // Write GLSL version.
     writeVersion(root);
 
     writePragma();
 
     // Write extension behaviour as needed
-    writeExtensionBehavior();
+    writeExtensionBehavior(root);
 
     bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
 
     if (precisionEmulation)
     {
         EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion());
         root->traverse(&emulatePrecision);
         emulatePrecision.updateTree();
@@ -151,24 +152,46 @@ void TranslatorGLSL::writeVersion(TInter
     // If there is no version directive in the shader, 110 is implied.
     if (version > 110)
     {
         TInfoSinkBase& sink = getInfoSink().obj;
         sink << "#version " << version << "\n";
     }
 }
 
-void TranslatorGLSL::writeExtensionBehavior() {
+void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root)
+{
     TInfoSinkBase& sink = getInfoSink().obj;
     const TExtensionBehavior& extBehavior = getExtensionBehavior();
-    for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
-         iter != extBehavior.end(); ++iter) {
-        if (iter->second == EBhUndefined)
+    for (const auto &iter : extBehavior)
+    {
+        if (iter.second == EBhUndefined)
+        {
             continue;
+        }
 
         // For GLSL output, we don't need to emit most extensions explicitly,
         // but some we need to translate.
-        if (iter->first == "GL_EXT_shader_texture_lod") {
-            sink << "#extension GL_ARB_shader_texture_lod : "
-                 << getBehaviorString(iter->second) << "\n";
+        if (iter.first == "GL_EXT_shader_texture_lod")
+        {
+            sink << "#extension GL_ARB_shader_texture_lod : " << getBehaviorString(iter.second)
+                 << "\n";
         }
     }
+
+    // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
+    if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT)
+    {
+        sink << "#extension GL_ARB_explicit_attrib_location : require\n";
+    }
+
+    TExtensionGLSL extensionGLSL(getOutputType());
+    root->traverse(&extensionGLSL);
+
+    for (const auto &ext : extensionGLSL.getEnabledExtensions())
+    {
+        sink << "#extension " << ext << " : enable\n";
+    }
+    for (const auto &ext : extensionGLSL.getRequiredExtensions())
+    {
+        sink << "#extension " << ext << " : require\n";
+    }
 }
--- a/gfx/angle/src/compiler/translator/TranslatorGLSL.h
+++ b/gfx/angle/src/compiler/translator/TranslatorGLSL.h
@@ -16,12 +16,12 @@ class TranslatorGLSL : public TCompiler
 
   protected:
     void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override;
 
     void translate(TIntermNode *root, int compileOptions) override;
 
   private:
     void writeVersion(TIntermNode *root);
-    void writeExtensionBehavior();
+    void writeExtensionBehavior(TIntermNode *root);
 };
 
 #endif  // COMPILER_TRANSLATOR_TRANSLATORGLSL_H_
--- a/gfx/angle/src/compiler/translator/Types.h
+++ b/gfx/angle/src/compiler/translator/Types.h
@@ -577,29 +577,33 @@ struct TPublicType
     TPrecision precision;
     unsigned char primarySize;          // size of vector or cols of matrix
     unsigned char secondarySize;        // rows of matrix
     bool array;
     int arraySize;
     TType *userDef;
     TSourceLoc line;
 
+    // true if the type was defined by a struct specifier rather than a reference to a type name.
+    bool isStructSpecifier;
+
     void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln)
     {
         type = bt;
         layoutQualifier = TLayoutQualifier::create();
         qualifier = q;
         invariant = false;
         precision = EbpUndefined;
         primarySize = 1;
         secondarySize = 1;
         array = false;
         arraySize = 0;
         userDef = 0;
         line = ln;
+        isStructSpecifier = false;
     }
 
     void setAggregate(unsigned char size)
     {
         primarySize = size;
     }
 
     void setMatrix(unsigned char c, unsigned char r)
--- a/gfx/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp
+++ b/gfx/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp
@@ -19,29 +19,49 @@ namespace
 class UnfoldShortCircuitTraverser : public TIntermTraverser
 {
   public:
     UnfoldShortCircuitTraverser();
 
     bool visitBinary(Visit visit, TIntermBinary *node) override;
     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
     bool visitSelection(Visit visit, TIntermSelection *node) override;
+    bool visitLoop(Visit visit, TIntermLoop *node) override;
 
     void nextIteration();
     bool foundShortCircuit() const { return mFoundShortCircuit; }
 
   protected:
+    // Check if the traversal is inside a loop condition or expression, in which case the unfolded
+    // expression needs to be copied inside the loop. Returns true if the copying is done, in which
+    // case no further unfolding should be done on the same traversal.
+    // The parameters are the node that will be unfolded to multiple statements and so can't remain
+    // inside a loop condition, and its parent.
+    bool copyLoopConditionOrExpression(TIntermNode *parent, TIntermTyped *node);
+
     // Marked to true once an operation that needs to be unfolded has been found.
     // After that, no more unfolding is performed on that traversal.
     bool mFoundShortCircuit;
+
+    // Set to the loop node while a loop condition or expression is being traversed.
+    TIntermLoop *mParentLoop;
+    // Parent of the loop node while a loop condition or expression is being traversed.
+    TIntermNode *mLoopParent;
+
+    bool mInLoopCondition;
+    bool mInLoopExpression;
 };
 
 UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser()
     : TIntermTraverser(true, false, true),
-      mFoundShortCircuit(false)
+      mFoundShortCircuit(false),
+      mParentLoop(nullptr),
+      mLoopParent(nullptr),
+      mInLoopCondition(false),
+      mInLoopExpression(false)
 {
 }
 
 bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
 {
     if (mFoundShortCircuit)
         return false;
     // If our right node doesn't have side effects, we know we don't need to unfold this
@@ -51,20 +71,22 @@ bool UnfoldShortCircuitTraverser::visitB
     {
         return true;
     }
 
     switch (node->getOp())
     {
       case EOpLogicalOr:
         mFoundShortCircuit = true;
+        if (!copyLoopConditionOrExpression(getParentNode(), node))
+        {
+            // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true;
+            // else s = y;",
+            // and then further simplifies down to "bool s = x; if(!s) s = y;".
 
-        // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; else s = y;",
-        // and then further simplifies down to "bool s = x; if(!s) s = y;".
-        {
             TIntermSequence insertions;
             TType boolType(EbtBool, EbpUndefined, EvqTemporary);
 
             ASSERT(node->getLeft()->getType() == boolType);
             insertions.push_back(createTempInitDeclaration(node->getLeft()));
 
             TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence);
             ASSERT(node->getRight()->getType() == boolType);
@@ -78,20 +100,21 @@ bool UnfoldShortCircuitTraverser::visitB
             insertStatementsInParentBlock(insertions);
 
             NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false);
             mReplacements.push_back(replaceVariable);
         }
         return false;
       case EOpLogicalAnd:
         mFoundShortCircuit = true;
-
-        // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; else s = false;",
-        // and then further simplifies down to "bool s = x; if(s) s = y;".
+        if (!copyLoopConditionOrExpression(getParentNode(), node))
         {
+            // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y;
+            // else s = false;",
+            // and then further simplifies down to "bool s = x; if(s) s = y;".
             TIntermSequence insertions;
             TType boolType(EbtBool, EbpUndefined, EvqTemporary);
 
             ASSERT(node->getLeft()->getType() == boolType);
             insertions.push_back(createTempInitDeclaration(node->getLeft()));
 
             TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence);
             ASSERT(node->getRight()->getType() == boolType);
@@ -115,39 +138,45 @@ bool UnfoldShortCircuitTraverser::visitS
 {
     if (mFoundShortCircuit)
         return false;
 
     // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
     if (visit == PreVisit && node->usesTernaryOperator())
     {
         mFoundShortCircuit = true;
-        TIntermSequence insertions;
+        if (!copyLoopConditionOrExpression(getParentNode(), node))
+        {
+            TIntermSequence insertions;
 
-        TIntermSymbol *tempSymbol = createTempSymbol(node->getType());
-        TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
-        tempDeclaration->getSequence()->push_back(tempSymbol);
-        insertions.push_back(tempDeclaration);
+            TIntermSymbol *tempSymbol         = createTempSymbol(node->getType());
+            TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
+            tempDeclaration->getSequence()->push_back(tempSymbol);
+            insertions.push_back(tempDeclaration);
 
-        TIntermAggregate *trueBlock = new TIntermAggregate(EOpSequence);
-        TIntermBinary *trueAssignment = createTempAssignment(node->getTrueBlock()->getAsTyped());
-        trueBlock->getSequence()->push_back(trueAssignment);
+            TIntermAggregate *trueBlock = new TIntermAggregate(EOpSequence);
+            TIntermBinary *trueAssignment =
+                createTempAssignment(node->getTrueBlock()->getAsTyped());
+            trueBlock->getSequence()->push_back(trueAssignment);
 
-        TIntermAggregate *falseBlock = new TIntermAggregate(EOpSequence);
-        TIntermBinary *falseAssignment = createTempAssignment(node->getFalseBlock()->getAsTyped());
-        falseBlock->getSequence()->push_back(falseAssignment);
+            TIntermAggregate *falseBlock = new TIntermAggregate(EOpSequence);
+            TIntermBinary *falseAssignment =
+                createTempAssignment(node->getFalseBlock()->getAsTyped());
+            falseBlock->getSequence()->push_back(falseAssignment);
 
-        TIntermSelection *ifNode = new TIntermSelection(node->getCondition()->getAsTyped(), trueBlock, falseBlock);
-        insertions.push_back(ifNode);
+            TIntermSelection *ifNode =
+                new TIntermSelection(node->getCondition()->getAsTyped(), trueBlock, falseBlock);
+            insertions.push_back(ifNode);
 
-        insertStatementsInParentBlock(insertions);
+            insertStatementsInParentBlock(insertions);
 
-        TIntermSymbol *ternaryResult = createTempSymbol(node->getType());
-        NodeUpdateEntry replaceVariable(getParentNode(), node, ternaryResult, false);
-        mReplacements.push_back(replaceVariable);
+            TIntermSymbol *ternaryResult = createTempSymbol(node->getType());
+            NodeUpdateEntry replaceVariable(getParentNode(), node, ternaryResult, false);
+            mReplacements.push_back(replaceVariable);
+        }
         return false;
     }
 
     return true;
 }
 
 bool UnfoldShortCircuitTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
 {
@@ -165,37 +194,160 @@ bool UnfoldShortCircuitTraverser::visitA
             // case a short-circuiting operator has not been found so far.
             // We need to unfold the sequence (comma) operator, otherwise the evaluation order of
             // statements would be messed up by unfolded operations inside.
             // Don't do any other unfolding on this round of traversal.
             mReplacements.clear();
             mMultiReplacements.clear();
             mInsertions.clear();
 
-            TIntermSequence insertions;
-            TIntermSequence *seq = node->getSequence();
-
-            TIntermSequence::size_type i = 0;
-            ASSERT(!seq->empty());
-            while (i < seq->size() - 1)
+            if (!copyLoopConditionOrExpression(getParentNode(), node))
             {
-                TIntermTyped *child = (*seq)[i]->getAsTyped();
-                insertions.push_back(child);
-                ++i;
-            }
+                TIntermSequence insertions;
+                TIntermSequence *seq = node->getSequence();
 
-            insertStatementsInParentBlock(insertions);
+                TIntermSequence::size_type i = 0;
+                ASSERT(!seq->empty());
+                while (i < seq->size() - 1)
+                {
+                    TIntermTyped *child = (*seq)[i]->getAsTyped();
+                    insertions.push_back(child);
+                    ++i;
+                }
 
-            NodeUpdateEntry replaceVariable(getParentNode(), node, (*seq)[i], false);
-            mReplacements.push_back(replaceVariable);
+                insertStatementsInParentBlock(insertions);
+
+                NodeUpdateEntry replaceVariable(getParentNode(), node, (*seq)[i], false);
+                mReplacements.push_back(replaceVariable);
+            }
         }
     }
     return true;
 }
 
+bool UnfoldShortCircuitTraverser::visitLoop(Visit visit, TIntermLoop *node)
+{
+    if (visit == PreVisit)
+    {
+        if (mFoundShortCircuit)
+            return false;  // No need to traverse further
+
+        mLoopParent = getParentNode();
+        mParentLoop = node;
+        incrementDepth(node);
+
+        if (node->getInit())
+        {
+            node->getInit()->traverse(this);
+            if (mFoundShortCircuit)
+            {
+                decrementDepth();
+                return false;
+            }
+        }
+
+        if (node->getCondition())
+        {
+            mInLoopCondition = true;
+            node->getCondition()->traverse(this);
+            mInLoopCondition = false;
+
+            if (mFoundShortCircuit)
+            {
+                decrementDepth();
+                return false;
+            }
+        }
+
+        if (node->getExpression())
+        {
+            mInLoopExpression = true;
+            node->getExpression()->traverse(this);
+            mInLoopExpression = false;
+
+            if (mFoundShortCircuit)
+            {
+                decrementDepth();
+                return false;
+            }
+        }
+
+        if (node->getBody())
+            node->getBody()->traverse(this);
+
+        decrementDepth();
+    }
+    return false;
+}
+
+bool UnfoldShortCircuitTraverser::copyLoopConditionOrExpression(TIntermNode *parent,
+                                                                TIntermTyped *node)
+{
+    if (mInLoopCondition)
+    {
+        mReplacements.push_back(
+            NodeUpdateEntry(parent, node, createTempSymbol(node->getType()), false));
+        TIntermAggregate *body = mParentLoop->getBody();
+        TIntermSequence empty;
+        if (mParentLoop->getType() == ELoopDoWhile)
+        {
+            // Declare the temporary variable before the loop.
+            TIntermSequence insertionsBeforeLoop;
+            insertionsBeforeLoop.push_back(createTempDeclaration(node->getType()));
+            insertStatementsInParentBlock(insertionsBeforeLoop);
+
+            // Move a part of do-while loop condition to inside the loop.
+            TIntermSequence insertionsInLoop;
+            insertionsInLoop.push_back(createTempAssignment(node));
+            mInsertions.push_back(NodeInsertMultipleEntry(body, body->getSequence()->size() - 1,
+                                                          empty, insertionsInLoop));
+        }
+        else
+        {
+            // The loop initializer expression and one copy of the part of the loop condition are
+            // executed before the loop. They need to be in a new scope.
+            TIntermAggregate *loopScope = new TIntermAggregate(EOpSequence);
+
+            TIntermNode *initializer = mParentLoop->getInit();
+            if (initializer != nullptr)
+            {
+                // Move the initializer to the newly created outer scope, so that condition can
+                // depend on it.
+                mReplacements.push_back(NodeUpdateEntry(mParentLoop, initializer, nullptr, false));
+                loopScope->getSequence()->push_back(initializer);
+            }
+
+            loopScope->getSequence()->push_back(createTempInitDeclaration(node));
+            loopScope->getSequence()->push_back(mParentLoop);
+            mReplacements.push_back(NodeUpdateEntry(mLoopParent, mParentLoop, loopScope, true));
+
+            // The second copy of the part of the loop condition is executed inside the loop.
+            TIntermSequence insertionsInLoop;
+            insertionsInLoop.push_back(createTempAssignment(node->deepCopy()));
+            mInsertions.push_back(NodeInsertMultipleEntry(body, body->getSequence()->size() - 1,
+                                                          empty, insertionsInLoop));
+        }
+        return true;
+    }
+
+    if (mInLoopExpression)
+    {
+        TIntermTyped *movedExpression = mParentLoop->getExpression();
+        mReplacements.push_back(NodeUpdateEntry(mParentLoop, movedExpression, nullptr, false));
+        TIntermAggregate *body = mParentLoop->getBody();
+        TIntermSequence empty;
+        TIntermSequence insertions;
+        insertions.push_back(movedExpression);
+        mInsertions.push_back(
+            NodeInsertMultipleEntry(body, body->getSequence()->size() - 1, empty, insertions));
+        return true;
+    }
+    return false;
+}
+
 void UnfoldShortCircuitTraverser::nextIteration()
 {
     mFoundShortCircuit = false;
     nextTemporaryIndex();
 }
 
 } // namespace
 
--- a/gfx/angle/src/compiler/translator/VariableInfo.cpp
+++ b/gfx/angle/src/compiler/translator/VariableInfo.cpp
@@ -546,32 +546,33 @@ template <>
 void CollectVariables::visitVariable(const TIntermSymbol *variable,
                                      std::vector<InterfaceBlock> *infoList) const
 {
     InterfaceBlock interfaceBlock;
     const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock();
     ASSERT(blockType);
 
     interfaceBlock.name = blockType->name().c_str();
-    interfaceBlock.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
+    interfaceBlock.mappedName =
+        TIntermTraverser::hash(blockType->name().c_str(), mHashFunction).c_str();
     interfaceBlock.instanceName = (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
     interfaceBlock.arraySize = variable->getArraySize();
     interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
     interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
 
     // Gather field information
     const TFieldList &fieldList = blockType->fields();
 
     for (size_t fieldIndex = 0; fieldIndex < fieldList.size(); ++fieldIndex)
     {
         const TField &field = *fieldList[fieldIndex];
         const TString &fullFieldName = InterfaceBlockFieldName(*blockType, field);
         const TType &fieldType = *field.type();
 
-        GetVariableTraverser traverser(mSymbolTable);
+        NameHashingTraverser traverser(mHashFunction, mSymbolTable);
         traverser.traverse(fieldType, fullFieldName, &interfaceBlock.fields);
 
         interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
     }
 
     infoList->push_back(interfaceBlock);
 }
 
--- a/gfx/angle/src/compiler/translator/glslang.l
+++ b/gfx/angle/src/compiler/translator/glslang.l
@@ -67,17 +67,17 @@ WHICH GENERATES THE GLSL ES LEXER (glsla
 
 static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner);
 static int check_type(yyscan_t yyscanner);
 static int reserved_word(yyscan_t yyscanner);
 static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
 static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
 static int ES2_ident_ES3_keyword(TParseContext *context, int token);
 static int uint_constant(TParseContext *context);
-static int int_constant(yyscan_t yyscanner);
+static int int_constant(TParseContext *context);
 static int float_constant(yyscan_t yyscanner);
 static int floatsuffix_check(TParseContext* context);
 %}
 
 %option noyywrap nounput never-interactive
 %option yylineno reentrant bison-bridge bison-locations
 %option extra-type="TParseContext*"
 %x FIELDS
@@ -316,19 +316,19 @@ O           [0-7]
 "namespace"    |
 "using"        { return reserved_word(yyscanner); }
 
 {L}({L}|{D})*       {
    yylval->lex.string = NewPoolTString(yytext); 
    return check_type(yyscanner);
 }
 
-0[xX]{H}+         { return int_constant(yyscanner); }
-0{O}+             { return int_constant(yyscanner); }
-{D}+              { return int_constant(yyscanner); }
+0[xX]{H}+         { return int_constant(context); }
+0{O}+             { return int_constant(context); }
+{D}+              { return int_constant(context); }
 
 0[xX]{H}+[uU]     { return uint_constant(context); }
 0{O}+[uU]         { return uint_constant(context); }
 {D}+[uU]          { return uint_constant(context); }
 
 {D}+{E}           { return float_constant(yyscanner); }
 {D}+"."{D}*({E})? { return float_constant(yyscanner); }
 "."{D}+({E})?     { return float_constant(yyscanner); }
@@ -473,27 +473,26 @@ int ES2_ident_ES3_keyword(TParseContext 
     }
 
     return token;
 }
 
 int uint_constant(TParseContext *context)
 {
     struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
-    yyscan_t yyscanner = (yyscan_t) context->getScanner();
 
     if (context->getShaderVersion() < 300)
     {
         context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, "");
         context->recover();
         return 0;
     }
 
-    if (!atoi_clamp(yytext, &(yylval->lex.i)))
-        yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+    if (!atoi_clamp(yytext, &(yylval->lex.u)))
+        yyextra->error(*yylloc, "Integer overflow", yytext, "");
 
     return UINTCONSTANT;
 }
 
 int floatsuffix_check(TParseContext* context)
 {
     struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
 
@@ -512,21 +511,28 @@ int floatsuffix_check(TParseContext* con
     return(FLOATCONSTANT);
 }
 
 void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* reason) {
     context->error(*lloc, reason, yyget_text(scanner));
     context->recover();
 }
 
-int int_constant(yyscan_t yyscanner) {
-    struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+int int_constant(TParseContext *context) {
+    struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
 
-    if (!atoi_clamp(yytext, &(yylval->lex.i)))
-        yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+    unsigned int u;
+    if (!atoi_clamp(yytext, &u))
+    {
+        if (context->getShaderVersion() >= 300)
+            yyextra->error(*yylloc, "Integer overflow", yytext, "");
+        else
+            yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+    }
+    yylval->lex.i = static_cast<int>(u);
     return INTCONSTANT;
 }
 
 int float_constant(yyscan_t yyscanner) {
     struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
 
     if (!strtof_clamp(yytext, &(yylval->lex.f)))
         yyextra->warning(*yylloc, "Float overflow", yytext, "");
--- a/gfx/angle/src/compiler/translator/glslang.y
+++ b/gfx/angle/src/compiler/translator/glslang.y
@@ -210,31 +210,17 @@ extern void yyerror(YYLTYPE* yylloc, TPa
 
 identifier
     : IDENTIFIER
     | TYPE_NAME
 
 variable_identifier
     : IDENTIFIER {
         // The symbol table search was done in the lexical phase
-        const TVariable *variable = context->getNamedVariable(@1, $1.string, $1.symbol);
-
-        if (variable->getType().getQualifier() == EvqConst)
-        {
-            TConstantUnion* constArray = variable->getConstPointer();
-            TType t(variable->getType());
-            $$ = context->intermediate.addConstantUnion(constArray, t, @1);
-        }
-        else
-        {
-            $$ = context->intermediate.addSymbol(variable->getUniqueId(),
-                                                 variable->getName(),
-                                                 variable->getType(),
-                                                 @1);
-        }
+        $$ = context->parseVariableIdentifier(@1, $1.string, $1.symbol);
 
         // don't delete $1.string, it's used by error recovery, and the pool
         // pop will reclaim the memory
     }
     ;
 
 primary_expression
     : variable_identifier {
@@ -337,17 +323,17 @@ function_call_header_no_parameters
     }
     ;
 
 function_call_header_with_parameters
     : function_call_header assignment_expression {
         const TType *type = new TType($2->getType());
         $1->addParameter(TConstParameter(type));
         $$.function = $1;
-        $$.nodePair.node1 = $2;
+        $$.nodePair.node1 = context->intermediate.makeAggregate($2, @2);
     }
     | function_call_header_with_parameters COMMA assignment_expression {
         const TType *type = new TType($3->getType());
         $1.function->addParameter(TConstParameter(type));
         $$.function = $1.function;
         $$.nodePair.node1 = context->intermediate.growAggregate($1.intermNode, $3, @2);
     }
     ;
@@ -568,22 +554,17 @@ assignment_operator
     }
     ;
 
 expression
     : assignment_expression {
         $$ = $1;
     }
     | expression COMMA assignment_expression {
-        $$ = context->intermediate.addComma($1, $3, @2);
-        if ($$ == 0) {
-            context->binaryOpError(@2, ",", $1->getCompleteString(), $3->getCompleteString());
-            context->recover();
-            $$ = $3;
-        }
+        $$ = context->addComma($1, $3, @2);
     }
     ;
 
 constant_expression
     : conditional_expression {
         if (context->constErrorCheck($1))
             context->recover();
         $$ = $1;
@@ -939,22 +920,22 @@ type_qualifier
             context->recover();
         if (context->getShaderType() == GL_VERTEX_SHADER)
             $$.setBasic(EbtVoid, EvqVaryingOut, @1);
         else
             $$.setBasic(EbtVoid, EvqVaryingIn, @1);
         $$.invariant = true;
     }
     | storage_qualifier {
-        if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) {
+        if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel())
+        {
             context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1.qualifier));
             context->recover();
-        } else {
-            $$.setBasic(EbtVoid, $1.qualifier, @1);
         }
+        $$.setBasic(EbtVoid, $1.qualifier, @1);
     }
     | interpolation_qualifier storage_qualifier {
         $$ = context->joinInterpolationQualifiers(@1, $1.qualifier, @2, $2.qualifier);
     }
     | interpolation_qualifier {
         context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString($1.qualifier));
         context->recover();
         
--- a/gfx/angle/src/compiler/translator/glslang_lex.cpp
+++ b/gfx/angle/src/compiler/translator/glslang_lex.cpp
@@ -1050,17 +1050,17 @@ WHICH GENERATES THE GLSL ES LEXER (glsla
 
 static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner);
 static int check_type(yyscan_t yyscanner);
 static int reserved_word(yyscan_t yyscanner);
 static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
 static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
 static int ES2_ident_ES3_keyword(TParseContext *context, int token);
 static int uint_constant(TParseContext *context);
-static int int_constant(yyscan_t yyscanner);
+static int int_constant(TParseContext *context);
 static int float_constant(yyscan_t yyscanner);
 static int floatsuffix_check(TParseContext* context);
 
 #define INITIAL 0
 #define FIELDS 1
 
 #define YY_EXTRA_TYPE TParseContext*
 
@@ -1828,25 +1828,25 @@ case 177:
 YY_RULE_SETUP
 {
    yylval->lex.string = NewPoolTString(yytext); 
    return check_type(yyscanner);
 }
 	YY_BREAK
 case 178:
 YY_RULE_SETUP
-{ return int_constant(yyscanner); }
+{ return int_constant(context); }
 	YY_BREAK
 case 179:
 YY_RULE_SETUP
-{ return int_constant(yyscanner); }
+{ return int_constant(context); }
 	YY_BREAK
 case 180:
 YY_RULE_SETUP
-{ return int_constant(yyscanner); }
+{ return int_constant(context); }
 	YY_BREAK
 case 181:
 YY_RULE_SETUP
 { return uint_constant(context); }
 	YY_BREAK
 case 182:
 YY_RULE_SETUP
 { return uint_constant(context); }
@@ -3308,27 +3308,26 @@ int ES2_ident_ES3_keyword(TParseContext 
     }
 
     return token;
 }
 
 int uint_constant(TParseContext *context)
 {
     struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
-    yyscan_t yyscanner = (yyscan_t) context->getScanner();
 
     if (context->getShaderVersion() < 300)
     {
         context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, "");
         context->recover();
         return 0;
     }
 
-    if (!atoi_clamp(yytext, &(yylval->lex.i)))
-        yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+    if (!atoi_clamp(yytext, &(yylval->lex.u)))
+        yyextra->error(*yylloc, "Integer overflow", yytext, "");
 
     return UINTCONSTANT;
 }
 
 int floatsuffix_check(TParseContext* context)
 {
     struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
 
@@ -3347,21 +3346,28 @@ int floatsuffix_check(TParseContext* con
     return(FLOATCONSTANT);
 }
 
 void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* reason) {
     context->error(*lloc, reason, yyget_text(scanner));
     context->recover();
 }
 
-int int_constant(yyscan_t yyscanner) {
-    struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
-
-    if (!atoi_clamp(yytext, &(yylval->lex.i)))
-        yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+int int_constant(TParseContext *context) {
+    struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+
+    unsigned int u;
+    if (!atoi_clamp(yytext, &u))
+    {
+        if (context->getShaderVersion() >= 300)
+            yyextra->error(*yylloc, "Integer overflow", yytext, "");
+        else
+            yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+    }
+    yylval->lex.i = static_cast<int>(u);
     return INTCONSTANT;
 }
 
 int float_constant(yyscan_t yyscanner) {
     struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
 
     if (!strtof_clamp(yytext, &(yylval->lex.f)))
         yyextra->warning(*yylloc, "Float overflow", yytext, "");
--- a/gfx/angle/src/compiler/translator/glslang_tab.cpp
+++ b/gfx/angle/src/compiler/translator/glslang_tab.cpp
@@ -689,44 +689,44 @@ static const yytype_uint8 yytranslate[] 
      115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
      125,   126,   127
 };
 
 #if YYDEBUG
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   212,   212,   213,   216,   240,   243,   248,   253,   258,
-     263,   269,   272,   275,   278,   281,   284,   290,   298,   309,
-     313,   321,   324,   330,   334,   341,   347,   356,   364,   370,
-     377,   387,   390,   393,   396,   406,   407,   408,   409,   417,
-     418,   421,   424,   431,   432,   435,   441,   442,   446,   453,
-     454,   457,   460,   463,   469,   470,   473,   479,   480,   487,
-     488,   495,   496,   503,   504,   510,   511,   517,   518,   524,
-     525,   531,   532,   540,   541,   542,   543,   547,   548,   549,
-     553,   557,   561,   565,   572,   575,   586,   594,   602,   630,
-     636,   647,   651,   655,   659,   666,   672,   675,   682,   690,
-     711,   738,   748,   776,   781,   791,   796,   806,   809,   812,
-     815,   821,   828,   831,   835,   839,   844,   849,   856,   860,
-     864,   868,   873,   878,   882,   889,   899,   905,   908,   914,
-     920,   927,   936,   946,   954,   957,   964,   968,   972,   977,
-     985,   988,   992,   996,  1005,  1014,  1022,  1032,  1044,  1047,
-    1050,  1056,  1063,  1066,  1072,  1075,  1078,  1084,  1087,  1092,
-    1107,  1111,  1115,  1119,  1123,  1127,  1132,  1137,  1142,  1147,
-    1152,  1157,  1162,  1167,  1172,  1177,  1182,  1187,  1192,  1197,
-    1202,  1207,  1212,  1217,  1222,  1227,  1232,  1236,  1240,  1244,
-    1248,  1252,  1256,  1260,  1264,  1268,  1272,  1276,  1280,  1284,
-    1288,  1292,  1300,  1308,  1312,  1325,  1325,  1328,  1328,  1334,
-    1337,  1353,  1356,  1365,  1369,  1375,  1382,  1397,  1401,  1405,
-    1406,  1412,  1413,  1414,  1415,  1416,  1417,  1418,  1422,  1423,
-    1423,  1423,  1433,  1434,  1438,  1438,  1439,  1439,  1444,  1447,
-    1457,  1460,  1466,  1467,  1471,  1479,  1483,  1490,  1490,  1497,
-    1500,  1507,  1512,  1527,  1527,  1532,  1532,  1539,  1539,  1547,
-    1550,  1556,  1559,  1565,  1569,  1576,  1579,  1582,  1585,  1588,
-    1597,  1601,  1608,  1611,  1617,  1617
+       0,   212,   212,   213,   216,   226,   229,   234,   239,   244,
+     249,   255,   258,   261,   264,   267,   270,   276,   284,   295,
+     299,   307,   310,   316,   320,   327,   333,   342,   350,   356,
+     363,   373,   376,   379,   382,   392,   393,   394,   395,   403,
+     404,   407,   410,   417,   418,   421,   427,   428,   432,   439,
+     440,   443,   446,   449,   455,   456,   459,   465,   466,   473,
+     474,   481,   482,   489,   490,   496,   497,   503,   504,   510,
+     511,   517,   518,   526,   527,   528,   529,   533,   534,   535,
+     539,   543,   547,   551,   558,   561,   567,   575,   583,   611,
+     617,   628,   632,   636,   640,   647,   653,   656,   663,   671,
+     692,   719,   729,   757,   762,   772,   777,   787,   790,   793,
+     796,   802,   809,   812,   816,   820,   825,   830,   837,   841,
+     845,   849,   854,   859,   863,   870,   880,   886,   889,   895,
+     901,   908,   917,   927,   935,   938,   945,   949,   953,   958,
+     966,   969,   973,   977,   986,   995,  1003,  1013,  1025,  1028,
+    1031,  1037,  1044,  1047,  1053,  1056,  1059,  1065,  1068,  1073,
+    1088,  1092,  1096,  1100,  1104,  1108,  1113,  1118,  1123,  1128,
+    1133,  1138,  1143,  1148,  1153,  1158,  1163,  1168,  1173,  1178,
+    1183,  1188,  1193,  1198,  1203,  1208,  1213,  1217,  1221,  1225,
+    1229,  1233,  1237,  1241,  1245,  1249,  1253,  1257,  1261,  1265,
+    1269,  1273,  1281,  1289,  1293,  1306,  1306,  1309,  1309,  1315,
+    1318,  1334,  1337,  1346,  1350,  1356,  1363,  1378,  1382,  1386,
+    1387,  1393,  1394,  1395,  1396,  1397,  1398,  1399,  1403,  1404,
+    1404,  1404,  1414,  1415,  1419,  1419,  1420,  1420,  1425,  1428,
+    1438,  1441,  1447,  1448,  1452,  1460,  1464,  1471,  1471,  1478,
+    1481,  1488,  1493,  1508,  1508,  1513,  1513,  1520,  1520,  1528,
+    1531,  1537,  1540,  1546,  1550,  1557,  1560,  1563,  1566,  1569,
+    1578,  1582,  1589,  1592,  1598,  1598
 };
 #endif
 
 #if YYDEBUG || YYERROR_VERBOSE || 0
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
@@ -2351,31 +2351,17 @@ yyreduce:
   YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
         case 4:
 
     {
         // The symbol table search was done in the lexical phase
-        const TVariable *variable = context->getNamedVariable((yylsp[0]), (yyvsp[0].lex).string, (yyvsp[0].lex).symbol);
-
-        if (variable->getType().getQualifier() == EvqConst)
-        {
-            TConstantUnion* constArray = variable->getConstPointer();
-            TType t(variable->getType());
-            (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yylsp[0]));
-        }
-        else
-        {
-            (yyval.interm.intermTypedNode) = context->intermediate.addSymbol(variable->getUniqueId(),
-                                                 variable->getName(),
-                                                 variable->getType(),
-                                                 (yylsp[0]));
-        }
+        (yyval.interm.intermTypedNode) = context->parseVariableIdentifier((yylsp[0]), (yyvsp[0].lex).string, (yyvsp[0].lex).symbol);
 
         // don't delete $1.string, it's used by error recovery, and the pool
         // pop will reclaim the memory
     }
 
     break;
 
   case 5:
@@ -2559,17 +2545,17 @@ yyreduce:
     break;
 
   case 25:
 
     {
         const TType *type = new TType((yyvsp[0].interm.intermTypedNode)->getType());
         (yyvsp[-1].interm.function)->addParameter(TConstParameter(type));
         (yyval.interm).function = (yyvsp[-1].interm.function);
-        (yyval.interm).nodePair.node1 = (yyvsp[0].interm.intermTypedNode);
+        (yyval.interm).nodePair.node1 = context->intermediate.makeAggregate((yyvsp[0].interm.intermTypedNode), (yylsp[0]));
     }
 
     break;
 
   case 26:
 
     {
         const TType *type = new TType((yyvsp[0].interm.intermTypedNode)->getType());
@@ -3029,22 +3015,17 @@ yyreduce:
         (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
     }
 
     break;
 
   case 85:
 
     {
-        (yyval.interm.intermTypedNode) = context->intermediate.addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
-        if ((yyval.interm.intermTypedNode) == 0) {
-            context->binaryOpError((yylsp[-1]), ",", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString());
-            context->recover();
-            (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
-        }
+        (yyval.interm.intermTypedNode) = context->addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1]));
     }
 
     break;
 
   case 86:
 
     {
         if (context->constErrorCheck((yyvsp[0].interm.intermTypedNode)))
@@ -3576,22 +3557,22 @@ yyreduce:
         (yyval.interm.type).invariant = true;
     }
 
     break;
 
   case 133:
 
     {
-        if ((yyvsp[0].interm.type).qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) {
+        if ((yyvsp[0].interm.type).qualifier != EvqConst && !context->symbolTable.atGlobalLevel())
+        {
             context->error((yylsp[0]), "Local variables can only use the const storage qualifier.", getQualifierString((yyvsp[0].interm.type).qualifier));
             context->recover();
-        } else {
-            (yyval.interm.type).setBasic(EbtVoid, (yyvsp[0].interm.type).qualifier, (yylsp[0]));
         }
+        (yyval.interm.type).setBasic(EbtVoid, (yyvsp[0].interm.type).qualifier, (yylsp[0]));
     }
 
     break;
 
   case 134:
 
     {
         (yyval.interm.type) = context->joinInterpolationQualifiers((yylsp[-1]), (yyvsp[-1].interm.type).qualifier, (yylsp[0]), (yyvsp[0].interm.type).qualifier);
deleted file mode 100644
--- a/gfx/angle/src/compiler/translator/parseConst.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-//
-// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-#include "compiler/translator/ParseContext.h"
-
-//
-// Use this class to carry along data from node to node in
-// the traversal
-//
-class TConstTraverser : public TIntermTraverser
-{
-  public:
-    TConstTraverser(TConstantUnion *cUnion, bool singleConstParam,
-                    TOperator constructType, TInfoSink &sink, TType &t)
-        : TIntermTraverser(true, false, false),
-          error(false),
-          mIndex(0),
-          mUnionArray(cUnion),
-          mType(t),
-          mConstructorType(constructType),
-          mSingleConstantParam(singleConstParam),
-          mInfoSink(sink),
-          mSize(0),
-          mIsDiagonalMatrixInit(false),
-          mMatrixCols(0),
-          mMatrixRows(0)
-    {
-    }
-
-    bool error;
-
-  protected:
-    void visitSymbol(TIntermSymbol *) override;
-    void visitConstantUnion(TIntermConstantUnion *) override;
-    bool visitBinary(Visit visit, TIntermBinary *) override;
-    bool visitUnary(Visit visit, TIntermUnary *) override;
-    bool visitSelection(Visit visit, TIntermSelection *) override;
-    bool visitAggregate(Visit visit, TIntermAggregate *) override;
-    bool visitLoop(Visit visit, TIntermLoop *) override;
-    bool visitBranch(Visit visit, TIntermBranch *) override;
-
-    size_t mIndex;
-    TConstantUnion *mUnionArray;
-    TType mType;
-    TOperator mConstructorType;
-    bool mSingleConstantParam;
-    TInfoSink &mInfoSink;
-    size_t mSize; // size of the constructor ( 4 for vec4)
-    bool mIsDiagonalMatrixInit;
-    int mMatrixCols; // columns of the matrix
-    int mMatrixRows; // rows of the matrix
-};
-
-//
-// The rest of the file are the traversal functions.  The last one
-// is the one that starts the traversal.
-//
-// Return true from interior nodes to have the external traversal
-// continue on to children.  If you process children yourself,
-// return false.
-//
-void TConstTraverser::visitSymbol(TIntermSymbol *node)
-{
-    mInfoSink.info.message(EPrefixInternalError, node->getLine(),
-                           "Symbol Node found in constant constructor");
-    return;
-}
-
-bool TConstTraverser::visitBinary(Visit visit, TIntermBinary *node)
-{
-    TQualifier qualifier = node->getType().getQualifier();
-
-    if (qualifier != EvqConst)
-    {
-        TString buf;
-        buf.append("'constructor' : assigning non-constant to ");
-        buf.append(mType.getCompleteString());
-        mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
-        error = true;
-        return false;
-    }
-
-    mInfoSink.info.message(EPrefixInternalError, node->getLine(),
-                           "Binary Node found in constant constructor");
-    return false;
-}
-
-bool TConstTraverser::visitUnary(Visit visit, TIntermUnary *node)
-{
-    TString buf;
-    buf.append("'constructor' : assigning non-constant to ");
-    buf.append(mType.getCompleteString());
-    mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
-    error = true;
-    return false;
-}
-
-bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
-{
-    if (!node->isConstructor() && node->getOp() != EOpComma)
-    {
-        TString buf;
-        buf.append("'constructor' : assigning non-constant to ");
-        buf.append(mType.getCompleteString());
-        mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
-        error = true;
-        return false;
-    }
-
-    if (node->getSequence()->size() == 0)
-    {
-        error = true;
-        return false;
-    }
-
-    bool flag = node->getSequence()->size() == 1 &&
-                (*node->getSequence())[0]->getAsTyped()->getAsConstantUnion();
-    if (flag)
-    {
-        mSingleConstantParam = true;
-        mConstructorType = node->getOp();
-        mSize = node->getType().getObjectSize();
-
-        if (node->getType().isMatrix())
-        {
-            mIsDiagonalMatrixInit = true;
-            mMatrixCols = node->getType().getCols();
-            mMatrixRows = node->getType().getRows();
-        }
-    }
-
-    for (TIntermSequence::iterator p = node->getSequence()->begin();
-         p != node->getSequence()->end(); p++)
-    {
-        if (node->getOp() == EOpComma)
-            mIndex = 0;
-        (*p)->traverse(this);
-    }
-    if (flag)
-    {
-        mSingleConstantParam = false;
-        mConstructorType = EOpNull;
-        mSize = 0;
-        mIsDiagonalMatrixInit = false;
-        mMatrixCols = 0;
-        mMatrixRows = 0;
-    }
-    return false;
-}
-
-bool TConstTraverser::visitSelection(Visit visit, TIntermSelection *node)
-{
-    mInfoSink.info.message(EPrefixInternalError, node->getLine(),
-                           "Selection Node found in constant constructor");
-    error = true;
-    return false;
-}
-
-void TConstTraverser::visitConstantUnion(TIntermConstantUnion *node)
-{
-    if (!node->getUnionArrayPointer())
-    {
-        // The constant was not initialized, this should already have been logged
-        ASSERT(mInfoSink.info.size() != 0);
-        return;
-    }
-
-    TConstantUnion *leftUnionArray = mUnionArray;
-    size_t instanceSize = mType.getObjectSize();
-    TBasicType basicType = mType.getBasicType();
-
-    if (mIndex >= instanceSize)
-        return;
-
-    if (!mSingleConstantParam)
-    {
-        size_t objectSize = node->getType().getObjectSize();
-        const TConstantUnion *rightUnionArray = node->getUnionArrayPointer();
-        for (size_t i=0; i < objectSize; i++)
-        {
-            if (mIndex >= instanceSize)
-                return;
-            leftUnionArray[mIndex].cast(basicType, rightUnionArray[i]);
-            mIndex++;
-        }
-    }
-    else
-    {
-        size_t totalSize = mIndex + mSize;
-        const TConstantUnion *rightUnionArray = node->getUnionArrayPointer();
-        if (!mIsDiagonalMatrixInit)
-        {
-            int count = 0;
-            for (size_t i = mIndex; i < totalSize; i++)
-            {
-                if (i >= instanceSize)
-                    return;
-                leftUnionArray[i].cast(basicType, rightUnionArray[count]);
-                mIndex++;
-                if (node->getType().getObjectSize() > 1)
-                    count++;
-            }
-        }
-        else
-        {
-            // for matrix diagonal constructors from a single scalar
-            for (int i = 0, col = 0; col < mMatrixCols; col++)
-            {
-                for (int row = 0; row < mMatrixRows; row++, i++)
-                {
-                    if (col == row)
-                    {
-                        leftUnionArray[i].cast(basicType, rightUnionArray[0]);
-                    }
-                    else
-                    {
-                        leftUnionArray[i].setFConst(0.0f);
-                    }
-                    mIndex++;
-                }
-            }
-        }
-    }
-}
-
-bool TConstTraverser::visitLoop(Visit visit, TIntermLoop *node)
-{
-    mInfoSink.info.message(EPrefixInternalError, node->getLine(),
-                           "Loop Node found in constant constructor");
-    error = true;
-    return false;
-}
-
-bool TConstTraverser::visitBranch(Visit visit, TIntermBranch *node)
-{
-    mInfoSink.info.message(EPrefixInternalError, node->getLine(),
-                           "Branch Node found in constant constructor");
-    error = true;
-    return false;
-}
-
-//
-// This function is the one to call externally to start the traversal.
-// Individual functions can be initialized to 0 to skip processing of that
-// type of node.  It's children will still be processed.
-//
-bool TIntermediate::parseConstTree(
-    const TSourceLoc &line, TIntermNode *root, TConstantUnion *unionArray,
-    TOperator constructorType, TType t, bool singleConstantParam)
-{
-    if (root == 0)
-        return false;
-
-    TConstTraverser it(unionArray, singleConstantParam, constructorType,
-                       mInfoSink, t);
-
-    root->traverse(&it);
-    if (it.error)
-        return true;
-    else
-        return false;
-}
--- a/gfx/angle/src/compiler/translator/util.cpp
+++ b/gfx/angle/src/compiler/translator/util.cpp
@@ -15,21 +15,21 @@
 bool strtof_clamp(const std::string &str, float *value)
 {
     bool success = pp::numeric_lex_float(str, value);
     if (!success)
         *value = std::numeric_limits<float>::max();
     return success;
 }
 
-bool atoi_clamp(const char *str, int *value)
+bool atoi_clamp(const char *str, unsigned int *value)
 {
     bool success = pp::numeric_lex_int(str, value);
     if (!success)
-        *value = std::numeric_limits<int>::max();
+        *value = std::numeric_limits<unsigned int>::max();
     return success;
 }
 
 namespace sh
 {
 
 GLenum GLVariableType(const TType &type)
 {
--- a/gfx/angle/src/compiler/translator/util.h
+++ b/gfx/angle/src/compiler/translator/util.h
@@ -15,19 +15,19 @@
 #include "compiler/translator/Types.h"
 
 // strtof_clamp is like strtof but
 //   1. it forces C locale, i.e. forcing '.' as decimal point.
 //   2. it clamps the value to -FLT_MAX or FLT_MAX if overflow happens.
 // Return false if overflow happens.
 bool strtof_clamp(const std::string &str, float *value);
 
-// If overflow happens, clamp the value to INT_MIN or INT_MAX.
+// If overflow happens, clamp the value to UINT_MIN or UINT_MAX.
 // Return false if overflow happens.
-bool atoi_clamp(const char *str, int *value);
+bool atoi_clamp(const char *str, unsigned int *value);
 
 class TSymbolTable;
 
 namespace sh
 {
 
 GLenum GLVariableType(const TType &type);
 GLenum GLVariablePrecision(const TType &type);
--- a/gfx/angle/src/libANGLE/Caps.cpp
+++ b/gfx/angle/src/libANGLE/Caps.cpp
@@ -105,16 +105,19 @@ Extensions::Extensions()
       textureHalfFloat(false),
       textureHalfFloatLinear(false),
       textureFloat(false),
       textureFloatLinear(false),
       textureRG(false),
       textureCompressionDXT1(false),
       textureCompressionDXT3(false),
       textureCompressionDXT5(false),
+      textureCompressionASTCHDR(false),
+      textureCompressionASTCLDR(false),
+      compressedETC1RGB8Texture(false),
       depthTextures(false),
       textureStorage(false),
       textureNPOT(false),
       drawBuffers(false),
       textureFilterAnisotropic(false),
       maxTextureAnisotropy(false),
       occlusionQueryBoolean(false),
       fence(false),
@@ -136,75 +139,80 @@ Extensions::Extensions()
       fboRenderMipmap(false),
       discardFramebuffer(false),
       debugMarker(false),
       eglImage(false),
       eglImageExternal(false),
       eglImageExternalEssl3(false),
       unpackSubimage(false),
       packSubimage(false),
+      vertexArrayObject(false),
       colorBufferFloat(false)
 {
 }
 
 std::vector<std::string> Extensions::getStrings() const
 {
     std::vector<std::string> extensionStrings;
 
     // clang-format off
-    //                   | Extension name                     | Supported flag          | Output vector   |
-    InsertExtensionString("GL_OES_element_index_uint",         elementIndexUint,         &extensionStrings);
-    InsertExtensionString("GL_OES_packed_depth_stencil",       packedDepthStencil,       &extensionStrings);
-    InsertExtensionString("GL_OES_get_program_binary",         getProgramBinary,         &extensionStrings);
-    InsertExtensionString("GL_OES_rgb8_rgba8",                 rgb8rgba8,                &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_format_BGRA8888",    textureFormatBGRA8888,    &extensionStrings);
-    InsertExtensionString("GL_EXT_read_format_bgra",           readFormatBGRA,           &extensionStrings);
-    InsertExtensionString("GL_NV_pixel_buffer_object",         pixelBufferObject,        &extensionStrings);
-    InsertExtensionString("GL_OES_mapbuffer",                  mapBuffer,                &extensionStrings);
-    InsertExtensionString("GL_EXT_map_buffer_range",           mapBufferRange,           &extensionStrings);
-    InsertExtensionString("GL_OES_texture_half_float",         textureHalfFloat,         &extensionStrings);
-    InsertExtensionString("GL_OES_texture_half_float_linear",  textureHalfFloatLinear,   &extensionStrings);
-    InsertExtensionString("GL_OES_texture_float",              textureFloat,             &extensionStrings);
-    InsertExtensionString("GL_OES_texture_float_linear",       textureFloatLinear,       &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_rg",                 textureRG,                &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_compression_dxt1",   textureCompressionDXT1,   &extensionStrings);
-    InsertExtensionString("GL_ANGLE_texture_compression_dxt3", textureCompressionDXT3,   &extensionStrings);
-    InsertExtensionString("GL_ANGLE_texture_compression_dxt5", textureCompressionDXT5,   &extensionStrings);
-    InsertExtensionString("GL_EXT_sRGB",                       sRGB,                     &extensionStrings);
-    InsertExtensionString("GL_ANGLE_depth_texture",            depthTextures,            &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_storage",            textureStorage,           &extensionStrings);
-    InsertExtensionString("GL_OES_texture_npot",               textureNPOT,              &extensionStrings);
-    InsertExtensionString("GL_EXT_draw_buffers",               drawBuffers,              &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_filter_anisotropic", textureFilterAnisotropic, &extensionStrings);
-    InsertExtensionString("GL_EXT_occlusion_query_boolean",    occlusionQueryBoolean,    &extensionStrings);
-    InsertExtensionString("GL_NV_fence",                       fence,                    &extensionStrings);
-    InsertExtensionString("GL_ANGLE_timer_query",              timerQuery,               &extensionStrings);
-    InsertExtensionString("GL_EXT_robustness",                 robustness,               &extensionStrings);
-    InsertExtensionString("GL_EXT_blend_minmax",               blendMinMax,              &extensionStrings);
-    InsertExtensionString("GL_ANGLE_framebuffer_blit",         framebufferBlit,          &extensionStrings);
-    InsertExtensionString("GL_ANGLE_framebuffer_multisample",  framebufferMultisample,   &extensionStrings);
-    InsertExtensionString("GL_ANGLE_instanced_arrays",         instancedArrays,          &extensionStrings);
-    InsertExtensionString("GL_ANGLE_pack_reverse_row_order",   packReverseRowOrder,      &extensionStrings);
-    InsertExtensionString("GL_OES_standard_derivatives",       standardDerivatives,      &extensionStrings);
-    InsertExtensionString("GL_EXT_shader_texture_lod",         shaderTextureLOD,         &extensionStrings);
-    InsertExtensionString("GL_NV_shader_framebuffer_fetch",    NVshaderFramebufferFetch, &extensionStrings);
-    InsertExtensionString("GL_ARM_shader_framebuffer_fetch",   ARMshaderFramebufferFetch,&extensionStrings);
-    InsertExtensionString("GL_EXT_shader_framebuffer_fetch",   shaderFramebufferFetch,   &extensionStrings);
-    InsertExtensionString("GL_EXT_frag_depth",                 fragDepth,                &extensionStrings);
-    InsertExtensionString("GL_ANGLE_texture_usage",            textureUsage,             &extensionStrings);
-    InsertExtensionString("GL_ANGLE_translated_shader_source", translatedShaderSource,   &extensionStrings);
-    InsertExtensionString("GL_OES_fbo_render_mipmap",          fboRenderMipmap,          &extensionStrings);
-    InsertExtensionString("GL_EXT_discard_framebuffer",        discardFramebuffer,       &extensionStrings);
-    InsertExtensionString("GL_EXT_debug_marker",               debugMarker,              &extensionStrings);
-    InsertExtensionString("GL_OES_EGL_image",                  eglImage,                 &extensionStrings);
-    InsertExtensionString("GL_OES_EGL_image_external",         eglImageExternal,         &extensionStrings);
-    InsertExtensionString("GL_OES_EGL_image_external_essl3",   eglImageExternalEssl3,    &extensionStrings);
-    InsertExtensionString("GL_EXT_unpack_subimage",            unpackSubimage,           &extensionStrings);
-    InsertExtensionString("GL_NV_pack_subimage",               packSubimage,             &extensionStrings);
-    InsertExtensionString("GL_EXT_color_buffer_float",         colorBufferFloat,         &extensionStrings);
+    //                   | Extension name                       | Supported flag           | Output vector   |
+    InsertExtensionString("GL_OES_element_index_uint",           elementIndexUint,          &extensionStrings);
+    InsertExtensionString("GL_OES_packed_depth_stencil",         packedDepthStencil,        &extensionStrings);
+    InsertExtensionString("GL_OES_get_program_binary",           getProgramBinary,          &extensionStrings);
+    InsertExtensionString("GL_OES_rgb8_rgba8",                   rgb8rgba8,                 &extensionStrings);
+    InsertExtensionString("GL_EXT_texture_format_BGRA8888",      textureFormatBGRA8888,     &extensionStrings);
+    InsertExtensionString("GL_EXT_read_format_bgra",             readFormatBGRA,            &extensionStrings);
+    InsertExtensionString("GL_NV_pixel_buffer_object",           pixelBufferObject,         &extensionStrings);
+    InsertExtensionString("GL_OES_mapbuffer",                    mapBuffer,                 &extensionStrings);
+    InsertExtensionString("GL_EXT_map_buffer_range",             mapBufferRange,            &extensionStrings);
+    InsertExtensionString("GL_OES_texture_half_float",           textureHalfFloat,          &extensionStrings);
+    InsertExtensionString("GL_OES_texture_half_float_linear",    textureHalfFloatLinear,    &extensionStrings);
+    InsertExtensionString("GL_OES_texture_float",                textureFloat,              &extensionStrings);
+    InsertExtensionString("GL_OES_texture_float_linear",         textureFloatLinear,        &extensionStrings);
+    InsertExtensionString("GL_EXT_texture_rg",                   textureRG,                 &extensionStrings);
+    InsertExtensionString("GL_EXT_texture_compression_dxt1",     textureCompressionDXT1,    &extensionStrings);
+    InsertExtensionString("GL_ANGLE_texture_compression_dxt3",   textureCompressionDXT3,    &extensionStrings);
+    InsertExtensionString("GL_ANGLE_texture_compression_dxt5",   textureCompressionDXT5,    &extensionStrings);
+    InsertExtensionString("GL_KHR_texture_compression_astc_hdr", textureCompressionASTCHDR, &extensionStrings);
+    InsertExtensionString("GL_KHR_texture_compression_astc_ldr", textureCompressionASTCLDR, &extensionStrings);
+    InsertExtensionString("GL_OES_compressed_ETC1_RGB8_texture", compressedETC1RGB8Texture, &extensionStrings);
+    InsertExtensionString("GL_EXT_sRGB",                         sRGB,                      &extensionStrings);
+    InsertExtensionString("GL_ANGLE_depth_texture",              depthTextures,             &extensionStrings);
+    InsertExtensionString("GL_EXT_texture_storage",              textureStorage,            &extensionStrings);
+    InsertExtensionString("GL_OES_texture_npot",                 textureNPOT,               &extensionStrings);
+    InsertExtensionString("GL_EXT_draw_buffers",                 drawBuffers,               &extensionStrings);
+    InsertExtensionString("GL_EXT_texture_filter_anisotropic",   textureFilterAnisotropic,  &extensionStrings);
+    InsertExtensionString("GL_EXT_occlusion_query_boolean",      occlusionQueryBoolean,     &extensionStrings);
+    InsertExtensionString("GL_NV_fence",                         fence,                     &extensionStrings);
+    InsertExtensionString("GL_ANGLE_timer_query",                timerQuery,                &extensionStrings);
+    InsertExtensionString("GL_EXT_robustness",                   robustness,                &extensionStrings);
+    InsertExtensionString("GL_EXT_blend_minmax",                 blendMinMax,               &extensionStrings);
+    InsertExtensionString("GL_ANGLE_framebuffer_blit",           framebufferBlit,           &extensionStrings);
+    InsertExtensionString("GL_ANGLE_framebuffer_multisample",    framebufferMultisample,    &extensionStrings);
+    InsertExtensionString("GL_ANGLE_instanced_arrays",           instancedArrays,           &extensionStrings);
+    InsertExtensionString("GL_ANGLE_pack_reverse_row_order",     packReverseRowOrder,       &extensionStrings);
+    InsertExtensionString("GL_OES_standard_derivatives",         standardDerivatives,       &extensionStrings);
+    InsertExtensionString("GL_EXT_shader_texture_lod",           shaderTextureLOD,          &extensionStrings);
+    InsertExtensionString("GL_NV_shader_framebuffer_fetch",      NVshaderFramebufferFetch,  &extensionStrings);
+    InsertExtensionString("GL_ARM_shader_framebuffer_fetch",     ARMshaderFramebufferFetch, &extensionStrings);
+    InsertExtensionString("GL_EXT_shader_framebuffer_fetch",     shaderFramebufferFetch,    &extensionStrings);
+    InsertExtensionString("GL_EXT_frag_depth",                   fragDepth,                 &extensionStrings);
+    InsertExtensionString("GL_ANGLE_texture_usage",              textureUsage,              &extensionStrings);
+    InsertExtensionString("GL_ANGLE_translated_shader_source",   translatedShaderSource,    &extensionStrings);
+    InsertExtensionString("GL_OES_fbo_render_mipmap",            fboRenderMipmap,           &extensionStrings);
+    InsertExtensionString("GL_EXT_discard_framebuffer",          discardFramebuffer,        &extensionStrings);
+    InsertExtensionString("GL_EXT_debug_marker",                 debugMarker,               &extensionStrings);
+    InsertExtensionString("GL_OES_EGL_image",                    eglImage,                  &extensionStrings);
+    InsertExtensionString("GL_OES_EGL_image_external",           eglImageExternal,          &extensionStrings);
+    InsertExtensionString("GL_OES_EGL_image_external_essl3",     eglImageExternalEssl3,     &extensionStrings);
+    InsertExtensionString("GL_EXT_unpack_subimage",              unpackSubimage,            &extensionStrings);
+    InsertExtensionString("GL_NV_pack_subimage",                 packSubimage,              &extensionStrings);
+    InsertExtensionString("GL_EXT_color_buffer_float",           colorBufferFloat,          &extensionStrings);
+    InsertExtensionString("GL_OES_vertex_array_object",          vertexArrayObject,         &extensionStrings);
     // clang-format on
 
     return extensionStrings;
 }
 
 Limitations::Limitations()
     : noFrontFacingSupport(false),
       noSampleAlphaToCoverageSupport(false),
@@ -352,16 +360,61 @@ static bool DetermineDXT3TextureSupport(
 static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps)
 {
     std::vector<GLenum> requiredFormats;
     requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE);
 
     return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
 }
 
+// Check for GL_KHR_texture_compression_astc_hdr and GL_KHR_texture_compression_astc_ldr
+static bool DetermineASTCTextureSupport(const TextureCapsMap &textureCaps)
+{
+    std::vector<GLenum> requiredFormats;
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_4x4_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_5x4_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_5x5_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_6x5_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_6x6_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_8x5_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_8x6_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_8x8_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x5_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x6_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x8_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x10_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_12x10_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_12x12_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR);
+    requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR);
+
+    return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
+}
+
+// Check for GL_ETC1_RGB8_OES
+static bool DetermineETC1RGB8TextureSupport(const TextureCapsMap &textureCaps)
+{
+    std::vector<GLenum> requiredFormats;
+    requiredFormats.push_back(GL_ETC1_RGB8_OES);
+
+    return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
+}
+
 // Check for GL_ANGLE_texture_compression_dxt5
 static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps)
 {
     std::vector<GLenum> requiredFilterFormats;
     requiredFilterFormats.push_back(GL_SRGB8);
     requiredFilterFormats.push_back(GL_SRGB8_ALPHA8);
 
     std::vector<GLenum> requiredRenderFormats;
@@ -405,16 +458,19 @@ void Extensions::setTextureExtensionSupp
     textureHalfFloat = DetermineHalfFloatTextureSupport(textureCaps);
     textureHalfFloatLinear = DetermineHalfFloatTextureFilteringSupport(textureCaps);
     textureFloat = DetermineFloatTextureSupport(textureCaps);
     textureFloatLinear = DetermineFloatTextureFilteringSupport(textureCaps);
     textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat);
     textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps);
     textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps);
     textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps);
+    textureCompressionASTCHDR = DetermineASTCTextureSupport(textureCaps);
+    textureCompressionASTCLDR = textureCompressionASTCHDR;
+    compressedETC1RGB8Texture = DetermineETC1RGB8TextureSupport(textureCaps);
     sRGB = DetermineSRGBTextureSupport(textureCaps);
     depthTextures = DetermineDepthTextureSupport(textureCaps);
     colorBufferFloat = DetermineColorBufferFloatSupport(textureCaps);
 }
 
 TypePrecision::TypePrecision()
 {
     range[0] = 0;
--- a/gfx/angle/src/libANGLE/Caps.h
+++ b/gfx/angle/src/libANGLE/Caps.h
@@ -75,16 +75,18 @@ struct Extensions
     // Determines support for:
     // GL_OES_packed_depth_stencil
     // GL_OES_rgb8_rgba8
     // GL_EXT_texture_format_BGRA8888
     // GL_OES_texture_half_float, GL_OES_texture_half_float_linear
     // GL_OES_texture_float, GL_OES_texture_float_linear
     // GL_EXT_texture_rg
     // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3, GL_ANGLE_texture_compression_dxt5
+    // GL_KHR_texture_compression_astc_hdr, GL_KHR_texture_compression_astc_ldr
+    // GL_OES_compressed_ETC1_RGB8_texture
     // GL_EXT_sRGB
     // GL_ANGLE_depth_texture
     // GL_EXT_color_buffer_float
     void setTextureExtensionSupport(const TextureCapsMap &textureCaps);
 
     // ES2 Extension support
 
     // GL_OES_element_index_uint
@@ -133,16 +135,26 @@ struct Extensions
 
     // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3 and GL_ANGLE_texture_compression_dxt5
     // Implies that TextureCaps for GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
     // GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE and GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE
     bool textureCompressionDXT1;
     bool textureCompressionDXT3;
     bool textureCompressionDXT5;
 
+    // GL_KHR_texture_compression_astc_hdr
+    bool textureCompressionASTCHDR;
+
+    // GL_KHR_texture_compression_astc_ldr
+    bool textureCompressionASTCLDR;
+
+    // GL_OES_compressed_ETC1_RGB8_texture
+    // Implies that TextureCaps for GL_ETC1_RGB8_OES exist
+    bool compressedETC1RGB8Texture;
+
     // GL_EXT_sRGB
     // Implies that TextureCaps for GL_SRGB8_ALPHA8 and GL_SRGB8 exist
     // TODO: Don't advertise this extension in ES3
     bool sRGB;
 
     // GL_ANGLE_depth_texture
     bool depthTextures;
 
@@ -229,16 +241,19 @@ struct Extensions
     bool eglImageExternalEssl3;
 
     // EXT_unpack_subimage
     bool unpackSubimage;
 
     // NV_pack_subimage
     bool packSubimage;
 
+    // GL_OES_vertex_array_object
+    bool vertexArrayObject;
+
     // ES3 Extension support
 
     // GL_EXT_color_buffer_float
     bool colorBufferFloat;
 };
 
 struct Limitations
 {
--- a/gfx/angle/src/libANGLE/Context.cpp
+++ b/gfx/angle/src/libANGLE/Context.cpp
@@ -33,17 +33,17 @@
 #include "libANGLE/validationES.h"
 #include "libANGLE/renderer/Renderer.h"
 
 namespace
 {
 
 void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback)
 {
-    if (transformFeedback->isActive() && !transformFeedback->isPaused())
+    if (transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
     {
         for (size_t tfBufferIndex = 0; tfBufferIndex < transformFeedback->getIndexedBufferCount();
              tfBufferIndex++)
         {
             const OffsetBindingPointer<gl::Buffer> &buffer =
                 transformFeedback->getIndexedBuffer(tfBufferIndex);
             if (buffer.get() != nullptr)
             {
@@ -58,26 +58,26 @@ namespace gl
 {
 
 Context::Context(const egl::Config *config,
                  int clientVersion,
                  const Context *shareContext,
                  rx::Renderer *renderer,
                  bool notifyResets,
                  bool robustAccess)
-    : mRenderer(renderer),
+    : ValidationContext(clientVersion,
+                        mState,
+                        mCaps,
+                        mTextureCaps,
+                        mExtensions,
+                        nullptr,
+                        mLimitations),
+      mRenderer(renderer),
       mConfig(config),
-      mCurrentSurface(nullptr),
-      mData(reinterpret_cast<uintptr_t>(this),
-            clientVersion,
-            mState,
-            mCaps,
-            mTextureCaps,
-            mExtensions,
-            nullptr)
+      mCurrentSurface(nullptr)
 {
     ASSERT(robustAccess == false);   // Unimplemented
 
     initCaps(clientVersion);
     mState.initialize(mCaps, clientVersion);
 
     mClientVersion = clientVersion;
 
@@ -133,22 +133,26 @@ Context::Context(const egl::Config *conf
         bindIndexedUniformBuffer(0, i, 0, -1);
     }
 
     bindCopyReadBuffer(0);
     bindCopyWriteBuffer(0);
     bindPixelPackBuffer(0);
     bindPixelUnpackBuffer(0);
 
-    // [OpenGL ES 3.0.2] section 2.14.1 pg 85:
-    // In the initial state, a default transform feedback object is bound and treated as
-    // a transform feedback object with a name of zero. That object is bound any time
-    // BindTransformFeedback is called with id of zero
-    mTransformFeedbackZero.set(new TransformFeedback(mRenderer->createTransformFeedback(), 0, mCaps));
-    bindTransformFeedback(0);
+    if (mClientVersion >= 3)
+    {
+        // [OpenGL ES 3.0.2] section 2.14.1 pg 85:
+        // In the initial state, a default transform feedback object is bound and treated as
+        // a transform feedback object with a name of zero. That object is bound any time
+        // BindTransformFeedback is called with id of zero
+        mTransformFeedbackZero.set(
+            new TransformFeedback(mRenderer->createTransformFeedback(), 0, mCaps));
+        bindTransformFeedback(0);
+    }
 
     mHasBeenCurrent = false;
     mContextLost = false;
     mResetStatus = GL_NO_ERROR;
     mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT);
     mRobustAccess = robustAccess;
 
     mCompiler = new Compiler(mRenderer, getData());
@@ -183,17 +187,17 @@ Context::~Context()
     for (auto vertexArray : mVertexArrayMap)
     {
         SafeDelete(vertexArray.second);
     }
 
     mTransformFeedbackZero.set(NULL);
     for (auto transformFeedback : mTransformFeedbackMap)
     {
-        SafeDelete(transformFeedback.second);
+        transformFeedback.second->release();
     }
 
     for (auto &zeroTexture : mZeroTextures)
     {
         zeroTexture.second.set(NULL);
     }
     mZeroTextures.clear();
 
@@ -1098,36 +1102,16 @@ bool Context::getQueryParameterInfo(GLen
                 *numParams = 1;
             }
             else
             {
                 return false;
             }
         }
         return true;
-        case GL_PACK_ROW_LENGTH:
-        case GL_PACK_SKIP_ROWS:
-        case GL_PACK_SKIP_PIXELS:
-            if ((mClientVersion < 3) && !mExtensions.packSubimage)
-            {
-                return false;
-            }
-            *type      = GL_INT;
-            *numParams = 1;
-            return true;
-        case GL_UNPACK_ROW_LENGTH:
-        case GL_UNPACK_SKIP_ROWS:
-        case GL_UNPACK_SKIP_PIXELS:
-            if ((mClientVersion < 3) && !mExtensions.unpackSubimage)
-            {
-                return false;
-            }
-            *type      = GL_INT;
-            *numParams = 1;
-            return true;
       case GL_MAX_VIEWPORT_DIMS:
         {
             *type = GL_INT;
             *numParams = 2;
         }
         return true;
       case GL_VIEWPORT:
       case GL_SCISSOR_BOX:
@@ -1190,16 +1174,49 @@ bool Context::getQueryParameterInfo(GLen
         {
             return false;
         }
         *type = GL_FLOAT;
         *numParams = 1;
         return true;
     }
 
+    // Check for ES3.0+ parameter names which are also exposed as ES2 extensions
+    switch (pname)
+    {
+        case GL_PACK_ROW_LENGTH:
+        case GL_PACK_SKIP_ROWS:
+        case GL_PACK_SKIP_PIXELS:
+            if ((mClientVersion < 3) && !mExtensions.packSubimage)
+            {
+                return false;
+            }
+            *type      = GL_INT;
+            *numParams = 1;
+            return true;
+        case GL_UNPACK_ROW_LENGTH:
+        case GL_UNPACK_SKIP_ROWS:
+        case GL_UNPACK_SKIP_PIXELS:
+            if ((mClientVersion < 3) && !mExtensions.unpackSubimage)
+            {
+                return false;
+            }
+            *type      = GL_INT;
+            *numParams = 1;
+            return true;
+        case GL_VERTEX_ARRAY_BINDING:
+            if ((mClientVersion < 3) && !mExtensions.vertexArrayObject)
+            {
+                return false;
+            }
+            *type      = GL_INT;
+            *numParams = 1;
+            return true;
+    }
+
     if (mClientVersion < 3)
     {
         return false;
     }
 
     // Check for ES3.0+ parameter names
     switch (pname)
     {
@@ -1215,37 +1232,30 @@ bool Context::getQueryParameterInfo(GLen
       case GL_MAX_3D_TEXTURE_SIZE:
       case GL_MAX_ARRAY_TEXTURE_LAYERS:
       case GL_MAX_VERTEX_UNIFORM_BLOCKS:
       case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
       case GL_MAX_COMBINED_UNIFORM_BLOCKS:
       case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
       case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
       case GL_MAX_VARYING_COMPONENTS:
-      case GL_VERTEX_ARRAY_BINDING:
       case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
       case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
       case GL_MIN_PROGRAM_TEXEL_OFFSET:
       case GL_MAX_PROGRAM_TEXEL_OFFSET:
       case GL_NUM_EXTENSIONS:
       case GL_MAJOR_VERSION:
       case GL_MINOR_VERSION:
       case GL_MAX_ELEMENTS_INDICES:
       case GL_MAX_ELEMENTS_VERTICES:
       case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
       case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
       case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
-      case GL_PACK_ROW_LENGTH:
-      case GL_PACK_SKIP_ROWS:
-      case GL_PACK_SKIP_PIXELS:
-      case GL_UNPACK_ROW_LENGTH:
       case GL_UNPACK_IMAGE_HEIGHT:
       case GL_UNPACK_SKIP_IMAGES:
-      case GL_UNPACK_SKIP_ROWS:
-      case GL_UNPACK_SKIP_PIXELS:
         {
             *type = GL_INT;
             *numParams = 1;
         }
         return true;
 
       case GL_MAX_ELEMENT_INDEX:
       case GL_MAX_UNIFORM_BLOCK_SIZE:
@@ -1255,16 +1265,17 @@ bool Context::getQueryParameterInfo(GLen
         {
             *type = GL_INT_64_ANGLEX;
             *numParams = 1;
         }
         return true;
 
       case GL_TRANSFORM_FEEDBACK_ACTIVE:
       case GL_TRANSFORM_FEEDBACK_PAUSED:
+      case GL_PRIMITIVE_RESTART_FIXED_INDEX:
         {
             *type = GL_BOOL;
             *numParams = 1;
         }
         return true;
 
       case GL_MAX_TEXTURE_LOD_BIAS:
         {
@@ -1449,21 +1460,16 @@ GLenum Context::getResetStatus()
     return status;
 }
 
 bool Context::isResetNotificationEnabled()
 {
     return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT);
 }
 
-int Context::getClientVersion() const
-{
-    return mClientVersion;
-}
-
 const egl::Config *Context::getConfig() const
 {
     return mConfig;
 }
 
 EGLenum Context::getClientType() const
 {
     return mClientType;
@@ -1481,36 +1487,16 @@ EGLenum Context::getRenderBuffer() const
         return backAttachment->getSurface()->getRenderBuffer();
     }
     else
     {
         return EGL_NONE;
     }
 }
 
-const Caps &Context::getCaps() const
-{
-    return mCaps;
-}
-
-const TextureCapsMap &Context::getTextureCaps() const
-{
-    return mTextureCaps;
-}
-
-const Extensions &Context::getExtensions() const
-{
-    return mExtensions;
-}
-
-const Limitations &Context::getLimitations() const
-{
-    return mLimitations;
-}
-
 void Context::detachTexture(GLuint texture)
 {
     // Simple pass-through to State's detachTexture method, as textures do not require
     // allocation map management either here or in the resource manager at detach time.
     // Zero textures are held by the Context, and we don't attempt to request them from
     // the State.
     mState.detachTexture(mZeroTextures, texture);
 }
--- a/gfx/angle/src/libANGLE/Context.h
+++ b/gfx/angle/src/libANGLE/Context.h
@@ -50,17 +50,17 @@ class FenceSync;
 class Query;
 class ResourceManager;
 class Buffer;
 struct VertexAttribute;
 class VertexArray;
 class Sampler;
 class TransformFeedback;
 
-class Context final : angle::NonCopyable
+class Context final : public ValidationContext
 {
   public:
     Context(const egl::Config *config, int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess);
 
     virtual ~Context();
 
     void makeCurrent(egl::Surface *surface);
     void releaseSurface();
@@ -188,45 +188,36 @@ class Context final : angle::NonCopyable
 
     Error flush();
     Error finish();
 
     void insertEventMarker(GLsizei length, const char *marker);
     void pushGroupMarker(GLsizei length, const char *marker);
     void popGroupMarker();
 
-    void recordError(const Error &error);
+    void recordError(const Error &error) override;
 
     GLenum getError();
     GLenum getResetStatus();
     virtual bool isResetNotificationEnabled();
 
-    virtual int getClientVersion() const;
-
     const egl::Config *getConfig() const;
     EGLenum getClientType() const;
     EGLenum getRenderBuffer() const;
 
-    const Caps &getCaps() const;
-    const TextureCapsMap &getTextureCaps() const;
-    const Extensions &getExtensions() const;
-    const Limitations &getLimitations() const;
-
     const std::string &getRendererString() const;
 
     const std::string &getExtensionString() const;
     const std::string &getExtensionString(size_t idx) const;
     size_t getExtensionStringCount() const;
 
     rx::Renderer *getRenderer() { return mRenderer; }
 
     State &getState() { return mState; }
-    const State &getState() const { return mState; }
 
-    const Data &getData() const { return mData; }
     void syncRendererState();
     void syncRendererState(const State::DirtyBits &bitMask);
 
   private:
     void detachBuffer(GLuint buffer);
     void detachTexture(GLuint texture);
     void detachFramebuffer(GLuint framebuffer);
     void detachRenderbuffer(GLuint renderbuffer);
@@ -291,16 +282,13 @@ class Context final : angle::NonCopyable
     bool mHasBeenCurrent;
     bool mContextLost;
     GLenum mResetStatus;
     GLenum mResetStrategy;
     bool mRobustAccess;
     egl::Surface *mCurrentSurface;
 
     ResourceManager *mResourceManager;
-
-    // Cache the Data object to avoid re-calling the constructor
-    Data mData;
 };
 
 }
 
 #endif   // LIBANGLE_CONTEXT_H_
--- a/gfx/angle/src/libANGLE/Data.cpp
+++ b/gfx/angle/src/libANGLE/Data.cpp
@@ -13,23 +13,42 @@ namespace gl
 {
 
 Data::Data(uintptr_t contextIn,
            GLint clientVersionIn,
            const State &stateIn,
            const Caps &capsIn,
            const TextureCapsMap &textureCapsIn,
            const Extensions &extensionsIn,
-           const ResourceManager *resourceManagerIn)
+           const ResourceManager *resourceManagerIn,
+           const Limitations &limitationsIn)
     : context(contextIn),
       clientVersion(clientVersionIn),
       state(&stateIn),
       caps(&capsIn),
       textureCaps(&textureCapsIn),
       extensions(&extensionsIn),
-      resourceManager(resourceManagerIn)
+      resourceManager(resourceManagerIn),
+      limitations(&limitationsIn)
 {}
 
 Data::~Data()
 {
 }
 
+ValidationContext::ValidationContext(GLint clientVersion,
+                                     const State &state,
+                                     const Caps &caps,
+                                     const TextureCapsMap &textureCaps,
+                                     const Extensions &extensions,
+                                     const ResourceManager *resourceManager,
+                                     const Limitations &limitations)
+    : mData(reinterpret_cast<uintptr_t>(this),
+            clientVersion,
+            state,
+            caps,
+            textureCaps,
+            extensions,
+            resourceManager,
+            limitations)
+{
 }
+}
--- a/gfx/angle/src/libANGLE/Data.h
+++ b/gfx/angle/src/libANGLE/Data.h
@@ -19,23 +19,51 @@ struct Data final : public angle::NonCop
 {
   public:
     Data(uintptr_t context,
          GLint clientVersion,
          const State &state,
          const Caps &caps,
          const TextureCapsMap &textureCaps,
          const Extensions &extensions,
-         const ResourceManager *resourceManager);
+         const ResourceManager *resourceManager,
+         const Limitations &limitations);
     ~Data();
 
     uintptr_t context;
     GLint clientVersion;
     const State *state;
     const Caps *caps;
     const TextureCapsMap *textureCaps;
     const Extensions *extensions;
     const ResourceManager *resourceManager;
+    const Limitations *limitations;
+};
+
+class ValidationContext : angle::NonCopyable
+{
+  public:
+    ValidationContext(GLint clientVersion,
+                      const State &state,
+                      const Caps &caps,
+                      const TextureCapsMap &textureCaps,
+                      const Extensions &extensions,
+                      const ResourceManager *resourceManager,
+                      const Limitations &limitations);
+    virtual ~ValidationContext() {}
+
+    virtual void recordError(const Error &error) = 0;
+
+    const Data &getData() const { return mData; }
+    int getClientVersion() const { return mData.clientVersion; }
+    const State &getState() const { return *mData.state; }
+    const Caps &getCaps() const { return *mData.caps; }
+    const TextureCapsMap &getTextureCaps() const { return *mData.textureCaps; }
+    const Extensions &getExtensions() const { return *mData.extensions; }
+    const Limitations &getLimitations() const { return *mData.limitations; }
+
+  protected:
+    Data mData;
 };
 
 }
 
 #endif // LIBANGLE_DATA_H_
--- a/gfx/angle/src/libANGLE/Device.cpp
+++ b/gfx/angle/src/libANGLE/Device.cpp
@@ -40,17 +40,20 @@ Device::Device(Display *display, rx::Dev
 
 Device::~Device()
 {
 
 }
 
 Error Device::getDevice(EGLAttrib *value)
 {
-    return getImplementation()->getDevice(value);
+    void *nativeDevice = nullptr;
+    egl::Error error = getImplementation()->getDevice(&nativeDevice);
+    *value = reinterpret_cast<EGLAttrib>(nativeDevice);
+    return error;
 }
 
 EGLint Device::getType()
 {
     return getImplementation()->getType();
 }
 
 void Device::initDeviceExtensions()
--- a/gfx/angle/src/libANGLE/Error.cpp
+++ b/gfx/angle/src/libANGLE/Error.cpp
@@ -36,16 +36,33 @@ void Error::createMessageString() const
 }
 
 const std::string &Error::getMessage() const
 {
     createMessageString();
     return *mMessage;
 }
 
+bool Error::operator==(const Error &other) const
+{
+    if (mCode != other.mCode)
+        return false;
+
+    // TODO(jmadill): Compare extended error codes instead of strings.
+    if ((mMessage == nullptr || other.mMessage == nullptr) &&
+        ((mMessage == nullptr) != (other.mMessage == nullptr)))
+        return false;
+
+    return (*mMessage == *other.mMessage);
+}
+
+bool Error::operator!=(const Error &other) const
+{
+    return !(*this == other);
+}
 }
 
 namespace egl
 {
 
 Error::Error(EGLint errorCode, const char *msg, ...)
     : mCode(errorCode),
       mID(0),
--- a/gfx/angle/src/libANGLE/Error.h
+++ b/gfx/angle/src/libANGLE/Error.h
@@ -30,16 +30,20 @@ class Error final
     inline Error &operator=(const Error &other);
     inline Error &operator=(Error &&other);
 
     inline GLenum getCode() const;
     inline bool isError() const;
 
     const std::string &getMessage() const;
 
+    // Useful for mocking and testing
+    bool operator==(const Error &other) const;
+    bool operator!=(const Error &other) const;
+
   private:
     void createMessageString() const;
 
     GLenum mCode;
     mutable std::string *mMessage;
 };
 
 }
--- a/gfx/angle/src/libANGLE/Platform.cpp
+++ b/gfx/angle/src/libANGLE/Platform.cpp
@@ -11,25 +11,25 @@
 #include "common/debug.h"
 
 namespace
 {
 angle::Platform *currentPlatform = nullptr;
 }
 
 // static
-ANGLE_EXPORT angle::Platform *ANGLEPlatformCurrent()
+angle::Platform *ANGLE_APIENTRY ANGLEPlatformCurrent()
 {
     return currentPlatform;
 }
 
 // static
-ANGLE_EXPORT void ANGLEPlatformInitialize(angle::Platform *platformImpl)
+void ANGLE_APIENTRY ANGLEPlatformInitialize(angle::Platform *platformImpl)
 {
     ASSERT(platformImpl != nullptr);
     currentPlatform = platformImpl;
 }
 
 // static
-ANGLE_EXPORT void ANGLEPlatformShutdown()
+void ANGLE_APIENTRY ANGLEPlatformShutdown()
 {
     currentPlatform = nullptr;
 }
--- a/gfx/angle/src/libANGLE/Program.cpp
+++ b/gfx/angle/src/libANGLE/Program.cpp
@@ -217,30 +217,20 @@ VariableLocation::VariableLocation()
 
 VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
     : name(name),
       element(element),
       index(index)
 {
 }
 
-LinkedVarying::LinkedVarying()
-{
-}
-
-LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
-                             unsigned int semanticIndex, unsigned int semanticIndexCount)
-    : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
-{
-}
-
 Program::Data::Data()
     : mAttachedFragmentShader(nullptr),
       mAttachedVertexShader(nullptr),
-      mTransformFeedbackBufferMode(GL_NONE)
+      mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS)
 {
 }
 
 Program::Data::~Data()
 {
     if (mAttachedVertexShader != nullptr)
     {
         mAttachedVertexShader->release();
@@ -1677,17 +1667,18 @@ void Program::indexUniforms()
                     uniform.name, arrayIndex, static_cast<unsigned int>(uniformIndex)));
             }
         }
     }
 }
 
 bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
 {
-    if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
+    // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
+    if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
     {
         return false;
     }
 
     if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
     {
         infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
         return false;
@@ -2009,16 +2000,22 @@ bool Program::linkValidateTransformFeedb
                 if (uniqueNames.count(tfVaryingName) > 0)
                 {
                     infoLog << "Two transform feedback varyings specify the same output variable ("
                             << tfVaryingName << ").";
                     return false;
                 }
                 uniqueNames.insert(tfVaryingName);
 
+                if (varying->isArray())
+                {
+                    infoLog << "Capture of arrays is undefined and not supported.";
+                    return false;
+                }
+
                 // TODO(jmadill): Investigate implementation limits on D3D11
                 size_t componentCount = gl::VariableComponentCount(varying->type);
                 if (mData.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
                     componentCount > caps.maxTransformFeedbackSeparateComponents)
                 {
                     infoLog << "Transform feedback varying's " << varying->name << " components ("
                             << componentCount << ") exceed the maximum separate components ("
                             << caps.maxTransformFeedbackSeparateComponents << ").";
@@ -2026,20 +2023,19 @@ bool Program::linkValidateTransformFeedb
                 }
 
                 totalComponents += componentCount;
                 found = true;
                 break;
             }
         }
 
-        // TODO(jmadill): investigate if we can support capturing array elements.
         if (tfVaryingName.find('[') != std::string::npos)
         {
-            infoLog << "Capture of array elements not currently supported.";
+            infoLog << "Capture of array elements is undefined and not supported.";
             return false;
         }
 
         // All transform feedback varyings are expected to exist since packVaryings checks for them.
         ASSERT(found);
         UNUSED_ASSERTION_VARIABLE(found);
     }
 
@@ -2240,17 +2236,21 @@ Program::VectorAndSamplerCount Program::
         }
         else
         {
             mData.mUniforms.push_back(linkedUniform);
         }
     }
 
     unsigned int elementCount          = uniform.elementCount();
-    vectorAndSamplerCount.vectorCount  = (VariableRegisterCount(uniform.type) * elementCount);
+
+    // Samplers aren't "real" uniforms, so they don't count towards register usage.
+    // Likewise, don't count "real" uniforms towards sampler count.
+    vectorAndSamplerCount.vectorCount =
+        (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
     vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
 
     return vectorAndSamplerCount;
 }
 
 void Program::gatherInterfaceBlockInfo()
 {
     std::set<std::string> visitedList;
--- a/gfx/angle/src/libANGLE/Program.h
+++ b/gfx/angle/src/libANGLE/Program.h
@@ -138,34 +138,16 @@ struct VariableLocation
     VariableLocation();
     VariableLocation(const std::string &name, unsigned int element, unsigned int index);
 
     std::string name;
     unsigned int element;
     unsigned int index;
 };
 
-struct LinkedVarying
-{
-    LinkedVarying();
-    LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
-        unsigned int semanticIndex, unsigned int semanticIndexCount);
-
-    // Original GL name
-    std::string name;
-
-    GLenum type;
-    GLsizei size;
-
-    // DirectX semantic information
-    std::string semanticName;
-    unsigned int semanticIndex;
-    unsigned int semanticIndexCount;
-};
-
 class Program : angle::NonCopyable
 {
   public:
     class Data final : angle::NonCopyable
     {
       public:
         Data();
         ~Data();
--- a/gfx/angle/src/libANGLE/RefCountObject.h
+++ b/gfx/angle/src/libANGLE/RefCountObject.h
@@ -71,16 +71,23 @@ class BindingPointer
         mObject = newObject;
     }
 
     ObjectType *get() const { return mObject; }
     ObjectType *operator->() const { return mObject; }
 
     GLuint id() const { return (mObject != nullptr) ? mObject->id() : 0; }
 
+    bool operator==(const BindingPointer<ObjectType> &other) const
+    {
+        return mObject == other.mObject;
+    }
+
+    bool operator!=(const BindingPointer<ObjectType> &other) const { return !(*this == other); }
+
   private:
     ObjectType *mObject;
 };
 
 template <class ObjectType>
 class OffsetBindingPointer : public BindingPointer<ObjectType>
 {
   public:
@@ -98,14 +105,24 @@ class OffsetBindingPointer : public Bind
         BindingPointer<ObjectType>::set(newObject);
         mOffset = offset;
         mSize = size;
     }
 
     GLintptr getOffset() const { return mOffset; }
     GLsizeiptr getSize() const { return mSize; }
 
+    bool operator==(const OffsetBindingPointer<ObjectType> &other) const
+    {
+        return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize;
+    }
+
+    bool operator!=(const OffsetBindingPointer<ObjectType> &other) const
+    {
+        return !(*this == other);
+    }
+
   private:
     GLintptr mOffset;
     GLsizeiptr mSize;
 };
 
 #endif   // LIBANGLE_REFCOUNTOBJECT_H_
--- a/gfx/angle/src/libANGLE/Shader.cpp
+++ b/gfx/angle/src/libANGLE/Shader.cpp
@@ -43,18 +43,20 @@ std::vector<VarT> GetActiveShaderVariabl
 
 template <typename VarT>
 const std::vector<VarT> &GetShaderVariables(const std::vector<VarT> *variableList)
 {
     ASSERT(variableList);
     return *variableList;
 }
 
+}  // anonymous namespace
+
 // true if varying x has a higher priority in packing than y
-bool CompareVarying(const sh::Varying &x, const sh::Varying &y)
+bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y)
 {
     if (x.type == y.type)
     {
         return x.arraySize > y.arraySize;
     }
 
     // Special case for handling structs: we sort these to the end of the list
     if (x.type == GL_STRUCT_ANGLEX)
@@ -65,18 +67,16 @@ bool CompareVarying(const sh::Varying &x
     if (y.type == GL_STRUCT_ANGLEX)
     {
         return true;
     }
 
     return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
 }
 
-}  // anonymous namespace
-
 Shader::Data::Data(GLenum shaderType) : mShaderType(shaderType), mShaderVersion(100)
 {
 }
 
 Shader::Data::~Data()
 {
 }
 
@@ -165,16 +165,27 @@ int Shader::getTranslatedSourceLength() 
     if (mData.mTranslatedSource.empty())
     {
         return 0;
     }
 
     return (static_cast<int>(mData.mTranslatedSource.length()) + 1);
 }
 
+int Shader::getTranslatedSourceWithDebugInfoLength() const
+{
+    const std::string &debugInfo = mImplementation->getDebugInfo();
+    if (debugInfo.empty())
+    {
+        return 0;
+    }
+
+    return (static_cast<int>(debugInfo.length()) + 1);
+}
+
 void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer)
 {
     int index = 0;
 
     if (bufSize > 0)
     {
         index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
         memcpy(buffer, source.c_str(), index);
@@ -195,17 +206,17 @@ void Shader::getSource(GLsizei bufSize, 
 
 void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const
 {
     getSourceImpl(mData.mTranslatedSource, bufSize, length, buffer);
 }
 
 void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const
 {
-    std::string debugInfo(mImplementation->getDebugInfo());
+    const std::string &debugInfo = mImplementation->getDebugInfo();
     getSourceImpl(debugInfo, bufSize, length, buffer);
 }
 
 void Shader::compile(Compiler *compiler)
 {
     mData.mTranslatedSource.clear();
     mInfoLog.clear();
     mData.mShaderVersion = 100;
@@ -214,30 +225,41 @@ void Shader::compile(Compiler *compiler)
     mData.mInterfaceBlocks.clear();
     mData.mActiveAttributes.clear();
     mData.mActiveOutputVariables.clear();
 
     ShHandle compilerHandle = compiler->getCompilerHandle(mData.mShaderType);
 
     std::stringstream sourceStream;
 
-    int additionalOptions = mImplementation->prepareSourceAndReturnOptions(&sourceStream);
+    std::string sourcePath;
+    int additionalOptions =
+        mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath);
     int compileOptions    = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
 
     // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
     // in fragment shaders. Shader compilation will fail. To provide a better error message we can
     // instruct the compiler to pre-validate.
     if (mRendererLimitations.shadersRequireIndexedLoopValidation)
     {
         compileOptions |= SH_VALIDATE_LOOP_INDEXING;
     }
 
     std::string sourceString  = sourceStream.str();
-    const char *sourceCString = sourceString.c_str();
-    bool result               = ShCompile(compilerHandle, &sourceCString, 1, compileOptions);
+    std::vector<const char *> sourceCStrings;
+
+    if (!sourcePath.empty())
+    {
+        sourceCStrings.push_back(sourcePath.c_str());
+    }
+
+    sourceCStrings.push_back(sourceString.c_str());
+
+    bool result =
+        ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions);
 
     if (!result)
     {
         mInfoLog = ShGetInfoLog(compilerHandle);
         TRACE("\n%s", mInfoLog.c_str());
         mCompiled = false;
         return;
     }
@@ -277,17 +299,17 @@ void Shader::compile(Compiler *compiler)
     {
         mData.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle));
     }
     else
     {
         ASSERT(mData.mShaderType == GL_FRAGMENT_SHADER);
 
         // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
-        std::sort(mData.mVaryings.begin(), mData.mVaryings.end(), CompareVarying);
+        std::sort(mData.mVaryings.begin(), mData.mVaryings.end(), CompareShaderVar);
         mData.mActiveOutputVariables =
             GetActiveShaderVariables(ShGetOutputVariables(compilerHandle));
     }
 
     ASSERT(!mData.mTranslatedSource.empty());
 
     mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog);
 }
--- a/gfx/angle/src/libANGLE/Shader.h
+++ b/gfx/angle/src/libANGLE/Shader.h
@@ -93,16 +93,17 @@ class Shader : angle::NonCopyable
 
     void deleteSource();
     void setSource(GLsizei count, const char *const *string, const GLint *length);
     int getInfoLogLength() const;
     void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
     int getSourceLength() const;
     void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const;
     int getTranslatedSourceLength() const;
+    int getTranslatedSourceWithDebugInfoLength() const;
     const std::string &getTranslatedSource() const { return mData.getTranslatedSource(); }
     void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const;
     void getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const;
 
     void compile(Compiler *compiler);
     bool isCompiled() const { return mCompiled; }
 
     void addRef();
@@ -132,11 +133,12 @@ class Shader : angle::NonCopyable
     unsigned int mRefCount;     // Number of program objects this shader is attached to
     bool mDeleteStatus;         // Flag to indicate that the shader can be deleted when no longer in use
     bool mCompiled;             // Indicates if this shader has been successfully compiled
     std::string mInfoLog;
 
     ResourceManager *mResourceManager;
 };
 
+bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y);
 }
 
 #endif   // LIBANGLE_SHADER_H_
--- a/gfx/angle/src/libANGLE/State.cpp
+++ b/gfx/angle/src/libANGLE/State.cpp
@@ -15,20 +15,38 @@
 #include "libANGLE/Query.h"
 #include "libANGLE/VertexArray.h"
 #include "libANGLE/formatutils.h"
 
 namespace gl
 {
 
 State::State()
+    : mMaxDrawBuffers(0),
+      mMaxCombinedTextureImageUnits(0),
+      mDepthClearValue(0),
+      mStencilClearValue(0),
+      mScissorTest(false),
+      mSampleCoverage(false),
+      mSampleCoverageValue(0),
+      mSampleCoverageInvert(false),
+      mStencilRef(0),
+      mStencilBackRef(0),
+      mLineWidth(0),
+      mGenerateMipmapHint(GL_NONE),
+      mFragmentShaderDerivativeHint(GL_NONE),
+      mNearZ(0),
+      mFarZ(0),
+      mReadFramebuffer(nullptr),
+      mDrawFramebuffer(nullptr),
+      mProgram(nullptr),
+      mVertexArray(nullptr),
+      mActiveSampler(0),
+      mPrimitiveRestart(false)
 {
-    mMaxDrawBuffers = 0;
-    mMaxCombinedTextureImageUnits = 0;
-
     // Initialize dirty bit masks
     // TODO(jmadill): additional ES3 state
     mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ALIGNMENT);
     mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ROW_LENGTH);
     mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_IMAGE_HEIGHT);
     mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_IMAGES);
     mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_ROWS);
     mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_PIXELS);
@@ -1260,16 +1278,19 @@ void State::getBooleanv(GLenum pname, GL
       case GL_SAMPLE_COVERAGE:           *params = mSampleCoverage;               break;
       case GL_SCISSOR_TEST:              *params = mScissorTest;                  break;
       case GL_STENCIL_TEST:              *params = mDepthStencil.stencilTest;     break;
       case GL_DEPTH_TEST:                *params = mDepthStencil.depthTest;       break;
       case GL_BLEND:                     *params = mBlend.blend;                  break;
       case GL_DITHER:                    *params = mBlend.dither;                 break;
       case GL_TRANSFORM_FEEDBACK_ACTIVE: *params = getCurrentTransformFeedback()->isActive() ? GL_TRUE : GL_FALSE; break;
       case GL_TRANSFORM_FEEDBACK_PAUSED: *params = getCurrentTransformFeedback()->isPaused() ? GL_TRUE : GL_FALSE; break;
+      case GL_PRIMITIVE_RESTART_FIXED_INDEX:
+          *params = mPrimitiveRestart;
+          break;
       default:
         UNREACHABLE();
         break;
     }
 }
 
 void State::getFloatv(GLenum pname, GLfloat *params)
 {
@@ -1499,16 +1520,19 @@ void State::getIntegerv(const gl::Data &
       case GL_TEXTURE_BINDING_2D_ARRAY:
         ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits);
         *params =
             getSamplerTextureId(static_cast<unsigned int>(mActiveSampler), GL_TEXTURE_2D_ARRAY);
         break;
       case GL_UNIFORM_BUFFER_BINDING:
         *params = mGenericUniformBuffer.id();
         break;
+      case GL_TRANSFORM_FEEDBACK_BINDING:
+        *params = mTransformFeedback->id();
+        break;
       case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
         *params = mTransformFeedback->getGenericBuffer().id();
         break;
       case GL_COPY_READ_BUFFER_BINDING:
         *params = mCopyReadBuffer.id();
         break;
       case GL_COPY_WRITE_BUFFER_BINDING:
         *params = mCopyWriteBuffer.id();
--- a/gfx/angle/src/libANGLE/Surface_unittest.cpp
+++ b/gfx/angle/src/libANGLE/Surface_unittest.cpp
@@ -7,19 +7,21 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "libANGLE/angletypes.h"
 #include "libANGLE/AttributeMap.h"
 #include "libANGLE/Config.h"
 #include "libANGLE/Data.h"
 #include "libANGLE/State.h"
 #include "libANGLE/Surface.h"
-#include "libANGLE/renderer/FramebufferImpl.h"
+#include "libANGLE/renderer/FramebufferImpl_mock.h"
 #include "libANGLE/renderer/SurfaceImpl.h"
 
+using namespace rx;
+
 namespace
 {
 
 class MockSurfaceImpl : public rx::SurfaceImpl
 {
   public:
     virtual ~MockSurfaceImpl() { destroy(); }
 
@@ -36,59 +38,16 @@ class MockSurfaceImpl : public rx::Surfa
     MOCK_CONST_METHOD0(getHeight, EGLint());
     MOCK_CONST_METHOD0(isPostSubBufferSupported, EGLint(void));
     MOCK_CONST_METHOD0(getSwapBehavior, EGLint(void));
     MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, rx::FramebufferAttachmentRenderTarget **));
 
     MOCK_METHOD0(destroy, void());
 };
 
-class MockFramebufferImpl : public rx::FramebufferImpl
-{
-  public:
-    MockFramebufferImpl() : rx::FramebufferImpl(gl::Framebuffer::Data()) {}
-    virtual ~MockFramebufferImpl() { destroy(); }
-
-    MOCK_METHOD1(onUpdateColorAttachment, void(size_t));
-    MOCK_METHOD0(onUpdateDepthAttachment, void());
-    MOCK_METHOD0(onUpdateStencilAttachment, void());
-    MOCK_METHOD0(onUpdateDepthStencilAttachment, void());
-
-    MOCK_METHOD2(setDrawBuffers, void(size_t, const GLenum *));
-    MOCK_METHOD1(setReadBuffer, void(GLenum));
-
-    MOCK_METHOD2(discard, gl::Error(size_t, const GLenum *));
-    MOCK_METHOD2(invalidate, gl::Error(size_t, const GLenum *));
-    MOCK_METHOD3(invalidateSub, gl::Error(size_t, const GLenum *, const gl::Rectangle &));
-
-    MOCK_METHOD2(clear, gl::Error(const gl::Data &, GLbitfield));
-    MOCK_METHOD4(clearBufferfv, gl::Error(const gl::State &, GLenum, GLint, const GLfloat *));
-    MOCK_METHOD4(clearBufferuiv, gl::Error(const gl::State &, GLenum, GLint, const GLuint *));
-    MOCK_METHOD4(clearBufferiv, gl::Error(const gl::State &, GLenum, GLint, const GLint *));
-    MOCK_METHOD5(clearBufferfi, gl::Error(const gl::State &, GLenum, GLint, GLfloat, GLint));
-
-    MOCK_CONST_METHOD0(getImplementationColorReadFormat, GLenum());
-    MOCK_CONST_METHOD0(getImplementationColorReadType, GLenum());
-    MOCK_CONST_METHOD5(
-        readPixels,
-        gl::Error(const gl::State &, const gl::Rectangle &, GLenum, GLenum, GLvoid *));
-
-    MOCK_METHOD6(blit,
-                 gl::Error(const gl::State &,
-                           const gl::Rectangle &,
-                           const gl::Rectangle &,
-                           GLbitfield,
-                           GLenum,
-                           const gl::Framebuffer *));
-
-    MOCK_CONST_METHOD0(checkStatus, GLenum());
-
-    MOCK_METHOD0(destroy, void());
-};
-
 TEST(SurfaceTest, DestructionDeletesImpl)
 {
     MockFramebufferImpl *framebuffer = new MockFramebufferImpl;
 
     MockSurfaceImpl *impl = new MockSurfaceImpl;
     EXPECT_CALL(*impl, getSwapBehavior());
     EXPECT_CALL(*impl, createDefaultFramebuffer(testing::_)).WillOnce(testing::Return(framebuffer));
 
--- a/gfx/angle/src/libANGLE/VertexArray.cpp
+++ b/gfx/angle/src/libANGLE/VertexArray.cpp
@@ -29,17 +29,16 @@ VertexArray::Data::~Data()
     mElementArrayBuffer.set(nullptr);
 }
 
 VertexArray::VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs)
     : mId(id),
       mVertexArray(factory->createVertexArray(mData)),
       mData(maxAttribs)
 {
-    ASSERT(mVertexArray != nullptr);
 }
 
 VertexArray::~VertexArray()
 {
     SafeDelete(mVertexArray);
 }
 
 GLuint VertexArray::id() const
--- a/gfx/angle/src/libANGLE/angletypes.cpp
+++ b/gfx/angle/src/libANGLE/angletypes.cpp
@@ -10,16 +10,40 @@
 #include "libANGLE/Program.h"
 #include "libANGLE/VertexAttribute.h"
 #include "libANGLE/State.h"
 #include "libANGLE/VertexArray.h"
 
 namespace gl
 {
 
+PrimitiveType GetPrimitiveType(GLenum drawMode)
+{
+    switch (drawMode)
+    {
+        case GL_POINTS:
+            return PRIMITIVE_POINTS;
+        case GL_LINES:
+            return PRIMITIVE_LINES;
+        case GL_LINE_STRIP:
+            return PRIMITIVE_LINE_STRIP;
+        case GL_LINE_LOOP:
+            return PRIMITIVE_LINE_LOOP;
+        case GL_TRIANGLES:
+            return PRIMITIVE_TRIANGLES;
+        case GL_TRIANGLE_STRIP:
+            return PRIMITIVE_TRIANGLE_STRIP;
+        case GL_TRIANGLE_FAN:
+            return PRIMITIVE_TRIANGLE_FAN;
+        default:
+            UNREACHABLE();
+            return PRIMITIVE_TYPE_MAX;
+    }
+}
+
 SamplerState::SamplerState()
     : minFilter(GL_NEAREST_MIPMAP_LINEAR),
       magFilter(GL_LINEAR),
       wrapS(GL_REPEAT),
       wrapT(GL_REPEAT),
       wrapR(GL_REPEAT),
       maxAnisotropy(1.0f),
       minLod(-1000.0f),
--- a/gfx/angle/src/libANGLE/angletypes.h
+++ b/gfx/angle/src/libANGLE/angletypes.h
@@ -19,16 +19,30 @@
 namespace gl
 {
 class Buffer;
 class State;
 class Program;
 struct VertexAttribute;
 struct VertexAttribCurrentValueData;
 
+enum PrimitiveType
+{
+    PRIMITIVE_POINTS,
+    PRIMITIVE_LINES,
+    PRIMITIVE_LINE_STRIP,
+    PRIMITIVE_LINE_LOOP,
+    PRIMITIVE_TRIANGLES,
+    PRIMITIVE_TRIANGLE_STRIP,
+    PRIMITIVE_TRIANGLE_FAN,
+    PRIMITIVE_TYPE_MAX,
+};
+
+PrimitiveType GetPrimitiveType(GLenum drawMode);
+
 enum SamplerType
 {
     SAMPLER_PIXEL,
     SAMPLER_VERTEX
 };
 
 template <typename T>
 struct Color
--- a/gfx/angle/src/libANGLE/features.h
+++ b/gfx/angle/src/libANGLE/features.h
@@ -27,20 +27,24 @@
 #define ANGLE_VSYNC ANGLE_ENABLED
 #endif
 
 // Program binary loading
 #if !defined(ANGLE_PROGRAM_BINARY_LOAD)
 #define ANGLE_PROGRAM_BINARY_LOAD ANGLE_ENABLED
 #endif
 
-// Shader debug info
-#if !defined(ANGLE_SHADER_DEBUG_INFO)
-#define ANGLE_SHADER_DEBUG_INFO ANGLE_DISABLED
-#endif
+// Append HLSL assembly to shader debug info. Defaults to enabled in Debug and off in Release.
+#if !defined(ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO)
+#if !defined(NDEBUG)
+#define ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO ANGLE_ENABLED
+#else
+#define ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO ANGLE_DISABLED
+#endif  // !defined(NDEBUG)
+#endif  // !defined(ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO)
 
 // Program link validation of precisions for uniforms. This feature was
 // requested by developers to allow non-conformant shaders to be used which
 // contain mismatched precisions.
 // ENABLED validate that precision for uniforms match between vertex and fragment shaders
 // DISABLED allow precision for uniforms to differ between vertex and fragment shaders
 #if !defined(ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION)
 #define ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION ANGLE_ENABLED
--- a/gfx/angle/src/libANGLE/formatutils.cpp
+++ b/gfx/angle/src/libANGLE/formatutils.cpp
@@ -207,16 +207,23 @@ static bool RequireESOrExtOrExt(GLuint c
 
 // Check support for two extensions
 template <ExtensionBool bool1, ExtensionBool bool2>
 static bool RequireExtAndExt(GLuint, const Extensions &extensions)
 {
     return extensions.*bool1 && extensions.*bool2;
 }
 
+// Check support for either of two extensions
+template <ExtensionBool bool1, ExtensionBool bool2>
+static bool RequireExtOrExt(GLuint, const Extensions &extensions)
+{
+    return extensions.*bool1 || extensions.*bool2;
+}
+
 InternalFormat::InternalFormat()
     : redBits(0),
       greenBits(0),
       blueBits(0),
       luminanceBits(0),
       alphaBits(0),
       sharedBits(0),
       depthBits(0),
@@ -454,25 +461,60 @@ static InternalFormatInfoMap BuildIntern
     map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2,                      CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB8_ETC2,                      GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
     map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2,                     CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_SRGB8_ETC2,                     GL_UNSIGNED_BYTE, true,  RequireES<3>, NeverSupported, AlwaysSupported)));
     map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,  GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
     map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true,  RequireES<3>, NeverSupported, AlwaysSupported)));
     map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC,                 CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC,                 GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
     map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,          GL_UNSIGNED_BYTE, true,  RequireES<3>, NeverSupported, AlwaysSupported)));
 
     // From GL_EXT_texture_compression_dxt1
-    //                               | Internal format                   |                |W |H | BS |CC| Format                            | Type            | SRGB | Supported                                      | Renderable    | Filterable    |
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT,    CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,    GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported)));
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,   CompressedFormat(4, 4,  64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,   GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported)));
+    //                               | Internal format                   |                |W |H | BS |CC| Format                            | Type            | SRGB | Supported                                         | Renderable    | Filterable    |
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT,    CompressedFormat(4, 4,  64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,    GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>,    NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,   CompressedFormat(4, 4,  64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,   GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>,    NeverSupported, AlwaysSupported)));
 
     // From GL_ANGLE_texture_compression_dxt3
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>,    NeverSupported, AlwaysSupported)));
 
     // From GL_ANGLE_texture_compression_dxt5
-    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>,    NeverSupported, AlwaysSupported)));
+
+    // From GL_OES_compressed_ETC1_RGB8_texture
+    map.insert(InternalFormatInfoPair(GL_ETC1_RGB8_OES,                   CompressedFormat(4, 4,  64, 3, GL_ETC1_RGB8_OES,                   GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::compressedETC1RGB8Texture>, NeverSupported, AlwaysSupported)));
+
+    // From KHR_texture_compression_astc_hdr
+    //                               | Internal format                          |                | W | H | BS |CC| Format                                   | Type            | SRGB | Supported                                                                                     | Renderable     | Filterable    |
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_4x4_KHR,           CompressedFormat( 4,  4, 128, 4, GL_COMPRESSED_RGBA_ASTC_4x4_KHR,           GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_5x4_KHR,           CompressedFormat( 5,  4, 128, 4, GL_COMPRESSED_RGBA_ASTC_5x4_KHR,           GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_5x5_KHR,           CompressedFormat( 5,  5, 128, 4, GL_COMPRESSED_RGBA_ASTC_5x5_KHR,           GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_6x5_KHR,           CompressedFormat( 6,  5, 128, 4, GL_COMPRESSED_RGBA_ASTC_6x5_KHR,           GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_6x6_KHR,           CompressedFormat( 6,  6, 128, 4, GL_COMPRESSED_RGBA_ASTC_6x6_KHR,           GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_8x5_KHR,           CompressedFormat( 8,  5, 128, 4, GL_COMPRESSED_RGBA_ASTC_8x5_KHR,           GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_8x6_KHR,           CompressedFormat( 8,  6, 128, 4, GL_COMPRESSED_RGBA_ASTC_8x6_KHR,           GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_8x8_KHR,           CompressedFormat( 8,  8, 128, 4, GL_COMPRESSED_RGBA_ASTC_8x8_KHR,           GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x5_KHR,          CompressedFormat(10,  5, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x5_KHR,          GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x6_KHR,          CompressedFormat(10,  6, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x6_KHR,          GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x8_KHR,          CompressedFormat(10,  8, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x8_KHR,          GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x10_KHR,         CompressedFormat(10, 10, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x10_KHR,         GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_12x10_KHR,         CompressedFormat(12, 10, 128, 4, GL_COMPRESSED_RGBA_ASTC_12x10_KHR,         GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_12x12_KHR,         CompressedFormat(12, 12, 128, 4, GL_COMPRESSED_RGBA_ASTC_12x12_KHR,         GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,   CompressedFormat( 4,  4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,   GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,   CompressedFormat( 5,  4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,   GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,   CompressedFormat( 5,  5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,   GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,   CompressedFormat( 6,  5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,   GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,   CompressedFormat( 6,  6, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,   GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,   CompressedFormat( 8,  5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,   GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,   CompressedFormat( 8,  6, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,   GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,   CompressedFormat( 8,  8, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,   GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,  CompressedFormat(10,  5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,  GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,  CompressedFormat(10,  6, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,  GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,  CompressedFormat(10,  8, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,  GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, CompressedFormat(10, 10, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, CompressedFormat(12, 10, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+    map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, CompressedFormat(12, 12, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, GL_UNSIGNED_BYTE, true,  RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
 
     // For STENCIL_INDEX8 we chose a normalized component type for the following reasons:
     // - Multisampled buffer are disallowed for non-normalized integer component types and we want to support it for STENCIL_INDEX8
     // - All other stencil formats (all depth-stencil) are either float or normalized
     // - It affects only validation of internalformat in RenderbufferStorageMultisample.
     //                               | Internal format  |                  |D |S |X | Format          | Type            | Component type        | Supported   | Renderable  | Filterable   |
     map.insert(InternalFormatInfoPair(GL_STENCIL_INDEX8, DepthStencilFormat(0, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, NeverSupported)));
     // clang-format on
--- a/gfx/angle/src/libANGLE/formatutils.h
+++ b/gfx/angle/src/libANGLE/formatutils.h
@@ -224,11 +224,11 @@ struct VertexFormat : angle::NonCopyable
     bool pureInteger;
 };
 
 VertexFormatType GetVertexFormatType(GLenum type, GLboolean normalized, GLuint components, bool pureInteger);
 VertexFormatType GetVertexFormatType(const VertexAttribute &attrib);
 VertexFormatType GetVertexFormatType(const VertexAttribute &attrib, GLenum currentValueType);
 const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType);
 
-}
+}  // namespace gl
 
 #endif // LIBANGLE_FORMATUTILS_H_
--- a/gfx/angle/src/libANGLE/moz.build
+++ b/gfx/angle/src/libANGLE/moz.build
@@ -42,16 +42,17 @@ UNIFIED_SOURCES += [
     '../compiler/translator/Compiler.cpp',
     '../compiler/translator/depgraph/DependencyGraph.cpp',
     '../compiler/translator/depgraph/DependencyGraphBuilder.cpp',
     '../compiler/translator/depgraph/DependencyGraphOutput.cpp',
     '../compiler/translator/depgraph/DependencyGraphTraverse.cpp',
     '../compiler/translator/Diagnostics.cpp',
     '../compiler/translator/DirectiveHandler.cpp',
     '../compiler/translator/EmulatePrecision.cpp',
+    '../compiler/translator/ExtensionGLSL.cpp',
     '../compiler/translator/FlagStd140Structs.cpp',
     '../compiler/translator/ForLoopUnroll.cpp',
     '../compiler/translator/InfoSink.cpp',
     '../compiler/translator/Initialize.cpp',
     '../compiler/translator/InitializeDll.cpp',
     '../compiler/translator/InitializeParseContext.cpp',
     '../compiler/translator/InitializeVariables.cpp',
     '../compiler/translator/Intermediate.cpp',
@@ -59,17 +60,16 @@ UNIFIED_SOURCES += [
     '../compiler/translator/intermOut.cpp',
     '../compiler/translator/IntermTraverse.cpp',
     '../compiler/translator/LoopInfo.cpp',
     '../compiler/translator/Operator.cpp',
     '../compiler/translator/OutputESSL.cpp',
     '../compiler/translator/OutputGLSL.cpp',
     '../compiler/translator/OutputGLSLBase.cpp',
     '../compiler/translator/OutputHLSL.cpp',
-    '../compiler/translator/parseConst.cpp',
     '../compiler/translator/ParseContext.cpp',
     '../compiler/translator/PoolAlloc.cpp',
     '../compiler/translator/PruneEmptyDeclarations.cpp',
     '../compiler/translator/RecordConstantPrecision.cpp',
     '../compiler/translator/RegenerateStructNames.cpp',
     '../compiler/translator/RemoveDynamicIndexing.cpp',
     '../compiler/translator/RemovePow.cpp',
     '../compiler/translator/RemoveSwitchFallThrough.cpp',
@@ -154,25 +154,27 @@ UNIFIED_SOURCES += [
     'renderer/d3d/DynamicHLSL.cpp',
     'renderer/d3d/EGLImageD3D.cpp',
     'renderer/d3d/formatutilsD3D.cpp',
     'renderer/d3d/FramebufferD3D.cpp',
     'renderer/d3d/ImageD3D.cpp',
     'renderer/d3d/IndexBuffer.cpp',
     'renderer/d3d/IndexDataManager.cpp',
     'renderer/d3d/loadimage.cpp',
+    'renderer/d3d/loadimage_etc.cpp',
     'renderer/d3d/ProgramD3D.cpp',
     'renderer/d3d/RenderbufferD3D.cpp',
     'renderer/d3d/RendererD3D.cpp',
     'renderer/d3d/RenderTargetD3D.cpp',
     'renderer/d3d/ShaderD3D.cpp',
     'renderer/d3d/ShaderExecutableD3D.cpp',
     'renderer/d3d/SurfaceD3D.cpp',
     'renderer/d3d/TextureD3D.cpp',
     'renderer/d3d/TransformFeedbackD3D.cpp',
+    'renderer/d3d/VaryingPacking.cpp',
     'renderer/d3d/VertexBuffer.cpp',
     'renderer/d3d/VertexDataManager.cpp',
     'renderer/DeviceImpl.cpp',
     'renderer/DisplayImpl.cpp',
     'renderer/gl/BlitGL.cpp',
     'renderer/gl/BufferGL.cpp',
     'renderer/gl/CompilerGL.cpp',
     'renderer/gl/DisplayGL.cpp',
@@ -231,26 +233,28 @@ if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
         'renderer/d3d/d3d11/DebugAnnotator11.cpp',
         'renderer/d3d/d3d11/dxgi_support_table.cpp',
         'renderer/d3d/d3d11/Fence11.cpp',
         'renderer/d3d/d3d11/formatutils11.cpp',
         'renderer/d3d/d3d11/Framebuffer11.cpp',
         'renderer/d3d/d3d11/Image11.cpp',
         'renderer/d3d/d3d11/IndexBuffer11.cpp',
         'renderer/d3d/d3d11/InputLayoutCache.cpp',
+        'renderer/d3d/d3d11/internal_format_initializer_table.cpp',
+        'renderer/d3d/d3d11/load_functions_table_autogen.cpp',
         'renderer/d3d/d3d11/PixelTransfer11.cpp',
         'renderer/d3d/d3d11/Query11.cpp',
         'renderer/d3d/d3d11/Renderer11.cpp',
         'renderer/d3d/d3d11/renderer11_utils.cpp',
         'renderer/d3d/d3d11/RenderStateCache.cpp',
         'renderer/d3d/d3d11/RenderTarget11.cpp',
         'renderer/d3d/d3d11/ShaderExecutable11.cpp',
-        'renderer/d3d/d3d11/swizzle_format_info.cpp',
-        'renderer/d3d/d3d11/texture_format_table.cpp',
-        'renderer/d3d/d3d11/texture_format_util.cpp',
+        'renderer/d3d/d3d11/StateManager11.cpp',
+        'renderer/d3d/d3d11/swizzle_format_info_autogen.cpp',
+        'renderer/d3d/d3d11/texture_format_table_autogen.cpp',
         'renderer/d3d/d3d11/TextureStorage11.cpp',
         'renderer/d3d/d3d11/Trim11.cpp',
         'renderer/d3d/d3d11/VertexBuffer11.cpp',
         'renderer/d3d/d3d11/win32/NativeWindow.cpp',
     ]
 if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
     SOURCES += [
         'renderer/d3d/d3d11/SwapChain11.cpp',
@@ -305,18 +309,18 @@ DEFINES['LIBANGLE_IMPLEMENTATION'] = "1"
 DEFINES['ANGLE_ENABLE_HLSL'] = "1"
 DEFINES['ANGLE_ENABLE_KEYEDMUTEX'] = "1"
 DEFINES['ANGLE_DEFAULT_D3D11'] = "0"
 
 if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
   OS_LIBS += [ 'd3d9', 'dxguid' ]
 else:
   EXTRA_DSO_LDOPTS += [
-    '%s/lib/%s/d3d9.lib' % (CONFIG['MOZ_DIRECTX_SDK_PATH'], CONFIG['MOZ_D3D_CPU_SUFFIX']),
-    '%s/lib/%s/dxguid.lib' % (CONFIG['MOZ_DIRECTX_SDK_PATH'], CONFIG['MOZ_D3D_CPU_SUFFIX']),
+    '\'%s/lib/%s/d3d9.lib\'' % (CONFIG['MOZ_DIRECTX_SDK_PATH'], CONFIG['MOZ_D3D_CPU_SUFFIX']),
+    '\'%s/lib/%s/dxguid.lib\'' % (CONFIG['MOZ_DIRECTX_SDK_PATH'], CONFIG['MOZ_D3D_CPU_SUFFIX']),
   ]
 
 Library('libANGLE')
 
 
 SOURCES['renderer/d3d/HLSLCompiler.cpp'].flags += ['-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES=\'{ TEXT("d3dcompiler_47.dll"), TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }\'']
 
 if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
--- a/gfx/angle/src/libANGLE/queryconversions.cpp
+++ b/gfx/angle/src/libANGLE/queryconversions.cpp
@@ -3,16 +3,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
 
 // queryconversions.cpp: Implementation of state query cast conversions
 
 #include "libANGLE/queryconversions.h"
 
+#include <vector>
+
 #include "libANGLE/Context.h"
 #include "common/utilities.h"
 
 namespace gl
 {
 
 namespace
 {
@@ -96,69 +98,53 @@ template <>
 GLenum GLTypeToGLenum<GLfloat>::value = GL_FLOAT;
 
 template <typename QueryT>
 void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
                      unsigned int numParams, QueryT *outParams)
 {
     if (nativeType == GL_INT)
     {
-        GLint *intParams = NULL;
-        intParams = new GLint[numParams];
-
-        context->getIntegerv(pname, intParams);
+        std::vector<GLint> intParams(numParams, 0);
+        context->getIntegerv(pname, intParams.data());
 
         for (unsigned int i = 0; i < numParams; ++i)
         {
             outParams[i] = CastStateValue<QueryT>(pname, intParams[i]);
         }
-
-        delete [] intParams;
     }
     else if (nativeType == GL_BOOL)
     {
-        GLboolean *boolParams = NULL;
-        boolParams = new GLboolean[numParams];
-
-        context->getBooleanv(pname, boolParams);
+        std::vector<GLboolean> boolParams(numParams, GL_FALSE);
+        context->getBooleanv(pname, boolParams.data());
 
         for (unsigned int i = 0; i < numParams; ++i)
         {
             outParams[i] = (boolParams[i] == GL_FALSE ? static_cast<QueryT>(0) : static_cast<QueryT>(1));
         }
-
-        delete [] boolParams;
     }
     else if (nativeType == GL_FLOAT)
     {
-        GLfloat *floatParams = NULL;
-        floatParams = new GLfloat[numParams];
-
-        context->getFloatv(pname, floatParams);
+        std::vector<GLfloat> floatParams(numParams, 0.0f);
+        context->getFloatv(pname, floatParams.data());
 
         for (unsigned int i = 0; i < numParams; ++i)
         {
             outParams[i] = CastStateValue<QueryT>(pname, floatParams[i]);
         }
-
-        delete [] floatParams;
     }
     else if (nativeType == GL_INT_64_ANGLEX)
     {
-        GLint64 *int64Params = NULL;
-        int64Params = new GLint64[numParams];
-
-        context->getInteger64v(pname, int64Params);
+        std::vector<GLint64> int64Params(numParams, 0);
+        context->getInteger64v(pname, int64Params.data());
 
         for (unsigned int i = 0; i < numParams; ++i)
         {
             outParams[i] = CastStateValue<QueryT>(pname, int64Params[i]);
         }
-
-        delete [] int64Params;
     }
     else UNREACHABLE();
 }
 
 // Explicit template instantiation (how we export template functions in different files)
 // The calls below will make CastStateValues successfully link with the GL state query types
 // The GL state query API types are: bool, int, uint, float, int64
 
--- a/gfx/angle/src/libANGLE/renderer/DeviceImpl.h
+++ b/gfx/angle/src/libANGLE/renderer/DeviceImpl.h
@@ -21,16 +21,16 @@ class Device;
 namespace rx
 {
 class DeviceImpl : angle::NonCopyable
 {
   public:
     DeviceImpl();
     virtual ~DeviceImpl();
 
-    virtual egl::Error getDevice(EGLAttrib *value) = 0;
+    virtual egl::Error getDevice(void **outValue) = 0;
     virtual EGLint getType() = 0;
     virtual void generateExtensions(egl::DeviceExtensions *outExtensions) const = 0;
 };
 
 }
 
 #endif // LIBANGLE_RENDERER_DEVICEIMPL_H_
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/FramebufferImpl_mock.h
@@ -0,0 +1,65 @@
+//
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FramebufferImpl_mock.h:
+//   Defines a mock of the FramebufferImpl class.
+//
+
+#ifndef LIBANGLE_RENDERER_FRAMEBUFFERIMPLMOCK_H_
+#define LIBANGLE_RENDERER_FRAMEBUFFERIMPLMOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "libANGLE/renderer/FramebufferImpl.h"
+
+namespace rx
+{
+
+class MockFramebufferImpl : public rx::FramebufferImpl
+{
+  public:
+    MockFramebufferImpl() : rx::FramebufferImpl(gl::Framebuffer::Data()) {}
+    virtual ~MockFramebufferImpl() { destroy(); }
+
+    MOCK_METHOD1(onUpdateColorAttachment, void(size_t));
+    MOCK_METHOD0(onUpdateDepthAttachment, void());
+    MOCK_METHOD0(onUpdateStencilAttachment, void());
+    MOCK_METHOD0(onUpdateDepthStencilAttachment, void());
+
+    MOCK_METHOD2(setDrawBuffers, void(size_t, const GLenum *));
+    MOCK_METHOD1(setReadBuffer, void(GLenum));
+
+    MOCK_METHOD2(discard, gl::Error(size_t, const GLenum *));
+    MOCK_METHOD2(invalidate, gl::Error(size_t, const GLenum *));
+    MOCK_METHOD3(invalidateSub, gl::Error(size_t, const GLenum *, const gl::Rectangle &));
+
+    MOCK_METHOD2(clear, gl::Error(const gl::Data &, GLbitfield));
+    MOCK_METHOD4(clearBufferfv, gl::Error(const gl::State &, GLenum, GLint, const GLfloat *));
+    MOCK_METHOD4(clearBufferuiv, gl::Error(const gl::State &, GLenum, GLint, const GLuint *));
+    MOCK_METHOD4(clearBufferiv, gl::Error(const gl::State &, GLenum, GLint, const GLint *));
+    MOCK_METHOD5(clearBufferfi, gl::Error(const gl::State &, GLenum, GLint, GLfloat, GLint));
+
+    MOCK_CONST_METHOD0(getImplementationColorReadFormat, GLenum());
+    MOCK_CONST_METHOD0(getImplementationColorReadType, GLenum());
+    MOCK_CONST_METHOD5(
+        readPixels,
+        gl::Error(const gl::State &, const gl::Rectangle &, GLenum, GLenum, GLvoid *));
+
+    MOCK_METHOD6(blit,
+                 gl::Error(const gl::State &,
+                           const gl::Rectangle &,
+                           const gl::Rectangle &,
+                           GLbitfield,
+                           GLenum,
+                           const gl::Framebuffer *));
+
+    MOCK_CONST_METHOD0(checkStatus, GLenum());
+
+    MOCK_METHOD0(destroy, void());
+};
+
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_FRAMEBUFFERIMPLMOCK_H_
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/ProgramImpl_mock.h
@@ -0,0 +1,64 @@
+//
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ProgramImpl_mock.h:
+//   Defines a mock of the ProgramImpl class.
+//
+
+#ifndef LIBANGLE_RENDERER_PROGRAMIMPLMOCK_H_
+#define LIBANGLE_RENDERER_PROGRAMIMPLMOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "libANGLE/renderer/ProgramImpl.h"
+
+namespace rx
+{
+
+class MockProgramImpl : public rx::ProgramImpl
+{
+  public:
+    MockProgramImpl() : ProgramImpl(gl::Program::Data()) {}
+    virtual ~MockProgramImpl() { destroy(); }
+
+    MOCK_METHOD2(load, LinkResult(gl::InfoLog &, gl::BinaryInputStream *));
+    MOCK_METHOD1(save, gl::Error(gl::BinaryOutputStream *));
+
+    MOCK_METHOD2(link, LinkResult(const gl::Data &, gl::InfoLog &));
+    MOCK_METHOD2(validate, GLboolean(const gl::Caps &, gl::InfoLog *));
+
+    MOCK_METHOD3(setUniform1fv, void(GLint, GLsizei, const GLfloat *));
+    MOCK_METHOD3(setUniform2fv, void(GLint, GLsizei, const GLfloat *));
+    MOCK_METHOD3(setUniform3fv, void(GLint, GLsizei, const GLfloat *));
+    MOCK_METHOD3(setUniform4fv, void(GLint, GLsizei, const GLfloat *));
+    MOCK_METHOD3(setUniform1iv, void(GLint, GLsizei, const GLint *));
+    MOCK_METHOD3(setUniform2iv, void(GLint, GLsizei, const GLint *));
+    MOCK_METHOD3(setUniform3iv, void(GLint, GLsizei, const GLint *));
+    MOCK_METHOD3(setUniform4iv, void(GLint, GLsizei, const GLint *));
+    MOCK_METHOD3(setUniform1uiv, void(GLint, GLsizei, const GLuint *));
+    MOCK_METHOD3(setUniform2uiv, void(GLint, GLsizei, const GLuint *));
+    MOCK_METHOD3(setUniform3uiv, void(GLint, GLsizei, const GLuint *));
+    MOCK_METHOD3(setUniform4uiv, void(GLint, GLsizei, const GLuint *));
+
+    MOCK_METHOD4(setUniformMatrix2fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+    MOCK_METHOD4(setUniformMatrix3fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+    MOCK_METHOD4(setUniformMatrix4fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+    MOCK_METHOD4(setUniformMatrix2x3fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+    MOCK_METHOD4(setUniformMatrix3x2fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+    MOCK_METHOD4(setUniformMatrix2x4fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+    MOCK_METHOD4(setUniformMatrix4x2fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+    MOCK_METHOD4(setUniformMatrix3x4fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+    MOCK_METHOD4(setUniformMatrix4x3fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+
+    MOCK_METHOD2(setUniformBlockBinding, void(GLuint, GLuint));
+    MOCK_CONST_METHOD2(getUniformBlockSize, bool(const std::string &, size_t *));
+    MOCK_CONST_METHOD2(getUniformBlockMemberInfo, bool(const std::string &, sh::BlockMemberInfo *));
+
+    MOCK_METHOD0(destroy, void());
+};
+
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_PROGRAMIMPLMOCK_H_
--- a/gfx/angle/src/libANGLE/renderer/ShaderImpl.h
+++ b/gfx/angle/src/libANGLE/renderer/ShaderImpl.h
@@ -17,21 +17,24 @@ namespace rx
 
 class ShaderImpl : angle::NonCopyable
 {
   public:
     ShaderImpl(const gl::Shader::Data &data) : mData(data) {}
     virtual ~ShaderImpl() { }
 
     // Returns additional ShCompile options.
-    virtual int prepareSourceAndReturnOptions(std::stringstream *sourceStream) = 0;
+    virtual int prepareSourceAndReturnOptions(std::stringstream *sourceStream,
+                                              std::string *sourcePath) = 0;
     // Returns success for compiling on the driver. Returns success.
     virtual bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) = 0;
 
     virtual std::string getDebugInfo() const = 0;
 
+    const gl::Shader::Data &getData() const { return mData; }
+
   protected:
     const gl::Shader::Data &mData;
 };
 
 }
 
 #endif // LIBANGLE_RENDERER_SHADERIMPL_H_
--- a/gfx/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp
+++ b/gfx/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp
@@ -3,40 +3,52 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
 
 // BufferD3D.cpp Defines common functionality between the Buffer9 and Buffer11 classes.
 
 #include "libANGLE/renderer/d3d/BufferD3D.h"
 
+#include "common/mathutil.h"
 #include "common/utilities.h"
 #include "libANGLE/renderer/d3d/IndexBuffer.h"
 #include "libANGLE/renderer/d3d/VertexBuffer.h"
 
 namespace rx
 {
 
 unsigned int BufferD3D::mNextSerial = 1;
 
 BufferD3D::BufferD3D(BufferFactoryD3D *factory)
     : BufferImpl(),
       mFactory(factory),
       mStaticVertexBuffer(nullptr),
       mStaticIndexBuffer(nullptr),
+      mStaticBufferCache(nullptr),
+      mStaticBufferCacheTotalSize(0),
+      mStaticVertexBufferOutOfDate(false),
       mUnmodifiedDataUse(0),
       mUsage(D3D_BUFFER_USAGE_STATIC)
 {
     updateSerial();
 }
 
 BufferD3D::~BufferD3D()
 {
     SafeDelete(mStaticVertexBuffer);
     SafeDelete(mStaticIndexBuffer);
+
+    // Empty the cache of static vertex buffers too
+    if (mStaticBufferCache != nullptr)
+    {
+        SafeDeleteContainer(*mStaticBufferCache);
+    }
+
+    mStaticBufferCacheTotalSize = 0;
 }
 
 void BufferD3D::updateSerial()
 {
     mSerial = mNextSerial++;
 }
 
 void BufferD3D::updateD3DBufferUsage(GLenum usage)
@@ -70,18 +82,140 @@ void BufferD3D::initializeStaticData()
         mStaticVertexBuffer = new StaticVertexBufferInterface(mFactory);
     }
     if (!mStaticIndexBuffer)
     {
         mStaticIndexBuffer = new StaticIndexBufferInterface(mFactory);
     }
 }
 
-void BufferD3D::invalidateStaticData()
+StaticIndexBufferInterface *BufferD3D::getStaticIndexBuffer()
+{
+    return mStaticIndexBuffer;
+}
+
+StaticVertexBufferInterface *BufferD3D::getStaticVertexBuffer(
+    const gl::VertexAttribute &attribute,
+    D3DStaticBufferCreationType creationType)
 {
+    if (!mStaticVertexBuffer)
+    {
+        // Early out if there aren't any static buffers at all
+        ASSERT(mStaticBufferCache == nullptr);
+        return nullptr;
+    }
+
+    if (mStaticBufferCache == nullptr && !mStaticVertexBuffer->isCommitted())
+    {
+        // Early out, the attribute can be added to mStaticVertexBuffer or is already in there
+        return mStaticVertexBuffer;
+    }
+
+    // At this point, see if any of the existing static buffers contains the attribute data
+
+    // If the default static vertex buffer contains the attribute, then return it
+    if (mStaticVertexBuffer->lookupAttribute(attribute, nullptr))
+    {
+        return mStaticVertexBuffer;
+    }
+
+    if (mStaticBufferCache != nullptr)
+    {
+        // If there is a cached static buffer that already contains the attribute, then return it
+        for (StaticVertexBufferInterface *staticBuffer : *mStaticBufferCache)
+        {
+            if (staticBuffer->lookupAttribute(attribute, nullptr))
+            {
+                return staticBuffer;
+            }
+        }
+    }
+
+    if (!mStaticVertexBuffer->isCommitted())
+    {
+        // None of the existing static buffers contain the attribute data and we are able to add
+        // the data to mStaticVertexBuffer, so we should just do so
+        return mStaticVertexBuffer;
+    }
+
+    // At this point, we must create a new static buffer for the attribute data
+    if (creationType != D3D_BUFFER_CREATE_IF_NECESSARY)
+    {
+        return nullptr;
+    }
+
+    ASSERT(mStaticVertexBuffer);
+    ASSERT(mStaticVertexBuffer->isCommitted());
+    unsigned int staticVertexBufferSize = mStaticVertexBuffer->getBufferSize();
+    if (IsUnsignedAdditionSafe(staticVertexBufferSize, mStaticBufferCacheTotalSize))
+    {
+        // Ensure that the total size of the static buffer cache remains less than 4x the
+        // size of the original buffer
+        unsigned int maxStaticCacheSize =
+            IsUnsignedMultiplicationSafe(static_cast<unsigned int>(getSize()), 4u)
+                ? 4u * static_cast<unsigned int>(getSize())
+                : std::numeric_limits<unsigned int>::max();
+
+        // We can't reuse the default static vertex buffer, so we add it to the cache
+        if (staticVertexBufferSize + mStaticBufferCacheTotalSize <= maxStaticCacheSize)
+        {
+            if (mStaticBufferCache == nullptr)
+            {
+                mStaticBufferCache = new std::vector<StaticVertexBufferInterface *>();
+            }
+
+            mStaticBufferCacheTotalSize += staticVertexBufferSize;
+            (*mStaticBufferCache).push_back(mStaticVertexBuffer);
+            mStaticVertexBuffer = nullptr;
+
+            // Then reinitialize the static buffers to create a new static vertex buffer
+            initializeStaticData();
+
+            // Return the default static vertex buffer
+            return mStaticVertexBuffer;
+        }
+    }
+
+    // At this point:
+    //   - mStaticVertexBuffer is committed and can't be altered
+    //   - mStaticBufferCache is full (or nearly overflowing)
+    // The inputted attribute should be put in some static buffer at some point, but it can't
+    // go in one right now, since mStaticBufferCache is full and we can't delete mStaticVertexBuffer
+    // in case another attribute is relying upon it for the current draw.
+    // We therefore mark mStaticVertexBuffer for deletion at the next possible time.
+    mStaticVertexBufferOutOfDate = true;
+    return nullptr;
+}
+
+void BufferD3D::reinitOutOfDateStaticData()
+{
+    if (mStaticVertexBufferOutOfDate)
+    {
+        // During the last draw the caller tried to use some attribute with static data, but neither
+        // the static buffer cache nor mStaticVertexBuffer contained that data.
+        // Therefore, invalidate mStaticVertexBuffer so that if the caller tries to use that
+        // attribute in the next draw, it'll successfully get put into mStaticVertexBuffer.
+        invalidateStaticData(D3D_BUFFER_INVALIDATE_DEFAULT_BUFFER_ONLY);
+        mStaticVertexBufferOutOfDate = false;
+    }
+}
+
+void BufferD3D::invalidateStaticData(D3DBufferInvalidationType invalidationType)
+{
+    if (invalidationType == D3D_BUFFER_INVALIDATE_WHOLE_CACHE && mStaticBufferCache != nullptr)
+    {
+        // Empty the cache of static vertex buffers too
+        for (StaticVertexBufferInterface *staticBuffer : *mStaticBufferCache)
+        {
+            SafeDelete(staticBuffer);
+        }
+        mStaticBufferCache->clear();
+        mStaticBufferCacheTotalSize = 0;
+    }
+
     if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0))
     {
         SafeDelete(mStaticVertexBuffer);
         SafeDelete(mStaticIndexBuffer);
 
         // If the buffer was created with a static usage then we recreate the static
         // buffers so that they are populated the next time we use this buffer.
         if (mUsage == D3D_BUFFER_USAGE_STATIC)
@@ -93,16 +227,20 @@ void BufferD3D::invalidateStaticData()
     mUnmodifiedDataUse = 0;
 }
 
 // Creates static buffers if sufficient used data has been left unmodified
 void BufferD3D::promoteStaticUsage(int dataSize)
 {
     if (!mStaticVertexBuffer && !mStaticIndexBuffer)
     {
+        // There isn't any scenario that involves promoting static usage and the static buffer cache
+        // being non-empty
+        ASSERT(mStaticBufferCache == nullptr);
+
         mUnmodifiedDataUse += dataSize;
 
         if (mUnmodifiedDataUse > 3 * getSize())
         {
             initializeStaticData();
         }
     }
 }
--- a/gfx/angle/src/libANGLE/renderer/d3d/BufferD3D.h
+++ b/gfx/angle/src/libANGLE/renderer/d3d/BufferD3D.h
@@ -8,47 +8,63 @@
 
 #ifndef LIBANGLE_RENDERER_D3D_BUFFERD3D_H_
 #define LIBANGLE_RENDERER_D3D_BUFFERD3D_H_
 
 #include "libANGLE/angletypes.h"
 #include "libANGLE/renderer/BufferImpl.h"
 
 #include <stdint.h>
+#include <vector>
 
 namespace rx
 {
 class BufferFactoryD3D;
 class StaticIndexBufferInterface;
 class StaticVertexBufferInterface;
 
 enum D3DBufferUsage
 {
     D3D_BUFFER_USAGE_STATIC,
     D3D_BUFFER_USAGE_DYNAMIC,
 };
 
+enum D3DBufferInvalidationType
+{
+    D3D_BUFFER_INVALIDATE_WHOLE_CACHE,
+    D3D_BUFFER_INVALIDATE_DEFAULT_BUFFER_ONLY,
+};
+
+enum D3DStaticBufferCreationType
+{
+    D3D_BUFFER_CREATE_IF_NECESSARY,
+    D3D_BUFFER_DO_NOT_CREATE,
+};
+
 class BufferD3D : public BufferImpl
 {
   public:
     BufferD3D(BufferFactoryD3D *factory);
     virtual ~BufferD3D();
 
     unsigned int getSerial() const { return mSerial; }
 
     virtual size_t getSize() const = 0;
     virtual bool supportsDirectBinding() const = 0;
     virtual void markTransformFeedbackUsage() = 0;
     virtual gl::Error getData(const uint8_t **outData) = 0;
 
-    StaticVertexBufferInterface *getStaticVertexBuffer() { return mStaticVertexBuffer; }
-    StaticIndexBufferInterface *getStaticIndexBuffer() { return mStaticIndexBuffer; }
+    StaticVertexBufferInterface *getStaticVertexBuffer(const gl::VertexAttribute &attribute,
+                                                       D3DStaticBufferCreationType creationType);
+    StaticIndexBufferInterface *getStaticIndexBuffer();
 
     void initializeStaticData();
-    void invalidateStaticData();
+    void invalidateStaticData(D3DBufferInvalidationType invalidationType);
+    void reinitOutOfDateStaticData();
+
     void promoteStaticUsage(int dataSize);
 
     gl::Error getIndexRange(GLenum type,
                             size_t offset,
                             size_t count,
                             bool primitiveRestartEnabled,
                             gl::IndexRange *outRange) override;
 
@@ -57,15 +73,18 @@ class BufferD3D : public BufferImpl
     void updateD3DBufferUsage(GLenum usage);
 
     BufferFactoryD3D *mFactory;
     unsigned int mSerial;
     static unsigned int mNextSerial;
 
     StaticVertexBufferInterface *mStaticVertexBuffer;
     StaticIndexBufferInterface *mStaticIndexBuffer;
+    std::vector<StaticVertexBufferInterface *> *mStaticBufferCache;
+    unsigned int mStaticBufferCacheTotalSize;
+    unsigned int mStaticVertexBufferOutOfDate;
     unsigned int mUnmodifiedDataUse;
     D3DBufferUsage mUsage;
 };
 
 }
 
 #endif // LIBANGLE_RENDERER_D3D_BUFFERD3D_H_
--- a/gfx/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp
+++ b/gfx/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp
@@ -12,43 +12,29 @@
 #include "libANGLE/Device.h"
 #include "libANGLE/Display.h"
 
 #include <EGL/eglext.h>
 
 namespace rx
 {
 
-DeviceD3D::DeviceD3D(rx::RendererD3D *renderer)
-    : mRenderer(renderer)
+DeviceD3D::DeviceD3D(void *device, EGLint deviceType) : mDevice(device), mDeviceType(deviceType)
 {
 }
 
-egl::Error DeviceD3D::getDevice(EGLAttrib *value)
+egl::Error DeviceD3D::getDevice(void **outValue)
 {
-    *value = reinterpret_cast<EGLAttrib>(mRenderer->getD3DDevice());
-    if (*value == 0)
-    {
-        return egl::Error(EGL_BAD_DEVICE_EXT);
-    }
+    *outValue = mDevice;
     return egl::Error(EGL_SUCCESS);
 }
 
 EGLint DeviceD3D::getType()
 {
-    switch (mRenderer->getRendererClass())
-    {
-      case RENDERER_D3D11:
-        return EGL_D3D11_DEVICE_ANGLE;
-      case RENDERER_D3D9:
-        return EGL_D3D9_DEVICE_ANGLE;
-      default:
-        UNREACHABLE();
-        return EGL_NONE;
-    }
+    return mDeviceType;
 }
 
 void DeviceD3D::generateExtensions(egl::DeviceExtensions *outExtensions) const
 {
     outExtensions->deviceD3D = true;
 }
 
 }
--- a/gfx/angle/src/libANGLE/renderer/d3d/DeviceD3D.h
+++ b/gfx/angle/src/libANGLE/renderer/d3d/DeviceD3D.h
@@ -13,21 +13,22 @@
 #include "libANGLE/renderer/DeviceImpl.h"
 #include "libANGLE/renderer/d3d/RendererD3D.h"
 
 namespace rx
 {
 class DeviceD3D : public DeviceImpl
 {
   public:
-    DeviceD3D(RendererD3D *renderer);
+    DeviceD3D(void *device, EGLint deviceType);
 
-    egl::Error getDevice(EGLAttrib *value) override;
+    egl::Error getDevice(void **outValue) override;
     EGLint getType() override;
     void generateExtensions(egl::DeviceExtensions *outExtensions) const override;
 
   private:
-    RendererD3D *mRenderer;
+    void *mDevice;
+    EGLint mDeviceType;
 };
 
 }
 
 #endif // LIBANGLE_RENDERER_D3D_DEVICED3D_H_
--- a/gfx/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp
+++ b/gfx/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp
@@ -136,19 +136,17 @@ egl::Error CreateRendererD3D(egl::Displa
             // Failed to create the renderer, try the next
             SafeDelete(renderer);
         }
     }
 
     return result;
 }
 
-DisplayD3D::DisplayD3D()
-    : mRenderer(nullptr),
-      mDevice(nullptr)
+DisplayD3D::DisplayD3D() : mRenderer(nullptr)
 {
 }
 
 
 SurfaceImpl *DisplayD3D::createWindowSurface(const egl::Config *configuration,
                                              EGLNativeWindowType window,
                                              const egl::AttributeMap &attribs)
 {
@@ -204,19 +202,17 @@ ImageImpl *DisplayD3D::createImage(EGLen
                                    egl::ImageSibling *buffer,
                                    const egl::AttributeMap &attribs)
 {
     return new EGLImageD3D(mRenderer, target, buffer, attribs);
 }
 
 egl::Error DisplayD3D::getDevice(DeviceImpl **device)
 {
-    *device = reinterpret_cast<DeviceImpl*>(mDevice);
-    ASSERT(*device != nullptr);
-    return egl::Error(EGL_SUCCESS);
+    return mRenderer->getEGLDevice(device);
 }
 
 egl::Error DisplayD3D::createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs,
                                      gl::Context **outContext)
 {
     ASSERT(mRenderer != nullptr);
 
     EGLint clientVersion = attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1);
@@ -237,25 +233,21 @@ egl::Error DisplayD3D::initialize(egl::D
     ASSERT(mRenderer == nullptr && display != nullptr);
     mDisplay = display;
     egl::Error error = CreateRendererD3D(display, &mRenderer);
     if (error.isError())
     {
         return error;
     }
 
-    ASSERT(mDevice == nullptr);
-    mDevice = new DeviceD3D(mRenderer);
-
     return egl::Error(EGL_SUCCESS);
 }
 
 void DisplayD3D::terminate()
 {
-    SafeDelete(mDevice);
     SafeDelete(mRenderer);
 }
 
 egl::ConfigSet DisplayD3D::generateConfigs() const
 {
     ASSERT(mRenderer != nullptr);
     return mRenderer->generateConfigs();
 }
--- a/gfx/angle/src/libANGLE/renderer/d3d/DisplayD3D.h
+++ b/gfx/angle/src/libANGLE/renderer/d3d/DisplayD3D.h
@@ -60,15 +60,13 @@ class DisplayD3D : public DisplayImpl
 
   private:
     void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
     void generateCaps(egl::Caps *outCaps) const override;
 
     egl::Display *mDisplay;
 
     rx::RendererD3D *mRenderer;
-
-    DeviceImpl *mDevice;
 };
 
 }
 
 #endif // LIBANGLE_RENDERER_D3D_DISPLAYD3D_H_
--- a/gfx/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/gfx/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -8,1257 +8,982 @@
 
 #include "libANGLE/renderer/d3d/DynamicHLSL.h"
 
 #include "common/utilities.h"
 #include "compiler/translator/blocklayoutHLSL.h"
 #include "libANGLE/Program.h"
 #include "libANGLE/Shader.h"
 #include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
 #include "libANGLE/renderer/d3d/RendererD3D.h"
 #include "libANGLE/renderer/d3d/ShaderD3D.h"
-
-// For use with ArrayString, see angleutils.h
-static_assert(GL_INVALID_INDEX == UINT_MAX, "GL_INVALID_INDEX must be equal to the max unsigned int.");
+#include "libANGLE/renderer/d3d/VaryingPacking.h"
 
 using namespace gl;
 
 namespace rx
 {
 
 namespace
 {
 
 std::string HLSLComponentTypeString(GLenum componentType)
 {
     switch (componentType)
     {
-      case GL_UNSIGNED_INT:         return "uint";
-      case GL_INT:                  return "int";
-      case GL_UNSIGNED_NORMALIZED:
-      case GL_SIGNED_NORMALIZED:
-      case GL_FLOAT:                return "float";
-      default: UNREACHABLE();       return "not-component-type";
+        case GL_UNSIGNED_INT:
+            return "uint";
+        case GL_INT:
+            return "int";
+        case GL_UNSIGNED_NORMALIZED:
+        case GL_SIGNED_NORMALIZED:
+        case GL_FLOAT:
+            return "float";
+        default:
+            UNREACHABLE();
+            return "not-component-type";
     }
 }
 
 std::string HLSLComponentTypeString(GLenum componentType, int componentCount)
 {
     return HLSLComponentTypeString(componentType) + (componentCount > 1 ? Str(componentCount) : "");
 }
 
 std::string HLSLMatrixTypeString(GLenum type)
 {
     switch (type)
     {
-      case GL_FLOAT_MAT2:     return "float2x2";
-      case GL_FLOAT_MAT3:     return "float3x3";
-      case GL_FLOAT_MAT4:     return "float4x4";
-      case GL_FLOAT_MAT2x3:   return "float2x3";
-      case GL_FLOAT_MAT3x2:   return "float3x2";
-      case GL_FLOAT_MAT2x4:   return "float2x4";
-      case GL_FLOAT_MAT4x2:   return "float4x2";
-      case GL_FLOAT_MAT3x4:   return "float3x4";
-      case GL_FLOAT_MAT4x3:   return "float4x3";
-      default: UNREACHABLE(); return "not-matrix-type";
+        case GL_FLOAT_MAT2:
+            return "float2x2";
+        case GL_FLOAT_MAT3:
+            return "float3x3";
+        case GL_FLOAT_MAT4:
+            return "float4x4";
+        case GL_FLOAT_MAT2x3:
+            return "float2x3";
+        case GL_FLOAT_MAT3x2:
+            return "float3x2";
+        case GL_FLOAT_MAT2x4:
+            return "float2x4";
+        case GL_FLOAT_MAT4x2:
+            return "float4x2";
+        case GL_FLOAT_MAT3x4:
+            return "float3x4";
+        case GL_FLOAT_MAT4x3:
+            return "float4x3";
+        default:
+            UNREACHABLE();
+            return "not-matrix-type";
     }
 }
 
 std::string HLSLTypeString(GLenum type)
 {
     if (gl::IsMatrixType(type))
     {
         return HLSLMatrixTypeString(type);
     }
 
-    return HLSLComponentTypeString(gl::VariableComponentType(type), gl::VariableComponentCount(type));
+    return HLSLComponentTypeString(gl::VariableComponentType(type),
+                                   gl::VariableComponentCount(type));
 }
 
-const PixelShaderOutputVariable *FindOutputAtLocation(const std::vector<PixelShaderOutputVariable> &outputVariables,
-                                                        unsigned int location)
+const PixelShaderOutputVariable *FindOutputAtLocation(
+    const std::vector<PixelShaderOutputVariable> &outputVariables,
+    unsigned int location)
 {
     for (size_t variableIndex = 0; variableIndex < outputVariables.size(); ++variableIndex)
     {
         if (outputVariables[variableIndex].outputIndex == location)
         {
             return &outputVariables[variableIndex];
         }
     }
 
-    return NULL;
+    return nullptr;
 }
 
-typedef const PackedVarying *VaryingPacking[gl::IMPLEMENTATION_MAX_VARYING_VECTORS][4];
-
-bool PackVarying(PackedVarying *packedVarying, const int maxVaryingVectors, VaryingPacking &packing)
+void WriteArrayString(std::stringstream &strstr, unsigned int i)
 {
-    // Make sure we use transposed matrix types to count registers correctly.
-    int registers = 0;
-    int elements = 0;
-
-    const sh::Varying &varying = *packedVarying->varying;
-
-    if (varying.isStruct())
+    static_assert(GL_INVALID_INDEX == UINT_MAX,
+                  "GL_INVALID_INDEX must be equal to the max unsigned int.");
+    if (i == UINT_MAX)
     {
-        registers = HLSLVariableRegisterCount(varying, true) * varying.elementCount();
-        elements = 4;
-    }
-    else
-    {
-        GLenum transposedType = TransposeMatrixType(varying.type);
-        registers             = VariableRowCount(transposedType) * varying.elementCount();
-        elements = VariableColumnCount(transposedType);
+        return;
     }
 
-    if (elements >= 2 && elements <= 4)
-    {
-        for (int r = 0; r <= maxVaryingVectors - registers; r++)
-        {
-            bool available = true;
-
-            for (int y = 0; y < registers && available; y++)
-            {
-                for (int x = 0; x < elements && available; x++)
-                {
-                    if (packing[r + y][x])
-                    {
-                        available = false;
-                    }
-                }
-            }
-
-            if (available)
-            {
-                packedVarying->registerIndex = r;
-                packedVarying->columnIndex   = 0;
-
-                for (int y = 0; y < registers; y++)
-                {
-                    for (int x = 0; x < elements; x++)
-                    {
-                        packing[r + y][x] = packedVarying;
-                    }
-                }
-
-                return true;
-            }
-        }
-
-        if (elements == 2)
-        {
-            for (int r = maxVaryingVectors - registers; r >= 0; r--)
-            {
-                bool available = true;
-
-                for (int y = 0; y < registers && available; y++)
-                {
-                    for (int x = 2; x < 4 && available; x++)
-                    {
-                        if (packing[r + y][x])
-                        {
-                            available = false;
-                        }
-                    }
-                }
-
-                if (available)
-                {
-                    packedVarying->registerIndex = r;
-                    packedVarying->columnIndex   = 2;
-
-                    for (int y = 0; y < registers; y++)
-                    {
-                        for (int x = 2; x < 4; x++)
-                        {
-                            packing[r + y][x] = packedVarying;
-                        }
-                    }
-
-                    return true;
-                }
-            }
-        }
-    }
-    else if (elements == 1)
-    {
-        int space[4] = { 0 };
-
-        for (int y = 0; y < maxVaryingVectors; y++)
-        {
-            for (int x = 0; x < 4; x++)
-            {
-                space[x] += packing[y][x] ? 0 : 1;
-            }
-        }
-
-        int column = 0;
-
-        for (int x = 0; x < 4; x++)
-        {
-            if (space[x] >= registers && (space[column] < registers || space[x] < space[column]))
-            {
-                column = x;
-            }
-        }
-
-        if (space[column] >= registers)
-        {
-            for (int r = 0; r < maxVaryingVectors; r++)
-            {
-                if (!packing[r][column])
-                {
-                    packedVarying->registerIndex = r;
-                    packedVarying->columnIndex   = column;
-
-                    for (int y = r; y < r + registers; y++)
-                    {
-                        packing[y][column] = packedVarying;
-                    }
-
-                    break;
-                }
-            }
-
-            return true;
-        }
-    }
-    else UNREACHABLE();
-
-    return false;
+    strstr << "[";
+    strstr << i;
+    strstr << "]";
 }
 
 const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@";
 const std::string PIXEL_OUTPUT_STUB_STRING     = "@@ PIXEL OUTPUT @@";
+}  // anonymous namespace
+
+std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize)
+{
+    // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
+    // In D3D11 we manually compute gl_PointCoord in the GS.
+    return ((programUsesPointSize && majorShaderModel < 4) ? "COLOR" : "TEXCOORD");
 }
 
+// DynamicHLSL implementation
+
 DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) : mRenderer(renderer)
 {
 }
 
-// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
-// Returns the number of used varying registers, or -1 if unsuccesful
-int DynamicHLSL::packVaryings(InfoLog &infoLog,
-                              std::vector<PackedVarying> *packedVaryings,
-                              const std::vector<std::string> &transformFeedbackVaryings)
+void DynamicHLSL::generateVaryingHLSL(const VaryingPacking &varyingPacking,
+                                      std::stringstream &hlslStream) const
 {
-    // TODO (geofflang):  Use context's caps
-    const int maxVaryingVectors = mRenderer->getRendererCaps().maxVaryingVectors;
+    std::string varyingSemantic =
+        GetVaryingSemantic(mRenderer->getMajorShaderModel(), varyingPacking.usesPointSize());
 
-    VaryingPacking packing = {};
-
-    std::set<std::string> uniqueVaryingNames;
+    for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
+    {
+        const auto &varying = *registerInfo.packedVarying->varying;
+        ASSERT(!varying.isStruct());
 
-    for (PackedVarying &packedVarying : *packedVaryings)
-    {
-        const sh::Varying &varying = *packedVarying.varying;
+        // TODO: Add checks to ensure D3D interpolation modifiers don't result in too many
+        // registers being used.
+        // For example, if there are N registers, and we have N vec3 varyings and 1 float
+        // varying, then D3D will pack them into N registers.
+        // If the float varying has the 'nointerpolation' modifier on it then we would need
+        // N + 1 registers, and D3D compilation will fail.
 
-        // Do not assign registers to built-in or unreferenced varyings
-        if (varying.isBuiltIn() || !varying.staticUse)
+        switch (registerInfo.packedVarying->interpolation)
         {
-            continue;
-        }
-
-        ASSERT(uniqueVaryingNames.count(varying.name) == 0);
-
-        if (PackVarying(&packedVarying, maxVaryingVectors, packing))
-        {
-            uniqueVaryingNames.insert(varying.name);
-        }
-        else
-        {
-            infoLog << "Could not pack varying " << varying.name;
-            return -1;
-        }
-    }
-
-    for (const std::string &transformFeedbackVaryingName : transformFeedbackVaryings)
-    {
-        if (transformFeedbackVaryingName == "gl_Position" ||
-            transformFeedbackVaryingName == "gl_PointSize")
-        {
-            // do not pack builtin XFB varyings
-            continue;
+            case sh::INTERPOLATION_SMOOTH:
+                hlslStream << "    ";
+                break;
+            case sh::INTERPOLATION_FLAT:
+                hlslStream << "    nointerpolation ";
+                break;
+            case sh::INTERPOLATION_CENTROID:
+                hlslStream << "    centroid ";
+                break;
+            default:
+                UNREACHABLE();
         }
 
-        if (uniqueVaryingNames.count(transformFeedbackVaryingName) == 0)
-        {
-            bool found = false;
-            for (PackedVarying &packedVarying : *packedVaryings)
-            {
-                const sh::Varying &varying = *packedVarying.varying;
-                if (transformFeedbackVaryingName == varying.name)
-                {
-                    if (!PackVarying(&packedVarying, maxVaryingVectors, packing))
-                    {
-                        infoLog << "Could not pack varying " << varying.name;
-                        return -1;
-                    }
-
-                    found = true;
-                    break;
-                }
-            }
-
-            if (!found)
-            {
-                infoLog << "Transform feedback varying " << transformFeedbackVaryingName
-                        << " does not exist in the vertex shader.";
-                return -1;
-            }
-        }
+        GLenum transposedType = gl::TransposeMatrixType(varying.type);
+        GLenum componentType  = gl::VariableComponentType(transposedType);
+        int columnCount = gl::VariableColumnCount(transposedType);
+        hlslStream << HLSLComponentTypeString(componentType, columnCount);
+        unsigned int semanticIndex = registerInfo.semanticIndex;
+        hlslStream << " v" << semanticIndex << " : " << varyingSemantic << semanticIndex << ";\n";
     }
-
-    // Return the number of used registers
-    int registers = 0;
-
-    for (int r = 0; r < maxVaryingVectors; r++)
-    {
-        if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
-        {
-            registers++;
-        }
-    }
-
-    return registers;
 }
 
-std::string DynamicHLSL::generateVaryingHLSL(const std::vector<PackedVarying> &varyings,
-                                             bool shaderUsesPointSize) const
+std::string DynamicHLSL::generateVertexShaderForInputLayout(
+    const std::string &sourceShader,
+    const InputLayout &inputLayout,
+    const std::vector<sh::Attribute> &shaderAttributes) const
 {
-    std::string varyingSemantic = getVaryingSemantic(shaderUsesPointSize);
-    std::string varyingHLS