Snap for 4662252 from 2d8bca0b7f655363cdfa31141621e43777d42c49 to pi-release

Change-Id: I0f59941ffbfe380cb5a5e340e013f11fdb00b333
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 2200c4b..c184044 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,12 +1,82 @@
 {
     "version": "0.2.0",
     "configurations": [
-
+        {
+            "name": "Gnome",
+            "type": "cppdbg",
+            "request": "launch",
+            "preLaunchTask": "make",
+            "program": "${workspaceRoot}/debug/OGLESIntroducingPVRApi",
+            "args": ["LD_LIBRARY_PATH=./"],
+            "stopAtEntry": false,
+            "cwd": "${workspaceRoot}/debug/",
+            "environment": [],
+            "externalConsole": true,
+            "linux": {
+                "MIMode": "gdb",
+                "setupCommands": [
+                    {
+                        "description": "Enable pretty-printing for gdb",
+                        "text": "-enable-pretty-printing",
+                        "ignoreFailures": true
+                    }
+                ]
+            },
+            "osx": {
+                "MIMode": "lldb"
+            },
+            "windows": {
+                "MIMode": "gdb",
+                "setupCommands": [
+                    {
+                        "description": "Enable pretty-printing for gdb",
+                        "text": "-enable-pretty-printing",
+                        "ignoreFailures": true
+                    }
+                ]
+            }
+        },
+        {
+            "name": "Glass",
+            "type": "cppdbg",
+            "request": "launch",
+            "preLaunchTask": "make",
+            "program": "${workspaceRoot}/debug/OGLESGlass",
+            "args": ["LD_LIBRARY_PATH=./"],
+            "stopAtEntry": false,
+            "cwd": "${workspaceRoot}/debug/",
+            "environment": [],
+            "externalConsole": true,
+            "linux": {
+                "MIMode": "gdb",
+                "setupCommands": [
+                    {
+                        "description": "Enable pretty-printing for gdb",
+                        "text": "-enable-pretty-printing",
+                        "ignoreFailures": true
+                    }
+                ]
+            },
+            "osx": {
+                "MIMode": "lldb"
+            },
+            "windows": {
+                "MIMode": "gdb",
+                "setupCommands": [
+                    {
+                        "description": "Enable pretty-printing for gdb",
+                        "text": "-enable-pretty-printing",
+                        "ignoreFailures": true
+                    }
+                ]
+            }
+        },
         {
             "name": "SubzeroTest",
             "type": "cppdbg",
             "request": "launch",
-            "program": "${workspaceRoot}/build/SubzeroTest",
+            "preLaunchTask": "make",
+            "program": "${workspaceRoot}/debug/SubzeroTest",
             "args": [],
             "stopAtEntry": false,
             "cwd": "${workspaceRoot}",
@@ -40,7 +110,8 @@
             "name": "OGLES2HelloAPI",
             "type": "cppdbg",
             "request": "launch",
-            "program": "${workspaceRoot}/build/OGLES2HelloAPI",
+            "preLaunchTask": "make",
+            "program": "${workspaceRoot}/debug/OGLES2HelloAPI",
             "args": [],
             "stopAtEntry": false,
             "cwd": "${workspaceRoot}",
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 71f226d..2c00e06 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -17,7 +17,7 @@
     "showOutput": "always",
     "suppressTaskName": true,
     "options": {
-        "cwd": "${workspaceRoot}/build"
+        "cwd": "${workspaceRoot}/debug"
     },
     "tasks": [
         {
diff --git a/BUILD.gn b/BUILD.gn
index 0ef68d9..7af9f6a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import("//build/config/c++/c++.gni")
 import("//build/config/compiler/compiler.gni")
 
 config("swiftshader_config") {
@@ -21,11 +22,22 @@
     cflags = [
       "/GS",  # Detects some buffer overruns
       "/Zc:wchar_t",
-      "/EHsc",
+      "/EHs-c-",  # Disable C++ exceptions
       "/nologo",
       "/Gd",  # Default calling convention
     ]
 
+    if (!use_custom_libcxx) {
+      # Disable EH usage in STL headers.
+      # libc++ uses a predefined macro to control whether to use exceptions, so
+      # defining this macro is unnecessary. Defining _HAS_EXCEPTIONS to 0 also
+      # breaks libc++ because it depends on MSVC headers that only provide
+      # certain declarations if _HAS_EXCEPTIONS is 1.
+      defines += [
+        "_HAS_EXCEPTIONS=0",
+      ]
+    }
+
     defines += [
       "_CRT_SECURE_NO_DEPRECATE",
       "NOMINMAX",
@@ -73,13 +85,16 @@
       cflags += [
         "-m64",
         "-fPIC",
-        "-march=core2",
+        "-march=x86-64",
+        "-mtune=generic",
       ]
     } else {  # 32 bit version
       cflags += [
         "-m32",
         "-msse2",
-        "-march=i686",
+        "-mfpmath=sse",
+        "-march=pentium4",
+        "-mtune=generic",
       ]
     }
 
@@ -97,6 +112,25 @@
   }
 }
 
+source_set("vertex_routine_fuzzer") {
+  sources = [
+    "tests/fuzzers/VertexRoutineFuzzer.cpp"
+  ]
+  if (is_win) {
+    cflags = [
+      "/wd4201",  # nameless struct/union
+      "/wd4065",  # switch statement contains 'default' but no 'case' labels
+      "/wd5030",  # attribute is not recognized
+    ]
+  }
+  include_dirs = [
+    "src/",
+  ]
+  deps = [
+    "src/OpenGL/libGLESv2:swiftshader_libGLESv2_static",
+  ]
+}
+
 group("swiftshader") {
   data_deps = [
     "src/OpenGL/libGLESv2:swiftshader_libGLESv2",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 619111f..834d4c1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -110,7 +110,8 @@
         # hides all the others. Gc sections is used in combination
         # with each functions being in its section, to reduce the
         # binary size.
-        set_target_properties(${TARGET} PROPERTIES LINK_FLAGS "${LINKFLAGS} -Wl,--hash-style=both,--version-script=${DIR}/exports.map,--gc-sections,--no-undefined")
+        set_target_properties(${TARGET} PROPERTIES LINK_FLAGS "${LINKFLAGS} -Wl,--hash-style=both,--version-script=${DIR}/${TARGET}.lds,--gc-sections,--no-undefined")
+        set_target_properties(${TARGET} PROPERTIES LINK_DEPENDS "${DIR}/${TARGET}.lds")
     endif()
 endmacro()
 
@@ -149,6 +150,8 @@
 else()
     set_cpp_flag("--std=c++11")
     set_cpp_flag("-Wall")
+    set_cpp_flag("-Werror=reorder")
+    set_cpp_flag("-Werror=sign-compare")
     set_cpp_flag("-fno-exceptions")
 
     # Don't allow symbols to be overridden by another module.
@@ -165,12 +168,15 @@
     if(ARCH EQUAL "x86")
         set_cpp_flag("-m32")
         set_cpp_flag("-msse2")
-        set_cpp_flag("-march=i686")
+        set_cpp_flag("-mfpmath=sse")
+        set_cpp_flag("-march=pentium4")
+        set_cpp_flag("-mtune=generic")
     endif()
     if(ARCH EQUAL "x86_64")
         set_cpp_flag("-m64")
         set_cpp_flag("-fPIC")
-        set_cpp_flag("-march=core2")
+        set_cpp_flag("-march=x86-64")
+        set_cpp_flag("-mtune=generic")
     endif()
 
     # Use -g3 to have even more debug info
@@ -687,11 +693,6 @@
 
 set(COMMON_INCLUDE_DIR
     ${SOURCE_DIR}
-    ${SOURCE_DIR}/Common
-    ${SOURCE_DIR}/Main
-    ${SOURCE_DIR}/Reactor
-    ${SOURCE_DIR}/Renderer
-    ${SOURCE_DIR}/Shader
     ${CMAKE_SOURCE_DIR}/include
     ${LLVM_INCLUDE_DIR}
 )
diff --git a/OWNERS b/OWNERS
index 7aa5e42..a402880 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,4 +4,6 @@
 # in this list has approved a SwiftShader related change before landing it.
 
 nicolascapens@google.com
-sugoi@google.com
\ No newline at end of file
+sugoi@google.com
+
+# COMPONENT: Internals>GPU>SwiftShader
\ No newline at end of file
diff --git a/SwiftShader.sln b/SwiftShader.sln
index d0501a3..c216b78 100644
--- a/SwiftShader.sln
+++ b/SwiftShader.sln
@@ -1,6 +1,6 @@
 Microsoft Visual Studio Solution File, Format Version 12.00

-# Visual Studio 14

-VisualStudioVersion = 14.0.25420.1

+# Visual Studio 15

+VisualStudioVersion = 15.0.26730.16

 MinimumVisualStudioVersion = 10.0.40219.1

 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LLVM", "LLVM", "{B408B98A-E888-4ECF-81E0-7A37A6854B17}"

 EndProject

@@ -826,4 +826,7 @@
 		{4EC107AB-89E8-4A0B-8366-B3E81085AE07} = {ED25C308-5BDB-43A7-BED6-C2C059FC2D7D}

 		{CF8EBC89-8762-49DC-9440-6C82B3499913} = {ED25C308-5BDB-43A7-BED6-C2C059FC2D7D}

 	EndGlobalSection

+	GlobalSection(ExtensibilityGlobals) = postSolution

+		SolutionGuid = {4DF423D2-8425-48A7-9CEC-835C4C3CA957}

+	EndGlobalSection

 EndGlobal

diff --git a/docs/Index.md b/docs/Index.md
index 12c4318..f51f87e 100644
--- a/docs/Index.md
+++ b/docs/Index.md
@@ -55,7 +55,7 @@
 

 The GLSL compiler is implemented in [src/OpenGL/compiler/](../src/OpenGL/compiler/). It uses [Flex](http://flex.sourceforge.net/) and [Bison](https://www.gnu.org/software/bison/) to tokenize and parse GLSL shader source. It produces an [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (AST), which is then traversed to output assembly-level instructions in [OutputASM.cpp](../src/OpenGL/compiler/OutputASM.cpp).

 

-The [EGL](https://www.khronos.org/registry/egl/specs/eglspec.1.4.20110406.pdf) API is implemented in [src/OpenGL/libEGL/](../src/OpenGL/libEGL/). Its entry functions are listed in [libEGL.def](../src/OpenGL/libEGL/libEGL.def) (for Windows) and [exports.map](../src/OpenGL/libEGL/exports.map) (for Linux), and defined in [main.cpp](../src/OpenGL/libEGL/main.cpp) and implemented in [libEGL.cpp](../src/OpenGL/libEGL/libEGL.cpp). The [Display](../src/OpenGL/libEGL/Display.h), [Surface](../src/OpenGL/libEGL/Surface.h), and [Config](../src/OpenGL/libEGL/Config.h) classes are respective implementations of the abstract EGLDisplay, EGLSurface, and EGLConfig types.

+The [EGL](https://www.khronos.org/registry/egl/specs/eglspec.1.4.20110406.pdf) API is implemented in [src/OpenGL/libEGL/](../src/OpenGL/libEGL/). Its entry functions are listed in [libEGL.def](../src/OpenGL/libEGL/libEGL.def) (for Windows) and [libEGL.lds](../src/OpenGL/libEGL/libEGL.lds) (for Linux), and defined in [main.cpp](../src/OpenGL/libEGL/main.cpp) and implemented in [libEGL.cpp](../src/OpenGL/libEGL/libEGL.cpp). The [Display](../src/OpenGL/libEGL/Display.h), [Surface](../src/OpenGL/libEGL/Surface.h), and [Config](../src/OpenGL/libEGL/Config.h) classes are respective implementations of the abstract EGLDisplay, EGLSurface, and EGLConfig types.

 

 [OpenGL ES 1.1](https://www.khronos.org/registry/gles/specs/1.1/es_full_spec_1.1.12.pdf) is implemented in [src/OpenGL/libGLES_CM/](../src/OpenGL/libGLES_CM/), while [OpenGL ES 2.0](https://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf) is implemented in [src/OpenGL/libGLESv2/](../src/OpenGL/libGLESv2/). Note that while [OpenGL ES 3.0](https://www.khronos.org/registry/gles/specs/3.0/es_spec_3.0.0.pdf) functions are implemented in [libGLESv3.cpp](../src/OpenGL/libGLESv2/libGLESv3.cpp), it is compiled into the libGLESv2 library as standard among most implementations (some platforms have a libGLESv3 symbolically link to libGLESv2). We'll focus on OpenGL ES 2.0 in this documentation.

 

diff --git a/src/Android.mk b/src/Android.mk
index dc31261..945daf8 100644
--- a/src/Android.mk
+++ b/src/Android.mk
@@ -4,11 +4,7 @@
 	bionic \
 	$(LOCAL_PATH)/../include \
 	$(LOCAL_PATH)/OpenGL/ \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/Renderer/ \
-	$(LOCAL_PATH)/Common/ \
-	$(LOCAL_PATH)/Shader/ \
-	$(LOCAL_PATH)/Main/
+	$(LOCAL_PATH)
 
 ifdef use_subzero
 COMMON_C_INCLUDES += \
diff --git a/src/Common/Debug.hpp b/src/Common/Debug.hpp
index 0632743..5ccc35a 100644
--- a/src/Common/Debug.hpp
+++ b/src/Common/Debug.hpp
@@ -27,19 +27,19 @@
 
 void trace(const char *format, ...);
 
-#ifndef NDEBUG
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
 	#define TRACE(format, ...) trace("[0x%0.8X]%s(" format ")\n", this, __FUNCTION__, ##__VA_ARGS__)
 #else
 	#define TRACE(...) ((void)0)
 #endif
 
-#ifndef NDEBUG
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
 	#define UNIMPLEMENTED() {trace("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); ASSERT(false);}
 #else
 	#define UNIMPLEMENTED() ((void)0)
 #endif
 
-#ifndef NDEBUG
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
 	#define ASSERT(expression) {if(!(expression)) trace("\t! Assert failed in %s(%d): " #expression "\n", __FUNCTION__, __LINE__); assert(expression);}
 #else
 	#define ASSERT assert
diff --git a/src/Common/Half.hpp b/src/Common/Half.hpp
index f62ea27..f2d378e 100644
--- a/src/Common/Half.hpp
+++ b/src/Common/Half.hpp
@@ -20,6 +20,7 @@
 	class half
 	{
 	public:
+		half() = default;
 		explicit half(float f);
 
 		operator float() const;
@@ -30,6 +31,63 @@
 	private:
 		unsigned short fp16i;
 	};
+
+	inline half shortAsHalf(short s)
+	{
+		union
+		{
+			half h;
+			short s;
+		} hs;
+
+		hs.s = s;
+
+		return hs.h;
+	}
+
+	class RGB9E5
+	{
+		unsigned int R : 9;
+		unsigned int G : 9;
+		unsigned int B : 9;
+		unsigned int E : 5;
+
+	public:
+		void toRGB16F(half rgb[3]) const
+		{
+			constexpr int offset = 24;   // Exponent bias (15) + number of mantissa bits per component (9) = 24
+
+			const float factor = (1u << E) * (1.0f / (1 << offset));
+			rgb[0] = half(R * factor);
+			rgb[1] = half(G * factor);
+			rgb[2] = half(B * factor);
+		}
+	};
+
+	class R11G11B10F
+	{
+		unsigned int R : 11;
+		unsigned int G : 11;
+		unsigned int B : 10;
+
+		static inline half float11ToFloat16(unsigned short fp11)
+		{
+			return shortAsHalf(fp11 << 4);   // Sign bit 0
+		}
+
+		static inline half float10ToFloat16(unsigned short fp10)
+		{
+			return shortAsHalf(fp10 << 5);   // Sign bit 0
+		}
+
+	public:
+		void toRGB16F(half rgb[3]) const
+		{
+			rgb[0] = float11ToFloat16(R);
+			rgb[1] = float11ToFloat16(G);
+			rgb[2] = float10ToFloat16(B);
+		}
+	};
 }
 
 #endif   // sw_Half_hpp
diff --git a/src/Common/Math.hpp b/src/Common/Math.hpp
index 0b4abe6..dd2bc9c 100644
--- a/src/Common/Math.hpp
+++ b/src/Common/Math.hpp
@@ -16,6 +16,7 @@
 #define sw_Math_hpp
 
 #include "Types.hpp"
+#include "Half.hpp"
 
 #include <cmath>
 #if defined(_MSC_VER)
@@ -73,6 +74,18 @@
 		b = t;
 	}
 
+	template <typename destType, typename sourceType>
+	destType bitCast(const sourceType &source)
+	{
+		union
+		{
+			sourceType s;
+			destType d;
+		} sd;
+		sd.s = source;
+		return sd.d;
+	}
+
 	inline int iround(float x)
 	{
 		return (int)floor(x + 0.5f);
@@ -295,6 +308,7 @@
 		static const unsigned int min = 0x80000000 >> (32 - n);
 		static const unsigned int max = 0xFFFFFFFF >> (32 - n + 1);
 		static const float maxf = static_cast<float>(max);
+		static const float minf = static_cast<float>(min);
 		static const unsigned int range = 0xFFFFFFFF >> (32 - n);
 
 		if(x > 0.0f)
@@ -305,18 +319,18 @@
 			}
 			else
 			{
-				return static_cast<int>(maxf * x + 0.5f);
+				return static_cast<int>(x + 0.5f);
 			}
 		}
 		else
 		{
-			if(x <= -1.0f)
+			if(x <= -minf)
 			{
 				return min;
 			}
 			else
 			{
-				return static_cast<int>(maxf * x - 0.5f) & range;
+				return static_cast<int>(x - 0.5f) & range;
 			}
 		}
 	}
@@ -359,122 +373,6 @@
 	{
 		return static_cast<int>(min(x, 0x7FFFFFFFu));
 	}
-
-	class RGB9E5Data
-	{
-		unsigned int R : 9;
-		unsigned int G : 9;
-		unsigned int B : 9;
-		unsigned int E : 5;
-
-	public:
-		void toRGBFloats(float* rgb) const
-		{
-			static const float Offset = -24.0f; // Exponent Bias (15) + Number of mantissa bits per component (9) = 24
-
-			const float factor = powf(2.0f, static_cast<float>(E) + Offset);
-			rgb[0] = static_cast<float>(R) * factor;
-			rgb[1] = static_cast<float>(G) * factor;
-			rgb[2] = static_cast<float>(B) * factor;
-		}
-	};
-
-	class R11G11B10FData
-	{
-		unsigned int R : 11;
-		unsigned int G : 11;
-		unsigned int B : 10;
-
-		static inline float float11ToFloat32(unsigned short fp11)
-		{
-			unsigned short exponent = (fp11 >> 6) & 0x1F;
-			unsigned short mantissa = fp11 & 0x3F;
-
-			unsigned int output;
-			if(exponent == 0x1F)
-			{
-				// INF or NAN
-				output = 0x7f800000 | (mantissa << 17);
-			}
-			else
-			{
-				if(exponent != 0)
-				{
-					// normalized
-				}
-				else if(mantissa != 0)
-				{
-					// The value is denormalized
-					exponent = 1;
-
-					do
-					{
-						exponent--;
-						mantissa <<= 1;
-					} while((mantissa & 0x40) == 0);
-
-					mantissa = mantissa & 0x3F;
-				}
-				else // The value is zero
-				{
-					exponent = static_cast<unsigned short>(-112);
-				}
-
-				output = ((exponent + 112) << 23) | (mantissa << 17);
-			}
-
-			return *(float*)(&output);
-		}
-
-		static inline float float10ToFloat32(unsigned short fp10)
-		{
-			unsigned short exponent = (fp10 >> 5) & 0x1F;
-			unsigned short mantissa = fp10 & 0x1F;
-
-			unsigned int output;
-			if(exponent == 0x1F)
-			{
-				// INF or NAN
-				output = 0x7f800000 | (mantissa << 17);
-			}
-			else
-			{
-				if(exponent != 0)
-				{
-					// normalized
-				}
-				else if(mantissa != 0)
-				{
-					// The value is denormalized
-					exponent = 1;
-
-					do
-					{
-						exponent--;
-						mantissa <<= 1;
-					} while((mantissa & 0x20) == 0);
-
-					mantissa = mantissa & 0x1F;
-				}
-				else // The value is zero
-				{
-					exponent = static_cast<unsigned short>(-112);
-				}
-
-				output = ((exponent + 112) << 23) | (mantissa << 18);
-			}
-
-			return *(float*)(&output);
-		}
-
-	public:
-		void toRGBFloats(float* rgb) const
-		{
-			rgb[0] = float11ToFloat32(R);
-			rgb[1] = float11ToFloat32(G);
-			rgb[2] = float10ToFloat32(B);
-		}
-	};
 }
 
 #endif   // sw_Math_hpp
diff --git a/src/Common/MutexLock.hpp b/src/Common/MutexLock.hpp
index 65b4d7e..3a071c9 100644
--- a/src/Common/MutexLock.hpp
+++ b/src/Common/MutexLock.hpp
@@ -57,7 +57,7 @@
 	};
 }
 
-#else   // !__ANDROID__
+#else   // !__linux__
 
 #include <atomic>
 
diff --git a/src/Common/Resource.cpp b/src/Common/Resource.cpp
index e16968a..0e71e05 100644
--- a/src/Common/Resource.cpp
+++ b/src/Common/Resource.cpp
@@ -38,7 +38,7 @@
 	{
 		criticalSection.lock();
 
-		while(count != 0 && accessor != claimer)
+		while(count > 0 && accessor != claimer)
 		{
 			blocked++;
 			criticalSection.unlock();
@@ -84,7 +84,7 @@
 		}
 
 		// Acquire
-		while(count != 0 && accessor != claimer)
+		while(count > 0 && accessor != claimer)
 		{
 			blocked++;
 			criticalSection.unlock();
diff --git a/src/Common/Socket.cpp b/src/Common/Socket.cpp
index a19f574..b098031 100644
--- a/src/Common/Socket.cpp
+++ b/src/Common/Socket.cpp
@@ -20,6 +20,7 @@
 	#include <unistd.h>
 	#include <netdb.h>
 	#include <netinet/in.h>
+	#include <sys/select.h>
 #endif
 
 namespace sw
diff --git a/src/Common/Thread.hpp b/src/Common/Thread.hpp
index 3b9e674..186d1bd 100644
--- a/src/Common/Thread.hpp
+++ b/src/Common/Thread.hpp
@@ -28,6 +28,21 @@
 	#define TLS_OUT_OF_INDEXES (pthread_key_t)(~0)
 #endif
 
+#include <stdlib.h>
+
+#if defined(__clang__)
+#if __has_include(<atomic>) // clang has an explicit check for the availability of atomic
+#define USE_STD_ATOMIC 1
+#endif
+// atomic is available in C++11 or newer, and in Visual Studio 2012 or newer
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
+#define USE_STD_ATOMIC 1
+#endif
+
+#if USE_STD_ATOMIC
+#include <atomic>
+#endif
+
 namespace sw
 {
 	class Event;
@@ -52,8 +67,9 @@
 
 		static LocalStorageKey allocateLocalStorageKey();
 		static void freeLocalStorageKey(LocalStorageKey key);
-		static void setLocalStorage(LocalStorageKey key, void *value);
+		static void *allocateLocalStorage(LocalStorageKey key, size_t size);
 		static void *getLocalStorage(LocalStorageKey key);
+		static void freeLocalStorage(LocalStorageKey key);
 
 	private:
 		struct Entry
@@ -135,7 +151,7 @@
 			return TlsAlloc();
 		#else
 			LocalStorageKey key;
-			pthread_key_create(&key, NULL);
+			pthread_key_create(&key, free);
 			return key;
 		#endif
 	}
@@ -149,16 +165,24 @@
 		#endif
 	}
 
-	inline void Thread::setLocalStorage(LocalStorageKey key, void *value)
+	inline void *Thread::allocateLocalStorage(LocalStorageKey key, size_t size)
 	{
+		if(key == TLS_OUT_OF_INDEXES)
+		{
+			return nullptr;
+		}
+
+		freeLocalStorage(key);
+
+		void *storage = malloc(size);
+
 		#if defined(_WIN32)
-			TlsSetValue(key, value);
+			TlsSetValue(key, storage);
 		#else
-			if(key != TLS_OUT_OF_INDEXES)   // Avoid undefined behavior.
-			{
-				pthread_setspecific(key, value);
-			}
+			pthread_setspecific(key, storage);
 		#endif
+
+		return storage;
 	}
 
 	inline void *Thread::getLocalStorage(LocalStorageKey key)
@@ -175,6 +199,17 @@
 		#endif
 	}
 
+	inline void Thread::freeLocalStorage(LocalStorageKey key)
+	{
+		free(getLocalStorage(key));
+
+		#if defined(_WIN32)
+			TlsSetValue(key, nullptr);
+		#else
+			pthread_setspecific(key, nullptr);
+		#endif
+	}
+
 	inline void Event::signal()
 	{
 		#if defined(_WIN32)
@@ -243,7 +278,7 @@
 
 	inline int atomicAdd(volatile int* target, int value)
 	{
-		#if defined(_MSC_VER)
+		#if defined(_WIN32)
 			return InterlockedExchangeAdd((volatile long*)target, value) + value;
 		#else
 			return __sync_add_and_fetch(target, value);
@@ -258,6 +293,46 @@
 			__asm__ __volatile__ ("nop");
 		#endif
 	}
+
+	#if USE_STD_ATOMIC
+		class AtomicInt
+		{
+		public:
+			AtomicInt() : ai() {}
+			AtomicInt(int i) : ai(i) {}
+
+			inline operator int() const { return ai.load(std::memory_order_acquire); }
+			inline void operator=(const AtomicInt& i) { ai.store(i.ai.load(std::memory_order_acquire), std::memory_order_release); }
+			inline void operator=(int i) { ai.store(i, std::memory_order_release); }
+			inline void operator--() { ai.fetch_sub(1, std::memory_order_acq_rel); }
+			inline void operator++() { ai.fetch_add(1, std::memory_order_acq_rel); }
+			inline int operator--(int) { return ai.fetch_sub(1, std::memory_order_acq_rel) - 1; }
+			inline int operator++(int) { return ai.fetch_add(1, std::memory_order_acq_rel) + 1; }
+			inline void operator-=(int i) { ai.fetch_sub(i, std::memory_order_acq_rel); }
+			inline void operator+=(int i) { ai.fetch_add(i, std::memory_order_acq_rel); }
+		private:
+			std::atomic<int> ai;
+		};
+	#else
+		class AtomicInt
+		{
+		public:
+			AtomicInt() {}
+			AtomicInt(int i) : vi(i) {}
+
+			inline operator int() const { return vi; } // Note: this isn't a guaranteed atomic operation
+			inline void operator=(const AtomicInt& i) { sw::atomicExchange(&vi, i.vi); }
+			inline void operator=(int i) { sw::atomicExchange(&vi, i); }
+			inline void operator--() { sw::atomicDecrement(&vi); }
+			inline void operator++() { sw::atomicIncrement(&vi); }
+			inline int operator--(int) { return sw::atomicDecrement(&vi); }
+			inline int operator++(int) { return sw::atomicIncrement(&vi); }
+			inline void operator-=(int i) { sw::atomicAdd(&vi, -i); }
+			inline void operator+=(int i) { sw::atomicAdd(&vi, i); }
+		private:
+			volatile int vi;
+		};
+	#endif
 }
 
 #endif   // sw_Thread_hpp
diff --git a/src/Common/Version.h b/src/Common/Version.h
index d1beda2..1747820 100644
--- a/src/Common/Version.h
+++ b/src/Common/Version.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define MAJOR_VERSION 3
-#define MINOR_VERSION 3
+#define MAJOR_VERSION 4
+#define MINOR_VERSION 0
 #define BUILD_VERSION 0
 #define BUILD_REVISION 2
 
diff --git a/src/D3D8/Capabilities.cpp b/src/D3D8/Capabilities.cpp
index dd0ba20..53cd68e 100644
--- a/src/D3D8/Capabilities.cpp
+++ b/src/D3D8/Capabilities.cpp
@@ -55,11 +55,11 @@
 	bool Capabilities::Surface::A8P8 = false;
 	bool Capabilities::Surface::G16R16 = true;
 	bool Capabilities::Surface::A2B10G10R10 = true;
-	bool Capabilities::Surface::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::Surface::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::Surface::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::Surface::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::Surface::DXT5 = S3TC_SUPPORT;
+	bool Capabilities::Surface::DXT1 = true;
+	bool Capabilities::Surface::DXT2 = true;
+	bool Capabilities::Surface::DXT3 = true;
+	bool Capabilities::Surface::DXT4 = true;
+	bool Capabilities::Surface::DXT5 = true;
 	bool Capabilities::Surface::V8U8 = true;
 	bool Capabilities::Surface::L6V5U5 = true;
 	bool Capabilities::Surface::X8L8V8U8 = true;
@@ -87,11 +87,11 @@
 	bool Capabilities::Volume::A8P8 = false;
 	bool Capabilities::Volume::G16R16 = true;
 	bool Capabilities::Volume::A2B10G10R10 = true;
-	bool Capabilities::Volume::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::Volume::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::Volume::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::Volume::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::Volume::DXT5 = S3TC_SUPPORT;
+	bool Capabilities::Volume::DXT1 = true;
+	bool Capabilities::Volume::DXT2 = true;
+	bool Capabilities::Volume::DXT3 = true;
+	bool Capabilities::Volume::DXT4 = true;
+	bool Capabilities::Volume::DXT5 = true;
 	bool Capabilities::Volume::V8U8 = true;
 	bool Capabilities::Volume::L6V5U5 = true;
 	bool Capabilities::Volume::X8L8V8U8 = true;
@@ -139,11 +139,11 @@
 	bool Capabilities::CubeMap::A8P8 = false;
 	bool Capabilities::CubeMap::G16R16 = true;
 	bool Capabilities::CubeMap::A2B10G10R10 = true;
-	bool Capabilities::CubeMap::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::DXT5 = S3TC_SUPPORT;
+	bool Capabilities::CubeMap::DXT1 = true;
+	bool Capabilities::CubeMap::DXT2 = true;
+	bool Capabilities::CubeMap::DXT3 = true;
+	bool Capabilities::CubeMap::DXT4 = true;
+	bool Capabilities::CubeMap::DXT5 = true;
 	bool Capabilities::CubeMap::V8U8 = true;
 	bool Capabilities::CubeMap::L6V5U5 = true;
 	bool Capabilities::CubeMap::X8L8V8U8 = true;
@@ -171,11 +171,11 @@
 	bool Capabilities::VolumeTexture::A8P8 = false;
 	bool Capabilities::VolumeTexture::G16R16 = true;
 	bool Capabilities::VolumeTexture::A2B10G10R10 = true;
-	bool Capabilities::VolumeTexture::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::DXT5 = S3TC_SUPPORT;
+	bool Capabilities::VolumeTexture::DXT1 = true;
+	bool Capabilities::VolumeTexture::DXT2 = true;
+	bool Capabilities::VolumeTexture::DXT3 = true;
+	bool Capabilities::VolumeTexture::DXT4 = true;
+	bool Capabilities::VolumeTexture::DXT5 = true;
 	bool Capabilities::VolumeTexture::V8U8 = true;
 	bool Capabilities::VolumeTexture::L6V5U5 = true;
 	bool Capabilities::VolumeTexture::X8L8V8U8 = true;
@@ -223,11 +223,11 @@
 	bool Capabilities::Texture::A8P8 = false;
 	bool Capabilities::Texture::G16R16 = true;
 	bool Capabilities::Texture::A2B10G10R10 = true;
-	bool Capabilities::Texture::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::Texture::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::Texture::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::Texture::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::Texture::DXT5 = S3TC_SUPPORT;
+	bool Capabilities::Texture::DXT1 = true;
+	bool Capabilities::Texture::DXT2 = true;
+	bool Capabilities::Texture::DXT3 = true;
+	bool Capabilities::Texture::DXT4 = true;
+	bool Capabilities::Texture::DXT5 = true;
 	bool Capabilities::Texture::V8U8 = true;
 	bool Capabilities::Texture::L6V5U5 = true;
 	bool Capabilities::Texture::X8L8V8U8 = true;
diff --git a/src/D3D8/D3D8.vcxproj b/src/D3D8/D3D8.vcxproj
index 6f42a4f..2cc027a 100644
--- a/src/D3D8/D3D8.vcxproj
+++ b/src/D3D8/D3D8.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -17,25 +17,26 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{F18D5ABF-CA3A-4B74-BDB2-4A1956C86F18}</ProjectGuid>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>false</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

@@ -102,8 +103,6 @@
       <ModuleDefinitionFile>d3d8.def</ModuleDefinitionFile>

       <GenerateDebugInformation>true</GenerateDebugInformation>

       <AssemblyDebug>true</AssemblyDebug>

-      <ProgramDatabaseFile>

-      </ProgramDatabaseFile>

       <GenerateMapFile>true</GenerateMapFile>

       <MapExports>true</MapExports>

       <SubSystem>Windows</SubSystem>

diff --git a/src/D3D8/Direct3DDevice8.cpp b/src/D3D8/Direct3DDevice8.cpp
index 7f6e769..1130d11 100644
--- a/src/D3D8/Direct3DDevice8.cpp
+++ b/src/D3D8/Direct3DDevice8.cpp
@@ -2149,7 +2149,7 @@
 		cursorBitmap->LockRect(&lock, 0, 0);
 
 		delete cursor;
-		cursor = sw::Surface::create(0, desc.Width, desc.Height, 1, sw::FORMAT_A8R8G8B8, false, false);
+		cursor = sw::Surface::create(0, desc.Width, desc.Height, 1, 0, 1, sw::FORMAT_A8R8G8B8, false, false);
 
 		void *buffer = cursor->lockExternal(0, 0, 0, sw::LOCK_DISCARD, sw::PUBLIC);
 		memcpy(buffer, lock.pBits, desc.Width * desc.Height * sizeof(unsigned int));
diff --git a/src/D3D8/Direct3DSurface8.cpp b/src/D3D8/Direct3DSurface8.cpp
index 6ad0e6b..f9d1e96 100644
--- a/src/D3D8/Direct3DSurface8.cpp
+++ b/src/D3D8/Direct3DSurface8.cpp
@@ -58,11 +58,12 @@
 		return 1;
 	}
 
-	Direct3DSurface8::Direct3DSurface8(Direct3DDevice8 *device, Unknown *container, int width, int height, D3DFORMAT format, D3DPOOL pool, D3DMULTISAMPLE_TYPE multiSample, bool lockable, unsigned long usage) : Surface(getParentResource(container), width, height, sampleCount(multiSample), translateFormat(format), lockable, (usage & D3DUSAGE_RENDERTARGET) == D3DUSAGE_RENDERTARGET || (usage & D3DUSAGE_DEPTHSTENCIL) == D3DUSAGE_DEPTHSTENCIL), device(device), container(container), width(width), height(height), format(format), pool(pool), multiSample(multiSample), lockable(lockable), usage(usage)
+	Direct3DSurface8::Direct3DSurface8(Direct3DDevice8 *device, Unknown *container, int width, int height, D3DFORMAT format, D3DPOOL pool, D3DMULTISAMPLE_TYPE multiSample, bool lockable, unsigned long usage)
+		: Surface(getParentResource(container), width, height, 1, 0, sampleCount(multiSample), translateFormat(format), lockable, (usage & D3DUSAGE_RENDERTARGET) == D3DUSAGE_RENDERTARGET || (usage & D3DUSAGE_DEPTHSTENCIL) == D3DUSAGE_DEPTHSTENCIL), device(device), container(container), width(width), height(height), format(format), pool(pool), multiSample(multiSample), lockable(lockable), usage(usage)
 	{
 		parentTexture = dynamic_cast<Direct3DBaseTexture8*>(container);
 
-		resource = new Direct3DResource8(device, D3DRTYPE_SURFACE, memoryUsage(width, height, format));
+		resource = new Direct3DResource8(device, D3DRTYPE_SURFACE, memoryUsage(width, height, multiSample, format));
 	}
 
 	Direct3DSurface8::~Direct3DSurface8()
@@ -227,7 +228,7 @@
 		desc->Type = D3DRTYPE_SURFACE;
 		desc->Height = height;
 		desc->Width = width;
-		desc->Size = size(getWidth(), getHeight(), getDepth(), getExternalFormat());
+		desc->Size = memoryUsage(width, height, multiSample, format);
 		desc->MultiSampleType = multiSample;
 		desc->Usage = usage;
 
@@ -283,8 +284,8 @@
 		return Surface::bytes(translateFormat(format));
 	}
 
-	unsigned int Direct3DSurface8::memoryUsage(int width, int height, D3DFORMAT format)
+	unsigned int Direct3DSurface8::memoryUsage(int width, int height, D3DMULTISAMPLE_TYPE multiSample, D3DFORMAT format)
 	{
-		return Surface::size(width, height, 1, translateFormat(format));
+		return Surface::size(width, height, 1, 0, sampleCount(multiSample), translateFormat(format));
 	}
 }
diff --git a/src/D3D8/Direct3DSurface8.hpp b/src/D3D8/Direct3DSurface8.hpp
index e07829d..5ccecf3 100644
--- a/src/D3D8/Direct3DSurface8.hpp
+++ b/src/D3D8/Direct3DSurface8.hpp
@@ -57,7 +57,7 @@
 		static int bytes(D3DFORMAT format);
 
 	private:
-		static unsigned int memoryUsage(int width, int height, D3DFORMAT format);   // FIXME: Surface::size
+		static unsigned int memoryUsage(int width, int height, D3DMULTISAMPLE_TYPE multiSample, D3DFORMAT format);   // FIXME: Surface::size
 
 		// Creation parameters
 		Direct3DDevice8 *const device;
diff --git a/src/D3D8/Direct3DSwapChain8.cpp b/src/D3D8/Direct3DSwapChain8.cpp
index a49bf11..d0e3b97 100644
--- a/src/D3D8/Direct3DSwapChain8.cpp
+++ b/src/D3D8/Direct3DSwapChain8.cpp
@@ -81,13 +81,9 @@
 			profiler.nextFrame();
 		#endif
 
-		void *source = backBuffer[0]->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);   // FIXME: External
-		sw::Format format = backBuffer[0]->getInternalFormat();
-		int stride = backBuffer[0]->getInternalPitchB();
-
 		if(!sourceRect && !destRect)   // FIXME: More cases?
 		{
-			frameBuffer->flip(destWindowOverride, source, format, stride);
+			frameBuffer->flip(destWindowOverride, backBuffer[0]);
 		}
 		else   // TODO: Check for SWAPEFFECT_COPY
 		{
@@ -110,11 +106,9 @@
 				dRect.y1 = destRect->bottom;
 			}
 
-			frameBuffer->blit(destWindowOverride, source, sourceRect ? &sRect : nullptr, destRect ? &dRect : nullptr, format, stride);
+			frameBuffer->blit(destWindowOverride, backBuffer[0], sourceRect ? &sRect : nullptr, destRect ? &dRect : nullptr);
 		}
 
-		backBuffer[0]->unlockInternal();   // FIXME: External
-
 		return D3D_OK;
 	}
 
@@ -133,7 +127,7 @@
 		}
 
 		this->backBuffer[index]->AddRef();
-		*backBuffer = this->backBuffer[index]; 
+		*backBuffer = this->backBuffer[index];
 
 		return D3D_OK;
 	}
@@ -155,7 +149,7 @@
 		device->GetCreationParameters(&creationParameters);
 
 		HWND windowHandle = presentParameters->hDeviceWindow ? presentParameters->hDeviceWindow : creationParameters.hFocusWindow;
-			
+
 		int width = 0;
 		int height = 0;
 
@@ -222,7 +216,7 @@
 	{
 		return backBuffer[index]->lockInternal(0, 0, 0, sw::LOCK_READWRITE, sw::PUBLIC);   // FIXME: External
 	}
-	
+
 	void Direct3DSwapChain8::unlockBackBuffer(int index)
 	{
 		backBuffer[index]->unlockInternal();   // FIXME: External
diff --git a/src/D3D8/Direct3DVolume8.cpp b/src/D3D8/Direct3DVolume8.cpp
index aa33ea1..9869068 100644
--- a/src/D3D8/Direct3DVolume8.cpp
+++ b/src/D3D8/Direct3DVolume8.cpp
@@ -23,7 +23,8 @@
 
 namespace D3D8
 {
-	Direct3DVolume8::Direct3DVolume8(Direct3DDevice8 *device, Direct3DVolumeTexture8 *container, int width, int height, int depth, D3DFORMAT format, D3DPOOL pool, bool lockable, unsigned long usage) : Surface(container->getResource(), width, height, depth, translateFormat(format), lockable, false), container(container), width(width), height(height), depth(depth), format(format), pool(pool), lockable(lockable), usage(usage)
+	Direct3DVolume8::Direct3DVolume8(Direct3DDevice8 *device, Direct3DVolumeTexture8 *container, int width, int height, int depth, D3DFORMAT format, D3DPOOL pool, bool lockable, unsigned long usage)
+		: Surface(container->getResource(), width, height, depth, 0, 1, translateFormat(format), lockable, false), container(container), width(width), height(height), depth(depth), format(format), pool(pool), lockable(lockable), usage(usage)
 	{
 		resource = new Direct3DResource8(device, D3DRTYPE_VOLUME, memoryUsage(width, height, depth, format));
 	}
@@ -144,8 +145,8 @@
 			return INVALIDCALL();
 		}
 
-		lockedVolume->RowPitch = pitchB(getWidth(), getExternalFormat(), false);
-		lockedVolume->SlicePitch = sliceB(getWidth(), getHeight(), getExternalFormat(), false);
+		lockedVolume->RowPitch = pitchB(getWidth(), 0, getExternalFormat(), false);
+		lockedVolume->SlicePitch = sliceB(getWidth(), getHeight(), 0, getExternalFormat(), false);
 
 		sw::Lock lock = sw::LOCK_READWRITE;
 
@@ -194,6 +195,6 @@
 
 	unsigned int Direct3DVolume8::memoryUsage(int width, int height, int depth, D3DFORMAT format)
 	{
-		return Surface::size(width, height, depth, translateFormat(format));
+		return Surface::size(width, height, depth, 0, 1, translateFormat(format));
 	}
 }
diff --git a/src/D3D9/Capabilities.cpp b/src/D3D9/Capabilities.cpp
index 2449045..572d983 100644
--- a/src/D3D9/Capabilities.cpp
+++ b/src/D3D9/Capabilities.cpp
@@ -71,13 +71,13 @@
 	bool Capabilities::Surface::A2R10G10B10 = true;
 	bool Capabilities::Surface::A2B10G10R10 = true;
 	bool Capabilities::Surface::A16B16G16R16 = true;
-	bool Capabilities::Surface::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::Surface::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::Surface::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::Surface::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::Surface::DXT5 = S3TC_SUPPORT;
-	bool Capabilities::Surface::ATI1 = S3TC_SUPPORT;
-	bool Capabilities::Surface::ATI2 = S3TC_SUPPORT;
+	bool Capabilities::Surface::DXT1 = true;
+	bool Capabilities::Surface::DXT2 = true;
+	bool Capabilities::Surface::DXT3 = true;
+	bool Capabilities::Surface::DXT4 = true;
+	bool Capabilities::Surface::DXT5 = true;
+	bool Capabilities::Surface::ATI1 = true;
+	bool Capabilities::Surface::ATI2 = true;
 	bool Capabilities::Surface::R16F = true;
 	bool Capabilities::Surface::G16R16F = true;
 	bool Capabilities::Surface::A16B16G16R16F = true;
@@ -117,13 +117,13 @@
 	bool Capabilities::Volume::A2R10G10B10 = true;
 	bool Capabilities::Volume::A2B10G10R10 = true;
 	bool Capabilities::Volume::A16B16G16R16 = true;
-	bool Capabilities::Volume::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::Volume::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::Volume::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::Volume::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::Volume::DXT5 = S3TC_SUPPORT;
-	bool Capabilities::Volume::ATI1 = S3TC_SUPPORT;
-	bool Capabilities::Volume::ATI2 = S3TC_SUPPORT;
+	bool Capabilities::Volume::DXT1 = true;
+	bool Capabilities::Volume::DXT2 = true;
+	bool Capabilities::Volume::DXT3 = true;
+	bool Capabilities::Volume::DXT4 = true;
+	bool Capabilities::Volume::DXT5 = true;
+	bool Capabilities::Volume::ATI1 = true;
+	bool Capabilities::Volume::ATI2 = true;
 	bool Capabilities::Volume::R16F = true;
 	bool Capabilities::Volume::G16R16F = true;
 	bool Capabilities::Volume::A16B16G16R16F = true;
@@ -195,13 +195,13 @@
 	bool Capabilities::CubeMap::A2R10G10B10 = true;
 	bool Capabilities::CubeMap::A2B10G10R10 = true;
 	bool Capabilities::CubeMap::A16B16G16R16 = true;
-	bool Capabilities::CubeMap::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::DXT5 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::ATI1 = S3TC_SUPPORT;
-	bool Capabilities::CubeMap::ATI2 = S3TC_SUPPORT;
+	bool Capabilities::CubeMap::DXT1 = true;
+	bool Capabilities::CubeMap::DXT2 = true;
+	bool Capabilities::CubeMap::DXT3 = true;
+	bool Capabilities::CubeMap::DXT4 = true;
+	bool Capabilities::CubeMap::DXT5 = true;
+	bool Capabilities::CubeMap::ATI1 = true;
+	bool Capabilities::CubeMap::ATI2 = true;
 	bool Capabilities::CubeMap::R16F = true;
 	bool Capabilities::CubeMap::G16R16F = true;
 	bool Capabilities::CubeMap::A16B16G16R16F = true;
@@ -239,13 +239,13 @@
 	bool Capabilities::VolumeTexture::A2R10G10B10 = true;
 	bool Capabilities::VolumeTexture::A2B10G10R10 = true;
 	bool Capabilities::VolumeTexture::A16B16G16R16 = true;
-	bool Capabilities::VolumeTexture::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::DXT5 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::ATI1 = S3TC_SUPPORT;
-	bool Capabilities::VolumeTexture::ATI2 = S3TC_SUPPORT;
+	bool Capabilities::VolumeTexture::DXT1 = true;
+	bool Capabilities::VolumeTexture::DXT2 = true;
+	bool Capabilities::VolumeTexture::DXT3 = true;
+	bool Capabilities::VolumeTexture::DXT4 = true;
+	bool Capabilities::VolumeTexture::DXT5 = true;
+	bool Capabilities::VolumeTexture::ATI1 = true;
+	bool Capabilities::VolumeTexture::ATI2 = true;
 	bool Capabilities::VolumeTexture::R16F = true;
 	bool Capabilities::VolumeTexture::G16R16F = true;
 	bool Capabilities::VolumeTexture::A16B16G16R16F = true;
@@ -318,13 +318,13 @@
 	bool Capabilities::Texture::A2R10G10B10 = true;
 	bool Capabilities::Texture::A2B10G10R10 = true;
 	bool Capabilities::Texture::A16B16G16R16 = true;
-	bool Capabilities::Texture::DXT1 = S3TC_SUPPORT;
-	bool Capabilities::Texture::DXT2 = S3TC_SUPPORT;
-	bool Capabilities::Texture::DXT3 = S3TC_SUPPORT;
-	bool Capabilities::Texture::DXT4 = S3TC_SUPPORT;
-	bool Capabilities::Texture::DXT5 = S3TC_SUPPORT;
-	bool Capabilities::Texture::ATI1 = S3TC_SUPPORT;
-	bool Capabilities::Texture::ATI2 = S3TC_SUPPORT;
+	bool Capabilities::Texture::DXT1 = true;
+	bool Capabilities::Texture::DXT2 = true;
+	bool Capabilities::Texture::DXT3 = true;
+	bool Capabilities::Texture::DXT4 = true;
+	bool Capabilities::Texture::DXT5 = true;
+	bool Capabilities::Texture::ATI1 = true;
+	bool Capabilities::Texture::ATI2 = true;
 	bool Capabilities::Texture::R16F = true;
 	bool Capabilities::Texture::G16R16F = true;
 	bool Capabilities::Texture::A16B16G16R16F = true;
diff --git a/src/D3D9/D3D9.vcxproj b/src/D3D9/D3D9.vcxproj
index 12389e8..71842ec 100644
--- a/src/D3D9/D3D9.vcxproj
+++ b/src/D3D9/D3D9.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -29,43 +29,44 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{F18D5ABF-CA3A-4B74-BDB2-4A1957C86F18}</ProjectGuid>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>false</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>false</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/src/D3D9/Direct3DCubeTexture9.cpp b/src/D3D9/Direct3DCubeTexture9.cpp
index b0b1925..7d34786 100644
--- a/src/D3D9/Direct3DCubeTexture9.cpp
+++ b/src/D3D9/Direct3DCubeTexture9.cpp
@@ -191,7 +191,7 @@
 
 		for(unsigned int face = 0; face < 6; face++)
 		{
-			if(!surfaceLevel[face][0]->hasDirtyMipmaps())
+			if(!surfaceLevel[face][0]->hasDirtyContents())
 			{
 				continue;
 			}
@@ -201,7 +201,7 @@
 				device->stretchRect(surfaceLevel[face][i], 0, surfaceLevel[face][i + 1], 0, GetAutoGenFilterType());
 			}
 
-			surfaceLevel[face][0]->cleanMipmaps();
+			surfaceLevel[face][0]->markContentsClean();
 		}
 
 		resource->unlock();
diff --git a/src/D3D9/Direct3DDevice9.cpp b/src/D3D9/Direct3DDevice9.cpp
index 4be7955..d033bcc 100644
--- a/src/D3D9/Direct3DDevice9.cpp
+++ b/src/D3D9/Direct3DDevice9.cpp
@@ -1831,14 +1831,15 @@
 
 			static void (__cdecl *blitFunction)(void *dst, void *src);
 			static sw::Routine *blitRoutine;
-			static sw::BlitState blitState = {0};
+			static sw::BlitState blitState = {};
 
 			sw::BlitState update;
 			update.width = sourceDescription.Width;
 			update.height = sourceDescription.Height;
 			update.sourceFormat = sw::FORMAT_A8R8G8B8;
+			update.sourceStride = source->getExternalPitchB();
 			update.destFormat = sw::FORMAT_A8R8G8B8;
-			update.stride = dest->getExternalPitchB();
+			update.destStride = dest->getExternalPitchB();
 			update.cursorHeight = 0;
 			update.cursorWidth = 0;
 
@@ -2659,7 +2660,7 @@
 		void *bitmap = cursorSurface->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
 
 		delete cursor;
-		cursor = sw::Surface::create(0, width, height, 1, sw::FORMAT_A8R8G8B8, false, false);
+		cursor = sw::Surface::create(nullptr, width, height, 1, 0, 1, sw::FORMAT_A8R8G8B8, false, false);
 
 		void *buffer = cursor->lockExternal(0, 0, 0, sw::LOCK_DISCARD, sw::PUBLIC);
 		memcpy(buffer, bitmap, width * height * sizeof(unsigned int));
@@ -2673,7 +2674,7 @@
 		}
 		else
 		{
-			sw::FrameBuffer::setCursorImage(0);
+			sw::FrameBuffer::setCursorImage(nullptr);
 		}
 
 		sw::FrameBuffer::setCursorOrigin(x0, y0);
@@ -6322,7 +6323,8 @@
 		}
 		else
 		{
-			renderer->blit(source, sRect, dest, dRect, filter >= D3DTEXF_LINEAR);
+			sw::SliceRectF sRectF((float)sRect.x0, (float)sRect.y0, (float)sRect.x1, (float)sRect.y1, 0);
+			renderer->blit(source, sRectF, dest, dRect, filter >= D3DTEXF_LINEAR);
 		}
 	}
 
diff --git a/src/D3D9/Direct3DSurface9.cpp b/src/D3D9/Direct3DSurface9.cpp
index fdbc099..8dfa3a8 100644
--- a/src/D3D9/Direct3DSurface9.cpp
+++ b/src/D3D9/Direct3DSurface9.cpp
@@ -76,7 +76,8 @@
 		return (pool != D3DPOOL_DEFAULT) || (usage & D3DUSAGE_DYNAMIC) || lockableOverride;
 	}
 
-	Direct3DSurface9::Direct3DSurface9(Direct3DDevice9 *device, Unknown *container, int width, int height, D3DFORMAT format, D3DPOOL pool, D3DMULTISAMPLE_TYPE multiSample, unsigned int quality, bool lockableOverride, unsigned long usage) : Direct3DResource9(device, D3DRTYPE_SURFACE, pool, memoryUsage(width, height, format)), Surface(getParentResource(container), width, height, sampleCount(multiSample, quality), translateFormat(format), isLockable(pool, usage, lockableOverride), (usage & D3DUSAGE_RENDERTARGET) || (usage & D3DUSAGE_DEPTHSTENCIL)), container(container), width(width), height(height), format(format), pool(pool), multiSample(multiSample), quality(quality), lockable(isLockable(pool, usage, lockableOverride)), usage(usage)
+	Direct3DSurface9::Direct3DSurface9(Direct3DDevice9 *device, Unknown *container, int width, int height, D3DFORMAT format, D3DPOOL pool, D3DMULTISAMPLE_TYPE multiSample, unsigned int quality, bool lockableOverride, unsigned long usage)
+		: Direct3DResource9(device, D3DRTYPE_SURFACE, pool, memoryUsage(width, height, multiSample, quality, format)), Surface(getParentResource(container), width, height, 1, 0, sampleCount(multiSample, quality), translateFormat(format), isLockable(pool, usage, lockableOverride), (usage & D3DUSAGE_RENDERTARGET) || (usage & D3DUSAGE_DEPTHSTENCIL)), container(container), width(width), height(height), format(format), pool(pool), multiSample(multiSample), quality(quality), lockable(isLockable(pool, usage, lockableOverride)), usage(usage)
 	{
 		parentTexture = dynamic_cast<Direct3DBaseTexture9*>(container);
 	}
@@ -343,7 +344,6 @@
 	{
 		switch(format)
 		{
-		#if S3TC_SUPPORT
 		case D3DFMT_NULL:			return sw::FORMAT_NULL;
 		case D3DFMT_DXT1:			return sw::FORMAT_DXT1;
 		case D3DFMT_DXT2:			return sw::FORMAT_DXT3;
@@ -352,7 +352,6 @@
 		case D3DFMT_DXT5:			return sw::FORMAT_DXT5;
 		case D3DFMT_ATI1:			return sw::FORMAT_ATI1;
 		case D3DFMT_ATI2:			return sw::FORMAT_ATI2;
-		#endif
 		case D3DFMT_R3G3B2:			return sw::FORMAT_R3G3B2;
 		case D3DFMT_A8R3G3B2:		return sw::FORMAT_A8R3G3B2;
 		case D3DFMT_X4R4G4B4:		return sw::FORMAT_X4R4G4B4;
@@ -410,8 +409,8 @@
 		return Surface::bytes(translateFormat(format));
 	}
 
-	unsigned int Direct3DSurface9::memoryUsage(int width, int height, D3DFORMAT format)
+	unsigned int Direct3DSurface9::memoryUsage(int width, int height, D3DMULTISAMPLE_TYPE multiSample, unsigned int quality, D3DFORMAT format)
 	{
-		return Surface::size(width, height, 1, translateFormat(format));
+		return Surface::size(width, height, 1, 0, sampleCount(multiSample, quality), translateFormat(format));
 	}
 }
diff --git a/src/D3D9/Direct3DSurface9.hpp b/src/D3D9/Direct3DSurface9.hpp
index b7060d8..fa5f481 100644
--- a/src/D3D9/Direct3DSurface9.hpp
+++ b/src/D3D9/Direct3DSurface9.hpp
@@ -64,7 +64,7 @@
 		static int bytes(D3DFORMAT format);
 
 	private:
-		static unsigned int memoryUsage(int width, int height, D3DFORMAT format);
+		static unsigned int memoryUsage(int width, int height, D3DMULTISAMPLE_TYPE multiSample, unsigned int quality, D3DFORMAT format);
 
 		// Creation parameters
 		Unknown *const container;
diff --git a/src/D3D9/Direct3DSwapChain9.cpp b/src/D3D9/Direct3DSwapChain9.cpp
index 4b510aa..b446a9f 100644
--- a/src/D3D9/Direct3DSwapChain9.cpp
+++ b/src/D3D9/Direct3DSwapChain9.cpp
@@ -149,9 +149,6 @@
 		#endif
 
 		HWND window = destWindowOverride ? destWindowOverride : presentParameters.hDeviceWindow;
-		void *source = backBuffer[0]->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);   // FIXME: External
-		sw::Format format = backBuffer[0]->getInternalFormat();
-		int stride = backBuffer[0]->getInternalPitchB();
 
 		POINT point;
 		GetCursorPos(&point);
@@ -161,7 +158,7 @@
 
 		if(!sourceRect && !destRect)   // FIXME: More cases?
 		{
-			frameBuffer->flip(window, source, format, stride);
+			frameBuffer->flip(window, backBuffer[0]);
 		}
 		else   // FIXME: Check for SWAPEFFECT_COPY
 		{
@@ -184,11 +181,9 @@
 				dRect.y1 = destRect->bottom;
 			}
 
-			frameBuffer->blit(window, source, sourceRect ? &sRect : nullptr, destRect ? &dRect : nullptr, format, stride);
+			frameBuffer->blit(window, backBuffer[0], sourceRect ? &sRect : nullptr, destRect ? &dRect : nullptr);
 		}
 
-		backBuffer[0]->unlockInternal();   // FIXME: External
-
 		return D3D_OK;
 	}
 
diff --git a/src/D3D9/Direct3DTexture9.cpp b/src/D3D9/Direct3DTexture9.cpp
index a964782..079fba7 100644
--- a/src/D3D9/Direct3DTexture9.cpp
+++ b/src/D3D9/Direct3DTexture9.cpp
@@ -173,7 +173,7 @@
 
 		TRACE("");
 
-		if(!(usage & D3DUSAGE_AUTOGENMIPMAP) || !surfaceLevel[0]->hasDirtyMipmaps())
+		if(!(usage & D3DUSAGE_AUTOGENMIPMAP) || !surfaceLevel[0]->hasDirtyContents())
 		{
 			return;
 		}
@@ -185,7 +185,7 @@
 			device->stretchRect(surfaceLevel[i], 0, surfaceLevel[i + 1], 0, GetAutoGenFilterType());
 		}
 
-		surfaceLevel[0]->cleanMipmaps();
+		surfaceLevel[0]->markContentsClean();
 
 		resource->unlock();
 	}
diff --git a/src/D3D9/Direct3DVolume9.cpp b/src/D3D9/Direct3DVolume9.cpp
index 4bf498b..ca0d8a8 100644
--- a/src/D3D9/Direct3DVolume9.cpp
+++ b/src/D3D9/Direct3DVolume9.cpp
@@ -30,7 +30,8 @@
 		return (pool != D3DPOOL_DEFAULT) || (usage & D3DUSAGE_DYNAMIC);
 	}
 
-	Direct3DVolume9::Direct3DVolume9(Direct3DDevice9 *device, Direct3DVolumeTexture9 *container, int width, int height, int depth, D3DFORMAT format, D3DPOOL pool, unsigned long usage) : device(device), Surface(container->getResource(), width, height, depth, translateFormat(format), isLockable(pool, usage), false), container(container), width(width), height(height), depth(depth), format(format), pool(pool), lockable(isLockable(pool, usage)), usage(usage)
+	Direct3DVolume9::Direct3DVolume9(Direct3DDevice9 *device, Direct3DVolumeTexture9 *container, int width, int height, int depth, D3DFORMAT format, D3DPOOL pool, unsigned long usage)
+		: device(device), Surface(container->getResource(), width, height, depth, 0, 1, translateFormat(format), isLockable(pool, usage), false), container(container), width(width), height(height), depth(depth), format(format), pool(pool), lockable(isLockable(pool, usage)), usage(usage)
 	{
 		resource = new Direct3DResource9(device, D3DRTYPE_VOLUME, pool, memoryUsage(width, height, depth, format));
 		resource->bind();
@@ -229,6 +230,6 @@
 
 	unsigned int Direct3DVolume9::memoryUsage(int width, int height, int depth, D3DFORMAT format)
 	{
-		return Surface::size(width, height, depth, translateFormat(format));
+		return Surface::size(width, height, depth, 0, 1, translateFormat(format));
 	}
 }
diff --git a/src/D3D9/Direct3DVolumeTexture9.cpp b/src/D3D9/Direct3DVolumeTexture9.cpp
index 35caf43..c9024d1 100644
--- a/src/D3D9/Direct3DVolumeTexture9.cpp
+++ b/src/D3D9/Direct3DVolumeTexture9.cpp
@@ -174,7 +174,7 @@
 
 		TRACE("");
 
-		if(!(usage & D3DUSAGE_AUTOGENMIPMAP) || !volumeLevel[0]->hasDirtyMipmaps())
+		if(!(usage & D3DUSAGE_AUTOGENMIPMAP) || !volumeLevel[0]->hasDirtyContents())
 		{
 			return;
 		}
@@ -230,7 +230,7 @@
 			dest->unlockInternal();
 		}
 
-		volumeLevel[0]->cleanMipmaps();
+		volumeLevel[0]->markContentsClean();
 
 		resource->unlock();
 	}
diff --git a/src/Main/BUILD.gn b/src/Main/BUILD.gn
index 1f6d69c..99882a9 100644
--- a/src/Main/BUILD.gn
+++ b/src/Main/BUILD.gn
@@ -72,7 +72,6 @@
 
   include_dirs = [
     "..",
-    "../Common",
   ]
 
   if (is_mac) {
diff --git a/src/Main/Config.cpp b/src/Main/Config.cpp
index cee01ee..7cb309a 100644
--- a/src/Main/Config.cpp
+++ b/src/Main/Config.cpp
@@ -14,8 +14,8 @@
 
 #include "Config.hpp"
 
-#include "Thread.hpp"
-#include "Timer.hpp"
+#include "Common/Thread.hpp"
+#include "Common/Timer.hpp"
 
 namespace sw
 {
diff --git a/src/Main/Config.hpp b/src/Main/Config.hpp
index b9256ea..ff8bb7e 100644
--- a/src/Main/Config.hpp
+++ b/src/Main/Config.hpp
@@ -20,11 +20,7 @@
 #define PERF_HUD 0       // Display time spent on vertex, setup and pixel processing for each thread
 #define PERF_PROFILE 0   // Profile various pipeline stages and display the timing in SwiftConfig
 
-#if defined(_WIN32)
-#define S3TC_SUPPORT 1
-#else
-#define S3TC_SUPPORT 0
-#endif
+#define ASTC_SUPPORT 0
 
 // Worker thread count when not set by SwiftConfig
 // 0 = process affinity count (recommended)
@@ -84,11 +80,11 @@
 		TEXTURE_IMAGE_UNITS = 16,
 		VERTEX_TEXTURE_IMAGE_UNITS = 16,
 		TOTAL_IMAGE_UNITS = TEXTURE_IMAGE_UNITS + VERTEX_TEXTURE_IMAGE_UNITS,
-		FRAGMENT_UNIFORM_VECTORS = 224,
-		VERTEX_UNIFORM_VECTORS = 256,
-		MAX_VERTEX_INPUTS = 16,
-		MAX_VERTEX_OUTPUTS = 22,
-		MAX_FRAGMENT_INPUTS = 20,
+		FRAGMENT_UNIFORM_VECTORS = 227,
+		VERTEX_UNIFORM_VECTORS = 259,
+		MAX_VERTEX_INPUTS = 32,
+		MAX_VERTEX_OUTPUTS = 34,
+		MAX_FRAGMENT_INPUTS = 32,
 		MAX_FRAGMENT_UNIFORM_BLOCKS = 12,
 		MAX_VERTEX_UNIFORM_BLOCKS = 12,
 		MAX_UNIFORM_BUFFER_BINDINGS = MAX_FRAGMENT_UNIFORM_BLOCKS + MAX_VERTEX_UNIFORM_BLOCKS,   // Limited to 127 by SourceParameter.bufferIndex in Shader.hpp
diff --git a/src/Main/FrameBuffer.cpp b/src/Main/FrameBuffer.cpp
index e95f766..82dff46 100644
--- a/src/Main/FrameBuffer.cpp
+++ b/src/Main/FrameBuffer.cpp
@@ -14,9 +14,9 @@
 
 #include "FrameBuffer.hpp"
 
-#include "Timer.hpp"
 #include "Renderer/Surface.hpp"
 #include "Reactor/Reactor.hpp"
+#include "Common/Timer.hpp"
 #include "Common/Debug.hpp"
 
 #include <stdio.h>
@@ -27,7 +27,7 @@
 #include <cutils/properties.h>
 #endif
 
-#define ASYNCHRONOUS_BLIT 0   // FIXME: Currently leads to rare race conditions
+#define ASYNCHRONOUS_BLIT false   // FIXME: Currently leads to rare race conditions
 
 namespace sw
 {
@@ -40,30 +40,18 @@
 	{
 		this->topLeftOrigin = topLeftOrigin;
 
-		locked = nullptr;
+		framebuffer = nullptr;
 
 		this->width = width;
 		this->height = height;
-		destFormat = FORMAT_X8R8G8B8;
-		sourceFormat = FORMAT_X8R8G8B8;
+		format = FORMAT_X8R8G8B8;
 		stride = 0;
 
-		if(forceWindowed)
-		{
-			fullscreen = false;
-		}
-
-		windowed = !fullscreen;
+		windowed = !fullscreen || forceWindowed;
 
 		blitFunction = nullptr;
 		blitRoutine = nullptr;
-
-		blitState.width = 0;
-		blitState.height = 0;
-		blitState.destFormat = FORMAT_X8R8G8B8;
-		blitState.sourceFormat = FORMAT_X8R8G8B8;
-		blitState.cursorWidth = 0;
-		blitState.cursorHeight = 0;
+		blitState = {};
 
 		if(ASYNCHRONOUS_BLIT)
 		{
@@ -86,21 +74,6 @@
 		delete blitRoutine;
 	}
 
-	int FrameBuffer::getWidth() const
-	{
-		return width;
-	}
-
-	int FrameBuffer::getHeight() const
-	{
-		return height;
-	}
-
-	int FrameBuffer::getStride() const
-	{
-		return stride;
-	}
-
 	void FrameBuffer::setCursorImage(sw::Surface *cursorImage)
 	{
 		if(cursorImage)
@@ -130,7 +103,7 @@
 		cursor.positionY = y;
 	}
 
-	void FrameBuffer::copy(void *source, Format format, size_t stride)
+	void FrameBuffer::copy(sw::Surface *source)
 	{
 		if(!source)
 		{
@@ -142,15 +115,23 @@
 			return;
 		}
 
-		sourceFormat = format;
+		int sourceStride = source->getInternalPitchB();
 
-		if(topLeftOrigin)
+		updateState = {};
+		updateState.width = width;
+		updateState.height = height;
+		updateState.destFormat = format;
+		updateState.destStride = stride;
+		updateState.sourceFormat = source->getInternalFormat();
+		updateState.sourceStride = topLeftOrigin ? sourceStride : -sourceStride;
+		updateState.cursorWidth = cursor.width;
+		updateState.cursorHeight = cursor.height;
+
+		renderbuffer = source->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
+
+		if(!topLeftOrigin)
 		{
-			target = source;
-		}
-		else
-		{
-			target = (byte*)source + (height - 1) * stride;
+			renderbuffer = (byte*)renderbuffer + (height - 1) * sourceStride;
 		}
 
 		cursor.x = cursor.positionX - cursor.hotspotX;
@@ -166,6 +147,7 @@
 			copyLocked();
 		}
 
+		source->unlockInternal();
 		unlock();
 
 		profiler.nextFrame();   // Assumes every copy() is a full frame
@@ -173,36 +155,26 @@
 
 	void FrameBuffer::copyLocked()
 	{
-		BlitState update = {};
-		update.width = width;
-		update.height = height;
-		update.destFormat = destFormat;
-		update.sourceFormat = sourceFormat;
-		update.stride = stride;
-		update.cursorWidth = cursor.width;
-		update.cursorHeight = cursor.height;
-
-		if(memcmp(&blitState, &update, sizeof(BlitState)) != 0)
+		if(memcmp(&blitState, &updateState, sizeof(BlitState)) != 0)
 		{
-			blitState = update;
+			blitState = updateState;
 			delete blitRoutine;
 
 			blitRoutine = copyRoutine(blitState);
 			blitFunction = (void(*)(void*, void*, Cursor*))blitRoutine->getEntry();
 		}
 
-		blitFunction(locked, target, &cursor);
+		blitFunction(framebuffer, renderbuffer, &cursor);
 	}
 
 	Routine *FrameBuffer::copyRoutine(const BlitState &state)
 	{
 		const int width = state.width;
 		const int height = state.height;
-		const int width2 = (state.width + 1) & ~1;
 		const int dBytes = Surface::bytes(state.destFormat);
-		const int dStride = state.stride;
+		const int dStride = state.destStride;
 		const int sBytes = Surface::bytes(state.sourceFormat);
-		const int sStride = topLeftOrigin ? (sBytes * width2) : -(sBytes * width2);
+		const int sStride = state.sourceStride;
 
 		Function<Void(Pointer<Byte>, Pointer<Byte>, Pointer<Byte>)> function;
 		{
@@ -253,10 +225,10 @@
 						case FORMAT_A16B16G16R16:
 							For(, x < width - 1, x += 2)
 							{
-								UShort4 c0 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0xC6)) >> 8;
-								UShort4 c1 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 8), 0xC6)) >> 8;
+								Short4 c0 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0xC6)) >> 8;
+								Short4 c1 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 8), 0xC6)) >> 8;
 
-								*Pointer<Int2>(d) = As<Int2>(Pack(c0, c1));
+								*Pointer<Int2>(d) = As<Int2>(PackUnsigned(c0, c1));
 
 								s += 2 * sBytes;
 								d += 2 * dBytes;
@@ -300,9 +272,9 @@
 								break;
 							case FORMAT_A16B16G16R16:
 								{
-									UShort4 c = As<UShort4>(Swizzle(*Pointer<Short4>(s), 0xC6)) >> 8;
+									Short4 c = As<UShort4>(Swizzle(*Pointer<Short4>(s), 0xC6)) >> 8;
 
-									*Pointer<Int>(d) = Int(As<Int2>(Pack(c, c)));
+									*Pointer<Int>(d) = Int(As<Int2>(PackUnsigned(c, c)));
 								}
 								break;
 							case FORMAT_R5G6B5:
@@ -361,10 +333,10 @@
 						case FORMAT_A16B16G16R16:
 							For(, x < width - 1, x += 2)
 							{
-								UShort4 c0 = *Pointer<UShort4>(s + 0) >> 8;
-								UShort4 c1 = *Pointer<UShort4>(s + 8) >> 8;
+								Short4 c0 = *Pointer<UShort4>(s + 0) >> 8;
+								Short4 c1 = *Pointer<UShort4>(s + 8) >> 8;
 
-								*Pointer<Int2>(d) = As<Int2>(Pack(c0, c1));
+								*Pointer<Int2>(d) = As<Int2>(PackUnsigned(c0, c1));
 
 								s += 2 * sBytes;
 								d += 2 * dBytes;
@@ -408,9 +380,9 @@
 								break;
 							case FORMAT_A16B16G16R16:
 								{
-									UShort4 c = *Pointer<UShort4>(s) >> 8;
+									Short4 c = *Pointer<UShort4>(s) >> 8;
 
-									*Pointer<Int>(d) = Int(As<Int2>(Pack(c, c)));
+									*Pointer<Int>(d) = Int(As<Int2>(PackUnsigned(c, c)));
 								}
 								break;
 							case FORMAT_R5G6B5:
@@ -503,8 +475,8 @@
 								break;
 							case FORMAT_A16B16G16R16:
 								{
-									UShort4 cc = *Pointer<UShort4>(s) >> 8;
-									Int c = Int(As<Int2>(Pack(cc, cc)));
+									Short4 cc = *Pointer<UShort4>(s) >> 8;
+									Int c = Int(As<Int2>(PackUnsigned(cc, cc)));
 
 									*Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
 									                           (c & 0x0000FC00) >> 5 |
@@ -615,7 +587,7 @@
 		{
 		case FORMAT_X8R8G8B8:
 		case FORMAT_A8R8G8B8:
-			*Pointer<Byte4>(d) = Byte4(Pack(As<UShort4>(c1), As<UShort4>(c1)));
+			*Pointer<Byte4>(d) = Byte4(PackUnsigned(c1, c1));
 			break;
 		case FORMAT_X8B8G8R8:
 		case FORMAT_A8B8G8R8:
@@ -624,12 +596,12 @@
 			{
 				c1 = Swizzle(c1, 0xC6);
 
-				*Pointer<Byte4>(d) = Byte4(Pack(As<UShort4>(c1), As<UShort4>(c1)));
+				*Pointer<Byte4>(d) = Byte4(PackUnsigned(c1, c1));
 			}
 			break;
 		case FORMAT_R8G8B8:
 			{
-				Int c = Int(As<Int2>(Pack(As<UShort4>(c1), As<UShort4>(c1))));
+				Int c = Int(As<Int2>(PackUnsigned(c1, c1)));
 
 				*Pointer<Byte>(d + 0) = Byte(c >> 0);
 				*Pointer<Byte>(d + 1) = Byte(c >> 8);
@@ -638,7 +610,7 @@
 			break;
 		case FORMAT_R5G6B5:
 			{
-				Int c = Int(As<Int2>(Pack(As<UShort4>(c1), As<UShort4>(c1))));
+				Int c = Int(As<Int2>(PackUnsigned(c1, c1)));
 
 				*Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 |
 				                           (c & 0x0000FC00) >> 5 |
diff --git a/src/Main/FrameBuffer.hpp b/src/Main/FrameBuffer.hpp
index a18a0b1..dd539e1 100644
--- a/src/Main/FrameBuffer.hpp
+++ b/src/Main/FrameBuffer.hpp
@@ -29,7 +29,8 @@
 		int height;
 		Format destFormat;
 		Format sourceFormat;
-		int stride;
+		int destStride;
+		int sourceStride;
 		int cursorWidth;
 		int cursorHeight;
 	};
@@ -41,12 +42,8 @@
 
 		virtual ~FrameBuffer() = 0;
 
-		int getWidth() const;
-		int getHeight() const;
-		int getStride() const;
-
-		virtual void flip(void *source, Format sourceFormat, size_t sourceStride) = 0;
-		virtual void blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) = 0;
+		virtual void flip(sw::Surface *source) = 0;
+		virtual void blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect) = 0;
 
 		virtual void *lock() = 0;
 		virtual void unlock() = 0;
@@ -58,22 +55,22 @@
 		static Routine *copyRoutine(const BlitState &state);
 
 	protected:
-		void copy(void *source, Format format, size_t stride);
-		int width;
-		int height;
-		Format sourceFormat;
-		Format destFormat;
-		int stride;
+		void copy(sw::Surface *source);
+
 		bool windowed;
 
-		void *locked;   // Video memory back buffer
+		void *framebuffer;   // Native window buffer.
+		int width;
+		int height;
+		int stride;
+		Format format;
 
 	private:
 		void copyLocked();
 
 		static void threadFunction(void *parameters);
 
-		void *target;   // Render target buffer
+		void *renderbuffer;   // Render target buffer.
 
 		struct Cursor
 		{
@@ -92,7 +89,8 @@
 
 		void (*blitFunction)(void *dst, void *src, Cursor *cursor);
 		Routine *blitRoutine;
-		BlitState blitState;
+		BlitState blitState;     // State of the current blitRoutine.
+		BlitState updateState;   // State of the routine to be generated.
 
 		static void blend(const BlitState &state, const Pointer<Byte> &d, const Pointer<Byte> &s, const Pointer<Byte> &c);
 
diff --git a/src/Main/FrameBufferAndroid.cpp b/src/Main/FrameBufferAndroid.cpp
index 16e63ab..9b47171 100644
--- a/src/Main/FrameBufferAndroid.cpp
+++ b/src/Main/FrameBufferAndroid.cpp
@@ -13,7 +13,8 @@
 // limitations under the License.
 
 #include "FrameBufferAndroid.hpp"
-#include "GrallocAndroid.hpp"
+
+#include "Common/GrallocAndroid.hpp"
 
 #include <system/window.h>
 #include <cutils/log.h>
@@ -60,15 +61,15 @@
 		nativeWindow->common.decRef(&nativeWindow->common);
 	}
 
-	void FrameBufferAndroid::blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
+	void FrameBufferAndroid::blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
 	{
-		copy(source, sourceFormat, sourceStride);
+		copy(source);
 
 		if(buffer)
 		{
-			if(locked)
+			if(framebuffer)
 			{
-				locked = nullptr;
+				framebuffer = nullptr;
 				unlock();
 			}
 
@@ -85,7 +86,7 @@
 
 		if(GrallocModule::getInstance()->lock(buffer->handle,
 		                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
-		                 0, 0, buffer->width, buffer->height, &locked) != 0)
+		                 0, 0, buffer->width, buffer->height, &framebuffer) != 0)
 		{
 			ALOGE("%s failed to lock buffer %p", __FUNCTION__, buffer);
 			return nullptr;
@@ -100,26 +101,26 @@
 
 		switch(buffer->format)
 		{
-		case HAL_PIXEL_FORMAT_RGB_565:   destFormat = FORMAT_R5G6B5; break;
-		case HAL_PIXEL_FORMAT_RGBA_8888: destFormat = FORMAT_A8B8G8R8; break;
+		case HAL_PIXEL_FORMAT_RGB_565:   format = FORMAT_R5G6B5; break;
+		case HAL_PIXEL_FORMAT_RGBA_8888: format = FORMAT_A8B8G8R8; break;
 #if ANDROID_PLATFORM_SDK_VERSION > 16
-		case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: destFormat = FORMAT_X8B8G8R8; break;
+		case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: format = FORMAT_X8B8G8R8; break;
 #endif
-		case HAL_PIXEL_FORMAT_RGBX_8888: destFormat = FORMAT_X8B8G8R8; break;
-		case HAL_PIXEL_FORMAT_BGRA_8888: destFormat = FORMAT_A8R8G8B8; break;
+		case HAL_PIXEL_FORMAT_RGBX_8888: format = FORMAT_X8B8G8R8; break;
+		case HAL_PIXEL_FORMAT_BGRA_8888: format = FORMAT_A8R8G8B8; break;
 		case HAL_PIXEL_FORMAT_RGB_888:
 			// Frame buffers are expected to have 16-bit or 32-bit colors, not 24-bit.
 			ALOGE("Unsupported frame buffer format RGB_888"); ASSERT(false);
-			destFormat = FORMAT_R8G8B8;   // Wrong component order.
+			format = FORMAT_R8G8B8;   // Wrong component order.
 			break;
 		default:
 			ALOGE("Unsupported frame buffer format %d", buffer->format); ASSERT(false);
-			destFormat = FORMAT_NULL;
+			format = FORMAT_NULL;
 			break;
 		}
 
-		stride = buffer->stride * Surface::bytes(destFormat);
-		return locked;
+		stride = buffer->stride * Surface::bytes(format);
+		return framebuffer;
 	}
 
 	void FrameBufferAndroid::unlock()
@@ -130,7 +131,7 @@
 			return;
 		}
 
-		locked = nullptr;
+		framebuffer = nullptr;
 
 		if(GrallocModule::getInstance()->unlock(buffer->handle) != 0)
 		{
diff --git a/src/Main/FrameBufferAndroid.hpp b/src/Main/FrameBufferAndroid.hpp
index 4400188..b71c32b 100644
--- a/src/Main/FrameBufferAndroid.hpp
+++ b/src/Main/FrameBufferAndroid.hpp
@@ -26,12 +26,12 @@
 	class FrameBufferAndroid : public FrameBuffer
 	{
 	public:
-		FrameBufferAndroid(ANativeWindow* window, int width, int height);
+		FrameBufferAndroid(ANativeWindow *window, int width, int height);
 
 		~FrameBufferAndroid() override;
 
-		void flip(void *source, Format sourceFormat, size_t sourceStride) override {blit(source, 0, 0, sourceFormat, sourceStride);};
-		void blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) override;
+		void flip(sw::Surface *source) override {blit(source, nullptr, nullptr);};
+		void blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect) override;
 
 		void *lock() override;
 		void unlock() override;
@@ -39,8 +39,8 @@
 		bool setSwapRectangle(int l, int t, int w, int h);
 
 	private:
-		ANativeWindow* nativeWindow;
-		ANativeWindowBuffer* buffer;
+		ANativeWindow *nativeWindow;
+		ANativeWindowBuffer *buffer;
 	};
 }
 
diff --git a/src/Main/FrameBufferDD.cpp b/src/Main/FrameBufferDD.cpp
index 9d85ea5..46ed89f 100644
--- a/src/Main/FrameBufferDD.cpp
+++ b/src/Main/FrameBufferDD.cpp
@@ -14,7 +14,7 @@
 
 #include "FrameBufferDD.hpp"
 
-#include "Debug.hpp"
+#include "Common/Debug.hpp"
 
 namespace sw
 {
@@ -38,7 +38,7 @@
 		frontBuffer = 0;
 		backBuffer = 0;
 
-		locked = 0;
+		framebuffer = nullptr;
 
 		ddraw = LoadLibrary("ddraw.dll");
 		DirectDrawCreate = (DIRECTDRAWCREATE)GetProcAddress(ddraw, "DirectDrawCreate");
@@ -106,13 +106,13 @@
 
 			switch(ddsd.ddpfPixelFormat.dwRGBBitCount)
 			{
-			case 32: destFormat = FORMAT_X8R8G8B8; break;
-			case 24: destFormat = FORMAT_R8G8B8;   break;
-			case 16: destFormat = FORMAT_R5G6B5;   break;
-			default: destFormat = FORMAT_NULL;     break;
+			case 32: format = FORMAT_X8R8G8B8; break;
+			case 24: format = FORMAT_R8G8B8;   break;
+			case 16: format = FORMAT_R5G6B5;   break;
+			default: format = FORMAT_NULL;     break;
 			}
 
-			if((result != DD_OK && result != DDERR_PRIMARYSURFACEALREADYEXISTS) || (destFormat == FORMAT_NULL))
+			if((result != DD_OK && result != DDERR_PRIMARYSURFACEALREADYEXISTS) || (format == FORMAT_NULL))
 			{
 				assert(!"Failed to initialize graphics: Incompatible display mode.");
 			}
@@ -206,17 +206,17 @@
 
 		do
 		{
-			destFormat = FORMAT_X8R8G8B8;
+			format = FORMAT_X8R8G8B8;
 			result = directDraw->SetDisplayMode(width, height, 32);
 
 			if(result == DDERR_INVALIDMODE)
 			{
-				destFormat = FORMAT_R8G8B8;
+				format = FORMAT_R8G8B8;
 				result = directDraw->SetDisplayMode(width, height, 24);
 
 				if(result == DDERR_INVALIDMODE)
 				{
-					destFormat = FORMAT_R5G6B5;
+					format = FORMAT_R5G6B5;
 					result = directDraw->SetDisplayMode(width, height, 16);
 
 					if(result == DDERR_INVALIDMODE)
@@ -250,9 +250,9 @@
 		updateBounds(windowHandle);
 	}
 
-	void FrameBufferDD::flip(void *source, Format sourceFormat, size_t sourceStride)
+	void FrameBufferDD::flip(sw::Surface *source)
 	{
-		copy(source, sourceFormat, sourceStride);
+		copy(source);
 
 		if(!readySurfaces())
 		{
@@ -281,9 +281,9 @@
 		}
 	}
 
-	void FrameBufferDD::blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
+	void FrameBufferDD::blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
 	{
-		copy(source, sourceFormat, sourceStride);
+		copy(source);
 
 		if(!readySurfaces())
 		{
@@ -320,20 +320,20 @@
 		}
 	}
 
-	void FrameBufferDD::flip(HWND windowOverride, void *source, Format sourceFormat, size_t sourceStride)
+	void FrameBufferDD::flip(HWND windowOverride, sw::Surface *source)
 	{
 		updateClipper(windowOverride);
 		updateBounds(windowOverride);
 
-		flip(source, sourceFormat, sourceStride);
+		flip(source);
 	}
 
-	void FrameBufferDD::blit(HWND windowOverride, void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
+	void FrameBufferDD::blit(HWND windowOverride, sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
 	{
 		updateClipper(windowOverride);
 		updateBounds(windowOverride);
 
-		blit(source, sourceRect, destRect, sourceFormat, sourceStride);
+		blit(source, sourceRect, destRect);
 	}
 
 	void FrameBufferDD::screenshot(void *destBuffer)
@@ -404,14 +404,14 @@
 
 	void *FrameBufferDD::lock()
 	{
-		if(locked)
+		if(framebuffer)
 		{
-			return locked;
+			return framebuffer;
 		}
 
 		if(!readySurfaces())
 		{
-			return 0;
+			return nullptr;
 		}
 
 		DDSURFACEDESC DDSD;
@@ -425,21 +425,21 @@
 			height = DDSD.dwHeight;
 			stride = DDSD.lPitch;
 
-			locked = DDSD.lpSurface;
+			framebuffer = DDSD.lpSurface;
 
-			return locked;
+			return framebuffer;
 		}
 
-		return 0;
+		return nullptr;
 	}
 
 	void FrameBufferDD::unlock()
 	{
-		if(!locked || !backBuffer) return;
+		if(!framebuffer || !backBuffer) return;
 
 		backBuffer->Unlock(0);
 
-		locked = 0;
+		framebuffer = nullptr;
 	}
 
 	void FrameBufferDD::drawText(int x, int y, const char *string, ...)
diff --git a/src/Main/FrameBufferDD.hpp b/src/Main/FrameBufferDD.hpp
index efe6d68..22d76c9 100644
--- a/src/Main/FrameBufferDD.hpp
+++ b/src/Main/FrameBufferDD.hpp
@@ -28,11 +28,11 @@
 
 		~FrameBufferDD() override;
 
-		void flip(void *source, Format sourceFormat, size_t sourceStride) override;
-		void blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) override;
+		void flip(sw::Surface *source) override;
+		void blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect) override;
 
-		void flip(HWND windowOverride, void *source, Format sourceFormat, size_t sourceStride) override;
-		void blit(HWND windowOverride, void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) override;
+		void flip(HWND windowOverride, sw::Surface *source) override;
+		void blit(HWND windowOverride, sw::Surface *source, const Rect *sourceRect, const Rect *destRect) override;
 
 		void *lock() override;
 		void unlock() override;
diff --git a/src/Main/FrameBufferGDI.cpp b/src/Main/FrameBufferGDI.cpp
index e528d26..90a469e 100644
--- a/src/Main/FrameBufferGDI.cpp
+++ b/src/Main/FrameBufferGDI.cpp
@@ -14,7 +14,7 @@
 
 #include "FrameBufferGDI.hpp"
 
-#include "Debug.hpp"
+#include "Common/Debug.hpp"
 
 namespace sw
 {
@@ -37,7 +37,7 @@
 
 		init(this->windowHandle);
 
-		destFormat = FORMAT_X8R8G8B8;
+		format = FORMAT_X8R8G8B8;
 	}
 
 	FrameBufferGDI::~FrameBufferGDI()
@@ -64,21 +64,21 @@
 	{
 		stride = width * 4;
 
-		return locked;
+		return framebuffer;
 	}
 
 	void FrameBufferGDI::unlock()
 	{
 	}
 
-	void FrameBufferGDI::flip(void *source, Format sourceFormat, size_t sourceStride)
+	void FrameBufferGDI::flip(sw::Surface *source)
 	{
-		blit(source, 0, 0, sourceFormat, sourceStride);
+		blit(source, nullptr, nullptr);
 	}
 
-	void FrameBufferGDI::blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
+	void FrameBufferGDI::blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
 	{
-		copy(source, sourceFormat, sourceStride);
+		copy(source);
 
 		int sourceLeft = sourceRect ? sourceRect->x0 : 0;
 		int sourceTop = sourceRect ? sourceRect->y0 : 0;
@@ -92,12 +92,12 @@
 		StretchBlt(windowContext, destLeft, destTop, destWidth, destHeight, bitmapContext, sourceLeft, sourceTop, sourceWidth, sourceHeight, SRCCOPY);
 	}
 
-	void FrameBufferGDI::flip(HWND windowOverride, void *source, Format sourceFormat, size_t sourceStride)
+	void FrameBufferGDI::flip(HWND windowOverride, sw::Surface *source)
 	{
-		blit(windowOverride, source, 0, 0, sourceFormat, sourceStride);
+		blit(windowOverride, source, nullptr, nullptr);
 	}
 
-	void FrameBufferGDI::blit(HWND windowOverride, void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
+	void FrameBufferGDI::blit(HWND windowOverride, sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
 	{
 		if(windowed && windowOverride != 0 && windowOverride != bitmapWindow)
 		{
@@ -105,7 +105,7 @@
 			init(windowOverride);
 		}
 
-		blit(source, sourceRect, destRect, sourceFormat, sourceStride);
+		blit(source, sourceRect, destRect);
 	}
 
 	void FrameBufferGDI::setGammaRamp(GammaRamp *gammaRamp, bool calibrate)
@@ -146,7 +146,7 @@
 		bitmapInfo.bmiHeader.biWidth = width;
 		bitmapInfo.bmiHeader.biCompression = BI_RGB;
 
-		bitmap = CreateDIBSection(bitmapContext, &bitmapInfo, DIB_RGB_COLORS, &locked, 0, 0);
+		bitmap = CreateDIBSection(bitmapContext, &bitmapInfo, DIB_RGB_COLORS, &framebuffer, 0, 0);
 		SelectObject(bitmapContext, bitmap);
 
 		updateBounds(window);
diff --git a/src/Main/FrameBufferGDI.hpp b/src/Main/FrameBufferGDI.hpp
index efe44a9..add2504 100644
--- a/src/Main/FrameBufferGDI.hpp
+++ b/src/Main/FrameBufferGDI.hpp
@@ -26,11 +26,11 @@
 
 		~FrameBufferGDI() override;
 
-		void flip(void *source, Format sourceFormat, size_t sourceStride) override;
-		void blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) override;
+		void flip(sw::Surface *source) override;
+		void blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect) override;
 
-		void flip(HWND windowOverride, void *source, Format sourceFormat, size_t sourceStride) override;
-		void blit(HWND windowOverride, void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) override;
+		void flip(HWND windowOverride, sw::Surface *source) override;
+		void blit(HWND windowOverride, sw::Surface *source, const Rect *sourceRect, const Rect *destRect) override;
 
 		void *lock() override;
 		void unlock() override;
@@ -48,7 +48,7 @@
 		HDC windowContext;
 		HDC bitmapContext;
 		HWND bitmapWindow;
-		
+
 		HBITMAP bitmap;
 	};
 }
diff --git a/src/Main/FrameBufferOSX.hpp b/src/Main/FrameBufferOSX.hpp
index 41f95fe..07f8d63 100644
--- a/src/Main/FrameBufferOSX.hpp
+++ b/src/Main/FrameBufferOSX.hpp
@@ -29,8 +29,8 @@
 		FrameBufferOSX(CALayer *layer, int width, int height);
 		~FrameBufferOSX() override;
 
-		void flip(void *source, Format sourceFormat, size_t sourceStride) override;
-		void blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) override;
+		void flip(sw::Surface *source) override;
+		void blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect) override;
 
 		void *lock() override;
 		void unlock() override;
diff --git a/src/Main/FrameBufferOSX.mm b/src/Main/FrameBufferOSX.mm
index 3a0cfc7..6d58ae7 100644
--- a/src/Main/FrameBufferOSX.mm
+++ b/src/Main/FrameBufferOSX.mm
@@ -25,7 +25,7 @@
 		: FrameBuffer(width, height, false, false), width(width), height(height),
 		  layer(layer), buffer(nullptr), provider(nullptr), currentImage(nullptr)
 	{
-		destFormat = sw::FORMAT_X8B8G8R8;
+		format = sw::FORMAT_X8B8G8R8;
 		int bufferSize = width * height * 4 * sizeof(uint8_t);
 		buffer = new uint8_t[bufferSize];
 		provider = CGDataProviderCreateWithData(nullptr, buffer, bufferSize, nullptr);
@@ -45,14 +45,14 @@
 		delete[] buffer;
 	}
 
-	void FrameBufferOSX::flip(void *source, Format sourceFormat, size_t sourceStride)
+	void FrameBufferOSX::flip(sw::Surface *source)
 	{
-		blit(source, nullptr, nullptr, sourceFormat, sourceStride);
+		blit(source, nullptr, nullptr);
 	}
 
-	void FrameBufferOSX::blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
+	void FrameBufferOSX::blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
 	{
-		copy(source, sourceFormat, sourceStride);
+		copy(source);
 
 		int bytesPerRow = width * 4 * sizeof(uint8_t);
 		CGImageRef image = CGImageCreate(width, height, 8, 32, bytesPerRow, colorspace, kCGBitmapByteOrder32Big, provider, nullptr, false, kCGRenderingIntentDefault);
@@ -72,13 +72,13 @@
 	void *FrameBufferOSX::lock()
 	{
 		stride = width * 4 * sizeof(uint8_t);
-		locked = buffer;
-		return locked;
+		framebuffer = buffer;
+		return framebuffer;
 	};
 
 	void FrameBufferOSX::unlock()
 	{
-		locked = nullptr;
+		framebuffer = nullptr;
 	};
 }
 
diff --git a/src/Main/FrameBufferOzone.cpp b/src/Main/FrameBufferOzone.cpp
index a9de407..95e0729 100644
--- a/src/Main/FrameBufferOzone.cpp
+++ b/src/Main/FrameBufferOzone.cpp
@@ -18,9 +18,9 @@
 {
 	FrameBufferOzone::FrameBufferOzone(intptr_t display, intptr_t window, int width, int height) : FrameBuffer(width, height, false, false)
 	{
-		buffer = sw::Surface::create(width, height, 1, destFormat, nullptr,
-		                             sw::Surface::pitchB(width, destFormat, true),
-		                             sw::Surface::sliceB(width, height, destFormat, true));
+		buffer = sw::Surface::create(width, height, 1, format, nullptr,
+		                             sw::Surface::pitchB(width, 0, format, true),
+		                             sw::Surface::sliceB(width, height, 0, format, true));
 	}
 
 	FrameBufferOzone::~FrameBufferOzone()
@@ -30,21 +30,21 @@
 
 	void *FrameBufferOzone::lock()
 	{
-		locked = buffer->lockInternal(0, 0, 0, sw::LOCK_READWRITE, sw::PUBLIC);
+		framebuffer = buffer->lockInternal(0, 0, 0, sw::LOCK_READWRITE, sw::PUBLIC);
 
-		return locked;
+		return framebuffer;
 	}
 
 	void FrameBufferOzone::unlock()
 	{
 		buffer->unlockInternal();
 
-		locked = nullptr;
+		framebuffer = nullptr;
 	}
 
-	void FrameBufferOzone::blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
+	void FrameBufferOzone::blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
 	{
-		copy(source, sourceFormat, sourceStride);
+		copy(source);
 	}
 }
 
diff --git a/src/Main/FrameBufferOzone.hpp b/src/Main/FrameBufferOzone.hpp
index 6843926..0dc9f60 100644
--- a/src/Main/FrameBufferOzone.hpp
+++ b/src/Main/FrameBufferOzone.hpp
@@ -26,8 +26,8 @@
 
 		~FrameBufferOzone() override;
 
-		void flip(void *source, Format sourceFormat, size_t sourceStride) override {blit(source, 0, 0, sourceFormat, sourceStride);};
-		void blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) override;
+		void flip(sw::Surface *source) override {blit(source, nullptr, nullptr);};
+		void blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect) override;
 
 		void *lock() override;
 		void unlock() override;
diff --git a/src/Main/FrameBufferWin.hpp b/src/Main/FrameBufferWin.hpp
index e302195..15c1e0e 100644
--- a/src/Main/FrameBufferWin.hpp
+++ b/src/Main/FrameBufferWin.hpp
@@ -33,11 +33,11 @@
 
 		~FrameBufferWin() override;
 
-		void flip(void *source, Format sourceFormat, size_t sourceStride) override = 0;
-		void blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) override = 0;
+		void flip(sw::Surface *source) override = 0;
+		void blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect) override = 0;
 
-		virtual void flip(HWND windowOverride, void *source, Format sourceFormat, size_t sourceStride) = 0;
-		virtual void blit(HWND windowOverride, void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) = 0;
+		virtual void flip(HWND windowOverride, sw::Surface *source) = 0;
+		virtual void blit(HWND windowOverride, sw::Surface *source, const Rect *sourceRect, const Rect *destRect) = 0;
 
 		virtual void setGammaRamp(GammaRamp *gammaRamp, bool calibrate) = 0;
 		virtual void getGammaRamp(GammaRamp *gammaRamp) = 0;
diff --git a/src/Main/FrameBufferX11.cpp b/src/Main/FrameBufferX11.cpp
index a065198..ca0bb4b 100644
--- a/src/Main/FrameBufferX11.cpp
+++ b/src/Main/FrameBufferX11.cpp
@@ -15,6 +15,7 @@
 #include "FrameBufferX11.hpp"
 
 #include "libX11.hpp"
+#include "Common/Timer.hpp"
 
 #include <sys/ipc.h>
 #include <sys/shm.h>
@@ -84,8 +85,11 @@
 
 		if(!mit_shm)
 		{
-			buffer = new char[width * height * 4];
-			x_image = libX11->XCreateImage(x_display, visual, depth, ZPixmap, 0, buffer, width, height, 32, width * 4);
+			int bytes_per_line = width * 4;
+			int bytes_per_image = height * bytes_per_line;
+			buffer = new char[bytes_per_image];
+			memset(buffer, 0, bytes_per_image);
+			x_image = libX11->XCreateImage(x_display, visual, depth, ZPixmap, 0, buffer, width, height, 32, bytes_per_line);
 		}
 	}
 
@@ -116,19 +120,19 @@
 	void *FrameBufferX11::lock()
 	{
 		stride = x_image->bytes_per_line;
-		locked = buffer;
+		framebuffer = buffer;
 
-		return locked;
+		return framebuffer;
 	}
 
 	void FrameBufferX11::unlock()
 	{
-		locked = nullptr;
+		framebuffer = nullptr;
 	}
 
-	void FrameBufferX11::blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
+	void FrameBufferX11::blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect)
 	{
-		copy(source, sourceFormat, sourceStride);
+		copy(source);
 
 		if(!mit_shm)
 		{
@@ -140,6 +144,36 @@
 		}
 
 		libX11->XSync(x_display, False);
+
+		if(false)   // Draw the framerate on screen
+		{
+			static double fpsTime = sw::Timer::seconds();
+			static int frames = -1;
+
+			double time = sw::Timer::seconds();
+			double delta = time - fpsTime;
+			frames++;
+
+			static double FPS = 0.0;
+			static double maxFPS = 0.0;
+
+			if(delta > 1.0)
+			{
+				FPS = frames / delta;
+
+				fpsTime = time;
+				frames = 0;
+
+				if(FPS > maxFPS)
+				{
+					maxFPS = FPS;
+				}
+			}
+
+			char string[256];
+			sprintf(string, "FPS: %.2f (max: %.2f)", FPS, maxFPS);
+			libX11->XDrawString(x_display, x_window, x_gc, 50, 50, string, strlen(string));
+		}
 	}
 }
 
diff --git a/src/Main/FrameBufferX11.hpp b/src/Main/FrameBufferX11.hpp
index ab0c205..f25487b 100644
--- a/src/Main/FrameBufferX11.hpp
+++ b/src/Main/FrameBufferX11.hpp
@@ -31,8 +31,8 @@
 
 		~FrameBufferX11() override;
 
-		void flip(void *source, Format sourceFormat, size_t sourceStride) override {blit(source, 0, 0, sourceFormat, sourceStride);};
-		void blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) override;
+		void flip(sw::Surface *source) override {blit(source, nullptr, nullptr);};
+		void blit(sw::Surface *source, const Rect *sourceRect, const Rect *destRect) override;
 
 		void *lock() override;
 		void unlock() override;
diff --git a/src/Main/SwiftConfig.cpp b/src/Main/SwiftConfig.cpp
index b1cc2e9..1c22394 100644
--- a/src/Main/SwiftConfig.cpp
+++ b/src/Main/SwiftConfig.cpp
@@ -14,16 +14,17 @@
 
 #include "SwiftConfig.hpp"
 
-#include "Configurator.hpp"
-#include "Debug.hpp"
 #include "Config.hpp"
-#include "Version.h"
+#include "Common/Configurator.hpp"
+#include "Common/Debug.hpp"
+#include "Common/Version.h"
 
 #include <sstream>
 #include <stdio.h>
 #include <time.h>
 #include <sys/stat.h>
 #include <string.h>
+#include <algorithm>
 
 namespace sw
 {
@@ -247,7 +248,7 @@
 		html += "function request()\n";
 		html += "{\n";
 		html += "var xhr = new XMLHttpRequest();\n";
-		html += "xhr.open('POST', 'http://localhost:8080/swiftshader/profile', true);\n";
+		html += "xhr.open('POST', '/swiftshader/profile', true);\n";
 		html += "xhr.onreadystatechange = function()\n";
 		html += "{\n";
 		html += "if(xhr.readyState == 4 && xhr.status == 200)\n";
diff --git a/src/Main/libX11.cpp b/src/Main/libX11.cpp
index 9c056bf..f3723ff 100644
--- a/src/Main/libX11.cpp
+++ b/src/Main/libX11.cpp
@@ -35,6 +35,7 @@
 	XCreateImage = (XImage *(*)(Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int))getProcAddress(libX11, "XCreateImage");
 	XCloseDisplay = (int (*)(Display*))getProcAddress(libX11, "XCloseDisplay");
 	XPutImage = (int (*)(Display*, Drawable, GC, XImage*, int, int, int, int, unsigned int, unsigned int))getProcAddress(libX11, "XPutImage");
+	XDrawString = (int (*)(Display*, Drawable, GC, int, int, char*, int))getProcAddress(libX11, "XDrawString");
 
 	XShmQueryExtension = (Bool (*)(Display*))getProcAddress(libXext, "XShmQueryExtension");
 	XShmCreateImage = (XImage *(*)(Display*, Visual*, unsigned int, int, char*, XShmSegmentInfo*, unsigned int, unsigned int))getProcAddress(libXext, "XShmCreateImage");
diff --git a/src/Main/libX11.hpp b/src/Main/libX11.hpp
index f9f88be..c188386 100644
--- a/src/Main/libX11.hpp
+++ b/src/Main/libX11.hpp
@@ -39,6 +39,7 @@
 	XImage *(*XCreateImage)(Display *display, Visual *visual, unsigned int depth, int format, int offset, char *data, unsigned int width, unsigned int height, int bitmap_pad, int bytes_per_line);
 	int (*XCloseDisplay)(Display *display);
 	int (*XPutImage)(Display *display, Drawable d, GC gc, XImage *image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height);
+	int (*XDrawString)(Display *display, Drawable d, GC gc, int x, int y, char *string, int length);
 
 	Bool (*XShmQueryExtension)(Display *display);
 	XImage *(*XShmCreateImage)(Display *display, Visual *visual, unsigned int depth, int format, char *data, XShmSegmentInfo *shminfo, unsigned int width, unsigned int height);
diff --git a/src/OpenGL/common/Image.cpp b/src/OpenGL/common/Image.cpp
index f75f92f..280486a 100644
--- a/src/OpenGL/common/Image.cpp
+++ b/src/OpenGL/common/Image.cpp
@@ -14,7 +14,6 @@
 
 #include "Image.hpp"
 
-#include "../libEGL/Context.hpp"
 #include "../libEGL/Texture.hpp"
 #include "../common/debug.h"
 #include "Common/Math.hpp"
@@ -23,404 +22,11 @@
 #include <GLES3/gl3.h>
 
 #include <string.h>
+#include <algorithm>
 
-namespace
+namespace gl
 {
-	int getNumBlocks(int w, int h, int blockSizeX, int blockSizeY)
-	{
-		return ((w + blockSizeX - 1) / blockSizeX) * ((h + blockSizeY - 1) / blockSizeY);
-	}
-
-	enum DataType
-	{
-		Bytes_1,
-		Bytes_2,
-		Bytes_4,
-		Bytes_8,
-		Bytes_16,
-		ByteRGB,
-		UByteRGB,
-		ShortRGB,
-		UShortRGB,
-		IntRGB,
-		UIntRGB,
-		RGB565,
-		FloatRGB,
-		HalfFloatRGB,
-		RGBA4444,
-		RGBA5551,
-		RGB10A2UI,
-		R11G11B10F,
-		RGB9E5,
-		SRGB,
-		SRGBA,
-		D16,
-		D24,
-		D32,
-		D32F,
-		S8,
-		S24_8,
-	};
-
-	template<DataType dataType>
-	void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		UNIMPLEMENTED();
-	}
-
-	template<>
-	void LoadImageRow<Bytes_1>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		memcpy(dest + xoffset, source, width);
-	}
-
-	template<>
-	void LoadImageRow<Bytes_2>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		memcpy(dest + xoffset * 2, source, width * 2);
-	}
-
-	template<>
-	void LoadImageRow<Bytes_4>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		memcpy(dest + xoffset * 4, source, width * 4);
-	}
-
-	template<>
-	void LoadImageRow<Bytes_8>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		memcpy(dest + xoffset * 8, source, width * 8);
-	}
-
-	template<>
-	void LoadImageRow<Bytes_16>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		memcpy(dest + xoffset * 16, source, width * 16);
-	}
-
-	template<>
-	void LoadImageRow<ByteRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		unsigned char *destB = dest + xoffset * 4;
-
-		for(int x = 0; x < width; x++)
-		{
-			destB[4 * x + 0] = source[x * 3 + 0];
-			destB[4 * x + 1] = source[x * 3 + 1];
-			destB[4 * x + 2] = source[x * 3 + 2];
-			destB[4 * x + 3] = 0x7F;
-		}
-	}
-
-	template<>
-	void LoadImageRow<UByteRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		unsigned char *destB = dest + xoffset * 4;
-
-		for(int x = 0; x < width; x++)
-		{
-			destB[4 * x + 0] = source[x * 3 + 0];
-			destB[4 * x + 1] = source[x * 3 + 1];
-			destB[4 * x + 2] = source[x * 3 + 2];
-			destB[4 * x + 3] = 0xFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<ShortRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned short *sourceS = reinterpret_cast<const unsigned short*>(source);
-		unsigned short *destS = reinterpret_cast<unsigned short*>(dest + xoffset * 8);
-
-		for(int x = 0; x < width; x++)
-		{
-			destS[4 * x + 0] = sourceS[x * 3 + 0];
-			destS[4 * x + 1] = sourceS[x * 3 + 1];
-			destS[4 * x + 2] = sourceS[x * 3 + 2];
-			destS[4 * x + 3] = 0x7FFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<UShortRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned short *sourceS = reinterpret_cast<const unsigned short*>(source);
-		unsigned short *destS = reinterpret_cast<unsigned short*>(dest + xoffset * 8);
-
-		for(int x = 0; x < width; x++)
-		{
-			destS[4 * x + 0] = sourceS[x * 3 + 0];
-			destS[4 * x + 1] = sourceS[x * 3 + 1];
-			destS[4 * x + 2] = sourceS[x * 3 + 2];
-			destS[4 * x + 3] = 0xFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<IntRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
-		unsigned int *destI = reinterpret_cast<unsigned int*>(dest + xoffset * 16);
-
-		for(int x = 0; x < width; x++)
-		{
-			destI[4 * x + 0] = sourceI[x * 3 + 0];
-			destI[4 * x + 1] = sourceI[x * 3 + 1];
-			destI[4 * x + 2] = sourceI[x * 3 + 2];
-			destI[4 * x + 3] = 0x7FFFFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<UIntRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
-		unsigned int *destI = reinterpret_cast<unsigned int*>(dest + xoffset * 16);
-
-		for(int x = 0; x < width; x++)
-		{
-			destI[4 * x + 0] = sourceI[x * 3 + 0];
-			destI[4 * x + 1] = sourceI[x * 3 + 1];
-			destI[4 * x + 2] = sourceI[x * 3 + 2];
-			destI[4 * x + 3] = 0xFFFFFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<RGB565>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		memcpy(dest + xoffset * 2, source, width * 2);
-	}
-
-	template<>
-	void LoadImageRow<FloatRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const float *sourceF = reinterpret_cast<const float*>(source);
-		float *destF = reinterpret_cast<float*>(dest + xoffset * 16);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[4 * x + 0] = sourceF[x * 3 + 0];
-			destF[4 * x + 1] = sourceF[x * 3 + 1];
-			destF[4 * x + 2] = sourceF[x * 3 + 2];
-			destF[4 * x + 3] = 1.0f;
-		}
-	}
-
-	template<>
-	void LoadImageRow<HalfFloatRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
-		unsigned short *destH = reinterpret_cast<unsigned short*>(dest + xoffset * 8);
-
-		for(int x = 0; x < width; x++)
-		{
-			destH[4 * x + 0] = sourceH[x * 3 + 0];
-			destH[4 * x + 1] = sourceH[x * 3 + 1];
-			destH[4 * x + 2] = sourceH[x * 3 + 2];
-			destH[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
-		}
-	}
-
-	template<>
-	void LoadImageRow<RGBA4444>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned short *source4444 = reinterpret_cast<const unsigned short*>(source);
-		unsigned char *dest4444 = dest + xoffset * 4;
-
-		for(int x = 0; x < width; x++)
-		{
-			unsigned short rgba = source4444[x];
-			dest4444[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
-			dest4444[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
-			dest4444[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
-			dest4444[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
-		}
-	}
-
-	template<>
-	void LoadImageRow<RGBA5551>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned short *source5551 = reinterpret_cast<const unsigned short*>(source);
-		unsigned char *dest5551 = dest + xoffset * 4;
-
-		for(int x = 0; x < width; x++)
-		{
-			unsigned short rgba = source5551[x];
-			dest5551[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
-			dest5551[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
-			dest5551[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
-			dest5551[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
-		}
-	}
-
-	template<>
-	void LoadImageRow<RGB10A2UI>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned int *source1010102U = reinterpret_cast<const unsigned int*>(source);
-		unsigned short *dest16U = reinterpret_cast<unsigned short*>(dest + xoffset * 8);
-
-		for(int x = 0; x < width; x++)
-		{
-			unsigned int rgba = source1010102U[x];
-			dest16U[4 * x + 0] = (rgba & 0x000003FF);
-			dest16U[4 * x + 1] = (rgba & 0x000FFC00) >> 10;
-			dest16U[4 * x + 2] = (rgba & 0x3FF00000) >> 20;
-			dest16U[4 * x + 3] = (rgba & 0xC0000000) >> 30;
-		}
-	}
-
-	template<>
-	void LoadImageRow<R11G11B10F>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const sw::R11G11B10FData *sourceRGB = reinterpret_cast<const sw::R11G11B10FData*>(source);
-		float *destF = reinterpret_cast<float*>(dest + xoffset * 16);
-
-		for(int x = 0; x < width; x++, sourceRGB++, destF+=4)
-		{
-			sourceRGB->toRGBFloats(destF);
-			destF[3] = 1.0f;
-		}
-	}
-
-	template<>
-	void LoadImageRow<RGB9E5>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const sw::RGB9E5Data *sourceRGB = reinterpret_cast<const sw::RGB9E5Data*>(source);
-		float *destF = reinterpret_cast<float*>(dest + xoffset * 16);
-
-		for(int x = 0; x < width; x++, sourceRGB++, destF += 4)
-		{
-			sourceRGB->toRGBFloats(destF);
-			destF[3] = 1.0f;
-		}
-	}
-
-	template<>
-	void LoadImageRow<SRGB>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		dest += xoffset * 4;
-
-		for(int x = 0; x < width; x++)
-		{
-			for(int rgb = 0; rgb < 3; ++rgb)
-			{
-				*dest++ = sw::sRGB8toLinear8(*source++);
-			}
-			*dest++ = 255;
-		}
-	}
-
-	template<>
-	void LoadImageRow<SRGBA>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		dest += xoffset * 4;
-
-		for(int x = 0; x < width; x++)
-		{
-			for(int rgb = 0; rgb < 3; ++rgb)
-			{
-				*dest++ = sw::sRGB8toLinear8(*source++);
-			}
-			*dest++ = *source++;
-		}
-	}
-
-	template<>
-	void LoadImageRow<D16>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned short *sourceD16 = reinterpret_cast<const unsigned short*>(source);
-		float *destF = reinterpret_cast<float*>(dest + xoffset * 4);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[x] = (float)sourceD16[x] / 0xFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<D24>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned int *sourceD24 = reinterpret_cast<const unsigned int*>(source);
-		float *destF = reinterpret_cast<float*>(dest + xoffset * 4);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[x] = (float)(sourceD24[x] & 0xFFFFFF00) / 0xFFFFFF00;
-		}
-	}
-
-	template<>
-	void LoadImageRow<D32>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned int *sourceD32 = reinterpret_cast<const unsigned int*>(source);
-		float *destF = reinterpret_cast<float*>(dest + xoffset * 4);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[x] = (float)sourceD32[x] / 0xFFFFFFFF;
-		}
-	}
-
-	template<>
-	void LoadImageRow<S8>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
-		unsigned char *destI = dest + xoffset;
-
-		for(int x = 0; x < width; x++)
-		{
-			destI[x] = static_cast<unsigned char>(sourceI[x] & 0x000000FF);   // FIXME: Quad layout
-		}
-	}
-
-	template<>
-	void LoadImageRow<D32F>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		struct D32FS8 { float depth32f; unsigned int stencil24_8; };
-		const D32FS8 *sourceD32FS8 = reinterpret_cast<const D32FS8*>(source);
-		float *destF = reinterpret_cast<float*>(dest + xoffset * 4);
-
-		for(int x = 0; x < width; x++)
-		{
-			destF[x] = sourceD32FS8[x].depth32f;
-		}
-	}
-
-	template<>
-	void LoadImageRow<S24_8>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
-	{
-		struct D32FS8 { float depth32f; unsigned int stencil24_8; };
-		const D32FS8 *sourceD32FS8 = reinterpret_cast<const D32FS8*>(source);
-		unsigned char *destI = dest + xoffset;
-
-		for(int x = 0; x < width; x++)
-		{
-			destI[x] = static_cast<unsigned char>(sourceD32FS8[x].stencil24_8 & 0x000000FF);   // FIXME: Quad layout
-		}
-	}
-
-	template<DataType dataType>
-	void LoadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, int destPitch, GLsizei destHeight, const void *input, void *buffer)
-	{
-		for(int z = 0; z < depth; ++z)
-		{
-			const unsigned char *inputStart = static_cast<const unsigned char*>(input) + (z * inputPitch * inputHeight);
-			unsigned char *destStart = static_cast<unsigned char*>(buffer) + ((zoffset + z) * destPitch * destHeight);
-			for(int y = 0; y < height; ++y)
-			{
-				const unsigned char *source = inputStart + y * inputPitch;
-				unsigned char *dest = destStart + (y + yoffset) * destPitch;
-
-				LoadImageRow<dataType>(source, dest, xoffset, width);
-			}
-		}
-	}
-}
-
-namespace egl
-{
-	sw::Format ConvertFormatType(GLenum format, GLenum type)
+	sw::Format ConvertReadFormatType(GLenum format, GLenum type)
 	{
 		switch(format)
 		{
@@ -434,12 +40,6 @@
 			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_LUMINANCE8_EXT:
-			return sw::FORMAT_L8;
-		case GL_LUMINANCE16F_EXT:
-			return sw::FORMAT_L16F;
-		case GL_LUMINANCE32F_EXT:
-			return sw::FORMAT_L32F;
 		case GL_LUMINANCE_ALPHA:
 			switch(type)
 			{
@@ -450,12 +50,6 @@
 			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_LUMINANCE8_ALPHA8_EXT:
-			return sw::FORMAT_A8L8;
-		case GL_LUMINANCE_ALPHA16F_EXT:
-			return sw::FORMAT_A16L16F;
-		case GL_LUMINANCE_ALPHA32F_EXT:
-			return sw::FORMAT_A32L32F;
 		case GL_RGBA:
 			switch(type)
 			{
@@ -465,11 +59,11 @@
 			case GL_HALF_FLOAT:             return sw::FORMAT_A16B16G16R16F;
 			case GL_HALF_FLOAT_OES:         return sw::FORMAT_A16B16G16R16F;
 			case GL_FLOAT:                  return sw::FORMAT_A32B32G32R32F;
+			case GL_UNSIGNED_INT_2_10_10_10_REV_EXT: return sw::FORMAT_A2B10G10R10;
 			default: UNREACHABLE(type);
 			}
 			break;
 		case GL_BGRA_EXT:
-		case GL_BGRA8_EXT:
 			switch(type)
 			{
 			case GL_UNSIGNED_BYTE:                  return sw::FORMAT_A8R8G8B8;
@@ -489,6 +83,26 @@
 			default: UNREACHABLE(type);
 			}
 			break;
+		case GL_RG:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:          return sw::FORMAT_G8R8;
+			case GL_HALF_FLOAT:             return sw::FORMAT_G16R16F;
+			case GL_HALF_FLOAT_OES:         return sw::FORMAT_G16R16F;
+			case GL_FLOAT:                  return sw::FORMAT_G32R32F;
+			default: UNREACHABLE(type);
+			}
+			break;
+		case GL_RED:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:          return sw::FORMAT_R8;
+			case GL_HALF_FLOAT:             return sw::FORMAT_R16F;
+			case GL_HALF_FLOAT_OES:         return sw::FORMAT_R16F;
+			case GL_FLOAT:                  return sw::FORMAT_R32F;
+			default: UNREACHABLE(type);
+			}
+			break;
 		case GL_ALPHA:
 			switch(type)
 			{
@@ -499,12 +113,6 @@
 			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_ALPHA8_EXT:
-			return sw::FORMAT_A8;
-		case GL_ALPHA16F_EXT:
-			return sw::FORMAT_A16F;
-		case GL_ALPHA32F_EXT:
-			return sw::FORMAT_A32F;
 		case GL_RED_INTEGER:
 			switch(type)
 			{
@@ -521,11 +129,20 @@
 			default: UNREACHABLE(type);
 			}
 			break;
+		case GL_RGB_INTEGER:
+			switch(type)
+			{
+			case GL_INT:          return sw::FORMAT_X32B32G32R32I;
+			case GL_UNSIGNED_INT: return sw::FORMAT_X32B32G32R32UI;
+			default: UNREACHABLE(type);
+			}
+			break;
 		case GL_RGBA_INTEGER:
 			switch(type)
 			{
 			case GL_INT:          return sw::FORMAT_A32B32G32R32I;
 			case GL_UNSIGNED_INT: return sw::FORMAT_A32B32G32R32UI;
+			case GL_UNSIGNED_INT_2_10_10_10_REV: return sw::FORMAT_A2B10G10R10UI;
 			default: UNREACHABLE(type);
 			}
 			break;
@@ -535,558 +152,516 @@
 			case GL_UNSIGNED_SHORT:        return sw::FORMAT_D16;
 			case GL_UNSIGNED_INT_24_8_OES: return sw::FORMAT_D24S8;
 			case GL_UNSIGNED_INT:          return sw::FORMAT_D32;
-			case GL_FLOAT:                 return sw::FORMAT_D32F;
+			case GL_FLOAT:                 return sw::FORMAT_D32F_LOCKABLE;
 			default: UNREACHABLE(type);
 			}
 			break;
 		default:
 			UNREACHABLE(format);
+			break;
 		}
 
 		return sw::FORMAT_NULL;
 	}
 
-	sw::Format SelectInternalFormat(GLenum format, GLenum type)
+	bool IsUnsizedInternalFormat(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_ALPHA:
+		case GL_LUMINANCE:
+		case GL_LUMINANCE_ALPHA:
+		case GL_RED:
+		case GL_RG:
+		case GL_RGB:
+		case GL_RGBA:
+		case GL_RED_INTEGER:
+		case GL_RG_INTEGER:
+		case GL_RGB_INTEGER:
+		case GL_RGBA_INTEGER:
+		case GL_BGRA_EXT:
+		case GL_DEPTH_COMPONENT:
+		case GL_DEPTH_STENCIL:
+		// GL_EXT_sRGB
+	//	case GL_SRGB_EXT:
+	//	case GL_SRGB_ALPHA_EXT:
+			return true;
+		default:
+			return false;
+		}
+	}
+
+	GLenum GetBaseInternalFormat(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		// [OpenGL ES 3.0 Table 3.13]
+		case GL_R8:       return GL_RED;
+		case GL_R8_SNORM: return GL_RED;
+		case GL_RG8:       return GL_RG;
+		case GL_RG8_SNORM: return GL_RG;
+		case GL_RGB8:       return GL_RGB;
+		case GL_RGB8_SNORM: return GL_RGB;
+		case GL_RGB565:     return GL_RGB;
+		case GL_RGBA4:        return GL_RGBA;
+		case GL_RGB5_A1:      return GL_RGBA;
+		case GL_RGBA8:        return GL_RGBA;
+		case GL_RGBA8_SNORM:  return GL_RGBA;
+		case GL_RGB10_A2:     return GL_RGBA;
+		case GL_RGB10_A2UI:   return GL_RGBA;
+		case GL_SRGB8:        return GL_RGB;
+		case GL_SRGB8_ALPHA8: return GL_RGBA;
+		case GL_R16F:    return GL_RED;
+		case GL_RG16F:   return GL_RG;
+		case GL_RGB16F:  return GL_RGB;
+		case GL_RGBA16F: return GL_RGBA;
+		case GL_R32F:    return GL_RED;
+		case GL_RG32F:   return GL_RG;
+		case GL_RGB32F:  return GL_RGB;
+		case GL_RGBA32F: return GL_RGBA;
+		case GL_R11F_G11F_B10F: return GL_RGB;
+		case GL_RGB9_E5:        return GL_RGB;
+		case GL_R8I:      return GL_RED;
+		case GL_R8UI:     return GL_RED;
+		case GL_R16I:     return GL_RED;
+		case GL_R16UI:    return GL_RED;
+		case GL_R32I:     return GL_RED;
+		case GL_R32UI:    return GL_RED;
+		case GL_RG8I:     return GL_RG;
+		case GL_RG8UI:    return GL_RG;
+		case GL_RG16I:    return GL_RG;
+		case GL_RG16UI:   return GL_RG;
+		case GL_RG32I:    return GL_RG;
+		case GL_RG32UI:   return GL_RG;
+		case GL_RGB8I:    return GL_RGB;
+		case GL_RGB8UI:   return GL_RGB;
+		case GL_RGB16I:   return GL_RGB;
+		case GL_RGB16UI:  return GL_RGB;
+		case GL_RGB32I:   return GL_RGB;
+		case GL_RGB32UI:  return GL_RGB;
+		case GL_RGBA8I:   return GL_RGBA;
+		case GL_RGBA8UI:  return GL_RGBA;
+		case GL_RGBA16I:  return GL_RGBA;
+		case GL_RGBA16UI: return GL_RGBA;
+		case GL_RGBA32I:  return GL_RGBA;
+		case GL_RGBA32UI: return GL_RGBA;
+
+		// GL_EXT_texture_storage
+		case GL_ALPHA8_EXT:            return GL_ALPHA;
+		case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA;
+		case GL_LUMINANCE8_EXT:        return GL_LUMINANCE;
+
+		case GL_BGRA8_EXT: return GL_BGRA_EXT;   // GL_APPLE_texture_format_BGRA8888
+
+		case GL_DEPTH_COMPONENT24:     return GL_DEPTH_COMPONENT;
+		case GL_DEPTH_COMPONENT32_OES: return GL_DEPTH_COMPONENT;
+		case GL_DEPTH_COMPONENT32F:    return GL_DEPTH_COMPONENT;
+		case GL_DEPTH_COMPONENT16:     return GL_DEPTH_COMPONENT;
+		case GL_DEPTH32F_STENCIL8:     return GL_DEPTH_STENCIL;
+		case GL_DEPTH24_STENCIL8:      return GL_DEPTH_STENCIL;
+		case GL_STENCIL_INDEX8:        return GL_STENCIL_INDEX_OES;
+		default:
+			UNREACHABLE(internalformat);
+			break;
+		}
+
+		return GL_NONE;
+	}
+
+	GLint GetSizedInternalFormat(GLint internalformat, GLenum type)
+	{
+		if(!IsUnsizedInternalFormat(internalformat))
+		{
+			return internalformat;
+		}
+
+		switch(internalformat)
+		{
+		case GL_RGBA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE: return GL_RGBA8;
+			case GL_BYTE:          return GL_RGBA8_SNORM;
+			case GL_UNSIGNED_SHORT_4_4_4_4:      return GL_RGBA4;
+			case GL_UNSIGNED_SHORT_5_5_5_1:      return GL_RGB5_A1;
+			case GL_UNSIGNED_INT_2_10_10_10_REV: return GL_RGB10_A2;
+			case GL_FLOAT:          return GL_RGBA32F;
+			case GL_HALF_FLOAT:     return GL_RGBA16F;
+			case GL_HALF_FLOAT_OES: return GL_RGBA16F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RGBA_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RGBA8UI;
+			case GL_BYTE:           return GL_RGBA8I;
+			case GL_UNSIGNED_SHORT: return GL_RGBA16UI;
+			case GL_SHORT:          return GL_RGBA16I;
+			case GL_UNSIGNED_INT:   return GL_RGBA32UI;
+			case GL_INT:            return GL_RGBA32I;
+			case GL_UNSIGNED_INT_2_10_10_10_REV: return GL_RGB10_A2UI;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RGB:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RGB8;
+			case GL_BYTE:           return GL_RGB8_SNORM;
+			case GL_UNSIGNED_SHORT_5_6_5:         return GL_RGB565;
+			case GL_UNSIGNED_INT_10F_11F_11F_REV: return GL_R11F_G11F_B10F;
+			case GL_UNSIGNED_INT_5_9_9_9_REV:     return GL_RGB9_E5;
+			case GL_FLOAT:          return GL_RGB32F;
+			case GL_HALF_FLOAT:     return GL_RGB16F;
+			case GL_HALF_FLOAT_OES: return GL_RGB16F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RGB_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RGB8UI;
+			case GL_BYTE:           return GL_RGB8I;
+			case GL_UNSIGNED_SHORT: return GL_RGB16UI;
+			case GL_SHORT:          return GL_RGB16I;
+			case GL_UNSIGNED_INT:   return GL_RGB32UI;
+			case GL_INT:            return GL_RGB32I;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RG:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RG8;
+			case GL_BYTE:           return GL_RG8_SNORM;
+			case GL_FLOAT:          return GL_RG32F;
+			case GL_HALF_FLOAT:     return GL_RG16F;
+			case GL_HALF_FLOAT_OES: return GL_RG16F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RG_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_RG8UI;
+			case GL_BYTE:           return GL_RG8I;
+			case GL_UNSIGNED_SHORT: return GL_RG16UI;
+			case GL_SHORT:          return GL_RG16I;
+			case GL_UNSIGNED_INT:   return GL_RG32UI;
+			case GL_INT:            return GL_RG32I;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RED:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_R8;
+			case GL_BYTE:           return GL_R8_SNORM;
+			case GL_FLOAT:          return GL_R32F;
+			case GL_HALF_FLOAT:     return GL_R16F;
+			case GL_HALF_FLOAT_OES: return GL_R16F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_RED_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_R8UI;
+			case GL_BYTE:           return GL_R8I;
+			case GL_UNSIGNED_SHORT: return GL_R16UI;
+			case GL_SHORT:          return GL_R16I;
+			case GL_UNSIGNED_INT:   return GL_R32UI;
+			case GL_INT:            return GL_R32I;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_LUMINANCE_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_LUMINANCE8_ALPHA8_EXT;
+			case GL_FLOAT:          return GL_LUMINANCE_ALPHA32F_EXT;
+			case GL_HALF_FLOAT:     return GL_LUMINANCE_ALPHA16F_EXT;
+			case GL_HALF_FLOAT_OES: return GL_LUMINANCE_ALPHA16F_EXT;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_LUMINANCE:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_LUMINANCE8_EXT;
+			case GL_FLOAT:          return GL_LUMINANCE32F_EXT;
+			case GL_HALF_FLOAT:     return GL_LUMINANCE16F_EXT;
+			case GL_HALF_FLOAT_OES: return GL_LUMINANCE16F_EXT;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  return GL_ALPHA8_EXT;
+			case GL_FLOAT:          return GL_ALPHA32F_EXT;
+			case GL_HALF_FLOAT:     return GL_ALPHA16F_EXT;
+			case GL_HALF_FLOAT_OES: return GL_ALPHA16F_EXT;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_BGRA_EXT:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:                  return GL_BGRA8_EXT;
+			case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: // Only valid for glReadPixels calls.
+			case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: // Only valid for glReadPixels calls.
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_DEPTH_COMPONENT:
+			switch(type)
+			{
+			case GL_UNSIGNED_SHORT: return GL_DEPTH_COMPONENT16;
+			case GL_UNSIGNED_INT:   return GL_DEPTH_COMPONENT32_OES;
+			case GL_FLOAT:          return GL_DEPTH_COMPONENT32F;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+		case GL_DEPTH_STENCIL:
+			switch(type)
+			{
+			case GL_UNSIGNED_INT_24_8:              return GL_DEPTH24_STENCIL8;
+			case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return GL_DEPTH32F_STENCIL8;
+			default: UNREACHABLE(type); return GL_NONE;
+			}
+
+		// GL_OES_texture_stencil8
+	//	case GL_STENCIL_INDEX_OES / GL_UNSIGNED_BYTE: return GL_STENCIL_INDEX8;
+
+		// GL_EXT_sRGB
+	//	case GL_SRGB_EXT / GL_UNSIGNED_BYTE: return GL_SRGB8;
+	//	case GL_SRGB_ALPHA_EXT / GL_UNSIGNED_BYTE: return GL_SRGB8_ALPHA8;
+
+		default:
+			UNREACHABLE(internalformat);
+		}
+
+		return GL_NONE;
+	}
+
+	sw::Format SelectInternalFormat(GLint format)
 	{
 		switch(format)
 		{
-		case GL_ETC1_RGB8_OES:
-			return sw::FORMAT_ETC1;
-		case GL_COMPRESSED_R11_EAC:
-			return sw::FORMAT_R11_EAC;
-		case GL_COMPRESSED_SIGNED_R11_EAC:
-			return sw::FORMAT_SIGNED_R11_EAC;
-		case GL_COMPRESSED_RG11_EAC:
-			return sw::FORMAT_RG11_EAC;
-		case GL_COMPRESSED_SIGNED_RG11_EAC:
-			return sw::FORMAT_SIGNED_RG11_EAC;
-		case GL_COMPRESSED_RGB8_ETC2:
-			return sw::FORMAT_RGB8_ETC2;
-		case GL_COMPRESSED_SRGB8_ETC2:
-			return sw::FORMAT_SRGB8_ETC2;
-		case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-			return sw::FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
-		case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-			return sw::FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
-		case GL_COMPRESSED_RGBA8_ETC2_EAC:
-			return sw::FORMAT_RGBA8_ETC2_EAC;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
-			return sw::FORMAT_SRGB8_ALPHA8_ETC2_EAC;
-		case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
-			return sw::FORMAT_RGBA_ASTC_4x4_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
-			return sw::FORMAT_RGBA_ASTC_5x4_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
-			return sw::FORMAT_RGBA_ASTC_5x5_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
-			return sw::FORMAT_RGBA_ASTC_6x5_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
-			return sw::FORMAT_RGBA_ASTC_6x6_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
-			return sw::FORMAT_RGBA_ASTC_8x5_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
-			return sw::FORMAT_RGBA_ASTC_8x6_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
-			return sw::FORMAT_RGBA_ASTC_8x8_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
-			return sw::FORMAT_RGBA_ASTC_10x5_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
-			return sw::FORMAT_RGBA_ASTC_10x6_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
-			return sw::FORMAT_RGBA_ASTC_10x8_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
-			return sw::FORMAT_RGBA_ASTC_10x10_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
-			return sw::FORMAT_RGBA_ASTC_12x10_KHR;
-		case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
-			return sw::FORMAT_RGBA_ASTC_12x12_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_4x4_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x4_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x5_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x5_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x6_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x5_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x6_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x8_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x5_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x6_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x8_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x10_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x10_KHR;
-		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
-			return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR;
-		#if S3TC_SUPPORT
-		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-			return sw::FORMAT_DXT1;
-		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-			return sw::FORMAT_DXT3;
-		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-			return sw::FORMAT_DXT5;
-		#endif
-		default:
-			break;
-		}
+		case GL_RGBA4:   return sw::FORMAT_A8B8G8R8;
+		case GL_RGB5_A1: return sw::FORMAT_A8B8G8R8;
+		case GL_RGBA8:   return sw::FORMAT_A8B8G8R8;
+		case GL_RGB565:  return sw::FORMAT_R5G6B5;
+		case GL_RGB8:    return sw::FORMAT_X8B8G8R8;
 
-		switch(type)
-		{
-		case GL_FLOAT:
-			switch(format)
-			{
-			case GL_ALPHA:
-			case GL_ALPHA32F_EXT:
-				return sw::FORMAT_A32F;
-			case GL_LUMINANCE:
-			case GL_LUMINANCE32F_EXT:
-				return sw::FORMAT_L32F;
-			case GL_LUMINANCE_ALPHA:
-			case GL_LUMINANCE_ALPHA32F_EXT:
-				return sw::FORMAT_A32L32F;
-			case GL_RED:
-			case GL_R32F:
-				return sw::FORMAT_R32F;
-			case GL_RG:
-			case GL_RG32F:
-				return sw::FORMAT_G32R32F;
-			case GL_RGB:
-			case GL_RGB32F:
-				return sw::FORMAT_X32B32G32R32F;
-			case GL_RGBA:
-			case GL_RGBA32F:
-				return sw::FORMAT_A32B32G32R32F;
-			case GL_DEPTH_COMPONENT:
-			case GL_DEPTH_COMPONENT32F:
-				return sw::FORMAT_D32F;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_HALF_FLOAT:
-		case GL_HALF_FLOAT_OES:
-			switch(format)
-			{
-			case GL_ALPHA:
-			case GL_ALPHA16F_EXT:
-				return sw::FORMAT_A16F;
-			case GL_LUMINANCE:
-			case GL_LUMINANCE16F_EXT:
-				return sw::FORMAT_L16F;
-			case GL_LUMINANCE_ALPHA:
-			case GL_LUMINANCE_ALPHA16F_EXT:
-				return sw::FORMAT_A16L16F;
-			case GL_RED:
-			case GL_R16F:
-				return sw::FORMAT_R16F;
-			case GL_RG:
-			case GL_RG16F:
-				return sw::FORMAT_G16R16F;
-			case GL_RGB:
-			case GL_RGB16F:
-			case GL_RGBA:
-			case GL_RGBA16F:
-				return sw::FORMAT_A16B16G16R16F;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_BYTE:
-			switch(format)
-			{
-			case GL_R8_SNORM:
-			case GL_R8:
-			case GL_RED:
-				return sw::FORMAT_R8I_SNORM;
-			case GL_R8I:
-			case GL_RED_INTEGER:
-				return sw::FORMAT_R8I;
-			case GL_RG8_SNORM:
-			case GL_RG8:
-			case GL_RG:
-				return sw::FORMAT_G8R8I_SNORM;
-			case GL_RG8I:
-			case GL_RG_INTEGER:
-				return sw::FORMAT_G8R8I;
-			case GL_RGB8_SNORM:
-			case GL_RGB8:
-			case GL_RGB:
-				return sw::FORMAT_X8B8G8R8I_SNORM;
-			case GL_RGB8I:
-			case GL_RGB_INTEGER:
-				return sw::FORMAT_X8B8G8R8I;
-			case GL_RGBA8_SNORM:
-			case GL_RGBA8:
-			case GL_RGBA:
-				return sw::FORMAT_A8B8G8R8I_SNORM;
-			case GL_RGBA8I:
-			case GL_RGBA_INTEGER:
-				return sw::FORMAT_A8B8G8R8I;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_UNSIGNED_BYTE:
-			switch(format)
-			{
-			case GL_LUMINANCE:
-			case GL_LUMINANCE8_EXT:
-				return sw::FORMAT_L8;
-			case GL_LUMINANCE_ALPHA:
-			case GL_LUMINANCE8_ALPHA8_EXT:
-				return sw::FORMAT_A8L8;
-			case GL_R8_SNORM:
-			case GL_R8:
-			case GL_RED:
-				return sw::FORMAT_R8;
-			case GL_R8UI:
-			case GL_RED_INTEGER:
-				return sw::FORMAT_R8UI;
-			case GL_RG8_SNORM:
-			case GL_RG8:
-			case GL_RG:
-				return sw::FORMAT_G8R8;
-			case GL_RG8UI:
-			case GL_RG_INTEGER:
-				return sw::FORMAT_G8R8UI;
-			case GL_RGB8_SNORM:
-			case GL_RGB8:
-			case GL_RGB:
-			case GL_SRGB8:
-				return sw::FORMAT_X8B8G8R8;
-			case GL_RGB8UI:
-			case GL_RGB_INTEGER:
-				return sw::FORMAT_X8B8G8R8UI;
-			case GL_RGBA8_SNORM:
-			case GL_RGBA8:
-			case GL_RGBA:
-			case GL_SRGB8_ALPHA8:
-				return sw::FORMAT_A8B8G8R8;
-			case GL_RGBA8UI:
-			case GL_RGBA_INTEGER:
-				return sw::FORMAT_A8B8G8R8UI;
-			case GL_BGRA_EXT:
-			case GL_BGRA8_EXT:
-				return sw::FORMAT_A8R8G8B8;
-			case GL_ALPHA:
-			case GL_ALPHA8_EXT:
-				return sw::FORMAT_A8;
-			case SW_YV12_BT601:
-				return sw::FORMAT_YV12_BT601;
-			case SW_YV12_BT709:
-				return sw::FORMAT_YV12_BT709;
-			case SW_YV12_JFIF:
-				return sw::FORMAT_YV12_JFIF;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_SHORT:
-			switch(format)
-			{
-			case GL_R16I:
-			case GL_RED_INTEGER:
-				return sw::FORMAT_R16I;
-			case GL_RG16I:
-			case GL_RG_INTEGER:
-				return sw::FORMAT_G16R16I;
-			case GL_RGB16I:
-			case GL_RGB_INTEGER:
-				return sw::FORMAT_X16B16G16R16I;
-			case GL_RGBA16I:
-			case GL_RGBA_INTEGER:
-				return sw::FORMAT_A16B16G16R16I;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_UNSIGNED_SHORT:
-			switch(format)
-			{
-			case GL_R16UI:
-			case GL_RED_INTEGER:
-				return sw::FORMAT_R16UI;
-			case GL_RG16UI:
-			case GL_RG_INTEGER:
-				return sw::FORMAT_G16R16UI;
-			case GL_RGB16UI:
-			case GL_RGB_INTEGER:
-				return sw::FORMAT_X16B16G16R16UI;
-			case GL_RGBA16UI:
-			case GL_RGBA_INTEGER:
-				return sw::FORMAT_A16B16G16R16UI;
-			case GL_DEPTH_COMPONENT:
-			case GL_DEPTH_COMPONENT16:
-				return sw::FORMAT_D32FS8_TEXTURE;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_INT:
-			switch(format)
-			{
-			case GL_RED_INTEGER:
-			case GL_R32I:
-				return sw::FORMAT_R32I;
-			case GL_RG_INTEGER:
-			case GL_RG32I:
-				return sw::FORMAT_G32R32I;
-			case GL_RGB_INTEGER:
-			case GL_RGB32I:
-				return sw::FORMAT_X32B32G32R32I;
-			case GL_RGBA_INTEGER:
-			case GL_RGBA32I:
-				return sw::FORMAT_A32B32G32R32I;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_UNSIGNED_INT:
-			switch(format)
-			{
-			case GL_RED_INTEGER:
-			case GL_R32UI:
-				return sw::FORMAT_R32UI;
-			case GL_RG_INTEGER:
-			case GL_RG32UI:
-				return sw::FORMAT_G32R32UI;
-			case GL_RGB_INTEGER:
-			case GL_RGB32UI:
-				return sw::FORMAT_X32B32G32R32UI;
-			case GL_RGBA_INTEGER:
-			case GL_RGBA32UI:
-				return sw::FORMAT_A32B32G32R32UI;
-			case GL_DEPTH_COMPONENT:
-			case GL_DEPTH_COMPONENT16:
-			case GL_DEPTH_COMPONENT24:
-			case GL_DEPTH_COMPONENT32_OES:
-				return sw::FORMAT_D32FS8_TEXTURE;
-			default:
-				UNREACHABLE(format);
-			}
-		case GL_UNSIGNED_INT_24_8_OES:
-			if(format == GL_DEPTH_STENCIL || format == GL_DEPTH24_STENCIL8)
-			{
-				return sw::FORMAT_D32FS8_TEXTURE;
-			}
-			else UNREACHABLE(format);
-		case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-			if(format == GL_DEPTH_STENCIL || format == GL_DEPTH32F_STENCIL8)
-			{
-				return sw::FORMAT_D32FS8_TEXTURE;
-			}
-			else UNREACHABLE(format);
-		case GL_UNSIGNED_SHORT_4_4_4_4:
-			return sw::FORMAT_A8R8G8B8;
-		case GL_UNSIGNED_SHORT_5_5_5_1:
-			return sw::FORMAT_A8R8G8B8;
-		case GL_UNSIGNED_SHORT_5_6_5:
-			return sw::FORMAT_R5G6B5;
-		case GL_UNSIGNED_INT_2_10_10_10_REV:
-			if(format == GL_RGB10_A2UI)
-			{
-				return sw::FORMAT_A16B16G16R16UI;
-			}
-			else
-			{
-				return sw::FORMAT_A2B10G10R10;
-			}
-		case GL_UNSIGNED_INT_10F_11F_11F_REV:
-		case GL_UNSIGNED_INT_5_9_9_9_REV:
-			return sw::FORMAT_A32B32G32R32F;
-		default:
-			UNREACHABLE(type);
-		}
+		case GL_DEPTH_COMPONENT32F:    return sw::FORMAT_D32F_LOCKABLE;
+		case GL_DEPTH_COMPONENT16:     return sw::FORMAT_D32F_LOCKABLE;
+		case GL_DEPTH_COMPONENT24:     return sw::FORMAT_D32F_LOCKABLE;
+		case GL_DEPTH_COMPONENT32_OES: return sw::FORMAT_D32F_LOCKABLE;
+		case GL_DEPTH24_STENCIL8:      return sw::FORMAT_D32FS8_TEXTURE;
+		case GL_DEPTH32F_STENCIL8:     return sw::FORMAT_D32FS8_TEXTURE;
+		case GL_STENCIL_INDEX8:        return sw::FORMAT_S8;
 
-		return sw::FORMAT_NULL;
+		case GL_R8:             return sw::FORMAT_R8;
+		case GL_RG8:            return sw::FORMAT_G8R8;
+		case GL_R8I:            return sw::FORMAT_R8I;
+		case GL_RG8I:           return sw::FORMAT_G8R8I;
+		case GL_RGB8I:          return sw::FORMAT_X8B8G8R8I;
+		case GL_RGBA8I:         return sw::FORMAT_A8B8G8R8I;
+		case GL_R8UI:           return sw::FORMAT_R8UI;
+		case GL_RG8UI:          return sw::FORMAT_G8R8UI;
+		case GL_RGB8UI:         return sw::FORMAT_X8B8G8R8UI;
+		case GL_RGBA8UI:        return sw::FORMAT_A8B8G8R8UI;
+		case GL_R16I:           return sw::FORMAT_R16I;
+		case GL_RG16I:          return sw::FORMAT_G16R16I;
+		case GL_RGB16I:         return sw::FORMAT_X16B16G16R16I;
+		case GL_RGBA16I:        return sw::FORMAT_A16B16G16R16I;
+		case GL_R16UI:          return sw::FORMAT_R16UI;
+		case GL_RG16UI:         return sw::FORMAT_G16R16UI;
+		case GL_RGB16UI:        return sw::FORMAT_X16B16G16R16UI;
+		case GL_RGBA16UI:       return sw::FORMAT_A16B16G16R16UI;
+		case GL_R32I:           return sw::FORMAT_R32I;
+		case GL_RG32I:          return sw::FORMAT_G32R32I;
+		case GL_RGB32I:         return sw::FORMAT_X32B32G32R32I;
+		case GL_RGBA32I:        return sw::FORMAT_A32B32G32R32I;
+		case GL_R32UI:          return sw::FORMAT_R32UI;
+		case GL_RG32UI:         return sw::FORMAT_G32R32UI;
+		case GL_RGB32UI:        return sw::FORMAT_X32B32G32R32UI;
+		case GL_RGBA32UI:       return sw::FORMAT_A32B32G32R32UI;
+		case GL_R16F:           return sw::FORMAT_R16F;
+		case GL_RG16F:          return sw::FORMAT_G16R16F;
+		case GL_R11F_G11F_B10F: return sw::FORMAT_X16B16G16R16F_UNSIGNED;
+		case GL_RGB16F:         return sw::FORMAT_X16B16G16R16F;
+		case GL_RGBA16F:        return sw::FORMAT_A16B16G16R16F;
+		case GL_R32F:           return sw::FORMAT_R32F;
+		case GL_RG32F:          return sw::FORMAT_G32R32F;
+		case GL_RGB32F:         return sw::FORMAT_X32B32G32R32F;
+		case GL_RGBA32F:        return sw::FORMAT_A32B32G32R32F;
+		case GL_RGB10_A2:       return sw::FORMAT_A2B10G10R10;
+		case GL_RGB10_A2UI:     return sw::FORMAT_A2B10G10R10UI;
+		case GL_SRGB8:          return sw::FORMAT_SRGB8_X8;
+		case GL_SRGB8_ALPHA8:   return sw::FORMAT_SRGB8_A8;
+
+		case GL_ETC1_RGB8_OES:              return sw::FORMAT_ETC1;
+		case GL_COMPRESSED_R11_EAC:         return sw::FORMAT_R11_EAC;
+		case GL_COMPRESSED_SIGNED_R11_EAC:  return sw::FORMAT_SIGNED_R11_EAC;
+		case GL_COMPRESSED_RG11_EAC:        return sw::FORMAT_RG11_EAC;
+		case GL_COMPRESSED_SIGNED_RG11_EAC: return sw::FORMAT_SIGNED_RG11_EAC;
+		case GL_COMPRESSED_RGB8_ETC2:       return sw::FORMAT_RGB8_ETC2;
+		case GL_COMPRESSED_SRGB8_ETC2:      return sw::FORMAT_SRGB8_ETC2;
+		case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:  return sw::FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+		case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: return sw::FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+		case GL_COMPRESSED_RGBA8_ETC2_EAC:        return sw::FORMAT_RGBA8_ETC2_EAC;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: return sw::FORMAT_SRGB8_ALPHA8_ETC2_EAC;
+		case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:   return sw::FORMAT_RGBA_ASTC_4x4_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:   return sw::FORMAT_RGBA_ASTC_5x4_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:   return sw::FORMAT_RGBA_ASTC_5x5_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:   return sw::FORMAT_RGBA_ASTC_6x5_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:   return sw::FORMAT_RGBA_ASTC_6x6_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:   return sw::FORMAT_RGBA_ASTC_8x5_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:   return sw::FORMAT_RGBA_ASTC_8x6_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:   return sw::FORMAT_RGBA_ASTC_8x8_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:  return sw::FORMAT_RGBA_ASTC_10x5_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:  return sw::FORMAT_RGBA_ASTC_10x6_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:  return sw::FORMAT_RGBA_ASTC_10x8_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: return sw::FORMAT_RGBA_ASTC_10x10_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: return sw::FORMAT_RGBA_ASTC_12x10_KHR;
+		case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: return sw::FORMAT_RGBA_ASTC_12x12_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_4x4_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x4_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x5_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x5_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x6_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x5_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x6_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:   return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x8_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:  return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x5_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:  return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x6_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:  return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x8_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x10_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x10_KHR;
+		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR;
+		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:    return sw::FORMAT_DXT1;
+		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:   return sw::FORMAT_DXT1;
+		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return sw::FORMAT_DXT3;
+		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return sw::FORMAT_DXT5;
+
+		case GL_ALPHA32F_EXT:           return sw::FORMAT_A32F;
+		case GL_LUMINANCE32F_EXT:       return sw::FORMAT_L32F;
+		case GL_LUMINANCE_ALPHA32F_EXT: return sw::FORMAT_A32L32F;
+		case GL_RGB9_E5:                return sw::FORMAT_X16B16G16R16F_UNSIGNED;
+		case GL_ALPHA16F_EXT:           return sw::FORMAT_A16F;
+		case GL_LUMINANCE16F_EXT:       return sw::FORMAT_L16F;
+		case GL_LUMINANCE_ALPHA16F_EXT: return sw::FORMAT_A16L16F;
+		case GL_R8_SNORM:    return sw::FORMAT_R8_SNORM;
+		case GL_RG8_SNORM:   return sw::FORMAT_G8R8_SNORM;
+		case GL_RGB8_SNORM:  return sw::FORMAT_X8B8G8R8_SNORM;
+		case GL_RGBA8_SNORM: return sw::FORMAT_A8B8G8R8_SNORM;
+		case GL_LUMINANCE8_EXT:        return sw::FORMAT_L8;
+		case GL_LUMINANCE8_ALPHA8_EXT: return sw::FORMAT_A8L8;
+		case GL_BGRA8_EXT:  return sw::FORMAT_A8R8G8B8;
+		case GL_ALPHA8_EXT: return sw::FORMAT_A8;
+
+		case SW_YV12_BT601: return sw::FORMAT_YV12_BT601;
+		case SW_YV12_BT709: return sw::FORMAT_YV12_BT709;
+		case SW_YV12_JFIF:  return sw::FORMAT_YV12_JFIF;
+
+		default:
+			UNREACHABLE(format);   // Not a sized internal format.
+			return sw::FORMAT_NULL;
+		}
 	}
 
-	// Returns the size, in bytes, of a single texel in an Image
+	// Returns the size, in bytes, of a single client-side pixel.
+    // OpenGL ES 3.0.5 table 3.2.
 	static int ComputePixelSize(GLenum format, GLenum type)
 	{
-		switch(type)
+		switch(format)
 		{
-		case GL_BYTE:
-			switch(format)
+		case GL_RED:
+		case GL_RED_INTEGER:
+		case GL_ALPHA:
+		case GL_LUMINANCE:
+			switch(type)
 			{
-			case GL_R8:
-			case GL_R8I:
-			case GL_R8_SNORM:
-			case GL_RED:             return sizeof(char);
-			case GL_RED_INTEGER:     return sizeof(char);
-			case GL_RG8:
-			case GL_RG8I:
-			case GL_RG8_SNORM:
-			case GL_RG:              return sizeof(char) * 2;
-			case GL_RG_INTEGER:      return sizeof(char) * 2;
-			case GL_RGB8:
-			case GL_RGB8I:
-			case GL_RGB8_SNORM:
-			case GL_RGB:             return sizeof(char) * 3;
-			case GL_RGB_INTEGER:     return sizeof(char) * 3;
-			case GL_RGBA8:
-			case GL_RGBA8I:
-			case GL_RGBA8_SNORM:
-			case GL_RGBA:            return sizeof(char) * 4;
-			case GL_RGBA_INTEGER:    return sizeof(char) * 4;
-			default: UNREACHABLE(format);
+			case GL_BYTE:           return 1;
+			case GL_UNSIGNED_BYTE:  return 1;
+			case GL_FLOAT:          return 4;
+			case GL_HALF_FLOAT:     return 2;
+			case GL_HALF_FLOAT_OES: return 2;
+			case GL_SHORT:          return 2;
+			case GL_UNSIGNED_SHORT: return 2;
+			case GL_INT:            return 4;
+			case GL_UNSIGNED_INT:   return 4;
+			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_UNSIGNED_BYTE:
-			switch(format)
+		case GL_RG:
+		case GL_RG_INTEGER:
+		case GL_LUMINANCE_ALPHA:
+			switch(type)
 			{
-			case GL_R8:
-			case GL_R8UI:
-			case GL_RED:             return sizeof(unsigned char);
-			case GL_RED_INTEGER:     return sizeof(unsigned char);
-			case GL_ALPHA8_EXT:
-			case GL_ALPHA:           return sizeof(unsigned char);
-			case GL_LUMINANCE8_EXT:
-			case GL_LUMINANCE:       return sizeof(unsigned char);
-			case GL_LUMINANCE8_ALPHA8_EXT:
-			case GL_LUMINANCE_ALPHA: return sizeof(unsigned char) * 2;
-			case GL_RG8:
-			case GL_RG8UI:
-			case GL_RG:              return sizeof(unsigned char) * 2;
-			case GL_RG_INTEGER:      return sizeof(unsigned char) * 2;
-			case GL_RGB8:
-			case GL_RGB8UI:
-			case GL_SRGB8:
-			case GL_RGB:             return sizeof(unsigned char) * 3;
-			case GL_RGB_INTEGER:     return sizeof(unsigned char) * 3;
-			case GL_RGBA8:
-			case GL_RGBA8UI:
-			case GL_SRGB8_ALPHA8:
-			case GL_RGBA:            return sizeof(unsigned char) * 4;
-			case GL_RGBA_INTEGER:    return sizeof(unsigned char) * 4;
-			case GL_BGRA_EXT:
-			case GL_BGRA8_EXT:       return sizeof(unsigned char)* 4;
-			default: UNREACHABLE(format);
+			case GL_BYTE:           return 2;
+			case GL_UNSIGNED_BYTE:  return 2;
+			case GL_FLOAT:          return 8;
+			case GL_HALF_FLOAT:     return 4;
+			case GL_HALF_FLOAT_OES: return 4;
+			case GL_SHORT:          return 4;
+			case GL_UNSIGNED_SHORT: return 4;
+			case GL_INT:            return 8;
+			case GL_UNSIGNED_INT:   return 8;
+			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_SHORT:
-			switch(format)
+		case GL_RGB:
+		case GL_RGB_INTEGER:
+			switch(type)
 			{
-			case GL_R16I:
-			case GL_RED_INTEGER:     return sizeof(short);
-			case GL_RG16I:
-			case GL_RG_INTEGER:      return sizeof(short) * 2;
-			case GL_RGB16I:
-			case GL_RGB_INTEGER:     return sizeof(short) * 3;
-			case GL_RGBA16I:
-			case GL_RGBA_INTEGER:    return sizeof(short) * 4;
-			default: UNREACHABLE(format);
+			case GL_BYTE:                         return 3;
+			case GL_UNSIGNED_BYTE:                return 3;
+			case GL_UNSIGNED_SHORT_5_6_5:         return 2;
+			case GL_UNSIGNED_INT_10F_11F_11F_REV: return 4;
+			case GL_UNSIGNED_INT_5_9_9_9_REV:     return 4;
+			case GL_FLOAT:                        return 12;
+			case GL_HALF_FLOAT:                   return 6;
+			case GL_HALF_FLOAT_OES:               return 6;
+			case GL_SHORT:                        return 6;
+			case GL_UNSIGNED_SHORT:               return 6;
+			case GL_INT:                          return 12;
+			case GL_UNSIGNED_INT:                 return 12;
+			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_UNSIGNED_SHORT:
-			switch(format)
+		case GL_RGBA:
+		case GL_RGBA_INTEGER:
+		case GL_BGRA_EXT:
+			switch(type)
 			{
-			case GL_DEPTH_COMPONENT16:
-			case GL_DEPTH_COMPONENT: return sizeof(unsigned short);
-			case GL_R16UI:
-			case GL_RED_INTEGER:     return sizeof(unsigned short);
-			case GL_RG16UI:
-			case GL_RG_INTEGER:      return sizeof(unsigned short) * 2;
-			case GL_RGB16UI:
-			case GL_RGB_INTEGER:     return sizeof(unsigned short) * 3;
-			case GL_RGBA16UI:
-			case GL_RGBA_INTEGER:    return sizeof(unsigned short) * 4;
-			default: UNREACHABLE(format);
+			case GL_BYTE:                           return 4;
+			case GL_UNSIGNED_BYTE:                  return 4;
+			case GL_UNSIGNED_SHORT_4_4_4_4:         return 2;
+			case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return 2;
+			case GL_UNSIGNED_SHORT_5_5_5_1:         return 2;
+			case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return 2;
+			case GL_UNSIGNED_INT_2_10_10_10_REV:    return 4;
+			case GL_FLOAT:                          return 16;
+			case GL_HALF_FLOAT:                     return 8;
+			case GL_HALF_FLOAT_OES:                 return 8;
+			case GL_SHORT:                          return 8;
+			case GL_UNSIGNED_SHORT:                 return 8;
+			case GL_INT:                            return 16;
+			case GL_UNSIGNED_INT:                   return 16;
+			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_INT:
-			switch(format)
+		case GL_DEPTH_COMPONENT:
+			switch(type)
 			{
-			case GL_R32I:
-			case GL_RED_INTEGER:     return sizeof(int);
-			case GL_RG32I:
-			case GL_RG_INTEGER:      return sizeof(int) * 2;
-			case GL_RGB32I:
-			case GL_RGB_INTEGER:     return sizeof(int) * 3;
-			case GL_RGBA32I:
-			case GL_RGBA_INTEGER:    return sizeof(int) * 4;
-			default: UNREACHABLE(format);
+			case GL_FLOAT:          return 4;
+			case GL_UNSIGNED_SHORT: return 2;
+			case GL_UNSIGNED_INT:   return 4;
+			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_UNSIGNED_INT:
-			switch(format)
+		case GL_DEPTH_STENCIL:
+			switch(type)
 			{
-			case GL_DEPTH_COMPONENT16:
-			case GL_DEPTH_COMPONENT24:
-			case GL_DEPTH_COMPONENT32_OES:
-			case GL_DEPTH_COMPONENT: return sizeof(unsigned int);
-			case GL_R32UI:
-			case GL_RED_INTEGER:     return sizeof(unsigned int);
-			case GL_RG32UI:
-			case GL_RG_INTEGER:      return sizeof(unsigned int) * 2;
-			case GL_RGB32UI:
-			case GL_RGB_INTEGER:     return sizeof(unsigned int) * 3;
-			case GL_RGBA32UI:
-			case GL_RGBA_INTEGER:    return sizeof(unsigned int) * 4;
-			default: UNREACHABLE(format);
+			case GL_UNSIGNED_INT_24_8:              return 4;
+			case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return 8;
+			default: UNREACHABLE(type);
 			}
 			break;
-		case GL_UNSIGNED_SHORT_4_4_4_4:
-		case GL_UNSIGNED_SHORT_5_5_5_1:
-		case GL_UNSIGNED_SHORT_5_6_5:
-		case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
-		case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
-			return sizeof(unsigned short);
-		case GL_UNSIGNED_INT_10F_11F_11F_REV:
-		case GL_UNSIGNED_INT_5_9_9_9_REV:
-		case GL_UNSIGNED_INT_2_10_10_10_REV:
-		case GL_UNSIGNED_INT_24_8_OES:
-			return sizeof(unsigned int);
-		case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-			return sizeof(float) + sizeof(unsigned int);
-		case GL_FLOAT:
-			switch(format)
-			{
-			case GL_DEPTH_COMPONENT32F:
-			case GL_DEPTH_COMPONENT: return sizeof(float);
-			case GL_ALPHA32F_EXT:
-			case GL_ALPHA:           return sizeof(float);
-			case GL_LUMINANCE32F_EXT:
-			case GL_LUMINANCE:       return sizeof(float);
-			case GL_LUMINANCE_ALPHA32F_EXT:
-			case GL_LUMINANCE_ALPHA: return sizeof(float) * 2;
-			case GL_RED:             return sizeof(float);
-			case GL_R32F:            return sizeof(float);
-			case GL_RG:              return sizeof(float) * 2;
-			case GL_RG32F:           return sizeof(float) * 2;
-			case GL_RGB:             return sizeof(float) * 3;
-			case GL_RGB32F:          return sizeof(float) * 3;
-			case GL_RGBA:            return sizeof(float) * 4;
-			case GL_RGBA32F:         return sizeof(float) * 4;
-			default: UNREACHABLE(format);
-			}
-			break;
-		case GL_HALF_FLOAT:
-		case GL_HALF_FLOAT_OES:
-			switch(format)
-			{
-			case GL_ALPHA16F_EXT:
-			case GL_ALPHA:           return sizeof(unsigned short);
-			case GL_LUMINANCE16F_EXT:
-			case GL_LUMINANCE:       return sizeof(unsigned short);
-			case GL_LUMINANCE_ALPHA16F_EXT:
-			case GL_LUMINANCE_ALPHA: return sizeof(unsigned short) * 2;
-			case GL_RED:             return sizeof(unsigned short);
-			case GL_R16F:            return sizeof(unsigned short);
-			case GL_RG:              return sizeof(unsigned short) * 2;
-			case GL_RG16F:           return sizeof(unsigned short) * 2;
-			case GL_RGB:             return sizeof(unsigned short) * 3;
-			case GL_RGB16F:          return sizeof(unsigned short) * 3;
-			case GL_RGBA:            return sizeof(unsigned short) * 4;
-			case GL_RGBA16F:         return sizeof(unsigned short) * 4;
-			default: UNREACHABLE(format);
-			}
-			break;
-		default: UNREACHABLE(type);
+		default:
+			UNREACHABLE(format);
 		}
 
 		return 0;
@@ -1100,10 +675,10 @@
 		return (rawPitch + alignment - 1) & ~(alignment - 1);
 	}
 
-	size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, GLint alignment, GLint skipImages, GLint skipRows, GLint skipPixels)
+	size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, const gl::PixelStorageModes &storageModes)
 	{
-		GLsizei pitchB = ComputePitch(width, format, type, alignment);
-		return (skipImages * height + skipRows) * pitchB + skipPixels * ComputePixelSize(format, type);
+		GLsizei pitchB = ComputePitch(width, format, type, storageModes.alignment);
+		return (storageModes.skipImages * height + storageModes.skipRows) * pitchB + storageModes.skipPixels * ComputePixelSize(format, type);
 	}
 
 	inline GLsizei ComputeCompressedPitch(GLsizei width, GLenum format)
@@ -1111,6 +686,11 @@
 		return ComputeCompressedSize(width, 1, format);
 	}
 
+	inline int GetNumCompressedBlocks(int w, int h, int blockSizeX, int blockSizeY)
+	{
+		return ((w + blockSizeX - 1) / blockSizeX) * ((h + blockSizeY - 1) / blockSizeY);
+	}
+
 	GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format)
 	{
 		switch(format)
@@ -1124,7 +704,7 @@
 		case GL_COMPRESSED_SRGB8_ETC2:
 		case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
 		case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-			return 8 * getNumBlocks(width, height, 4, 4);
+			return 8 * GetNumCompressedBlocks(width, height, 4, 4);
 		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
 		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
 		case GL_COMPRESSED_RG11_EAC:
@@ -1133,62 +713,450 @@
 		case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
 		case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
-			return 16 * getNumBlocks(width, height, 4, 4);
+			return 16 * GetNumCompressedBlocks(width, height, 4, 4);
 		case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
-			return 16 * getNumBlocks(width, height, 5, 4);
+			return 16 * GetNumCompressedBlocks(width, height, 5, 4);
 		case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
-			return 16 * getNumBlocks(width, height, 5, 5);
+			return 16 * GetNumCompressedBlocks(width, height, 5, 5);
 		case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
-			return 16 * getNumBlocks(width, height, 6, 5);
+			return 16 * GetNumCompressedBlocks(width, height, 6, 5);
 		case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
-			return 16 * getNumBlocks(width, height, 6, 6);
+			return 16 * GetNumCompressedBlocks(width, height, 6, 6);
 		case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
-			return 16 * getNumBlocks(width, height, 8, 5);
+			return 16 * GetNumCompressedBlocks(width, height, 8, 5);
 		case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
-			return 16 * getNumBlocks(width, height, 8, 6);
+			return 16 * GetNumCompressedBlocks(width, height, 8, 6);
 		case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
-			return 16 * getNumBlocks(width, height, 8, 8);
+			return 16 * GetNumCompressedBlocks(width, height, 8, 8);
 		case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
-			return 16 * getNumBlocks(width, height, 10, 5);
+			return 16 * GetNumCompressedBlocks(width, height, 10, 5);
 		case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
-			return 16 * getNumBlocks(width, height, 10, 6);
+			return 16 * GetNumCompressedBlocks(width, height, 10, 6);
 		case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
-			return 16 * getNumBlocks(width, height, 10, 8);
+			return 16 * GetNumCompressedBlocks(width, height, 10, 8);
 		case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
-			return 16 * getNumBlocks(width, height, 10, 10);
+			return 16 * GetNumCompressedBlocks(width, height, 10, 10);
 		case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
-			return 16 * getNumBlocks(width, height, 12, 10);
+			return 16 * GetNumCompressedBlocks(width, height, 12, 10);
 		case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
-			return 16 * getNumBlocks(width, height, 12, 12);
+			return 16 * GetNumCompressedBlocks(width, height, 12, 12);
 		default:
+			UNREACHABLE(format);
 			return 0;
 		}
 	}
+}
+
+namespace egl
+{
+	enum TransferType
+	{
+		Bytes,
+		RGB8toRGBX8,
+		RGB16toRGBX16,
+		RGB32toRGBX32,
+		RGB32FtoRGBX32F,
+		RGB16FtoRGBX16F,
+		RGBA4toRGBA8,
+		RGBA5_A1toRGBA8,
+		R11G11B10FtoRGBX16F,
+		RGB9_E5FtoRGBX16F,
+		D16toD32F,
+		D24X8toD32F,
+		D32toD32F,
+		D32FtoD32F_CLAMPED,
+		D32FX32toD32F,
+		X24S8toS8,
+		X56S8toS8,
+		RGBA1010102toRGBA8,
+		RGB8toRGB565,
+		R32FtoR16F,
+		RG32FtoRG16F,
+		RGB32FtoRGB16F,
+		RGB32FtoRGB16F_UNSIGNED,
+		RGBA32FtoRGBA16F
+	};
+
+	template<TransferType transferType>
+	void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes);
+
+	template<>
+	void TransferRow<Bytes>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		memcpy(dest, source, width * bytes);
+	}
+
+	template<>
+	void TransferRow<RGB8toRGBX8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		unsigned char *destB = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			destB[4 * x + 0] = source[x * 3 + 0];
+			destB[4 * x + 1] = source[x * 3 + 1];
+			destB[4 * x + 2] = source[x * 3 + 2];
+			destB[4 * x + 3] = 0xFF;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB16toRGBX16>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *sourceS = reinterpret_cast<const unsigned short*>(source);
+		unsigned short *destS = reinterpret_cast<unsigned short*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destS[4 * x + 0] = sourceS[x * 3 + 0];
+			destS[4 * x + 1] = sourceS[x * 3 + 1];
+			destS[4 * x + 2] = sourceS[x * 3 + 2];
+			destS[4 * x + 3] = 0xFFFF;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB32toRGBX32>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
+		unsigned int *destI = reinterpret_cast<unsigned int*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destI[4 * x + 0] = sourceI[x * 3 + 0];
+			destI[4 * x + 1] = sourceI[x * 3 + 1];
+			destI[4 * x + 2] = sourceI[x * 3 + 2];
+			destI[4 * x + 3] = 0xFFFFFFFF;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB32FtoRGBX32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *sourceF = reinterpret_cast<const float*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[4 * x + 0] = sourceF[x * 3 + 0];
+			destF[4 * x + 1] = sourceF[x * 3 + 1];
+			destF[4 * x + 2] = sourceF[x * 3 + 2];
+			destF[4 * x + 3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB16FtoRGBX16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
+		unsigned short *destH = reinterpret_cast<unsigned short*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destH[4 * x + 0] = sourceH[x * 3 + 0];
+			destH[4 * x + 1] = sourceH[x * 3 + 1];
+			destH[4 * x + 2] = sourceH[x * 3 + 2];
+			destH[4 * x + 3] = 0x3C00;   // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16-bit floating-point representation of 1.0
+		}
+	}
+
+	template<>
+	void TransferRow<RGBA4toRGBA8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *source4444 = reinterpret_cast<const unsigned short*>(source);
+		unsigned char *dest4444 = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			unsigned short rgba = source4444[x];
+			dest4444[4 * x + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
+			dest4444[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
+			dest4444[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
+			dest4444[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
+		}
+	}
+
+	template<>
+	void TransferRow<RGBA5_A1toRGBA8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *source5551 = reinterpret_cast<const unsigned short*>(source);
+		unsigned char *dest8888 = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			unsigned short rgba = source5551[x];
+			dest8888[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+			dest8888[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
+			dest8888[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
+			dest8888[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
+		}
+	}
+
+	template<>
+	void TransferRow<RGBA1010102toRGBA8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *source1010102 = reinterpret_cast<const unsigned int*>(source);
+		unsigned char *dest8888 = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			unsigned int rgba = source1010102[x];
+			dest8888[4 * x + 0] = sw::unorm<8>((rgba & 0x000003FF) * (1.0f / 0x000003FF));
+			dest8888[4 * x + 1] = sw::unorm<8>((rgba & 0x000FFC00) * (1.0f / 0x000FFC00));
+			dest8888[4 * x + 2] = sw::unorm<8>((rgba & 0x3FF00000) * (1.0f / 0x3FF00000));
+			dest8888[4 * x + 3] = sw::unorm<8>((rgba & 0xC0000000) * (1.0f / 0xC0000000));
+		}
+	}
+
+	template<>
+	void TransferRow<RGB8toRGB565>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		unsigned short *dest565 = reinterpret_cast<unsigned short*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			float r = source[3 * x + 0] * (1.0f / 0xFF);
+			float g = source[3 * x + 1] * (1.0f / 0xFF);
+			float b = source[3 * x + 2] * (1.0f / 0xFF);
+			dest565[x] = (sw::unorm<5>(r) << 11) | (sw::unorm<6>(g) << 5) | (sw::unorm<5>(b) << 0);
+		}
+	}
+
+	template<>
+	void TransferRow<R11G11B10FtoRGBX16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const sw::R11G11B10F *sourceRGB = reinterpret_cast<const sw::R11G11B10F*>(source);
+		sw::half *destF = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++, sourceRGB++, destF += 4)
+		{
+			sourceRGB->toRGB16F(destF);
+			destF[3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB9_E5FtoRGBX16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const sw::RGB9E5 *sourceRGB = reinterpret_cast<const sw::RGB9E5*>(source);
+		sw::half *destF = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++, sourceRGB++, destF += 4)
+		{
+			sourceRGB->toRGB16F(destF);
+			destF[3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<R32FtoR16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[x] = source32F[x];
+		}
+	}
+
+	template<>
+	void TransferRow<RG32FtoRG16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[2 * x + 0] = source32F[2 * x + 0];
+			dest16F[2 * x + 1] = source32F[2 * x + 1];
+		}
+	}
+
+	template<>
+	void TransferRow<RGB32FtoRGB16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[4 * x + 0] = source32F[3 * x + 0];
+			dest16F[4 * x + 1] = source32F[3 * x + 1];
+			dest16F[4 * x + 2] = source32F[3 * x + 2];
+			dest16F[4 * x + 3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<RGB32FtoRGB16F_UNSIGNED>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[4 * x + 0] = std::max(source32F[3 * x + 0], 0.0f);
+			dest16F[4 * x + 1] = std::max(source32F[3 * x + 1], 0.0f);
+			dest16F[4 * x + 2] = std::max(source32F[3 * x + 2], 0.0f);
+			dest16F[4 * x + 3] = 1.0f;
+		}
+	}
+
+	template<>
+	void TransferRow<RGBA32FtoRGBA16F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *source32F = reinterpret_cast<const float*>(source);
+		sw::half *dest16F = reinterpret_cast<sw::half*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			dest16F[4 * x + 0] = source32F[4 * x + 0];
+			dest16F[4 * x + 1] = source32F[4 * x + 1];
+			dest16F[4 * x + 2] = source32F[4 * x + 2];
+			dest16F[4 * x + 3] = source32F[4 * x + 3];
+		}
+	}
+
+	template<>
+	void TransferRow<D16toD32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned short *sourceD16 = reinterpret_cast<const unsigned short*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = (float)sourceD16[x] / 0xFFFF;
+		}
+	}
+
+	template<>
+	void TransferRow<D24X8toD32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *sourceD24 = reinterpret_cast<const unsigned int*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = (float)(sourceD24[x] & 0xFFFFFF00) / 0xFFFFFF00;
+		}
+	}
+
+	template<>
+	void TransferRow<D32toD32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *sourceD32 = reinterpret_cast<const unsigned int*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = (float)sourceD32[x] / 0xFFFFFFFF;
+		}
+	}
+
+	template<>
+	void TransferRow<D32FtoD32F_CLAMPED>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const float *sourceF = reinterpret_cast<const float*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = sw::clamp(sourceF[x], 0.0f, 1.0f);
+		}
+	}
+
+	template<>
+	void TransferRow<D32FX32toD32F>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		struct D32FS8 { float depth32f; unsigned int stencil24_8; };
+		const D32FS8 *sourceD32FS8 = reinterpret_cast<const D32FS8*>(source);
+		float *destF = reinterpret_cast<float*>(dest);
+
+		for(int x = 0; x < width; x++)
+		{
+			destF[x] = sw::clamp(sourceD32FS8[x].depth32f, 0.0f, 1.0f);
+		}
+	}
+
+	template<>
+	void TransferRow<X24S8toS8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
+		unsigned char *destI = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			destI[x] = static_cast<unsigned char>(sourceI[x] & 0x000000FF);   // FIXME: Quad layout
+		}
+	}
+
+	template<>
+	void TransferRow<X56S8toS8>(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes)
+	{
+		struct D32FS8 { float depth32f; unsigned int stencil24_8; };
+		const D32FS8 *sourceD32FS8 = reinterpret_cast<const D32FS8*>(source);
+		unsigned char *destI = dest;
+
+		for(int x = 0; x < width; x++)
+		{
+			destI[x] = static_cast<unsigned char>(sourceD32FS8[x].stencil24_8 & 0x000000FF);   // FIXME: Quad layout
+		}
+	}
+
+	struct Rectangle
+	{
+		GLsizei bytes;
+		GLsizei width;
+		GLsizei height;
+		GLsizei depth;
+		int inputPitch;
+		int inputHeight;
+		int destPitch;
+		GLsizei destSlice;
+	};
+
+	template<TransferType transferType>
+	void Transfer(void *buffer, const void *input, const Rectangle &rect)
+	{
+		for(int z = 0; z < rect.depth; z++)
+		{
+			const unsigned char *inputStart = static_cast<const unsigned char*>(input) + (z * rect.inputPitch * rect.inputHeight);
+			unsigned char *destStart = static_cast<unsigned char*>(buffer) + (z * rect.destSlice);
+			for(int y = 0; y < rect.height; y++)
+			{
+				const unsigned char *source = inputStart + y * rect.inputPitch;
+				unsigned char *dest = destStart + y * rect.destPitch;
+
+				TransferRow<transferType>(dest, source, rect.width, rect.bytes);
+			}
+		}
+	}
 
 	class ImageImplementation : public Image
 	{
 	public:
-		ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
-			: Image(parentTexture, width, height, format, type) {}
-		ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type)
-			: Image(parentTexture, width, height, depth, format, type) {}
-		ImageImplementation(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP)
-			: Image(width, height, format, type, pitchP) {}
-		ImageImplementation(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable)
-			: Image(width, height, internalFormat, multiSampleDepth, lockable) {}
+		ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat)
+			: Image(parentTexture, width, height, internalformat) {}
+		ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat)
+			: Image(parentTexture, width, height, depth, border, internalformat) {}
+		ImageImplementation(GLsizei width, GLsizei height, GLint internalformat, int pitchP)
+			: Image(width, height, internalformat, pitchP) {}
+		ImageImplementation(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable)
+			: Image(width, height, internalformat, multiSampleDepth, lockable) {}
 
 		~ImageImplementation() override
 		{
@@ -1211,24 +1179,24 @@
 		}
 	};
 
-	Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
+	Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat)
 	{
-		return new ImageImplementation(parentTexture, width, height, format, type);
+		return new ImageImplementation(parentTexture, width, height, internalformat);
 	}
 
-	Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type)
+	Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat)
 	{
-		return new ImageImplementation(parentTexture, width, height, depth, format, type);
+		return new ImageImplementation(parentTexture, width, height, depth, border, internalformat);
 	}
 
-	Image *Image::create(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP)
+	Image *Image::create(GLsizei width, GLsizei height, GLint internalformat, int pitchP)
 	{
-		return new ImageImplementation(width, height, format, type, pitchP);
+		return new ImageImplementation(width, height, internalformat, pitchP);
 	}
 
-	Image *Image::create(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable)
+	Image *Image::create(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable)
 	{
-		return new ImageImplementation(width, height, internalFormat, multiSampleDepth, lockable);
+		return new ImageImplementation(width, height, internalformat, multiSampleDepth, lockable);
 	}
 
 	Image::~Image()
@@ -1287,434 +1255,381 @@
 		return parentTexture == parent;
 	}
 
-	void Image::loadImageData(Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const UnpackInfo& unpackInfo, const void *input)
+	void Image::loadImageData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer)
 	{
-		sw::Format selectedInternalFormat = SelectInternalFormat(format, type);
-		if(selectedInternalFormat == sw::FORMAT_NULL)
+		Rectangle rect;
+		rect.bytes = gl::ComputePixelSize(format, type);
+		rect.width = width;
+		rect.height = height;
+		rect.depth = depth;
+		rect.inputPitch = inputPitch;
+		rect.inputHeight = inputHeight;
+		rect.destPitch = getPitch();
+		rect.destSlice = getSlice();
+
+		// [OpenGL ES 3.0.5] table 3.2 and 3.3.
+		switch(format)
 		{
-			return;
-		}
-
-		GLsizei inputWidth = (unpackInfo.rowLength == 0) ? width : unpackInfo.rowLength;
-		GLsizei inputPitch = ComputePitch(inputWidth, format, type, unpackInfo.alignment);
-		GLsizei inputHeight = (unpackInfo.imageHeight == 0) ? height : unpackInfo.imageHeight;
-		input = ((char*)input) + ComputePackingOffset(format, type, inputWidth, inputHeight, unpackInfo.alignment, unpackInfo.skipImages, unpackInfo.skipRows, unpackInfo.skipPixels);
-
-		if(selectedInternalFormat == internalFormat)
-		{
-			void *buffer = lock(0, 0, sw::LOCK_WRITEONLY);
-
-			if(buffer)
+		case GL_RGBA:
+			switch(type)
 			{
-				switch(type)
+			case GL_UNSIGNED_BYTE:
+				switch(internalformat)
 				{
-				case GL_BYTE:
-					switch(format)
-					{
-					case GL_R8:
-					case GL_R8I:
-					case GL_R8_SNORM:
-					case GL_RED:
-					case GL_RED_INTEGER:
-					case GL_ALPHA:
-					case GL_ALPHA8_EXT:
-					case GL_LUMINANCE:
-					case GL_LUMINANCE8_EXT:
-						LoadImageData<Bytes_1>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RG8:
-					case GL_RG8I:
-					case GL_RG8_SNORM:
-					case GL_RG:
-					case GL_RG_INTEGER:
-					case GL_LUMINANCE_ALPHA:
-					case GL_LUMINANCE8_ALPHA8_EXT:
-						LoadImageData<Bytes_2>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGB8:
-					case GL_RGB8I:
-					case GL_RGB8_SNORM:
-					case GL_RGB:
-					case GL_RGB_INTEGER:
-						LoadImageData<ByteRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGBA8:
-					case GL_RGBA8I:
-					case GL_RGBA8_SNORM:
-					case GL_RGBA:
-					case GL_RGBA_INTEGER:
-					case GL_BGRA_EXT:
-					case GL_BGRA8_EXT:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_BYTE:
-					switch(format)
-					{
-					case GL_R8:
-					case GL_R8UI:
-					case GL_R8_SNORM:
-					case GL_RED:
-					case GL_RED_INTEGER:
-					case GL_ALPHA:
-					case GL_ALPHA8_EXT:
-					case GL_LUMINANCE:
-					case GL_LUMINANCE8_EXT:
-						LoadImageData<Bytes_1>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RG8:
-					case GL_RG8UI:
-					case GL_RG8_SNORM:
-					case GL_RG:
-					case GL_RG_INTEGER:
-					case GL_LUMINANCE_ALPHA:
-					case GL_LUMINANCE8_ALPHA8_EXT:
-						LoadImageData<Bytes_2>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGB8:
-					case GL_RGB8UI:
-					case GL_RGB8_SNORM:
-					case GL_RGB:
-					case GL_RGB_INTEGER:
-						LoadImageData<UByteRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGBA8:
-					case GL_RGBA8UI:
-					case GL_RGBA8_SNORM:
-					case GL_RGBA:
-					case GL_RGBA_INTEGER:
-					case GL_BGRA_EXT:
-					case GL_BGRA8_EXT:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_SRGB8:
-						LoadImageData<SRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_SRGB8_ALPHA8:
-						LoadImageData<SRGBA>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_SHORT_5_6_5:
-					switch(format)
-					{
-					case GL_RGB565:
-					case GL_RGB:
-						LoadImageData<RGB565>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_SHORT_4_4_4_4:
-					switch(format)
-					{
-					case GL_RGBA4:
-					case GL_RGBA:
-						LoadImageData<RGBA4444>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_SHORT_5_5_5_1:
-					switch(format)
-					{
-					case GL_RGB5_A1:
-					case GL_RGBA:
-						LoadImageData<RGBA5551>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_INT_10F_11F_11F_REV:
-					switch(format)
-					{
-					case GL_R11F_G11F_B10F:
-					case GL_RGB:
-						LoadImageData<R11G11B10F>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_INT_5_9_9_9_REV:
-					switch(format)
-					{
-					case GL_RGB9_E5:
-					case GL_RGB:
-						LoadImageData<RGB9E5>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_INT_2_10_10_10_REV:
-					switch(format)
-					{
-					case GL_RGB10_A2UI:
-						LoadImageData<RGB10A2UI>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGB10_A2:
-					case GL_RGBA:
-					case GL_RGBA_INTEGER:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_FLOAT:
-					switch(format)
-					{
-					// float textures are converted to RGBA, not BGRA
-					case GL_ALPHA:
-					case GL_ALPHA32F_EXT:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_LUMINANCE:
-					case GL_LUMINANCE32F_EXT:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_LUMINANCE_ALPHA:
-					case GL_LUMINANCE_ALPHA32F_EXT:
-						LoadImageData<Bytes_8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RED:
-					case GL_R32F:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RG:
-					case GL_RG32F:
-						LoadImageData<Bytes_8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGB:
-					case GL_RGB32F:
-						LoadImageData<FloatRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGBA:
-					case GL_RGBA32F:
-						LoadImageData<Bytes_16>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_DEPTH_COMPONENT:
-					case GL_DEPTH_COMPONENT32F:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_HALF_FLOAT:
-				case GL_HALF_FLOAT_OES:
-					switch(format)
-					{
-					case GL_ALPHA:
-					case GL_ALPHA16F_EXT:
-						LoadImageData<Bytes_2>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_LUMINANCE:
-					case GL_LUMINANCE16F_EXT:
-						LoadImageData<Bytes_2>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_LUMINANCE_ALPHA:
-					case GL_LUMINANCE_ALPHA16F_EXT:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RED:
-					case GL_R16F:
-						LoadImageData<Bytes_2>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RG:
-					case GL_RG16F:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGB:
-					case GL_RGB16F:
-						LoadImageData<HalfFloatRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGBA:
-					case GL_RGBA16F:
-						LoadImageData<Bytes_8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_SHORT:
-					switch(format)
-					{
-					case GL_R16I:
-					case GL_RED:
-					case GL_RED_INTEGER:
-					case GL_ALPHA:
-					case GL_LUMINANCE:
-						LoadImageData<Bytes_2>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RG16I:
-					case GL_RG:
-					case GL_RG_INTEGER:
-					case GL_LUMINANCE_ALPHA:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGB16I:
-					case GL_RGB:
-					case GL_RGB_INTEGER:
-						LoadImageData<ShortRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGBA16I:
-					case GL_RGBA:
-					case GL_RGBA_INTEGER:
-					case GL_BGRA_EXT:
-					case GL_BGRA8_EXT:
-						LoadImageData<Bytes_8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_SHORT:
-					switch(format)
-					{
-					case GL_R16UI:
-					case GL_RED:
-					case GL_RED_INTEGER:
-					case GL_ALPHA:
-					case GL_LUMINANCE:
-						LoadImageData<Bytes_2>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RG16UI:
-					case GL_RG:
-					case GL_RG_INTEGER:
-					case GL_LUMINANCE_ALPHA:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGB16UI:
-					case GL_RGB:
-					case GL_RGB_INTEGER:
-						LoadImageData<UShortRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGBA16UI:
-					case GL_RGBA:
-					case GL_RGBA_INTEGER:
-					case GL_BGRA_EXT:
-					case GL_BGRA8_EXT:
-						LoadImageData<Bytes_8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_DEPTH_COMPONENT:
-					case GL_DEPTH_COMPONENT16:
-						LoadImageData<D16>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_INT:
-					switch(format)
-					{
-					case GL_R32I:
-					case GL_RED:
-					case GL_RED_INTEGER:
-					case GL_ALPHA:
-					case GL_LUMINANCE:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RG32I:
-					case GL_RG:
-					case GL_RG_INTEGER:
-					case GL_LUMINANCE_ALPHA:
-						LoadImageData<Bytes_8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGB32I:
-					case GL_RGB:
-					case GL_RGB_INTEGER:
-						LoadImageData<IntRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGBA32I:
-					case GL_RGBA:
-					case GL_RGBA_INTEGER:
-					case GL_BGRA_EXT:
-					case GL_BGRA8_EXT:
-						LoadImageData<Bytes_16>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_INT:
-					switch(format)
-					{
-					case GL_R32UI:
-					case GL_RED:
-					case GL_RED_INTEGER:
-					case GL_ALPHA:
-					case GL_LUMINANCE:
-						LoadImageData<Bytes_4>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RG32UI:
-					case GL_RG:
-					case GL_RG_INTEGER:
-					case GL_LUMINANCE_ALPHA:
-						LoadImageData<Bytes_8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGB32UI:
-					case GL_RGB:
-					case GL_RGB_INTEGER:
-						LoadImageData<UIntRGB>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_RGBA32UI:
-					case GL_RGBA:
-					case GL_RGBA_INTEGER:
-					case GL_BGRA_EXT:
-					case GL_BGRA8_EXT:
-						LoadImageData<Bytes_16>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					case GL_DEPTH_COMPONENT16:
-					case GL_DEPTH_COMPONENT24:
-					case GL_DEPTH_COMPONENT32_OES:
-					case GL_DEPTH_COMPONENT:
-						LoadImageData<D32>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
-						break;
-					default: UNREACHABLE(format);
-					}
-					break;
-				case GL_UNSIGNED_INT_24_8_OES:
-					loadD24S8ImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, input, buffer);
-					break;
-				case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-					loadD32FS8ImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, input, buffer);
-					break;
-				default: UNREACHABLE(type);
+				case GL_RGBA8:
+				case GL_SRGB8_ALPHA8:
+					return Transfer<Bytes>(buffer, input, rect);
+				case GL_RGB5_A1:
+				case GL_RGBA4:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_A8B8G8R8);
+					return Transfer<Bytes>(buffer, input, rect);
+				default:
+					UNREACHABLE(internalformat);
 				}
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA8_SNORM && getExternalFormat() == sw::FORMAT_A8B8G8R8_SNORM);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT_4_4_4_4:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA4 && getExternalFormat() == sw::FORMAT_A8B8G8R8);
+				return Transfer<RGBA4toRGBA8>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT_5_5_5_1:
+				ASSERT_OR_RETURN(internalformat == GL_RGB5_A1 && getExternalFormat() == sw::FORMAT_A8B8G8R8);
+				return Transfer<RGBA5_A1toRGBA8>(buffer, input, rect);
+			case GL_UNSIGNED_INT_2_10_10_10_REV:
+				switch(internalformat)
+				{
+				case GL_RGB10_A2:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_A2B10G10R10);
+					return Transfer<Bytes>(buffer, input, rect);
+				case GL_RGB5_A1:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_A8B8G8R8);
+					return Transfer<RGBA1010102toRGBA8>(buffer, input, rect);
+				default:
+					UNREACHABLE(internalformat);
+				}
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA16F && getExternalFormat() == sw::FORMAT_A16B16G16R16F);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_RGBA32F: return Transfer<Bytes>(buffer, input, rect);
+				case GL_RGBA16F: return Transfer<RGBA32FtoRGBA16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			default:
+				UNREACHABLE(type);
 			}
-
-			unlock();
-		}
-		else
-		{
-			sw::Surface *source = sw::Surface::create(width, height, depth, ConvertFormatType(format, type), const_cast<void*>(input), inputPitch, inputPitch * inputHeight);
-			sw::Rect sourceRect(0, 0, width, height);
-			sw::Rect destRect(xoffset, yoffset, xoffset + width, yoffset + height);
-			context->blit(source, sourceRect, this, destRect);
-			delete source;
+		case GL_RGBA_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA8UI && getExternalFormat() == sw::FORMAT_A8B8G8R8UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA8I && getExternalFormat() == sw::FORMAT_A8B8G8R8I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA16UI && getExternalFormat() == sw::FORMAT_A16B16G16R16UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA16I && getExternalFormat() == sw::FORMAT_A16B16G16R16I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA32UI && getExternalFormat() == sw::FORMAT_A32B32G32R32UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RGBA32I && getExternalFormat() == sw::FORMAT_A32B32G32R32I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT_2_10_10_10_REV:
+				ASSERT_OR_RETURN(internalformat == GL_RGB10_A2UI && getExternalFormat() == sw::FORMAT_A2B10G10R10UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_BGRA_EXT:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_BGRA8_EXT && getExternalFormat() == sw::FORMAT_A8R8G8B8);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:   // Only valid for glReadPixels calls.
+			case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:   // Only valid for glReadPixels calls.
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RGB:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				switch(internalformat)
+				{
+				case GL_RGB8:   return Transfer<RGB8toRGBX8>(buffer, input, rect);
+				case GL_SRGB8:  return Transfer<RGB8toRGBX8>(buffer, input, rect);
+				case GL_RGB565: return Transfer<RGB8toRGB565>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGB8_SNORM && getExternalFormat() == sw::FORMAT_X8B8G8R8_SNORM);
+				return Transfer<RGB8toRGBX8>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT_5_6_5:
+				ASSERT_OR_RETURN(internalformat == GL_RGB565 && getExternalFormat() == sw::FORMAT_R5G6B5);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT_10F_11F_11F_REV:
+				ASSERT_OR_RETURN(internalformat == GL_R11F_G11F_B10F && getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED);
+				return Transfer<R11G11B10FtoRGBX16F>(buffer, input, rect);
+			case GL_UNSIGNED_INT_5_9_9_9_REV:
+				ASSERT_OR_RETURN(internalformat == GL_RGB9_E5 && getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED);
+				return Transfer<RGB9_E5FtoRGBX16F>(buffer, input, rect);
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				switch(internalformat)
+				{
+				case GL_RGB16F:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F);
+					return Transfer<RGB16FtoRGBX16F>(buffer, input, rect);
+				case GL_R11F_G11F_B10F:
+				case GL_RGB9_E5:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED);
+					return Transfer<RGB16FtoRGBX16F>(buffer, input, rect);
+				default:
+					UNREACHABLE(internalformat);
+				}
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_RGB32F:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X32B32G32R32F);
+					return Transfer<RGB32FtoRGBX32F>(buffer, input, rect);
+				case GL_RGB16F:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F);
+					return Transfer<RGB32FtoRGB16F>(buffer, input, rect);
+				case GL_R11F_G11F_B10F:
+				case GL_RGB9_E5:
+					ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED);
+					return Transfer<RGB32FtoRGB16F_UNSIGNED>(buffer, input, rect);
+				default:
+					UNREACHABLE(internalformat);
+				}
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RGB_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGB8UI && getExternalFormat() == sw::FORMAT_X8B8G8R8UI);
+				return Transfer<RGB8toRGBX8>(buffer, input, rect);
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RGB8I && getExternalFormat() == sw::FORMAT_X8B8G8R8I);
+				return Transfer<RGB8toRGBX8>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RGB16UI && getExternalFormat() == sw::FORMAT_X16B16G16R16UI);
+				return Transfer<RGB16toRGBX16>(buffer, input, rect);
+			case GL_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RGB16I && getExternalFormat() == sw::FORMAT_X16B16G16R16I);
+				return Transfer<RGB16toRGBX16>(buffer, input, rect);
+			case GL_UNSIGNED_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RGB32UI && getExternalFormat() == sw::FORMAT_X32B32G32R32UI);
+				return Transfer<RGB32toRGBX32>(buffer, input, rect);
+			case GL_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RGB32I && getExternalFormat() == sw::FORMAT_X32B32G32R32I);
+				return Transfer<RGB32toRGBX32>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RG:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+			case GL_BYTE:
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_RG32F: return Transfer<Bytes>(buffer, input, rect);
+				case GL_RG16F: return Transfer<RG32FtoRG16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RG_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RG8UI && getExternalFormat() == sw::FORMAT_G8R8UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_RG8I && getExternalFormat() == sw::FORMAT_G8R8I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RG16UI && getExternalFormat() == sw::FORMAT_G16R16UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_RG16I && getExternalFormat() == sw::FORMAT_G16R16I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RG32UI && getExternalFormat() == sw::FORMAT_G32R32UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_INT:
+				ASSERT_OR_RETURN(internalformat == GL_RG32I && getExternalFormat() == sw::FORMAT_G32R32I);
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RED:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+			case GL_BYTE:
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_R32F: return Transfer<Bytes>(buffer, input, rect);
+				case GL_R16F: return Transfer<R32FtoR16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_RED_INTEGER:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_R8UI && getExternalFormat() == sw::FORMAT_R8UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_BYTE:
+				ASSERT_OR_RETURN(internalformat == GL_R8I && getExternalFormat() == sw::FORMAT_R8I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_R16UI && getExternalFormat() == sw::FORMAT_R16UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_SHORT:
+				ASSERT_OR_RETURN(internalformat == GL_R16I && getExternalFormat() == sw::FORMAT_R16I);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_UNSIGNED_INT:
+				ASSERT_OR_RETURN(internalformat == GL_R32UI && getExternalFormat() == sw::FORMAT_R32UI);
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_INT:
+				ASSERT_OR_RETURN(internalformat == GL_R32I && getExternalFormat() == sw::FORMAT_R32I);
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_DEPTH_COMPONENT:
+			switch(type)
+			{
+			case GL_UNSIGNED_SHORT: return Transfer<D16toD32F>(buffer, input, rect);
+			case GL_UNSIGNED_INT:   return Transfer<D32toD32F>(buffer, input, rect);
+			case GL_FLOAT:          return Transfer<D32FtoD32F_CLAMPED>(buffer, input, rect);
+			case GL_DEPTH_COMPONENT24:       // Only valid for glRenderbufferStorage calls.
+			case GL_DEPTH_COMPONENT32_OES:   // Only valid for glRenderbufferStorage calls.
+			default: UNREACHABLE(type);
+			}
+		case GL_DEPTH_STENCIL:
+			switch(type)
+			{
+			case GL_UNSIGNED_INT_24_8:              return Transfer<D24X8toD32F>(buffer, input, rect);
+			case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return Transfer<D32FX32toD32F>(buffer, input, rect);
+			default: UNREACHABLE(type);
+			}
+		case GL_LUMINANCE_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_LUMINANCE_ALPHA32F_EXT: return Transfer<Bytes>(buffer, input, rect);
+				case GL_LUMINANCE_ALPHA16F_EXT: return Transfer<RG32FtoRG16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				ASSERT_OR_RETURN(internalformat == GL_LUMINANCE_ALPHA16F_EXT);
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		case GL_LUMINANCE:
+		case GL_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:
+				return Transfer<Bytes>(buffer, input, rect);
+			case GL_FLOAT:
+				switch(internalformat)
+				{
+				case GL_LUMINANCE32F_EXT: return Transfer<Bytes>(buffer, input, rect);
+				case GL_LUMINANCE16F_EXT: return Transfer<R32FtoR16F>(buffer, input, rect);
+				case GL_ALPHA32F_EXT:     return Transfer<Bytes>(buffer, input, rect);
+				case GL_ALPHA16F_EXT:     return Transfer<R32FtoR16F>(buffer, input, rect);
+				default: UNREACHABLE(internalformat);
+				}
+			case GL_HALF_FLOAT:
+			case GL_HALF_FLOAT_OES:
+				ASSERT_OR_RETURN(internalformat == GL_LUMINANCE16F_EXT || internalformat == GL_ALPHA16F_EXT);
+				return Transfer<Bytes>(buffer, input, rect);
+			default:
+				UNREACHABLE(type);
+			}
+		default:
+			UNREACHABLE(format);
 		}
 	}
 
-	void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer)
+	void Image::loadStencilData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer)
 	{
-		LoadImageData<D24>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
+		Rectangle rect;
+		rect.bytes = gl::ComputePixelSize(format, type);
+		rect.width = width;
+		rect.height = height;
+		rect.depth = depth;
+		rect.inputPitch = inputPitch;
+		rect.inputHeight = inputHeight;
+		rect.destPitch = getStencilPitchB();
+		rect.destSlice = getStencilSliceB();
 
-		unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(0, 0, 0, sw::PUBLIC));
-
-		if(stencil)
+		switch(type)
 		{
-			LoadImageData<S8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getStencilPitchB(), getHeight(), input, stencil);
-
-			unlockStencil();
+		case GL_UNSIGNED_INT_24_8:              return Transfer<X24S8toS8>(buffer, input, rect);
+		case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return Transfer<X56S8toS8>(buffer, input, rect);
+		default: UNREACHABLE(format);
 		}
 	}
 
-	void Image::loadD32FS8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer)
+	void Image::loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 	{
-		LoadImageData<D32F>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer);
+		GLsizei inputWidth = (unpackParameters.rowLength == 0) ? width : unpackParameters.rowLength;
+		GLsizei inputPitch = gl::ComputePitch(inputWidth, format, type, unpackParameters.alignment);
+		GLsizei inputHeight = (unpackParameters.imageHeight == 0) ? height : unpackParameters.imageHeight;
+		char *input = ((char*)pixels) + gl::ComputePackingOffset(format, type, inputWidth, inputHeight, unpackParameters);
 
-		unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(0, 0, 0, sw::PUBLIC));
+		void *buffer = lock(xoffset, yoffset, zoffset, sw::LOCK_WRITEONLY);
 
-		if(stencil)
+		if(buffer)
 		{
-			LoadImageData<S24_8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getStencilPitchB(), getHeight(), input, stencil);
+			loadImageData(width, height, depth, inputPitch, inputHeight, format, type, input, buffer);
+		}
+
+		unlock();
+
+		if(hasStencil())
+		{
+			unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(xoffset, yoffset, zoffset, sw::PUBLIC));
+
+			if(stencil)
+			{
+				loadStencilData(width, height, depth, inputPitch, inputHeight, format, type, input, stencil);
+			}
 
 			unlockStencil();
 		}
@@ -1722,20 +1637,22 @@
 
 	void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
 	{
-		if(zoffset != 0 || depth != 1)
-		{
-			UNIMPLEMENTED();   // FIXME
-		}
+		int inputPitch = gl::ComputeCompressedPitch(width, internalformat);
+		int inputSlice = imageSize / depth;
+		int rows = inputSlice / inputPitch;
 
-		int inputPitch = ComputeCompressedPitch(width, format);
-		int rows = imageSize / inputPitch;
-		void *buffer = lock(xoffset, yoffset, sw::LOCK_WRITEONLY);
+		void *buffer = lock(xoffset, yoffset, zoffset, sw::LOCK_WRITEONLY);
 
 		if(buffer)
 		{
-			for(int i = 0; i < rows; i++)
+			for(int z = 0; z < depth; z++)
 			{
-				memcpy((void*)((GLbyte*)buffer + i * getPitch()), (void*)((GLbyte*)pixels + i * inputPitch), inputPitch);
+				for(int y = 0; y < rows; y++)
+				{
+					GLbyte *dest = (GLbyte*)buffer + y * getPitch() + z * getSlice();
+					GLbyte *source = (GLbyte*)pixels + y * inputPitch + z * inputSlice;
+					memcpy(dest, source, inputPitch);
+				}
 			}
 		}
 
diff --git a/src/OpenGL/common/Image.hpp b/src/OpenGL/common/Image.hpp
index ecd6cd7..c6cc6a0 100644
--- a/src/OpenGL/common/Image.hpp
+++ b/src/OpenGL/common/Image.hpp
@@ -36,36 +36,50 @@
 #define SW_YV12_BT709 0x48315659   // YCrCb 4:2:0 Planar, 16-byte aligned, BT.709 color space, studio swing
 #define SW_YV12_JFIF  0x4A315659   // YCrCb 4:2:0 Planar, 16-byte aligned, BT.601 color space, full swing
 
-namespace egl
+namespace gl
 {
 
-class Context;
+struct PixelStorageModes
+{
+	GLint rowLength = 0;
+	GLint skipRows = 0;
+	GLint skipPixels = 0;
+	GLint alignment = 4;
+	GLint imageHeight = 0;
+	GLint skipImages = 0;
+};
 
-sw::Format ConvertFormatType(GLenum format, GLenum type);
-sw::Format SelectInternalFormat(GLenum format, GLenum type);
+GLint GetSizedInternalFormat(GLint internalFormat, GLenum type);
+sw::Format ConvertReadFormatType(GLenum format, GLenum type);
+sw::Format SelectInternalFormat(GLint format);
+bool IsUnsizedInternalFormat(GLint internalformat);
+GLenum GetBaseInternalFormat(GLint internalformat);
 GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment);
 GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format);
-size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, GLint alignment, GLint skipImages, GLint skipRows, GLint skipPixels);
+size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, const PixelStorageModes &storageModes);
+
+}
+
+namespace egl
+{
 
 class [[clang::lto_visibility_public]] Image : public sw::Surface, public gl::Object
 {
 protected:
 	// 2D texture image
-	Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
-		: sw::Surface(parentTexture->getResource(), width, height, 1, SelectInternalFormat(format, type), true, true),
-		  width(width), height(height), format(format), type(type), internalFormat(SelectInternalFormat(format, type)), depth(1),
-		  parentTexture(parentTexture)
+	Image(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat)
+		: sw::Surface(parentTexture->getResource(), width, height, 1, 0, 1, gl::SelectInternalFormat(internalformat), true, true),
+		  width(width), height(height), depth(1), internalformat(internalformat), parentTexture(parentTexture)
 	{
 		shared = false;
 		Object::addRef();
 		parentTexture->addRef();
 	}
 
-	// 3D texture image
-	Image(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type)
-		: sw::Surface(parentTexture->getResource(), width, height, depth, SelectInternalFormat(format, type), true, true),
-		  width(width), height(height), format(format), type(type), internalFormat(SelectInternalFormat(format, type)), depth(depth),
-		  parentTexture(parentTexture)
+	// 3D/Cube texture image
+	Image(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat)
+		: sw::Surface(parentTexture->getResource(), width, height, depth, border, 1, gl::SelectInternalFormat(internalformat), true, true),
+		  width(width), height(height), depth(depth), internalformat(internalformat), parentTexture(parentTexture)
 	{
 		shared = false;
 		Object::addRef();
@@ -73,20 +87,18 @@
 	}
 
 	// Native EGL image
-	Image(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP)
-		: sw::Surface(nullptr, width, height, 1, SelectInternalFormat(format, type), true, true, pitchP),
-		  width(width), height(height), format(format), type(type), internalFormat(SelectInternalFormat(format, type)), depth(1),
-		  parentTexture(nullptr)
+	Image(GLsizei width, GLsizei height, GLint internalformat, int pitchP)
+		: sw::Surface(nullptr, width, height, 1, 0, 1, gl::SelectInternalFormat(internalformat), true, true, pitchP),
+		  width(width), height(height), depth(1), internalformat(internalformat), parentTexture(nullptr)
 	{
 		shared = true;
 		Object::addRef();
 	}
 
 	// Render target
-	Image(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable)
-		: sw::Surface(nullptr, width, height, multiSampleDepth, internalFormat, lockable, true),
-		  width(width), height(height), format(0 /*GL_NONE*/), type(0 /*GL_NONE*/), internalFormat(internalFormat), depth(multiSampleDepth),
-		  parentTexture(nullptr)
+	Image(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable)
+		: sw::Surface(nullptr, width, height, 1, 0, multiSampleDepth, gl::SelectInternalFormat(internalformat), lockable, true),
+		  width(width), height(height), depth(1), internalformat(internalformat), parentTexture(nullptr)
 	{
 		shared = false;
 		Object::addRef();
@@ -94,16 +106,16 @@
 
 public:
 	// 2D texture image
-	static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type);
+	static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat);
 
-	// 3D texture image
-	static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type);
+	// 3D/Cube texture image
+	static Image *create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat);
 
 	// Native EGL image
-	static Image *create(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP);
+	static Image *create(GLsizei width, GLsizei height, GLint internalformat, int pitchP);
 
 	// Render target
-	static Image *create(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable);
+	static Image *create(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable);
 
 	GLsizei getWidth() const
 	{
@@ -122,19 +134,9 @@
 		return depth;
 	}
 
-	GLenum getFormat() const
+	GLint getFormat() const
 	{
-		return format;
-	}
-
-	GLenum getType() const
-	{
-		return type;
-	}
-
-	sw::Format getInternalFormat() const
-	{
-		return internalFormat;
+		return internalformat;
 	}
 
 	bool isShared() const
@@ -147,9 +149,9 @@
 		shared = true;
 	}
 
-	virtual void *lock(unsigned int left, unsigned int top, sw::Lock lock)
+	virtual void *lock(int x, int y, int z, sw::Lock lock)
 	{
-		return lockExternal(left, top, 0, lock, sw::PUBLIC);
+		return lockExternal(x, y, z, lock, sw::PUBLIC);
 	}
 
 	unsigned int getPitch() const
@@ -157,6 +159,11 @@
 		return getExternalPitchB();
 	}
 
+	unsigned int getSlice() const
+	{
+		return getExternalSliceB();
+	}
+
 	virtual void unlock()
 	{
 		unlockExternal();
@@ -165,19 +172,7 @@
 	void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) override = 0;
 	void unlockInternal() override = 0;
 
-	struct UnpackInfo
-	{
-		UnpackInfo() : alignment(4), rowLength(0), imageHeight(0), skipPixels(0), skipRows(0), skipImages(0) {}
-
-		GLint alignment;
-		GLint rowLength;
-		GLint imageHeight;
-		GLint skipPixels;
-		GLint skipRows;
-		GLint skipImages;
-	};
-
-	void loadImageData(Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const UnpackInfo& unpackInfo, const void *input);
+	void loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
 
 	void release() override = 0;
@@ -194,10 +189,8 @@
 protected:
 	const GLsizei width;
 	const GLsizei height;
-	const GLenum format;
-	const GLenum type;
-	const sw::Format internalFormat;
 	const int depth;
+	const GLint internalformat;
 
 	bool shared;   // Used as an EGLImage
 
@@ -205,8 +198,8 @@
 
 	~Image() override = 0;
 
-	void loadD24S8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer);
-	void loadD32FS8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer);
+	void loadImageData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer);
+	void loadStencilData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer);
 };
 
 #ifdef __ANDROID__
@@ -233,35 +226,12 @@
 	}
 }
 
-inline GLenum GLPixelTypeFromAndroid(int halFormat)
-{
-	switch(halFormat)
-	{
-	case HAL_PIXEL_FORMAT_RGBA_8888: return GL_UNSIGNED_BYTE;
-#if ANDROID_PLATFORM_SDK_VERSION > 16
-	case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return GL_UNSIGNED_BYTE;
-#endif
-	case HAL_PIXEL_FORMAT_RGBX_8888: return GL_UNSIGNED_BYTE;
-	case HAL_PIXEL_FORMAT_BGRA_8888: return GL_UNSIGNED_BYTE;
-	case HAL_PIXEL_FORMAT_RGB_565:   return GL_UNSIGNED_SHORT_5_6_5;
-	case HAL_PIXEL_FORMAT_YV12:      return GL_UNSIGNED_BYTE;
-#ifdef GRALLOC_MODULE_API_VERSION_0_2
-	case HAL_PIXEL_FORMAT_YCbCr_420_888: return GL_UNSIGNED_BYTE;
-#endif
-	case HAL_PIXEL_FORMAT_RGB_888:   // Unsupported.
-	default:
-		ALOGE("Unsupported EGL image format %d", halFormat); ASSERT(false);
-		return GL_NONE;
-	}
-}
-
 class AndroidNativeImage : public egl::Image
 {
 public:
 	explicit AndroidNativeImage(ANativeWindowBuffer *nativeBuffer)
 		: egl::Image(nativeBuffer->width, nativeBuffer->height,
 		             GLPixelFormatFromAndroid(nativeBuffer->format),
-		             GLPixelTypeFromAndroid(nativeBuffer->format),
 		             nativeBuffer->stride),
 		  nativeBuffer(nativeBuffer)
 	{
@@ -320,10 +290,10 @@
 		sw::Surface::unlockInternal();
 	}
 
-	void *lock(unsigned int left, unsigned int top, sw::Lock lock) override
+	void *lock(int x, int y, int z, sw::Lock lock) override
 	{
 		LOGLOCK("image=%p op=%s lock=%d", this, __FUNCTION__, lock);
-		(void)sw::Surface::lockExternal(left, top, 0, lock, sw::PUBLIC);
+		(void)sw::Surface::lockExternal(x, y, z, lock, sw::PUBLIC);
 
 		return lockNativeBuffer(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
 	}
diff --git a/src/OpenGL/common/Surface.hpp b/src/OpenGL/common/Surface.hpp
index 50a9d00..493d676 100644
--- a/src/OpenGL/common/Surface.hpp
+++ b/src/OpenGL/common/Surface.hpp
@@ -40,8 +40,6 @@
 	virtual egl::Image *getRenderTarget() = 0;
 	virtual egl::Image *getDepthStencil() = 0;
 
-	virtual sw::Format getInternalFormat() const = 0;
-
 	virtual EGLint getWidth() const = 0;
 	virtual EGLint getHeight() const = 0;
 
diff --git a/src/OpenGL/common/debug.h b/src/OpenGL/common/debug.h
index bbf7521..aadb535 100644
--- a/src/OpenGL/common/debug.h
+++ b/src/OpenGL/common/debug.h
@@ -56,19 +56,19 @@
 
 // A macro asserting a condition and outputting failures to the debug log
 #undef ASSERT
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
 #define ASSERT(expression) do { \
-	if(!(expression)) \
+	if(!(expression)) { \
 		ERR("\t! Assert failed in %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \
 		assert(expression); \
-	} while(0)
+	} } while(0)
 #else
 #define ASSERT(expression) (void(0))
 #endif
 
 // A macro to indicate unimplemented functionality
 #undef UNIMPLEMENTED
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
 #define UNIMPLEMENTED() do { \
 	FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \
 	assert(false); \
@@ -79,7 +79,7 @@
 
 // A macro for code which is not expected to be reached under valid assumptions
 #undef UNREACHABLE
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
 #define UNREACHABLE(value) do { \
 	ERR("\t! Unreachable case reached: %s(%d). %s: %d\n", __FUNCTION__, __LINE__, #value, value); \
 	assert(false); \
@@ -88,6 +88,14 @@
 	#define UNREACHABLE(value) ERR("\t! Unreachable reached: %s(%d). %s: %d\n", __FUNCTION__, __LINE__, #value, value)
 #endif
 
-#endif   // __ANDROID__
+#endif   // !__ANDROID__
+
+// A macro asserting a condition and outputting failures to the debug log, or return when in release mode.
+#undef ASSERT_OR_RETURN
+#define ASSERT_OR_RETURN(expression) do { \
+	if(!(expression)) { \
+		ASSERT(expression); \
+		return; \
+	} } while(0)
 
 #endif   // COMMON_DEBUG_H_
diff --git a/src/OpenGL/compiler/Android.mk b/src/OpenGL/compiler/Android.mk
index 4eb2349..6924e48 100644
--- a/src/OpenGL/compiler/Android.mk
+++ b/src/OpenGL/compiler/Android.mk
@@ -44,8 +44,8 @@
 endif
 
 COMMON_SRC_FILES := \
-	preprocessor/Diagnostics.cpp \
-	preprocessor/DirectiveHandler.cpp \
+	preprocessor/DiagnosticsBase.cpp \
+	preprocessor/DirectiveHandlerBase.cpp \
 	preprocessor/DirectiveParser.cpp \
 	preprocessor/ExpressionParser.cpp \
 	preprocessor/Input.cpp \
diff --git a/src/OpenGL/compiler/BUILD.gn b/src/OpenGL/compiler/BUILD.gn
index 3759f1c..ea72f32 100644
--- a/src/OpenGL/compiler/BUILD.gn
+++ b/src/OpenGL/compiler/BUILD.gn
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import("../../swiftshader.gni")
+import("//testing/libfuzzer/fuzzer_test.gni")
 
 # Need a separate config to ensure the warnings are added to the end.
 config("swiftshader_opengl_compiler_private_config") {
@@ -37,6 +38,10 @@
   }
 }
 
+config("swiftshader_translator_disable_pool_alloc") {
+    defines = [ "SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC" ]
+}
+
 swiftshader_source_set("swiftshader_opengl_compiler") {
   deps = [
     "preprocessor:swiftshader_opengl_preprocessor",
@@ -67,7 +72,11 @@
     "util.cpp",
   ]
 
-  if (is_linux || is_mac) {
+  if (use_fuzzing_engine) {
+    all_dependent_configs = [ ":swiftshader_translator_disable_pool_alloc" ]
+  }
+
+  if (is_linux || is_mac || is_fuchsia) {
     sources += [ "ossource_posix.cpp" ]
   } else if (is_win) {
     sources += [ "ossource_win.cpp" ]
diff --git a/src/OpenGL/compiler/BaseTypes.h b/src/OpenGL/compiler/BaseTypes.h
index 01f9948..67b465d 100644
--- a/src/OpenGL/compiler/BaseTypes.h
+++ b/src/OpenGL/compiler/BaseTypes.h
@@ -64,6 +64,7 @@
 	EbtSampler3D,
 	EbtSamplerCube,
 	EbtSampler2DArray,
+	EbtSampler2DRect,       // Only valid if ARB_texture_rectangle exists.
 	EbtSamplerExternalOES,  // Only valid if OES_EGL_image_external exists.
 	EbtISampler2D,
 	EbtISampler3D,
@@ -113,6 +114,7 @@
 	case EbtBool:               return "bool";
 	case EbtSampler2D:          return "sampler2D";
 	case EbtSamplerCube:        return "samplerCube";
+	case EbtSampler2DRect:      return "sampler2DRect";
 	case EbtSamplerExternalOES: return "samplerExternalOES";
 	case EbtSampler3D:			return "sampler3D";
 	case EbtStruct:             return "structure";
@@ -164,6 +166,7 @@
 	case EbtSampler2D:
 	case EbtSampler3D:
 	case EbtSamplerCube:
+	case EbtSampler2DRect:
 	case EbtSamplerExternalOES:
 	case EbtSampler2DArray:
 	case EbtSampler2DShadow:
@@ -187,6 +190,7 @@
 	case EbtSampler2DArray:
 	case EbtISampler2DArray:
 	case EbtUSampler2DArray:
+	case EbtSampler2DRect:
 	case EbtSamplerExternalOES:
 	case EbtSampler2DShadow:
 	case EbtSampler2DArrayShadow:
@@ -217,6 +221,7 @@
 		return true;
 	case EbtSampler2D:
 	case EbtSampler3D:
+	case EbtSampler2DRect:
 	case EbtSamplerExternalOES:
 	case EbtSampler2DArray:
 	case EbtISampler2D:
@@ -245,6 +250,7 @@
 		return true;
 	case EbtSampler2D:
 	case EbtSamplerCube:
+	case EbtSampler2DRect:
 	case EbtSamplerExternalOES:
 	case EbtSampler2DArray:
 	case EbtISampler2D:
@@ -276,6 +282,7 @@
 	case EbtSampler2D:
 	case EbtISampler2D:
 	case EbtUSampler2D:
+	case EbtSampler2DRect:
 	case EbtSamplerExternalOES:
 	case EbtSampler3D:
 	case EbtISampler3D:
@@ -312,6 +319,7 @@
 	case EbtSampler2D:
 	case EbtSampler3D:
 	case EbtSamplerCube:
+	case EbtSampler2DRect:
 	case EbtSamplerExternalOES:
 	case EbtSampler2DArray:
 		return false;
diff --git a/src/OpenGL/compiler/Compiler.cpp b/src/OpenGL/compiler/Compiler.cpp
index 7861acf..ae93385 100644
--- a/src/OpenGL/compiler/Compiler.cpp
+++ b/src/OpenGL/compiler/Compiler.cpp
@@ -227,7 +227,11 @@
 	else if(depth > maxCallStackDepth)
 	{
 		infoSink.info.prefix(EPrefixError);
-		infoSink.info << "Function call stack too deep";
+		infoSink.info << "Function call stack too deep (depth was ";
+		infoSink.info << depth;
+		infoSink.info << " while maximum call stack depth is ";
+		infoSink.info << maxCallStackDepth;
+		infoSink.info << ")";
 		return false;
 	}
 
diff --git a/src/OpenGL/compiler/Compiler.h b/src/OpenGL/compiler/Compiler.h
index 8cdc755..89acc04 100644
--- a/src/OpenGL/compiler/Compiler.h
+++ b/src/OpenGL/compiler/Compiler.h
@@ -58,6 +58,7 @@
 	int OES_fragment_precision_high;
 	int OES_EGL_image_external;
 	int EXT_draw_buffers;
+	int ARB_texture_rectangle;
 
 	unsigned int MaxCallStackDepth;
 };
@@ -66,6 +67,29 @@
 #define GL_FRAGMENT_SHADER                0x8B30
 #define GL_VERTEX_SHADER                  0x8B31
 
+// Note: GL_ARB_texture_rectangle is part of gl2extchromium.h in the Chromium repo
+// GL_ARB_texture_rectangle
+#ifndef GL_ARB_texture_rectangle
+#define GL_ARB_texture_rectangle 1
+
+#ifndef GL_SAMPLER_2D_RECT_ARB
+#define GL_SAMPLER_2D_RECT_ARB 0x8B63
+#endif
+
+#ifndef GL_TEXTURE_BINDING_RECTANGLE_ARB
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6
+#endif
+
+#ifndef GL_TEXTURE_RECTANGLE_ARB
+#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
+#endif
+
+#ifndef GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif
+
+#endif  // GL_ARB_texture_rectangle
+
 //
 // The base class for the machine dependent compiler to derive from
 // for managing object code from the compile.
diff --git a/src/OpenGL/compiler/Compiler.vcxproj b/src/OpenGL/compiler/Compiler.vcxproj
index c4f56bf..1360d93 100644
--- a/src/OpenGL/compiler/Compiler.vcxproj
+++ b/src/OpenGL/compiler/Compiler.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,41 +31,42 @@
     <RootNamespace>compiler</RootNamespace>

     <Keyword>Win32Proj</Keyword>

     <ProjectName>Compiler</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

@@ -126,6 +127,8 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;4005;</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

+      <ErrorReporting>Queue</ErrorReporting>

     </ClCompile>

   </ItemDefinitionGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

@@ -143,6 +146,8 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;4005;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

+      <ErrorReporting>Queue</ErrorReporting>

     </ClCompile>

   </ItemDefinitionGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

@@ -159,6 +164,8 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;4005;</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

+      <ErrorReporting>Queue</ErrorReporting>

     </ClCompile>

   </ItemDefinitionGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

@@ -175,6 +182,8 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;4005;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

+      <ErrorReporting>Queue</ErrorReporting>

     </ClCompile>

   </ItemDefinitionGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">

@@ -191,6 +200,8 @@
       <OmitFramePointers>false</OmitFramePointers>

       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;4005;</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

+      <ErrorReporting>Queue</ErrorReporting>

     </ClCompile>

   </ItemDefinitionGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'">

@@ -207,6 +218,8 @@
       <OmitFramePointers>false</OmitFramePointers>

       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;4005;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

+      <ErrorReporting>Queue</ErrorReporting>

     </ClCompile>

   </ItemDefinitionGroup>

   <ItemGroup>

diff --git a/src/OpenGL/compiler/Diagnostics.h b/src/OpenGL/compiler/Diagnostics.h
index 35983ac..43ee573 100644
--- a/src/OpenGL/compiler/Diagnostics.h
+++ b/src/OpenGL/compiler/Diagnostics.h
@@ -15,7 +15,7 @@
 #ifndef COMPILER_DIAGNOSTICS_H_
 #define COMPILER_DIAGNOSTICS_H_
 
-#include "preprocessor/Diagnostics.h"
+#include "preprocessor/DiagnosticsBase.h"
 
 class TInfoSink;
 
diff --git a/src/OpenGL/compiler/DirectiveHandler.cpp b/src/OpenGL/compiler/DirectiveHandler.cpp
index 2391d35..ef61d47 100644
--- a/src/OpenGL/compiler/DirectiveHandler.cpp
+++ b/src/OpenGL/compiler/DirectiveHandler.cpp
@@ -54,7 +54,8 @@
 
 void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
                                      const std::string& name,
-                                     const std::string& value)
+                                     const std::string& value,
+                                     bool stdgl)
 {
 	static const std::string kSTDGL("STDGL");
 	static const std::string kOptimize("optimize");
@@ -63,7 +64,7 @@
 	static const std::string kOff("off");
 
 	bool invalidValue = false;
-	if (name == kSTDGL)
+	if (stdgl || (name == kSTDGL))
 	{
 		// The STDGL pragma is used to reserve pragmas for use by future
 		// revisions of GLSL. Ignore it.
@@ -83,7 +84,7 @@
 	}
 	else
 	{
-		mDiagnostics.report(pp::Diagnostics::UNRECOGNIZED_PRAGMA, loc, name);
+		mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
 		return;
 	}
 
diff --git a/src/OpenGL/compiler/DirectiveHandler.h b/src/OpenGL/compiler/DirectiveHandler.h
index f77d1f9..0538c59 100644
--- a/src/OpenGL/compiler/DirectiveHandler.h
+++ b/src/OpenGL/compiler/DirectiveHandler.h
@@ -17,7 +17,7 @@
 
 #include "ExtensionBehavior.h"
 #include "Pragma.h"
-#include "preprocessor/DirectiveHandler.h"
+#include "preprocessor/DirectiveHandlerBase.h"
 
 class TDiagnostics;
 
@@ -37,7 +37,8 @@
 
 	virtual void handlePragma(const pp::SourceLocation& loc,
 	                          const std::string& name,
-	                          const std::string& value);
+	                          const std::string& value,
+	                          bool stdgl);
 
 	virtual void handleExtension(const pp::SourceLocation& loc,
 	                             const std::string& name,
diff --git a/src/OpenGL/compiler/Initialize.cpp b/src/OpenGL/compiler/Initialize.cpp
index c374531..23bc792 100644
--- a/src/OpenGL/compiler/Initialize.cpp
+++ b/src/OpenGL/compiler/Initialize.cpp
@@ -103,6 +103,7 @@
 	symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genUType, "clamp", genUType, genUType, genUType);
 	symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, float1);
 	symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, genType);
+	symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, genBType);
 	symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpStep, genType, "step", genType, genType);
 	symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpStep, genType, "step", float1, genType);
 	symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSmoothStep, genType, "smoothstep", genType, genType, genType);
@@ -242,6 +243,18 @@
 	symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3);
 	symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture3D", sampler3D, float3);
 
+	if(resources.ARB_texture_rectangle)
+	{
+		TType *sampler2DRect = new TType(EbtSampler2DRect);
+
+		symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRect", sampler2DRect, float2);
+		symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float3);
+		symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float4);
+		symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", sampler2DRect, float2);
+		symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", sampler2DRect, float3);
+		symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", sampler2DRect, float4);
+	}
+
 	if(resources.OES_EGL_image_external)
 	{
 		TType *samplerExternalOES = new TType(EbtSamplerExternalOES);
@@ -427,10 +440,10 @@
 	fields->push_back(diff);
 	TStructure *depthRangeStruct = new TStructure(NewPoolTString("gl_DepthRangeParameters"), fields);
 	TVariable *depthRangeParameters = new TVariable(&depthRangeStruct->name(), depthRangeStruct, true);
-	symbolTable.insert(COMMON_BUILTINS, *depthRangeParameters);
+	symbolTable.insert(COMMON_BUILTINS, depthRangeParameters);
 	TVariable *depthRange = new TVariable(NewPoolTString("gl_DepthRange"), TType(depthRangeStruct));
 	depthRange->setQualifier(EvqUniform);
-	symbolTable.insert(COMMON_BUILTINS, *depthRange);
+	symbolTable.insert(COMMON_BUILTINS, depthRange);
 
 	//
 	// Implementation dependent built-in constants.
@@ -441,8 +454,8 @@
 	symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxCombinedTextureImageUnits", resources.MaxCombinedTextureImageUnits);
 	symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits", resources.MaxTextureImageUnits);
 	symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors", resources.MaxFragmentUniformVectors);
+	symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers);
 	symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors);
-	symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers);
 	symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", resources.MaxVertexOutputVectors);
 	symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors", resources.MaxFragmentInputVectors);
 	symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset", resources.MinProgramTexelOffset);
@@ -460,18 +473,18 @@
 	switch(shaderType)
 	{
 	case GL_FRAGMENT_SHADER:
-		symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord,   4)));
-		symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool,  EbpUndefined, EvqFrontFacing, 1)));
-		symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord,  2)));
-		symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor,   4)));
-		symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData,    4)));
-		symbolTable.insert(ESSL3_BUILTINS, *new TVariable(NewPoolTString("gl_FragDepth"), TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
+		symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord,   4)));
+		symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool,  EbpUndefined, EvqFrontFacing, 1)));
+		symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord,  2)));
+		symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor,   4)));
+		symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData,    4)));
+		symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_FragDepth"), TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
 		break;
 	case GL_VERTEX_SHADER:
-		symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition,    4)));
-		symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize,   1)));
-		symbolTable.insert(ESSL3_BUILTINS, *new TVariable(NewPoolTString("gl_InstanceID"), TType(EbtInt, EbpHigh, EvqInstanceID, 1)));
-		symbolTable.insert(ESSL3_BUILTINS, *new TVariable(NewPoolTString("gl_VertexID"), TType(EbtInt, EbpHigh, EvqVertexID, 1)));
+		symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition,    4)));
+		symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize,   1)));
+		symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_InstanceID"), TType(EbtInt, EbpHigh, EvqInstanceID, 1)));
+		symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_VertexID"), TType(EbtInt, EbpHigh, EvqVertexID, 1)));
 		break;
 	default: assert(false && "Language not supported");
 	}
@@ -484,7 +497,7 @@
 			// Set up gl_FragData.  The array size.
 			TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true);
 			fragData.setArraySize(resources.MaxDrawBuffers);
-			symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragData"), fragData));
+			symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData));
 		}
 		break;
 	default: break;
@@ -502,4 +515,6 @@
 		extBehavior["GL_OES_EGL_image_external"] = EBhUndefined;
 	if(resources.EXT_draw_buffers)
 		extBehavior["GL_EXT_draw_buffers"] = EBhUndefined;
+	if(resources.ARB_texture_rectangle)
+		extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined;
 }
diff --git a/src/OpenGL/compiler/Intermediate.cpp b/src/OpenGL/compiler/Intermediate.cpp
index a6b1b82..fbcb16b 100644
--- a/src/OpenGL/compiler/Intermediate.cpp
+++ b/src/OpenGL/compiler/Intermediate.cpp
@@ -402,7 +402,10 @@
 	node->setLeft(left);
 	node->setRight(right);
 	if (!node->promote(infoSink))
+	{
+		delete node;
 		return 0;
+	}
 
 	//
 	// See if we can fold constants.
@@ -1775,10 +1778,12 @@
 		//
 		TIntermConstantUnion *newNode = 0;
 		ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
+		TType type = getType();
+		TBasicType basicType = type.getBasicType();
 		for (size_t i = 0; i < objectSize; i++) {
 			switch(op) {
 				case EOpNegative:
-					switch (getType().getBasicType()) {
+					switch (basicType) {
 						case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
 						case EbtInt:   tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
 						default:
@@ -1787,7 +1792,7 @@
 					}
 					break;
 				case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
-					switch (getType().getBasicType()) {
+					switch (basicType) {
 						case EbtBool:  tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
 						default:
 							infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1795,7 +1800,7 @@
 					}
 					break;
 				case EOpBitwiseNot:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 						case EbtInt: tempConstArray[i].setIConst(~unionArray[i].getIConst()); break;
 						case EbtUInt: tempConstArray[i].setUConst(~unionArray[i].getUConst()); break;
 						default:
@@ -1804,7 +1809,7 @@
 					}
 					break;
 				case EOpRadians:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(unionArray[i].getFConst() * 1.74532925e-2f); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1812,7 +1817,7 @@
 					}
 					break;
 				case EOpDegrees:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(unionArray[i].getFConst() * 5.72957795e+1f); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1820,7 +1825,7 @@
 					}
 					break;
 				case EOpSin:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(sinf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1828,7 +1833,7 @@
 					}
 					break;
 				case EOpCos:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(cosf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1836,7 +1841,7 @@
 					}
 					break;
 				case EOpTan:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(tanf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1844,7 +1849,7 @@
 					}
 					break;
 				case EOpAsin:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(asinf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1852,7 +1857,7 @@
 					}
 					break;
 				case EOpAcos:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(acosf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1860,7 +1865,7 @@
 					}
 					break;
 				case EOpAtan:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(atanf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1868,7 +1873,7 @@
 					}
 					break;
 				case EOpSinh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(sinhf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1876,7 +1881,7 @@
 					}
 					break;
 				case EOpCosh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(coshf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1884,7 +1889,7 @@
 					}
 					break;
 				case EOpTanh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(tanhf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1892,7 +1897,7 @@
 					}
 					break;
 				case EOpAsinh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(asinhf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1900,7 +1905,7 @@
 					}
 					break;
 				case EOpAcosh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(acoshf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1908,7 +1913,7 @@
 					}
 					break;
 				case EOpAtanh:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(atanhf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1916,7 +1921,7 @@
 					}
 					break;
 				case EOpLog:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(logf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1924,7 +1929,7 @@
 					}
 					break;
 				case EOpLog2:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(sw::log2(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1932,7 +1937,7 @@
 					}
 					break;
 				case EOpExp:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(expf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1940,7 +1945,7 @@
 					}
 					break;
 				case EOpExp2:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(exp2f(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1948,7 +1953,7 @@
 					}
 					break;
 				case EOpSqrt:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(sqrtf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
@@ -1956,18 +1961,63 @@
 					}
 					break;
 				case EOpInverseSqrt:
-					switch(getType().getBasicType()) {
+					switch(basicType) {
 					case EbtFloat: tempConstArray[i].setFConst(1.0f / sqrtf(unionArray[i].getFConst())); break;
 					default:
 						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
 						return 0;
 					}
 					break;
+				case EOpFloatBitsToInt:
+					switch(basicType) {
+					case EbtFloat:
+						tempConstArray[i].setIConst(sw::bitCast<int>(unionArray[i].getFConst()));
+						type.setBasicType(EbtInt);
+						break;
+					default:
+						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+						return 0;
+					}
+					break;
+					break;
+				case EOpFloatBitsToUint:
+					switch(basicType) {
+					case EbtFloat:
+						tempConstArray[i].setUConst(sw::bitCast<unsigned int>(unionArray[i].getFConst()));
+						type.setBasicType(EbtUInt);
+						break;
+					default:
+						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+						return 0;
+					}
+					break;
+				case EOpIntBitsToFloat:
+					switch(basicType) {
+					case EbtInt:
+						tempConstArray[i].setFConst(sw::bitCast<float>(unionArray[i].getIConst()));
+						type.setBasicType(EbtFloat);
+						break;
+					default:
+						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+						return 0;
+					}
+					break;
+				case EOpUintBitsToFloat:
+					switch(basicType) {
+					case EbtUInt:
+						tempConstArray[i].setFConst(sw::bitCast<float>(unionArray[i].getUConst()));
+						type.setBasicType(EbtFloat);
+						break;
+					default:
+						infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+						return 0;
+					}
+					break;
 				default:
 					return 0;
 			}
 		}
-		newNode = new TIntermConstantUnion(tempConstArray, getType());
+		newNode = new TIntermConstantUnion(tempConstArray, type);
 		newNode->setLine(getLine());
 		return newNode;
 	}
diff --git a/src/OpenGL/compiler/OutputASM.cpp b/src/OpenGL/compiler/OutputASM.cpp
index 1c70f6c..b3385c2 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -26,6 +26,185 @@
 
 #include <stdlib.h>
 
+namespace
+{
+	GLenum glVariableType(const TType &type)
+	{
+		switch(type.getBasicType())
+		{
+		case EbtFloat:
+			if(type.isScalar())
+			{
+				return GL_FLOAT;
+			}
+			else if(type.isVector())
+			{
+				switch(type.getNominalSize())
+				{
+				case 2: return GL_FLOAT_VEC2;
+				case 3: return GL_FLOAT_VEC3;
+				case 4: return GL_FLOAT_VEC4;
+				default: UNREACHABLE(type.getNominalSize());
+				}
+			}
+			else if(type.isMatrix())
+			{
+				switch(type.getNominalSize())
+				{
+				case 2:
+					switch(type.getSecondarySize())
+					{
+					case 2: return GL_FLOAT_MAT2;
+					case 3: return GL_FLOAT_MAT2x3;
+					case 4: return GL_FLOAT_MAT2x4;
+					default: UNREACHABLE(type.getSecondarySize());
+					}
+				case 3:
+					switch(type.getSecondarySize())
+					{
+					case 2: return GL_FLOAT_MAT3x2;
+					case 3: return GL_FLOAT_MAT3;
+					case 4: return GL_FLOAT_MAT3x4;
+					default: UNREACHABLE(type.getSecondarySize());
+					}
+				case 4:
+					switch(type.getSecondarySize())
+					{
+					case 2: return GL_FLOAT_MAT4x2;
+					case 3: return GL_FLOAT_MAT4x3;
+					case 4: return GL_FLOAT_MAT4;
+					default: UNREACHABLE(type.getSecondarySize());
+					}
+				default: UNREACHABLE(type.getNominalSize());
+				}
+			}
+			else UNREACHABLE(0);
+			break;
+		case EbtInt:
+			if(type.isScalar())
+			{
+				return GL_INT;
+			}
+			else if(type.isVector())
+			{
+				switch(type.getNominalSize())
+				{
+				case 2: return GL_INT_VEC2;
+				case 3: return GL_INT_VEC3;
+				case 4: return GL_INT_VEC4;
+				default: UNREACHABLE(type.getNominalSize());
+				}
+			}
+			else UNREACHABLE(0);
+			break;
+		case EbtUInt:
+			if(type.isScalar())
+			{
+				return GL_UNSIGNED_INT;
+			}
+			else if(type.isVector())
+			{
+				switch(type.getNominalSize())
+				{
+				case 2: return GL_UNSIGNED_INT_VEC2;
+				case 3: return GL_UNSIGNED_INT_VEC3;
+				case 4: return GL_UNSIGNED_INT_VEC4;
+				default: UNREACHABLE(type.getNominalSize());
+				}
+			}
+			else UNREACHABLE(0);
+			break;
+		case EbtBool:
+			if(type.isScalar())
+			{
+				return GL_BOOL;
+			}
+			else if(type.isVector())
+			{
+				switch(type.getNominalSize())
+				{
+				case 2: return GL_BOOL_VEC2;
+				case 3: return GL_BOOL_VEC3;
+				case 4: return GL_BOOL_VEC4;
+				default: UNREACHABLE(type.getNominalSize());
+				}
+			}
+			else UNREACHABLE(0);
+			break;
+		case EbtSampler2D:
+			return GL_SAMPLER_2D;
+		case EbtISampler2D:
+			return GL_INT_SAMPLER_2D;
+		case EbtUSampler2D:
+			return GL_UNSIGNED_INT_SAMPLER_2D;
+		case EbtSamplerCube:
+			return GL_SAMPLER_CUBE;
+		case EbtSampler2DRect:
+			return GL_SAMPLER_2D_RECT_ARB;
+		case EbtISamplerCube:
+			return GL_INT_SAMPLER_CUBE;
+		case EbtUSamplerCube:
+			return GL_UNSIGNED_INT_SAMPLER_CUBE;
+		case EbtSamplerExternalOES:
+			return GL_SAMPLER_EXTERNAL_OES;
+		case EbtSampler3D:
+			return GL_SAMPLER_3D_OES;
+		case EbtISampler3D:
+			return GL_INT_SAMPLER_3D;
+		case EbtUSampler3D:
+			return GL_UNSIGNED_INT_SAMPLER_3D;
+		case EbtSampler2DArray:
+			return GL_SAMPLER_2D_ARRAY;
+		case EbtISampler2DArray:
+			return GL_INT_SAMPLER_2D_ARRAY;
+		case EbtUSampler2DArray:
+			return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
+		case EbtSampler2DShadow:
+			return GL_SAMPLER_2D_SHADOW;
+		case EbtSamplerCubeShadow:
+			return GL_SAMPLER_CUBE_SHADOW;
+		case EbtSampler2DArrayShadow:
+			return GL_SAMPLER_2D_ARRAY_SHADOW;
+		default:
+			UNREACHABLE(type.getBasicType());
+			break;
+		}
+
+		return GL_NONE;
+	}
+
+	GLenum glVariablePrecision(const TType &type)
+	{
+		if(type.getBasicType() == EbtFloat)
+		{
+			switch(type.getPrecision())
+			{
+			case EbpHigh:   return GL_HIGH_FLOAT;
+			case EbpMedium: return GL_MEDIUM_FLOAT;
+			case EbpLow:    return GL_LOW_FLOAT;
+			case EbpUndefined:
+				// Should be defined as the default precision by the parser
+			default: UNREACHABLE(type.getPrecision());
+			}
+		}
+		else if(type.getBasicType() == EbtInt)
+		{
+			switch(type.getPrecision())
+			{
+			case EbpHigh:   return GL_HIGH_INT;
+			case EbpMedium: return GL_MEDIUM_INT;
+			case EbpLow:    return GL_LOW_INT;
+			case EbpUndefined:
+				// Should be defined as the default precision by the parser
+			default: UNREACHABLE(type.getPrecision());
+			}
+		}
+
+		// Other types (boolean, sampler) don't have a precision
+		return GL_NONE;
+	}
+}
+
 namespace glsl
 {
 	// Integer to TString conversion
@@ -81,8 +260,21 @@
 		ConstantUnion constants[4];
 	};
 
-	Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo) :
-		type(type), precision(precision), name(name), arraySize(arraySize), registerIndex(registerIndex), blockId(blockId), blockInfo(blockMemberInfo)
+	ShaderVariable::ShaderVariable(const TType& type, const std::string& name, int registerIndex) :
+		type(type.isStruct() ? GL_NONE : glVariableType(type)), precision(glVariablePrecision(type)),
+		name(name), arraySize(type.getArraySize()), registerIndex(registerIndex)
+	{
+		if(type.isStruct())
+		{
+			for(const auto& field : type.getStruct()->fields())
+			{
+				fields.push_back(ShaderVariable(*(field->type()), field->name().c_str(), -1));
+			}
+		}
+	}
+
+	Uniform::Uniform(const TType& type, const std::string &name, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo) :
+		ShaderVariable(type, name, registerIndex), blockId(blockId), blockInfo(blockMemberInfo)
 	{
 	}
 
@@ -93,8 +285,8 @@
 	{
 	}
 
-	BlockLayoutEncoder::BlockLayoutEncoder(bool rowMajor)
-		: mCurrentOffset(0), isRowMajor(rowMajor)
+	BlockLayoutEncoder::BlockLayoutEncoder()
+		: mCurrentOffset(0)
 	{
 	}
 
@@ -103,6 +295,7 @@
 		int arrayStride;
 		int matrixStride;
 
+		bool isRowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
 		getBlockLayoutInfo(type, type.getArraySize(), isRowMajor, &arrayStride, &matrixStride);
 
 		const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * BytesPerComponent),
@@ -132,7 +325,7 @@
 		mCurrentOffset = sw::align(mCurrentOffset, ComponentsPerRegister);
 	}
 
-	Std140BlockEncoder::Std140BlockEncoder(bool rowMajor) : BlockLayoutEncoder(rowMajor)
+	Std140BlockEncoder::Std140BlockEncoder() : BlockLayoutEncoder()
 	{
 	}
 
@@ -216,23 +409,23 @@
 
 	sw::PixelShader *Shader::getPixelShader() const
 	{
-		return 0;
+		return nullptr;
 	}
 
 	sw::VertexShader *Shader::getVertexShader() const
 	{
-		return 0;
+		return nullptr;
 	}
 
 	OutputASM::TextureFunction::TextureFunction(const TString& nodeName) : method(IMPLICIT), proj(false), offset(false)
 	{
 		TString name = TFunction::unmangleName(nodeName);
 
-		if(name == "texture2D" || name == "textureCube" || name == "texture" || name == "texture3D")
+		if(name == "texture2D" || name == "textureCube" || name == "texture" || name == "texture3D" || name == "texture2DRect")
 		{
 			method = IMPLICIT;
 		}
-		else if(name == "texture2DProj" || name == "textureProj")
+		else if(name == "texture2DProj" || name == "textureProj" || name == "texture2DRectProj")
 		{
 			method = IMPLICIT;
 			proj = true;
@@ -306,9 +499,9 @@
 
 	OutputASM::OutputASM(TParseContext &context, Shader *shaderObject) : TIntermTraverser(true, true, true), shaderObject(shaderObject), mContext(context)
 	{
-		shader = 0;
-		pixelShader = 0;
-		vertexShader = 0;
+		shader = nullptr;
+		pixelShader = nullptr;
+		vertexShader = nullptr;
 
 		if(shaderObject)
 		{
@@ -317,9 +510,9 @@
 			vertexShader = shaderObject->getVertexShader();
 		}
 
-		functionArray.push_back(Function(0, "main(", 0, 0));
+		functionArray.push_back(Function(0, "main(", nullptr, nullptr));
 		currentFunction = 0;
-		outputQualifier = EvqOutput; // Set outputQualifier to any value other than EvqFragColor or EvqFragData
+		outputQualifier = EvqOutput;   // Initialize outputQualifier to any value other than EvqFragColor or EvqFragData
 	}
 
 	OutputASM::~OutputASM()
@@ -465,14 +658,26 @@
 
 	void OutputASM::visitSymbol(TIntermSymbol *symbol)
 	{
-		// Vertex varyings don't have to be actively used to successfully link
-		// against pixel shaders that use them. So make sure they're declared.
-		if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut || symbol->getQualifier() == EvqVertexOut)
+		// The type of vertex outputs and fragment inputs with the same name must match (validated at link time),
+		// so declare them but don't assign a register index yet (one will be assigned when referenced in reachable code).
+		switch(symbol->getQualifier())
 		{
+		case EvqVaryingIn:
+		case EvqVaryingOut:
+		case EvqInvariantVaryingIn:
+		case EvqInvariantVaryingOut:
+		case EvqVertexOut:
+		case EvqFragmentIn:
 			if(symbol->getBasicType() != EbtInvariant)   // Typeless declarations are not new varyings
 			{
 				declareVarying(symbol, -1);
 			}
+			break;
+		case EvqFragmentOut:
+			declareFragmentOutput(symbol);
+			break;
+		default:
+			break;
 		}
 
 		TInterfaceBlock* block = symbol->getType().getInterfaceBlock();
@@ -507,32 +712,41 @@
 		switch(node->getOp())
 		{
 		case EOpAssign:
-			if(visit == PostVisit)
-			{
-				assignLvalue(left, right);
-				copy(result, right);
-			}
-			break;
+			assert(visit == PreVisit);
+			right->traverse(this);
+			assignLvalue(left, right);
+			copy(result, right);
+			return false;
 		case EOpInitialize:
-			if(visit == PostVisit)
+			assert(visit == PreVisit);
+			// Constant arrays go into the constant register file.
+			if(leftType.getQualifier() == EvqConstExpr && leftType.isArray() && leftType.getArraySize() > 1)
 			{
+				for(int i = 0; i < left->totalRegisterCount(); i++)
+				{
+					emit(sw::Shader::OPCODE_DEF, left, i, right, i);
+				}
+			}
+			else
+			{
+				right->traverse(this);
 				copy(left, right);
 			}
-			break;
+			return false;
 		case EOpMatrixTimesScalarAssign:
-			if(visit == PostVisit)
+			assert(visit == PreVisit);
+			right->traverse(this);
+			for(int i = 0; i < leftType.getNominalSize(); i++)
 			{
-				for(int i = 0; i < leftType.getNominalSize(); i++)
-				{
-					emit(sw::Shader::OPCODE_MUL, result, i, left, i, right);
-				}
-
-				assignLvalue(left, result);
+				emit(sw::Shader::OPCODE_MUL, result, i, left, i, right);
 			}
-			break;
+
+			assignLvalue(left, result);
+			return false;
 		case EOpVectorTimesMatrixAssign:
-			if(visit == PostVisit)
+			assert(visit == PreVisit);
 			{
+				right->traverse(this);
 				int size = leftType.getNominalSize();
 
 				for(int i = 0; i < size; i++)
@@ -543,10 +757,11 @@
 
 				assignLvalue(left, result);
 			}
-			break;
+			return false;
 		case EOpMatrixTimesMatrixAssign:
-			if(visit == PostVisit)
+			assert(visit == PreVisit);
 			{
+				right->traverse(this);
 				int dim = leftType.getNominalSize();
 
 				for(int i = 0; i < dim; i++)
@@ -563,94 +778,14 @@
 
 				assignLvalue(left, result);
 			}
-			break;
+			return false;
 		case EOpIndexDirect:
-			if(visit == PostVisit)
-			{
-				int index = right->getAsConstantUnion()->getIConst(0);
-
-				if(result->isMatrix() || result->isStruct() || result->isInterfaceBlock())
-				{
-					ASSERT(left->isArray());
-					copy(result, left, index * left->elementRegisterCount());
-				}
-				else if(result->isRegister())
-				{
-					int srcIndex = 0;
-					if(left->isRegister())
-					{
-						srcIndex = 0;
-					}
-					else if(left->isArray())
-					{
-						srcIndex = index * left->elementRegisterCount();
-					}
-					else if(left->isMatrix())
-					{
-						ASSERT(index < left->getNominalSize());   // FIXME: Report semantic error
-						srcIndex = index;
-					}
-					else UNREACHABLE(0);
-
-					Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, 0, left, srcIndex);
-
-					if(left->isRegister())
-					{
-						mov->src[0].swizzle = index;
-					}
-				}
-				else UNREACHABLE(0);
-			}
-			break;
 		case EOpIndexIndirect:
-			if(visit == PostVisit)
-			{
-				if(left->isArray() || left->isMatrix())
-				{
-					for(int index = 0; index < result->totalRegisterCount(); index++)
-					{
-						Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, index, left, index);
-						mov->dst.mask = writeMask(result, index);
-
-						if(left->totalRegisterCount() > 1)
-						{
-							sw::Shader::SourceParameter relativeRegister;
-							argument(relativeRegister, right);
-
-							mov->src[0].rel.type = relativeRegister.type;
-							mov->src[0].rel.index = relativeRegister.index;
-							mov->src[0].rel.scale =	result->totalRegisterCount();
-							mov->src[0].rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
-						}
-					}
-				}
-				else if(left->isRegister())
-				{
-					emit(sw::Shader::OPCODE_EXTRACT, result, left, right);
-				}
-				else UNREACHABLE(0);
-			}
-			break;
 		case EOpIndexDirectStruct:
 		case EOpIndexDirectInterfaceBlock:
-			if(visit == PostVisit)
-			{
-				ASSERT(leftType.isStruct() || (leftType.isInterfaceBlock()));
-
-				const TFieldList& fields = (node->getOp() == EOpIndexDirectStruct) ?
-				                           leftType.getStruct()->fields() :
-				                           leftType.getInterfaceBlock()->fields();
-				int index = right->getAsConstantUnion()->getIConst(0);
-				int fieldOffset = 0;
-
-				for(int i = 0; i < index; i++)
-				{
-					fieldOffset += fields[i]->type()->totalRegisterCount();
-				}
-
-				copy(result, left, fieldOffset);
-			}
-			break;
+			assert(visit == PreVisit);
+			evaluateRvalue(node);
+			return false;
 		case EOpVectorSwizzle:
 			if(visit == PostVisit)
 			{
@@ -1233,6 +1368,7 @@
 				else
 				{
 					const TextureFunction textureFunction(node->getName());
+					TIntermTyped *s = arg[0]->getAsTyped();
 					TIntermTyped *t = arg[1]->getAsTyped();
 
 					Temporary coord(this);
@@ -1245,73 +1381,88 @@
 
 						Instruction *mul = emit(sw::Shader::OPCODE_MUL, &coord, arg[1], &coord);
 						mul->dst.mask = 0x7;
+
+						if(IsShadowSampler(s->getBasicType()))
+						{
+							ASSERT(s->getBasicType() == EbtSampler2DShadow);
+							Instruction *mov = emit(sw::Shader::OPCODE_MOV, &coord, &coord);
+							mov->src[0].swizzle = 0xA4;
+						}
 					}
 					else
 					{
-						emit(sw::Shader::OPCODE_MOV, &coord, arg[1]);
+						Instruction *mov = emit(sw::Shader::OPCODE_MOV, &coord, arg[1]);
+
+						if(IsShadowSampler(s->getBasicType()) && t->getNominalSize() == 3)
+						{
+							ASSERT(s->getBasicType() == EbtSampler2DShadow);
+							mov->src[0].swizzle = 0xA4;
+						}
 					}
 
 					switch(textureFunction.method)
 					{
 					case TextureFunction::IMPLICIT:
+						if(!textureFunction.offset)
 						{
-							TIntermNode* offset = textureFunction.offset ? arg[2] : 0;
-
-							if(argumentCount == 2 || (textureFunction.offset && argumentCount == 3))
+							if(argumentCount == 2)
 							{
-								emit(textureFunction.offset ? sw::Shader::OPCODE_TEXOFFSET : sw::Shader::OPCODE_TEX,
-								     result, &coord, arg[0], offset);
+								emit(sw::Shader::OPCODE_TEX, result, &coord, s);
 							}
-							else if(argumentCount == 3 || (textureFunction.offset && argumentCount == 4))   // bias
+							else if(argumentCount == 3)   // Bias
 							{
-								Instruction *bias = emit(sw::Shader::OPCODE_MOV, &coord, arg[textureFunction.offset ? 3 : 2]);
-								bias->dst.mask = 0x8;
-
-								Instruction *tex = emit(textureFunction.offset ? sw::Shader::OPCODE_TEXOFFSET : sw::Shader::OPCODE_TEX,
-								                        result, &coord, arg[0], offset); // FIXME: Implement an efficient TEXLDB instruction
-								tex->bias = true;
+								emit(sw::Shader::OPCODE_TEXBIAS, result, &coord, s, arg[2]);
+							}
+							else UNREACHABLE(argumentCount);
+						}
+						else   // Offset
+						{
+							if(argumentCount == 3)
+							{
+								emit(sw::Shader::OPCODE_TEXOFFSET, result, &coord, s, arg[2]);
+							}
+							else if(argumentCount == 4)   // Bias
+							{
+								emit(sw::Shader::OPCODE_TEXOFFSETBIAS, result, &coord, s, arg[2], arg[3]);
 							}
 							else UNREACHABLE(argumentCount);
 						}
 						break;
 					case TextureFunction::LOD:
+						if(!textureFunction.offset && argumentCount == 3)
 						{
-							Instruction *lod = emit(sw::Shader::OPCODE_MOV, &coord, arg[2]);
-							lod->dst.mask = 0x8;
-
-							emit(textureFunction.offset ? sw::Shader::OPCODE_TEXLDLOFFSET : sw::Shader::OPCODE_TEXLDL,
-							     result, &coord, arg[0], textureFunction.offset ? arg[3] : nullptr);
+							emit(sw::Shader::OPCODE_TEXLOD, result, &coord, s, arg[2]);
 						}
+						else if(argumentCount == 4)   // Offset
+						{
+							emit(sw::Shader::OPCODE_TEXLODOFFSET, result, &coord, s, arg[3], arg[2]);
+						}
+						else UNREACHABLE(argumentCount);
 						break;
 					case TextureFunction::FETCH:
+						if(!textureFunction.offset && argumentCount == 3)
 						{
-							if(argumentCount == 3 || (textureFunction.offset && argumentCount == 4))
-							{
-								Instruction *lod = emit(sw::Shader::OPCODE_MOV, &coord, arg[2]);
-								lod->dst.mask = 0x8;
-
-								TIntermNode *offset = textureFunction.offset ? arg[3] : nullptr;
-
-								emit(textureFunction.offset ? sw::Shader::OPCODE_TEXELFETCHOFFSET : sw::Shader::OPCODE_TEXELFETCH,
-								     result, &coord, arg[0], offset);
-							}
-							else UNREACHABLE(argumentCount);
+							emit(sw::Shader::OPCODE_TEXELFETCH, result, &coord, s, arg[2]);
 						}
+						else if(argumentCount == 4)   // Offset
+						{
+							emit(sw::Shader::OPCODE_TEXELFETCHOFFSET, result, &coord, s, arg[3], arg[2]);
+						}
+						else UNREACHABLE(argumentCount);
 						break;
 					case TextureFunction::GRAD:
+						if(!textureFunction.offset && argumentCount == 4)
 						{
-							if(argumentCount == 4 || (textureFunction.offset && argumentCount == 5))
-							{
-								TIntermNode *offset = textureFunction.offset ? arg[4] : nullptr;
-
-								emit(textureFunction.offset ? sw::Shader::OPCODE_TEXGRADOFFSET : sw::Shader::OPCODE_TEXGRAD,
-								     result, &coord, arg[0], arg[2], arg[3], offset);
-							}
-							else UNREACHABLE(argumentCount);
+							emit(sw::Shader::OPCODE_TEXGRAD, result, &coord, s, arg[2], arg[3]);
 						}
+						else if(argumentCount == 5)   // Offset
+						{
+							emit(sw::Shader::OPCODE_TEXGRADOFFSET, result, &coord, s, arg[2], arg[3], arg[4]);
+						}
+						else UNREACHABLE(argumentCount);
 						break;
 					case TextureFunction::SIZE:
-						emit(sw::Shader::OPCODE_TEXSIZE, result, arg[1], arg[0]);
+						emit(sw::Shader::OPCODE_TEXSIZE, result, arg[1], s);
 						break;
 					default:
 						UNREACHABLE(textureFunction.method);
@@ -1357,6 +1508,23 @@
 
 						component += size;
 					}
+					else if(!result->isMatrix()) // Construct a non matrix from a matrix
+					{
+						Instruction *mov = emitCast(result, arrayIndex, argi, 0);
+						mov->dst.mask = (0xF << swizzle) & 0xF;
+						mov->src[0].swizzle = readSwizzle(argi, size) << (swizzle * 2);
+
+						// At most one more instruction when constructing a vec3 from a mat2 or a vec4 from a mat2/mat3
+						if(result->getNominalSize() > size)
+						{
+							Instruction *mov = emitCast(result, arrayIndex, argi, 1);
+							mov->dst.mask = (0xF << (swizzle + size)) & 0xF;
+							// mat2: xxxy (0x40), mat3: xxxx (0x00)
+							mov->src[0].swizzle = ((size == 2) ? 0x40 : 0x00) << (swizzle * 2);
+						}
+
+						component += size;
+					}
 					else   // Matrix
 					{
 						int column = 0;
@@ -1498,7 +1666,19 @@
 				emit(getOpcode(sw::Shader::OPCODE_MIN, result), result, result, arg[2]);
 			}
 			break;
-		case EOpMix:         if(visit == PostVisit) emit(sw::Shader::OPCODE_LRP, result, arg[2], arg[1], arg[0]); break;
+		case EOpMix:
+			if(visit == PostVisit)
+			{
+				if(arg[2]->getAsTyped()->getBasicType() == EbtBool)
+				{
+					emit(sw::Shader::OPCODE_SELECT, result, arg[2], arg[1], arg[0]);
+				}
+				else
+				{
+					emit(sw::Shader::OPCODE_LRP, result, arg[2], arg[1], arg[0]);
+				}
+			}
+			break;
 		case EOpStep:        if(visit == PostVisit) emit(sw::Shader::OPCODE_STEP, result, arg[0], arg[1]); break;
 		case EOpSmoothStep:  if(visit == PostVisit) emit(sw::Shader::OPCODE_SMOOTH, result, arg[0], arg[1], arg[2]); break;
 		case EOpDistance:    if(visit == PostVisit) emit(sw::Shader::OPCODE_DIST(dim(arg[0])), result, arg[0], arg[1]); break;
@@ -1820,10 +2000,16 @@
 					emit(sw::Shader::OPCODE_IF, 0, &result);
 					nbCases++;
 
+					// Emit the code for this case and all subsequent cases until we hit a break statement.
+					// TODO: This can repeat a lot of code for switches with many fall-through cases.
 					for(++caseIt; caseIt != sequence.end(); ++caseIt)
 					{
 						(*caseIt)->traverse(this);
-						if((*caseIt)->getAsBranchNode()) // Kill, Break, Continue or Return
+
+						// Stop if we encounter an unconditional branch (break, continue, return, or kill).
+						// TODO: This doesn't work if the statement is at a deeper scope level (e.g. {break;}).
+						// Note that this eliminates useless operations but shouldn't affect correctness.
+						if((*caseIt)->getAsBranchNode())
 						{
 							break;
 						}
@@ -1872,17 +2058,20 @@
 
 		if(dst)
 		{
-			instruction->dst.type = registerType(dst);
-			instruction->dst.index = registerIndex(dst) + dstIndex;
-			instruction->dst.mask = writeMask(dst);
-			instruction->dst.integer = (dst->getBasicType() == EbtInt);
+			destination(instruction->dst, dst, dstIndex);
 		}
 
-		argument(instruction->src[0], src0, index0);
-		argument(instruction->src[1], src1, index1);
-		argument(instruction->src[2], src2, index2);
-		argument(instruction->src[3], src3, index3);
-		argument(instruction->src[4], src4, index4);
+		if(src0)
+		{
+			TIntermTyped* src = src0->getAsTyped();
+			instruction->dst.partialPrecision = src && (src->getPrecision() <= EbpLow);
+		}
+
+		source(instruction->src[0], src0, index0);
+		source(instruction->src[1], src1, index1);
+		source(instruction->src[2], src2, index2);
+		source(instruction->src[3], src3, index3);
+		source(instruction->src[4], src4, index4);
 
 		shader->append(instruction);
 
@@ -1997,9 +2186,9 @@
 			const TFieldList& fields = type.getStruct() ? type.getStruct()->fields() : type.getInterfaceBlock()->fields();
 			int elements = 0;
 
-			for(TFieldList::const_iterator field = fields.begin(); field != fields.end(); field++)
+			for(const auto &field : fields)
 			{
-				const TType &fieldType = *((*field)->type());
+				const TType &fieldType = *(field->type());
 
 				if(fieldType.totalRegisterCount() <= registers)
 				{
@@ -2049,9 +2238,9 @@
 			const TFieldList& fields = type.getStruct() ? type.getStruct()->fields() : type.getInterfaceBlock()->fields();
 			int elements = 0;
 
-			for(TFieldList::const_iterator field = fields.begin(); field != fields.end(); field++)
+			for(const auto &field : fields)
 			{
-				const TType &fieldType = *((*field)->type());
+				const TType &fieldType = *(field->type());
 
 				if(fieldType.totalRegisterCount() <= registers)
 				{
@@ -2156,7 +2345,7 @@
 		return argumentInfo;
 	}
 
-	void OutputASM::argument(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index)
+	void OutputASM::source(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index)
 	{
 		if(argument)
 		{
@@ -2187,7 +2376,7 @@
 					arg = &unpackedUniform;
 					index = 0;
 				}
-				else if((srcBlock->matrixPacking() == EmpRowMajor) && memberType.isMatrix())
+				else if((memberType.getLayoutQualifier().matrixPacking == EmpRowMajor) && memberType.isMatrix())
 				{
 					int numCols = memberType.getNominalSize();
 					int numRows = memberType.getSecondarySize();
@@ -2266,12 +2455,18 @@
 		}
 	}
 
+	void OutputASM::destination(sw::Shader::DestinationParameter &parameter, TIntermTyped *arg, int index)
+	{
+		parameter.type = registerType(arg);
+		parameter.index = registerIndex(arg) + index;
+		parameter.mask = writeMask(arg, index);
+	}
+
 	void OutputASM::copy(TIntermTyped *dst, TIntermNode *src, int offset)
 	{
 		for(int index = 0; index < dst->totalRegisterCount(); index++)
 		{
 			Instruction *mov = emit(sw::Shader::OPCODE_MOV, dst, index, src, offset + index);
-			mov->dst.mask = writeMask(dst, index);
 		}
 	}
 
@@ -2290,9 +2485,8 @@
 
 	void OutputASM::assignLvalue(TIntermTyped *dst, TIntermTyped *src)
 	{
-		if(src &&
-			((src->isVector() && (!dst->isVector() || (src->getNominalSize() != dst->getNominalSize()))) ||
-			 (src->isMatrix() && (!dst->isMatrix() || (src->getNominalSize() != dst->getNominalSize()) || (src->getSecondarySize() != dst->getSecondarySize())))))
+		if((src->isVector() && (!dst->isVector() || (src->getNominalSize() != dst->getNominalSize()))) ||
+		   (src->isMatrix() && (!dst->isMatrix() || (src->getNominalSize() != dst->getNominalSize()) || (src->getSecondarySize() != dst->getSecondarySize()))))
 		{
 			return mContext.error(src->getLine(), "Result type should match the l-value type in compound assignment", src->isVector() ? "vector" : "matrix");
 		}
@@ -2303,41 +2497,106 @@
 		{
 			Instruction *insert = new Instruction(sw::Shader::OPCODE_INSERT);
 
-			Temporary address(this);
-			lvalue(insert->dst, address, dst);
+			lvalue(insert->dst, dst);
 
 			insert->src[0].type = insert->dst.type;
 			insert->src[0].index = insert->dst.index;
 			insert->src[0].rel = insert->dst.rel;
-			argument(insert->src[1], src);
-			argument(insert->src[2], binary->getRight());
+			source(insert->src[1], src);
+			source(insert->src[2], binary->getRight());
 
 			shader->append(insert);
 		}
 		else
 		{
-			for(int offset = 0; offset < dst->totalRegisterCount(); offset++)
+			Instruction *mov1 = new Instruction(sw::Shader::OPCODE_MOV);
+
+			int swizzle = lvalue(mov1->dst, dst);
+
+			source(mov1->src[0], src);
+			mov1->src[0].swizzle = swizzleSwizzle(mov1->src[0].swizzle, swizzle);
+
+			shader->append(mov1);
+
+			for(int offset = 1; offset < dst->totalRegisterCount(); offset++)
 			{
 				Instruction *mov = new Instruction(sw::Shader::OPCODE_MOV);
 
-				Temporary address(this);
-				int swizzle = lvalue(mov->dst, address, dst);
+				mov->dst = mov1->dst;
 				mov->dst.index += offset;
+				mov->dst.mask = writeMask(dst, offset);
 
-				if(offset > 0)
-				{
-					mov->dst.mask = writeMask(dst, offset);
-				}
-
-				argument(mov->src[0], src, offset);
-				mov->src[0].swizzle = swizzleSwizzle(mov->src[0].swizzle, swizzle);
+				source(mov->src[0], src, offset);
 
 				shader->append(mov);
 			}
 		}
 	}
 
-	int OutputASM::lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node)
+	void OutputASM::evaluateRvalue(TIntermTyped *node)
+	{
+		TIntermBinary *binary = node->getAsBinaryNode();
+
+		if(binary && binary->getOp() == EOpIndexIndirect && binary->getLeft()->isVector() && node->isScalar())
+		{
+			Instruction *insert = new Instruction(sw::Shader::OPCODE_EXTRACT);
+
+			destination(insert->dst, node);
+
+			Temporary address(this);
+			unsigned char mask;
+			TIntermTyped *root = nullptr;
+			unsigned int offset = 0;
+			int swizzle = lvalue(root, offset, insert->src[0].rel, mask, address, node);
+
+			source(insert->src[0], root, offset);
+			insert->src[0].swizzle = swizzleSwizzle(insert->src[0].swizzle, swizzle);
+
+			source(insert->src[1], binary->getRight());
+
+			shader->append(insert);
+		}
+		else
+		{
+			Instruction *mov1 = new Instruction(sw::Shader::OPCODE_MOV);
+
+			destination(mov1->dst, node, 0);
+
+			Temporary address(this);
+			unsigned char mask;
+			TIntermTyped *root = nullptr;
+			unsigned int offset = 0;
+			int swizzle = lvalue(root, offset, mov1->src[0].rel, mask, address, node);
+
+			source(mov1->src[0], root, offset);
+			mov1->src[0].swizzle = swizzleSwizzle(mov1->src[0].swizzle, swizzle);
+
+			shader->append(mov1);
+
+			for(int i = 1; i < node->totalRegisterCount(); i++)
+			{
+				Instruction *mov = emit(sw::Shader::OPCODE_MOV, node, i, root, offset + i);
+				mov->src[0].rel = mov1->src[0].rel;
+			}
+		}
+	}
+
+	int OutputASM::lvalue(sw::Shader::DestinationParameter &dst, TIntermTyped *node)
+	{
+		Temporary address(this);
+		TIntermTyped *root = nullptr;
+		unsigned int offset = 0;
+		unsigned char mask = 0xF;
+		int swizzle = lvalue(root, offset, dst.rel, mask, address, node);
+
+		dst.type = registerType(root);
+		dst.index = registerIndex(root) + offset;
+		dst.mask = mask;
+
+		return swizzle;
+	}
+
+	int OutputASM::lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node)
 	{
 		TIntermTyped *result = node;
 		TIntermBinary *binary = node->getAsBinaryNode();
@@ -2348,7 +2607,7 @@
 			TIntermTyped *left = binary->getLeft();
 			TIntermTyped *right = binary->getRight();
 
-			int leftSwizzle = lvalue(dst, address, left);   // Resolve the l-value of the left side
+			int leftSwizzle = lvalue(root, offset, rel, mask, address, left);   // Resolve the l-value of the left side
 
 			switch(binary->getOp())
 			{
@@ -2358,22 +2617,22 @@
 
 					if(left->isRegister())
 					{
-						int leftMask = dst.mask;
+						int leftMask = mask;
 
-						dst.mask = 1;
-						while((leftMask & dst.mask) == 0)
+						mask = 1;
+						while((leftMask & mask) == 0)
 						{
-							dst.mask = dst.mask << 1;
+							mask = mask << 1;
 						}
 
 						int element = swizzleElement(leftSwizzle, rightIndex);
-						dst.mask = 1 << element;
+						mask = 1 << element;
 
 						return element;
 					}
 					else if(left->isArray() || left->isMatrix())
 					{
-						dst.index += rightIndex * result->totalRegisterCount();
+						offset += rightIndex * result->totalRegisterCount();
 						return 0xE4;
 					}
 					else UNREACHABLE(0);
@@ -2381,6 +2640,8 @@
 				break;
 			case EOpIndexIndirect:
 				{
+					right->traverse(this);
+
 					if(left->isRegister())
 					{
 						// Requires INSERT instruction (handled by calling function)
@@ -2389,42 +2650,42 @@
 					{
 						int scale = result->totalRegisterCount();
 
-						if(dst.rel.type == sw::Shader::PARAMETER_VOID)   // Use the index register as the relative address directly
+						if(rel.type == sw::Shader::PARAMETER_VOID)   // Use the index register as the relative address directly
 						{
 							if(left->totalRegisterCount() > 1)
 							{
 								sw::Shader::SourceParameter relativeRegister;
-								argument(relativeRegister, right);
+								source(relativeRegister, right);
 
-								dst.rel.index = relativeRegister.index;
-								dst.rel.type = relativeRegister.type;
-								dst.rel.scale = scale;
-								dst.rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
+								rel.index = relativeRegister.index;
+								rel.type = relativeRegister.type;
+								rel.scale = scale;
+								rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
 							}
 						}
-						else if(dst.rel.index != registerIndex(&address))   // Move the previous index register to the address register
+						else if(rel.index != registerIndex(&address))   // Move the previous index register to the address register
 						{
 							if(scale == 1)
 							{
-								Constant oldScale((int)dst.rel.scale);
+								Constant oldScale((int)rel.scale);
 								Instruction *mad = emit(sw::Shader::OPCODE_IMAD, &address, &address, &oldScale, right);
-								mad->src[0].index = dst.rel.index;
-								mad->src[0].type = dst.rel.type;
+								mad->src[0].index = rel.index;
+								mad->src[0].type = rel.type;
 							}
 							else
 							{
-								Constant oldScale((int)dst.rel.scale);
+								Constant oldScale((int)rel.scale);
 								Instruction *mul = emit(sw::Shader::OPCODE_IMUL, &address, &address, &oldScale);
-								mul->src[0].index = dst.rel.index;
-								mul->src[0].type = dst.rel.type;
+								mul->src[0].index = rel.index;
+								mul->src[0].type = rel.type;
 
 								Constant newScale(scale);
 								emit(sw::Shader::OPCODE_IMAD, &address, right, &newScale, &address);
 							}
 
-							dst.rel.type = sw::Shader::PARAMETER_TEMP;
-							dst.rel.index = registerIndex(&address);
-							dst.rel.scale = 1;
+							rel.type = sw::Shader::PARAMETER_TEMP;
+							rel.index = registerIndex(&address);
+							rel.scale = 1;
 						}
 						else   // Just add the new index to the address register
 						{
@@ -2456,9 +2717,8 @@
 						fieldOffset += fields[i]->type()->totalRegisterCount();
 					}
 
-					dst.type = registerType(left);
-					dst.index += fieldOffset;
-					dst.mask = writeMask(result);
+					offset += fieldOffset;
+					mask = writeMask(result);
 
 					return 0xE4;
 				}
@@ -2467,7 +2727,7 @@
 				{
 					ASSERT(left->isRegister());
 
-					int leftMask = dst.mask;
+					int leftMask = mask;
 
 					int swizzle = 0;
 					int rightMask = 0;
@@ -2483,7 +2743,7 @@
 						swizzle = swizzle | swizzleElement(leftSwizzle, i) << (element * 2);
 					}
 
-					dst.mask = leftMask & rightMask;
+					mask = leftMask & rightMask;
 
 					return swizzle;
 				}
@@ -2495,9 +2755,20 @@
 		}
 		else if(symbol)
 		{
-			dst.type = registerType(symbol);
-			dst.index = registerIndex(symbol);
-			dst.mask = writeMask(symbol);
+			root = symbol;
+			offset = 0;
+			mask = writeMask(symbol);
+
+			return 0xE4;
+		}
+		else
+		{
+			node->traverse(this);
+
+			root = node;
+			offset = 0;
+			mask = writeMask(node);
+
 			return 0xE4;
 		}
 
@@ -2512,10 +2783,10 @@
 		}
 
 		const TQualifier qualifier = operand->getQualifier();
-		if((EvqFragColor == qualifier) || (EvqFragData == qualifier))
+		if((qualifier == EvqFragColor) || (qualifier == EvqFragData))
 		{
-			if(((EvqFragData == qualifier) && (EvqFragColor == outputQualifier)) ||
-			   ((EvqFragColor == qualifier) && (EvqFragData == outputQualifier)))
+			if(((qualifier == EvqFragData) && (outputQualifier == EvqFragColor)) ||
+			   ((qualifier == EvqFragColor) && (outputQualifier == EvqFragData)))
 			{
 				mContext.error(operand->getLine(), "static assignment to both gl_FragData and gl_FragColor", "");
 			}
@@ -2524,7 +2795,15 @@
 
 		if(qualifier == EvqConstExpr && (!operand->getAsConstantUnion() || !operand->getAsConstantUnion()->getUnionArrayPointer()))
 		{
-			return sw::Shader::PARAMETER_TEMP;
+			// Constant arrays are in the constant register file.
+			if(operand->isArray() && operand->getArraySize() > 1)
+			{
+				return sw::Shader::PARAMETER_CONST;
+			}
+			else
+			{
+				return sw::Shader::PARAMETER_TEMP;
+			}
 		}
 
 		switch(qualifier)
@@ -2755,6 +3034,28 @@
 		return allocate(temporaries, temporary);
 	}
 
+	void OutputASM::setPixelShaderInputs(const TType& type, int var, bool flat)
+	{
+		if(type.isStruct())
+		{
+			const TFieldList &fields = type.getStruct()->fields();
+			int fieldVar = var;
+			for(const auto &field : fields)
+			{
+				const TType& fieldType = *(field->type());
+				setPixelShaderInputs(fieldType, fieldVar, flat);
+				fieldVar += fieldType.totalRegisterCount();
+			}
+		}
+		else
+		{
+			for(int i = 0; i < type.totalRegisterCount(); i++)
+			{
+				pixelShader->setInput(var + i, type.registerSize(), sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i, flat));
+			}
+		}
+	}
+
 	int OutputASM::varyingRegister(TIntermTyped *varying)
 	{
 		int var = lookup(varyings, varying);
@@ -2762,7 +3063,6 @@
 		if(var == -1)
 		{
 			var = allocate(varyings, varying);
-			int componentCount = varying->registerSize();
 			int registerCount = varying->totalRegisterCount();
 
 			if(pixelShader)
@@ -2776,16 +3076,11 @@
 				if(varying->getQualifier() == EvqPointCoord)
 				{
 					ASSERT(varying->isRegister());
-					pixelShader->setInput(var, componentCount, sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var));
+					pixelShader->setInput(var, varying->registerSize(), sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var));
 				}
 				else
 				{
-					for(int i = 0; i < varying->totalRegisterCount(); i++)
-					{
-						bool flat = hasFlatQualifier(varying);
-
-						pixelShader->setInput(var + i, componentCount, sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i, flat));
-					}
+					setPixelShaderInputs(varying->getType(), var, hasFlatQualifier(varying));
 				}
 			}
 			else if(vertexShader)
@@ -2823,26 +3118,105 @@
 	{
 		if(varying->getQualifier() != EvqPointCoord)   // gl_PointCoord does not need linking
 		{
-			const TType &type = varying->getType();
-			const char *name = varying->getAsSymbolNode()->getSymbol().c_str();
-			VaryingList &activeVaryings = shaderObject->varyings;
+			TIntermSymbol *symbol = varying->getAsSymbolNode();
+			declareVarying(varying->getType(), symbol->getSymbol(), reg);
+		}
+	}
 
+	void OutputASM::declareVarying(const TType &type, const TString &varyingName, int registerIndex)
+	{
+		const char *name = varyingName.c_str();
+		VaryingList &activeVaryings = shaderObject->varyings;
+
+		TStructure* structure = type.getStruct();
+		if(structure)
+		{
+			int fieldRegisterIndex = registerIndex;
+
+			const TFieldList &fields = type.getStruct()->fields();
+			for(const auto &field : fields)
+			{
+				const TType& fieldType = *(field->type());
+				declareVarying(fieldType, varyingName + "." + field->name(), fieldRegisterIndex);
+				if(fieldRegisterIndex >= 0)
+				{
+					fieldRegisterIndex += fieldType.totalRegisterCount();
+				}
+			}
+		}
+		else
+		{
 			// Check if this varying has been declared before without having a register assigned
 			for(VaryingList::iterator v = activeVaryings.begin(); v != activeVaryings.end(); v++)
 			{
 				if(v->name == name)
 				{
-					if(reg >= 0)
+					if(registerIndex >= 0)
 					{
-						ASSERT(v->reg < 0 || v->reg == reg);
-						v->reg = reg;
+						ASSERT(v->registerIndex < 0 || v->registerIndex == registerIndex);
+						v->registerIndex = registerIndex;
 					}
 
 					return;
 				}
 			}
 
-			activeVaryings.push_back(glsl::Varying(glVariableType(type), name, varying->getArraySize(), reg, 0));
+			activeVaryings.push_back(glsl::Varying(type, name, registerIndex, 0));
+		}
+	}
+
+	void OutputASM::declareFragmentOutput(TIntermTyped *fragmentOutput)
+	{
+		int requestedLocation = fragmentOutput->getType().getLayoutQualifier().location;
+		int registerCount = fragmentOutput->totalRegisterCount();
+		if(requestedLocation < 0)
+		{
+			ASSERT(requestedLocation == -1); // All other negative values would have been prevented in TParseContext::parseLayoutQualifier
+			return; // No requested location
+		}
+		else if((requestedLocation + registerCount) > sw::RENDERTARGETS)
+		{
+			mContext.error(fragmentOutput->getLine(), "Fragment output location larger or equal to MAX_DRAW_BUFFERS", "fragment shader");
+		}
+		else
+		{
+			int currentIndex = lookup(fragmentOutputs, fragmentOutput);
+			if(requestedLocation != currentIndex)
+			{
+				if(currentIndex != -1)
+				{
+					mContext.error(fragmentOutput->getLine(), "Multiple locations for fragment output", "fragment shader");
+				}
+				else
+				{
+					if(fragmentOutputs.size() <= (size_t)requestedLocation)
+					{
+						while(fragmentOutputs.size() < (size_t)requestedLocation)
+						{
+							fragmentOutputs.push_back(nullptr);
+						}
+						for(int i = 0; i < registerCount; i++)
+						{
+							fragmentOutputs.push_back(fragmentOutput);
+						}
+					}
+					else
+					{
+						for(int i = 0; i < registerCount; i++)
+						{
+							if(!fragmentOutputs[requestedLocation + i])
+							{
+								fragmentOutputs[requestedLocation + i] = fragmentOutput;
+							}
+							else
+							{
+								mContext.error(fragmentOutput->getLine(), "Fragment output location aliasing", "fragment shader");
+								return;
+							}
+						}
+					}
+				}
+			}
 		}
 	}
 
@@ -2872,7 +3246,7 @@
 				int blockMemberIndex = blockMemberLookup(type, name, index);
 				if(blockMemberIndex == -1)
 				{
-					declareUniform(type, name, index);
+					declareUniform(type, name, index, false);
 				}
 				else
 				{
@@ -2973,7 +3347,7 @@
 			{
 			case EOpIndexDirect:
 				ASSERT(left->isArray());
-				offset = index * leftType.elementRegisterCount();
+				offset = index * leftType.samplerRegisterCount();
 				break;
 			case EOpIndexDirectStruct:
 				ASSERT(leftType.isStruct());
@@ -2982,7 +3356,7 @@
 
 					for(int i = 0; i < index; i++)
 					{
-						offset += fields[i]->type()->totalRegisterCount();
+						offset += fields[i]->type()->totalSamplerRegisterCount();
 					}
 				}
 				break;
@@ -3017,12 +3391,12 @@
 
 		if(index == -1)
 		{
-			index = allocate(samplers, sampler);
+			index = allocate(samplers, sampler, true);
 
 			if(sampler->getQualifier() == EvqUniform)
 			{
 				const char *name = sampler->getSymbol().c_str();
-				declareUniform(type, name, index);
+				declareUniform(type, name, index, true);
 			}
 		}
 
@@ -3108,13 +3482,13 @@
 		return -1;
 	}
 
-	int OutputASM::allocate(VariableArray &list, TIntermTyped *variable)
+	int OutputASM::allocate(VariableArray &list, TIntermTyped *variable, bool samplersOnly)
 	{
 		int index = lookup(list, variable);
 
 		if(index == -1)
 		{
-			unsigned int registerCount = variable->blockRegisterCount();
+			unsigned int registerCount = variable->blockRegisterCount(samplersOnly);
 
 			for(unsigned int i = 0; i < list.size(); i++)
 			{
@@ -3202,7 +3576,7 @@
 		return -1;
 	}
 
-	void OutputASM::declareUniform(const TType &type, const TString &name, int registerIndex, int blockId, BlockLayoutEncoder* encoder)
+	void OutputASM::declareUniform(const TType &type, const TString &name, int registerIndex, bool samplersOnly, int blockId, BlockLayoutEncoder* encoder)
 	{
 		const TStructure *structure = type.getStruct();
 		const TInterfaceBlock *block = (type.isInterfaceBlock() || (blockId == -1)) ? type.getInterfaceBlock() : nullptr;
@@ -3213,19 +3587,22 @@
 			const BlockMemberInfo blockInfo = encoder ? encoder->encodeType(type) : BlockMemberInfo::getDefaultBlockInfo();
 			if(blockId >= 0)
 			{
-				blockDefinitions[blockId][registerIndex] = TypedMemberInfo(blockInfo, type);
+				blockDefinitions[blockId].insert(BlockDefinitionIndexMap::value_type(registerIndex, TypedMemberInfo(blockInfo, type)));
 				shaderObject->activeUniformBlocks[blockId].fields.push_back(activeUniforms.size());
 			}
 			int fieldRegisterIndex = encoder ? shaderObject->activeUniformBlocks[blockId].registerIndex + BlockLayoutEncoder::getBlockRegister(blockInfo) : registerIndex;
-			activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(),
-			                                 fieldRegisterIndex, blockId, blockInfo));
-			if(IsSampler(type.getBasicType()))
+			bool isSampler = IsSampler(type.getBasicType());
+			if(isSampler && samplersOnly)
 			{
 				for(int i = 0; i < type.totalRegisterCount(); i++)
 				{
 					shader->declareSampler(fieldRegisterIndex + i);
 				}
 			}
+			if(isSampler == samplersOnly)
+			{
+				activeUniforms.push_back(Uniform(type, name.c_str(), fieldRegisterIndex, blockId, blockInfo));
+			}
 		}
 		else if(block)
 		{
@@ -3241,12 +3618,12 @@
 			                                           block->blockStorage(), isRowMajor, registerIndex, blockId));
 			blockDefinitions.push_back(BlockDefinitionIndexMap());
 
-			Std140BlockEncoder currentBlockEncoder(isRowMajor);
+			Std140BlockEncoder currentBlockEncoder;
 			currentBlockEncoder.enterAggregateType();
-			for(size_t i = 0; i < fields.size(); i++)
+			for(const auto &field : fields)
 			{
-				const TType &fieldType = *(fields[i]->type());
-				const TString &fieldName = fields[i]->name();
+				const TType &fieldType = *(field->type());
+				const TString &fieldName = field->name();
 				if(isUniformBlockMember && (fieldName == name))
 				{
 					registerIndex = fieldRegisterIndex;
@@ -3254,7 +3631,7 @@
 
 				const TString uniformName = block->hasInstanceName() ? blockName + "." + fieldName : fieldName;
 
-				declareUniform(fieldType, uniformName, fieldRegisterIndex, blockId, &currentBlockEncoder);
+				declareUniform(fieldType, uniformName, fieldRegisterIndex, samplersOnly, blockId, &currentBlockEncoder);
 				fieldRegisterIndex += fieldType.totalRegisterCount();
 			}
 			currentBlockEncoder.exitAggregateType();
@@ -3262,6 +3639,9 @@
 		}
 		else
 		{
+			// Store struct for program link time validation
+			shaderObject->activeUniformStructs.push_back(Uniform(type, name.c_str(), registerIndex, -1, BlockMemberInfo::getDefaultBlockInfo()));
+
 			int fieldRegisterIndex = registerIndex;
 
 			const TFieldList& fields = structure->fields();
@@ -3273,14 +3653,14 @@
 					{
 						encoder->enterAggregateType();
 					}
-					for(size_t j = 0; j < fields.size(); j++)
+					for(const auto &field : fields)
 					{
-						const TType &fieldType = *(fields[j]->type());
-						const TString &fieldName = fields[j]->name();
+						const TType &fieldType = *(field->type());
+						const TString &fieldName = field->name();
 						const TString uniformName = name + "[" + str(i) + "]." + fieldName;
 
-						declareUniform(fieldType, uniformName, fieldRegisterIndex, blockId, encoder);
-						fieldRegisterIndex += fieldType.totalRegisterCount();
+						declareUniform(fieldType, uniformName, fieldRegisterIndex, samplersOnly, blockId, encoder);
+						fieldRegisterIndex += samplersOnly ? fieldType.totalSamplerRegisterCount() : fieldType.totalRegisterCount();
 					}
 					if(encoder)
 					{
@@ -3294,14 +3674,14 @@
 				{
 					encoder->enterAggregateType();
 				}
-				for(size_t i = 0; i < fields.size(); i++)
+				for(const auto &field : fields)
 				{
-					const TType &fieldType = *(fields[i]->type());
-					const TString &fieldName = fields[i]->name();
+					const TType &fieldType = *(field->type());
+					const TString &fieldName = field->name();
 					const TString uniformName = name + "." + fieldName;
 
-					declareUniform(fieldType, uniformName, fieldRegisterIndex, blockId, encoder);
-					fieldRegisterIndex += fieldType.totalRegisterCount();
+					declareUniform(fieldType, uniformName, fieldRegisterIndex, samplersOnly, blockId, encoder);
+					fieldRegisterIndex += samplersOnly ? fieldType.totalSamplerRegisterCount() : fieldType.totalRegisterCount();
 				}
 				if(encoder)
 				{
@@ -3311,180 +3691,6 @@
 		}
 	}
 
-	GLenum OutputASM::glVariableType(const TType &type)
-	{
-		switch(type.getBasicType())
-		{
-		case EbtFloat:
-			if(type.isScalar())
-			{
-				return GL_FLOAT;
-			}
-			else if(type.isVector())
-			{
-				switch(type.getNominalSize())
-				{
-				case 2: return GL_FLOAT_VEC2;
-				case 3: return GL_FLOAT_VEC3;
-				case 4: return GL_FLOAT_VEC4;
-				default: UNREACHABLE(type.getNominalSize());
-				}
-			}
-			else if(type.isMatrix())
-			{
-				switch(type.getNominalSize())
-				{
-				case 2:
-					switch(type.getSecondarySize())
-					{
-					case 2: return GL_FLOAT_MAT2;
-					case 3: return GL_FLOAT_MAT2x3;
-					case 4: return GL_FLOAT_MAT2x4;
-					default: UNREACHABLE(type.getSecondarySize());
-					}
-				case 3:
-					switch(type.getSecondarySize())
-					{
-					case 2: return GL_FLOAT_MAT3x2;
-					case 3: return GL_FLOAT_MAT3;
-					case 4: return GL_FLOAT_MAT3x4;
-					default: UNREACHABLE(type.getSecondarySize());
-					}
-				case 4:
-					switch(type.getSecondarySize())
-					{
-					case 2: return GL_FLOAT_MAT4x2;
-					case 3: return GL_FLOAT_MAT4x3;
-					case 4: return GL_FLOAT_MAT4;
-					default: UNREACHABLE(type.getSecondarySize());
-					}
-				default: UNREACHABLE(type.getNominalSize());
-				}
-			}
-			else UNREACHABLE(0);
-			break;
-		case EbtInt:
-			if(type.isScalar())
-			{
-				return GL_INT;
-			}
-			else if(type.isVector())
-			{
-				switch(type.getNominalSize())
-				{
-				case 2: return GL_INT_VEC2;
-				case 3: return GL_INT_VEC3;
-				case 4: return GL_INT_VEC4;
-				default: UNREACHABLE(type.getNominalSize());
-				}
-			}
-			else UNREACHABLE(0);
-			break;
-		case EbtUInt:
-			if(type.isScalar())
-			{
-				return GL_UNSIGNED_INT;
-			}
-			else if(type.isVector())
-			{
-				switch(type.getNominalSize())
-				{
-				case 2: return GL_UNSIGNED_INT_VEC2;
-				case 3: return GL_UNSIGNED_INT_VEC3;
-				case 4: return GL_UNSIGNED_INT_VEC4;
-				default: UNREACHABLE(type.getNominalSize());
-				}
-			}
-			else UNREACHABLE(0);
-			break;
-		case EbtBool:
-			if(type.isScalar())
-			{
-				return GL_BOOL;
-			}
-			else if(type.isVector())
-			{
-				switch(type.getNominalSize())
-				{
-				case 2: return GL_BOOL_VEC2;
-				case 3: return GL_BOOL_VEC3;
-				case 4: return GL_BOOL_VEC4;
-				default: UNREACHABLE(type.getNominalSize());
-				}
-			}
-			else UNREACHABLE(0);
-			break;
-		case EbtSampler2D:
-			return GL_SAMPLER_2D;
-		case EbtISampler2D:
-			return GL_INT_SAMPLER_2D;
-		case EbtUSampler2D:
-			return GL_UNSIGNED_INT_SAMPLER_2D;
-		case EbtSamplerCube:
-			return GL_SAMPLER_CUBE;
-		case EbtISamplerCube:
-			return GL_INT_SAMPLER_CUBE;
-		case EbtUSamplerCube:
-			return GL_UNSIGNED_INT_SAMPLER_CUBE;
-		case EbtSamplerExternalOES:
-			return GL_SAMPLER_EXTERNAL_OES;
-		case EbtSampler3D:
-			return GL_SAMPLER_3D_OES;
-		case EbtISampler3D:
-			return GL_INT_SAMPLER_3D;
-		case EbtUSampler3D:
-			return GL_UNSIGNED_INT_SAMPLER_3D;
-		case EbtSampler2DArray:
-			return GL_SAMPLER_2D_ARRAY;
-		case EbtISampler2DArray:
-			return GL_INT_SAMPLER_2D_ARRAY;
-		case EbtUSampler2DArray:
-			return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
-		case EbtSampler2DShadow:
-			return GL_SAMPLER_2D_SHADOW;
-		case EbtSamplerCubeShadow:
-			return GL_SAMPLER_CUBE_SHADOW;
-		case EbtSampler2DArrayShadow:
-			return GL_SAMPLER_2D_ARRAY_SHADOW;
-		default:
-			UNREACHABLE(type.getBasicType());
-			break;
-		}
-
-		return GL_NONE;
-	}
-
-	GLenum OutputASM::glVariablePrecision(const TType &type)
-	{
-		if(type.getBasicType() == EbtFloat)
-		{
-			switch(type.getPrecision())
-			{
-			case EbpHigh:   return GL_HIGH_FLOAT;
-			case EbpMedium: return GL_MEDIUM_FLOAT;
-			case EbpLow:    return GL_LOW_FLOAT;
-			case EbpUndefined:
-				// Should be defined as the default precision by the parser
-			default: UNREACHABLE(type.getPrecision());
-			}
-		}
-		else if(type.getBasicType() == EbtInt)
-		{
-			switch(type.getPrecision())
-			{
-			case EbpHigh:   return GL_HIGH_INT;
-			case EbpMedium: return GL_MEDIUM_INT;
-			case EbpLow:    return GL_LOW_INT;
-			case EbpUndefined:
-				// Should be defined as the default precision by the parser
-			default: UNREACHABLE(type.getPrecision());
-			}
-		}
-
-		// Other types (boolean, sampler) don't have a precision
-		return GL_NONE;
-	}
-
 	int OutputASM::dim(TIntermNode *v)
 	{
 		TIntermTyped *vector = v->getAsTyped();
diff --git a/src/OpenGL/compiler/OutputASM.h b/src/OpenGL/compiler/OutputASM.h
index 34f154a..3391035 100644
--- a/src/OpenGL/compiler/OutputASM.h
+++ b/src/OpenGL/compiler/OutputASM.h
@@ -55,9 +55,9 @@
 		bool isRowMajorMatrix;
 	};
 
-	struct Uniform
+	struct ShaderVariable
 	{
-		Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo);
+		ShaderVariable(const TType& type, const std::string& name, int registerIndex);
 
 		GLenum type;
 		GLenum precision;
@@ -66,6 +66,13 @@
 
 		int registerIndex;
 
+		std::vector<ShaderVariable> fields;
+	};
+
+	struct Uniform : public ShaderVariable
+	{
+		Uniform(const TType& type, const std::string &name, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo);
+
 		int blockId;
 		BlockMemberInfo blockInfo;
 	};
@@ -92,7 +99,7 @@
 	class BlockLayoutEncoder
 	{
 	public:
-		BlockLayoutEncoder(bool rowMajor);
+		BlockLayoutEncoder();
 		virtual ~BlockLayoutEncoder() {}
 
 		BlockMemberInfo encodeType(const TType &type);
@@ -110,7 +117,6 @@
 
 	protected:
 		size_t mCurrentOffset;
-		bool isRowMajor;
 
 		void nextRegister();
 
@@ -123,7 +129,7 @@
 	class Std140BlockEncoder : public BlockLayoutEncoder
 	{
 	public:
-		Std140BlockEncoder(bool rowMajor);
+		Std140BlockEncoder();
 
 		void enterAggregateType() override;
 		void exitAggregateType() override;
@@ -150,10 +156,10 @@
 
 	typedef std::vector<Attribute> ActiveAttributes;
 
-	struct Varying
+	struct Varying : public ShaderVariable
 	{
-		Varying(GLenum type, const std::string &name, int arraySize, int reg = -1, int col = -1)
-			: type(type), name(name), arraySize(arraySize), reg(reg), col(col)
+		Varying(const TType& type, const std::string &name, int reg = -1, int col = -1)
+			: ShaderVariable(type, name, reg), qualifier(type.getQualifier()), column(col)
 		{
 		}
 
@@ -167,12 +173,8 @@
 			return arraySize > 0 ? arraySize : 1;
 		}
 
-		GLenum type;
-		std::string name;
-		int arraySize;
-
-		int reg;    // First varying register, assigned during link
-		int col;    // First register element, assigned during link
+		TQualifier qualifier;
+		int column;    // First register element, assigned during link
 	};
 
 	typedef std::list<Varying> VaryingList;
@@ -185,12 +187,15 @@
 		virtual sw::Shader *getShader() const = 0;
 		virtual sw::PixelShader *getPixelShader() const;
 		virtual sw::VertexShader *getVertexShader() const;
+		int getShaderVersion() const { return shaderVersion; }
 
 	protected:
 		VaryingList varyings;
 		ActiveUniforms activeUniforms;
+		ActiveUniforms activeUniformStructs;
 		ActiveAttributes activeAttributes;
 		ActiveUniformBlocks activeUniformBlocks;
+		int shaderVersion;
 	};
 
 	struct Function
@@ -240,7 +245,7 @@
 				LOD,
 				SIZE,   // textureSize()
 				FETCH,
-				GRAD
+				GRAD,
 			};
 
 			Method method;
@@ -251,14 +256,14 @@
 		void emitShader(Scope scope);
 
 		// Visit AST nodes and output their code to the body stream
-		virtual void visitSymbol(TIntermSymbol*);
-		virtual bool visitBinary(Visit visit, TIntermBinary*);
-		virtual bool visitUnary(Visit visit, TIntermUnary*);
-		virtual bool visitSelection(Visit visit, TIntermSelection*);
-		virtual bool visitAggregate(Visit visit, TIntermAggregate*);
-		virtual bool visitLoop(Visit visit, TIntermLoop*);
-		virtual bool visitBranch(Visit visit, TIntermBranch*);
-		virtual bool visitSwitch(Visit, TIntermSwitch*);
+		void visitSymbol(TIntermSymbol*) 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;
+		bool visitSwitch(Visit, TIntermSwitch*) override;
 
 		sw::Shader::Opcode getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const;
 		Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0, TIntermNode *src3 = 0, TIntermNode *src4 = 0);
@@ -270,10 +275,13 @@
 		void emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1 = 0);
 		void emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index = 0);
 		void emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col = -1, int row = -1, int outCol = 0, int outRow = 0);
-		void argument(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index = 0);
+		void source(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index = 0);
+		void destination(sw::Shader::DestinationParameter &parameter, TIntermTyped *argument, int index = 0);
 		void copy(TIntermTyped *dst, TIntermNode *src, int offset = 0);
 		void assignLvalue(TIntermTyped *dst, TIntermTyped *src);
-		int lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node);
+		void evaluateRvalue(TIntermTyped *node);
+		int lvalue(sw::Shader::DestinationParameter &dst, TIntermTyped *node);
+		int lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node);
 		sw::Shader::ParameterType registerType(TIntermTyped *operand);
 		bool hasFlatQualifier(TIntermTyped *operand);
 		unsigned int registerIndex(TIntermTyped *operand);
@@ -285,7 +293,10 @@
 
 		int temporaryRegister(TIntermTyped *temporary);
 		int varyingRegister(TIntermTyped *varying);
+		void setPixelShaderInputs(const TType& type, int var, bool flat);
 		void declareVarying(TIntermTyped *varying, int reg);
+		void declareVarying(const TType &type, const TString &name, int registerIndex);
+		void declareFragmentOutput(TIntermTyped *fragmentOutput);
 		int uniformRegister(TIntermTyped *uniform);
 		int attributeRegister(TIntermTyped *attribute);
 		int fragmentOutputRegister(TIntermTyped *fragmentOutput);
@@ -298,12 +309,10 @@
 		int lookup(VariableArray &list, TIntermTyped *variable);
 		int lookup(VariableArray &list, TInterfaceBlock *block);
 		int blockMemberLookup(const TType &type, const TString &name, int registerIndex);
-		int allocate(VariableArray &list, TIntermTyped *variable);
+		int allocate(VariableArray &list, TIntermTyped *variable, bool samplersOnly = false);
 		void free(VariableArray &list, TIntermTyped *variable);
 
-		void declareUniform(const TType &type, const TString &name, int registerIndex, int blockId = -1, BlockLayoutEncoder* encoder = nullptr);
-		GLenum glVariableType(const TType &type);
-		GLenum glVariablePrecision(const TType &type);
+		void declareUniform(const TType &type, const TString &name, int registerIndex, bool samplersOnly, int blockId = -1, BlockLayoutEncoder* encoder = nullptr);
 
 		static int dim(TIntermNode *v);
 		static int dim2(TIntermNode *m);
@@ -323,7 +332,6 @@
 
 		struct TypedMemberInfo : public BlockMemberInfo
 		{
-			TypedMemberInfo() {}
 			TypedMemberInfo(const BlockMemberInfo& b, const TType& t) : BlockMemberInfo(b), type(t) {}
 			TType type;
 		};
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp
index 3fea084..c7100ba 100644
--- a/src/OpenGL/compiler/ParseHelper.cpp
+++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -14,6 +14,7 @@
 
 #include "ParseHelper.h"
 
+#include <limits>
 #include <stdarg.h>
 #include <stdio.h>
 
@@ -189,55 +190,6 @@
 	return true;
 }
 
-
-//
-// Look at a '.' field selector string and change it into offsets
-// for a matrix.
-//
-bool TParseContext::parseMatrixFields(const TString& compString, int matCols, int matRows, TMatrixFields& fields, const TSourceLoc &line)
-{
-	fields.wholeRow = false;
-	fields.wholeCol = false;
-	fields.row = -1;
-	fields.col = -1;
-
-	if (compString.size() != 2) {
-		error(line, "illegal length of matrix field selection", compString.c_str());
-		return false;
-	}
-
-	if (compString[0] == '_') {
-		if (compString[1] < '0' || compString[1] > '3') {
-			error(line, "illegal matrix field selection", compString.c_str());
-			return false;
-		}
-		fields.wholeCol = true;
-		fields.col = compString[1] - '0';
-	} else if (compString[1] == '_') {
-		if (compString[0] < '0' || compString[0] > '3') {
-			error(line, "illegal matrix field selection", compString.c_str());
-			return false;
-		}
-		fields.wholeRow = true;
-		fields.row = compString[0] - '0';
-	} else {
-		if (compString[0] < '0' || compString[0] > '3' ||
-			compString[1] < '0' || compString[1] > '3') {
-			error(line, "illegal matrix field selection", compString.c_str());
-			return false;
-		}
-		fields.row = compString[0] - '0';
-		fields.col = compString[1] - '0';
-	}
-
-	if (fields.row >= matRows || fields.col >= matCols) {
-		error(line, "matrix field selection out of range", compString.c_str());
-		return false;
-	}
-
-	return true;
-}
-
 ///////////////////////////////////////////////////////////////////////
 //
 // Errors
@@ -352,7 +304,6 @@
 		case EOpIndexDirect:
 		case EOpIndexIndirect:
 		case EOpIndexDirectStruct:
-		case EOpIndexDirectInterfaceBlock:
 			return lValueErrorCheck(line, op, binaryNode->getLeft());
 		case EOpVectorSwizzle:
 			errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
@@ -375,6 +326,7 @@
 			}
 
 			return errorReturn;
+		case EOpIndexDirectInterfaceBlock:
 		default:
 			break;
 		}
@@ -829,9 +781,8 @@
 		return true;
 
 	if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) {
-		const TFieldList& fields = type.getStruct()->fields();
-		for(unsigned int i = 0; i < fields.size(); ++i) {
-			if (containsSampler(*fields[i]->type()))
+		for(const auto &field : type.getStruct()->fields()) {
+			if (containsSampler(*(field->type())))
 				return true;
 		}
 	}
@@ -1066,7 +1017,7 @@
 		return false;
 
 	(*variable) = new TVariable(&identifier, type);
-	if(!symbolTable.declare(**variable))
+	if(!symbolTable.declare(*variable))
 	{
 		error(line, "redefinition", identifier.c_str());
 		delete (*variable);
@@ -1171,10 +1122,10 @@
 	mDirectiveHandler.handleExtension(loc, extName, behavior);
 }
 
-void TParseContext::handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value)
+void TParseContext::handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value, bool stdgl)
 {
 	pp::SourceLocation loc(line.first_file, line.first_line);
-	mDirectiveHandler.handlePragma(loc, name, value);
+	mDirectiveHandler.handlePragma(loc, name, value, stdgl);
 }
 
 /////////////////////////////////////////////////////////////////////////////////
@@ -1234,7 +1185,7 @@
 	{
 		TType type(EbtFloat, EbpUndefined);
 		TVariable *fakeVariable = new TVariable(name, type);
-		symbolTable.declare(*fakeVariable);
+		symbolTable.declare(fakeVariable);
 		variable = fakeVariable;
 	}
 
@@ -1251,11 +1202,11 @@
 	// First find by unmangled name to check whether the function name has been
 	// hidden by a variable name or struct typename.
 	const TSymbol* symbol = symbolTable.find(call->getName(), mShaderVersion, builtIn);
-	if (symbol == 0) {
+	if (!symbol || symbol->isFunction()) {
 		symbol = symbolTable.find(call->getMangledName(), mShaderVersion, builtIn);
 	}
 
-	if (symbol == 0) {
+	if (!symbol) {
 		error(line, "no matching overloaded function found", call->getName().c_str());
 		return nullptr;
 	}
@@ -1345,15 +1296,21 @@
 		}
 	}
 
-	if (!variable->isConstant()) {
+	// Constants which aren't indexable arrays get propagated by value
+	// and thus don't need to initialize the symbol.
+	if (variable->isConstant() && !(type.isArray() && type.getArraySize() > 1))
+	{
+		*intermNode = nullptr;
+	}
+	else
+	{
 		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;
+	}
 
 	return false;
 }
@@ -1365,13 +1322,6 @@
 	returnType.invariant = invariant;
 	returnType.layoutQualifier = layoutQualifier;
 
-	if(typeSpecifier.array)
-	{
-		error(typeSpecifier.line, "not supported", "first-class array");
-		recover();
-		returnType.clearArrayness();
-	}
-
 	if(mShaderVersion < 300)
 	{
 		if(typeSpecifier.array)
@@ -2014,7 +1964,7 @@
 			//
 			// Insert the parameters with name in the symbol table.
 			//
-			if(!symbolTable.declare(*variable))
+			if(!symbolTable.declare(variable))
 			{
 				error(location, "redefinition", variable->getName().c_str());
 				recover();
@@ -2090,10 +2040,16 @@
 			recover();
 		}
 	}
+	else
+	{
+		// Insert the unmangled name to detect potential future redefinition as a variable.
+		TFunction *unmangledFunction = new TFunction(NewPoolTString(function->getName().c_str()), function->getReturnType());
+		symbolTable.getOuterLevel()->insertUnmangled(unmangledFunction);
+	}
 
 	// We're at the inner scope level of the function's arguments and body statement.
 	// Add the function prototype to the surrounding scope instead.
-	symbolTable.getOuterLevel()->insert(*function);
+	symbolTable.getOuterLevel()->insert(function);
 
 	//
 	// If this is a redeclaration, it could also be a definition, in which case, we want to use the
@@ -2250,7 +2206,9 @@
 		constArray[i] = unionArray[fields.offsets[i]];
 
 	}
-	typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
+
+	TType type(node->getType().getBasicType(), node->getType().getPrecision(), EvqConstExpr, fields.num);
+	typedNode = intermediate.addConstantUnion(constArray, type, line);
 	return typedNode;
 }
 
@@ -2339,11 +2297,11 @@
 	size_t instanceSize = 0;
 	TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
 
-	for(size_t index = 0; index < fields.size(); ++index) {
-		if (fields[index]->name() == identifier) {
+	for(const auto &field : fields) {
+		if (field->name() == identifier) {
 			break;
 		} else {
-			instanceSize += fields[index]->type()->getObjectSize();
+			instanceSize += field->type()->getObjectSize();
 		}
 	}
 
@@ -2393,14 +2351,13 @@
 	}
 
 	TSymbol* blockNameSymbol = new TSymbol(&blockName);
-	if(!symbolTable.declare(*blockNameSymbol)) {
+	if(!symbolTable.declare(blockNameSymbol)) {
 		error(nameLine, "redefinition", blockName.c_str(), "interface block name");
 		recover();
 	}
 
 	// check for sampler types and apply layout qualifiers
-	for(size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) {
-		TField* field = (*fieldList)[memberIndex];
+	for(const auto &field : *fieldList) {
 		TType* fieldType = field->type();
 		if(IsSampler(fieldType->getBasicType())) {
 			error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks");
@@ -2436,13 +2393,15 @@
 		{
 			fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
 		}
-		else if(!fieldType->isMatrix())
+		else if(!fieldType->isMatrix() && (fieldType->getBasicType() != EbtStruct))
 		{
-			error(field->line(), "invalid layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "can only be used on matrix types");
-			recover();
+			warning(field->line(), "extraneous layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "only has an effect on matrix types");
 		}
 
 		fieldType->setLayoutQualifier(fieldLayoutQualifier);
+
+		// Recursively propagate the matrix packing setting down to all block/structure members
+		fieldType->setMatrixPackingIfUnspecified(fieldLayoutQualifier.matrixPacking);
 	}
 
 	// add array index
@@ -2462,9 +2421,8 @@
 	if(!instanceName)
 	{
 		// define symbols for the members of the interface block
-		for(size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
+		for(const auto &field : *fieldList)
 		{
-			TField* field = (*fieldList)[memberIndex];
 			TType* fieldType = field->type();
 
 			// set parent pointer of the field variable
@@ -2473,7 +2431,7 @@
 			TVariable* fieldVariable = new TVariable(&field->name(), *fieldType);
 			fieldVariable->setQualifier(typeQualifier.qualifier);
 
-			if(!symbolTable.declare(*fieldVariable)) {
+			if(!symbolTable.declare(fieldVariable)) {
 				error(field->line(), "redefinition", field->name().c_str(), "interface block member name");
 				recover();
 			}
@@ -2481,11 +2439,14 @@
 	}
 	else
 	{
+		if(reservedErrorCheck(nameLine, *instanceName))
+			recover();
+
 		// add a symbol for this interface block
 		TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
 		instanceTypeDef->setQualifier(typeQualifier.qualifier);
 
-		if(!symbolTable.declare(*instanceTypeDef)) {
+		if(!symbolTable.declare(instanceTypeDef)) {
 			error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name");
 			recover();
 		}
@@ -2524,7 +2485,7 @@
 
 	TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
 
-	if(indexExpression->getQualifier() == EvqConstExpr && indexConstantUnion)
+	if(indexExpression->getQualifier() == EvqConstExpr && indexConstantUnion)   // TODO: Qualifier check redundant?
 	{
 		int index = indexConstantUnion->getIConst(0);
 		if(index < 0)
@@ -2536,7 +2497,7 @@
 			recover();
 			index = 0;
 		}
-		if(baseExpression->getType().getQualifier() == EvqConstExpr)
+		if(baseExpression->getType().getQualifier() == EvqConstExpr && baseExpression->getAsConstantUnion())   // TODO: Qualifier check redundant?
 		{
 			if(baseExpression->isArray())
 			{
@@ -2693,11 +2654,6 @@
 				recover();
 				indexedExpression = baseExpression;
 			}
-			else
-			{
-				indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(),
-					EvqConstExpr, (unsigned char)(fieldString).size()));
-			}
 		}
 		else
 		{
@@ -2708,41 +2664,6 @@
 				baseExpression->getQualifier() == EvqConstExpr ? EvqConstExpr : EvqTemporary, (unsigned char)vectorString.size()));
 		}
 	}
-	else if(baseExpression->isMatrix())
-	{
-		TMatrixFields fields;
-		if(!parseMatrixFields(fieldString, baseExpression->getNominalSize(), baseExpression->getSecondarySize(), fields, fieldLocation))
-		{
-			fields.wholeRow = false;
-			fields.wholeCol = false;
-			fields.row = 0;
-			fields.col = 0;
-			recover();
-		}
-
-		if(fields.wholeRow || fields.wholeCol)
-		{
-			error(dotLocation, " non-scalar fields not implemented yet", ".");
-			recover();
-			ConstantUnion *unionArray = new ConstantUnion[1];
-			unionArray->setIConst(0);
-			TIntermTyped *index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConstExpr),
-				fieldLocation);
-			indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
-			indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(),
-				EvqTemporary, static_cast<unsigned char>(baseExpression->getNominalSize()),
-				static_cast<unsigned char>(baseExpression->getSecondarySize())));
-		}
-		else
-		{
-			ConstantUnion *unionArray = new ConstantUnion[1];
-			unionArray->setIConst(fields.col * baseExpression->getSecondarySize() + fields.row);
-			TIntermTyped *index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConstExpr),
-				fieldLocation);
-			indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
-			indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision()));
-		}
-	}
 	else if(baseExpression->getBasicType() == EbtStruct)
 	{
 		bool fieldFound = false;
@@ -2840,13 +2761,13 @@
 	{
 		if(mShaderVersion < 300)
 		{
-			error(dotLocation, " field selection requires structure, vector, or matrix on left hand side",
+			error(dotLocation, " field selection requires structure or vector on left hand side",
 				fieldString.c_str());
 		}
 		else
 		{
 			error(dotLocation,
-				" field selection requires structure, vector, matrix, or interface block on left hand side",
+				" field selection requires structure, vector, or interface block on left hand side",
 				fieldString.c_str());
 		}
 		recover();
@@ -2902,7 +2823,7 @@
 {
 	TLayoutQualifier qualifier;
 
-	qualifier.location = -1;
+	qualifier.location = -1;  // -1 isn't a valid location, it means the value isn't set. Negative values are checked lower in this function.
 	qualifier.matrixPacking = EmpUnspecified;
 	qualifier.blockStorage = EbsUnspecified;
 
@@ -3001,12 +2922,12 @@
 		recover();
 	}
 
-	for(unsigned int i = 0; i < fieldList->size(); ++i)
+	for(const auto &field : *fieldList)
 	{
 		//
 		// Careful not to replace already known aspects of type, like array-ness
 		//
-		TType *type = (*fieldList)[i]->type();
+		TType *type = field->type();
 		type->setBasicType(typeSpecifier.type);
 		type->setNominalSize(typeSpecifier.primarySize);
 		type->setSecondarySize(typeSpecifier.secondarySize);
@@ -3027,7 +2948,7 @@
 			type->setStruct(typeSpecifier.userDef->getStruct());
 		}
 
-		if(structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i]))
+		if(structNestingErrorCheck(typeSpecifier.line, *field))
 		{
 			recover();
 		}
@@ -3054,7 +2975,7 @@
 			recover();
 		}
 		TVariable *userTypeDef = new TVariable(structName, *structureType, true);
-		if(!symbolTable.declare(*userTypeDef))
+		if(!symbolTable.declare(userTypeDef))
 		{
 			error(nameLine, "redefinition", structName->c_str(), "struct");
 			recover();
@@ -3062,17 +2983,16 @@
 	}
 
 	// ensure we do not specify any storage qualifiers on the struct members
-	for(unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
+	for(const auto &field : *fieldList)
 	{
-		const TField &field = *(*fieldList)[typeListIndex];
-		const TQualifier qualifier = field.type()->getQualifier();
+		const TQualifier qualifier = field->type()->getQualifier();
 		switch(qualifier)
 		{
 		case EvqGlobal:
 		case EvqTemporary:
 			break;
 		default:
-			error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier));
+			error(field->line(), "invalid qualifier on struct member", getQualifierString(qualifier));
 			recover();
 			break;
 		}
@@ -3621,18 +3541,6 @@
 		else
 		{
 			arraySize = typedThis->getArraySize();
-			if(typedThis->getAsSymbolNode() == nullptr)
-			{
-				// This code path can be hit with expressions like these:
-				// (a = b).length()
-				// (func()).length()
-				// (int[3](0, 1, 2)).length()
-				// ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid expression.
-				// It allows "An array name with the length method applied" in contrast to GLSL 4.4 spec section 5.9
-				// which allows "An array, vector or matrix expression with the length method applied".
-				error(loc, "length can only be called on array names, not on array expressions", "length");
-				recover();
-			}
 		}
 		unionArray->setIConst(arraySize);
 		callNode = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConstExpr), loc);
diff --git a/src/OpenGL/compiler/ParseHelper.h b/src/OpenGL/compiler/ParseHelper.h
index ea613eb..07abf0f 100644
--- a/src/OpenGL/compiler/ParseHelper.h
+++ b/src/OpenGL/compiler/ParseHelper.h
@@ -56,7 +56,7 @@
 			mDefaultBlockStorage(EbsShared),
 			mDiagnostics(is),
 			mDirectiveHandler(ext, mDiagnostics, mShaderVersion),
-			mPreprocessor(&mDiagnostics, &mDirectiveHandler),
+			mPreprocessor(&mDiagnostics, &mDirectiveHandler, pp::PreprocessorSettings()),
 			mScanner(nullptr),
 			mUsesFragData(false),
 			mUsesFragColor(false) {  }
@@ -112,7 +112,6 @@
 	const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
 
 	bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc &line);
-	bool parseMatrixFields(const TString&, int matCols, int matRows, TMatrixFields&, const TSourceLoc &line);
 
 	bool reservedErrorCheck(const TSourceLoc &line, const TString& identifier);
 	void assignError(const TSourceLoc &line, const char* op, TString left, TString right);
@@ -149,7 +148,7 @@
 	void handleExtensionDirective(const TSourceLoc &line, const char* extName, const char* behavior);
 
 	const TPragma& pragma() const { return mDirectiveHandler.pragma(); }
-	void handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value);
+	void handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value, bool stdgl);
 
 	bool containsSampler(TType& type);
 	const TFunction* findFunction(const TSourceLoc &line, TFunction* pfnCall, bool *builtIn = 0);
diff --git a/src/OpenGL/compiler/PoolAlloc.cpp b/src/OpenGL/compiler/PoolAlloc.cpp
index f3d19eb..1235023 100644
--- a/src/OpenGL/compiler/PoolAlloc.cpp
+++ b/src/OpenGL/compiler/PoolAlloc.cpp
@@ -57,27 +57,16 @@
 // is documented in PoolAlloc.h.
 //
 TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
-	pageSize(growthIncrement),
-	alignment(allocationAlignment),
+	alignment(allocationAlignment)
+#if !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
+	, pageSize(growthIncrement),
 	freeList(0),
 	inUseList(0),
 	numCalls(0),
 	totalBytes(0)
+#endif
 {
 	//
-	// Don't allow page sizes we know are smaller than all common
-	// OS page sizes.
-	//
-	if (pageSize < 4*1024)
-		pageSize = 4*1024;
-
-	//
-	// A large currentPageOffset indicates a new page needs to
-	// be obtained to allocate memory.
-	//
-	currentPageOffset = pageSize;
-
-	//
 	// Adjust alignment to be at least pointer aligned and
 	// power of 2.
 	//
@@ -91,6 +80,20 @@
 	alignment = a;
 	alignmentMask = a - 1;
 
+#if !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
+	//
+	// Don't allow page sizes we know are smaller than all common
+	// OS page sizes.
+	//
+	if (pageSize < 4*1024)
+		pageSize = 4*1024;
+
+	//
+	// A large currentPageOffset indicates a new page needs to
+	// be obtained to allocate memory.
+	//
+	currentPageOffset = pageSize;
+
 	//
 	// Align header skip
 	//
@@ -98,10 +101,14 @@
 	if (headerSkip < sizeof(tHeader)) {
 		headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
 	}
+#else  // !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
+	mStack.push_back({});
+#endif
 }
 
 TPoolAllocator::~TPoolAllocator()
 {
+#if !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
 	while (inUseList) {
 		tHeader* next = inUseList->nextPage;
 		inUseList->~tHeader();
@@ -118,6 +125,14 @@
 		delete [] reinterpret_cast<char*>(freeList);
 		freeList = next;
 	}
+#else  // !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
+	for (auto& allocs : mStack) {
+		for (auto alloc : allocs) {
+			free(alloc);
+		}
+	}
+	mStack.clear();
+#endif
 }
 
 // Support MSVC++ 6.0
@@ -158,14 +173,18 @@
 
 void TPoolAllocator::push()
 {
+#if !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
 	tAllocState state = { currentPageOffset, inUseList };
 
-	stack.push_back(state);
+	mStack.push_back(state);
 
 	//
 	// Indicate there is no current page to allocate from.
 	//
 	currentPageOffset = pageSize;
+#else  // !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
+	mStack.push_back({});
+#endif
 }
 
 //
@@ -177,11 +196,12 @@
 //
 void TPoolAllocator::pop()
 {
-	if (stack.size() < 1)
+	if (mStack.size() < 1)
 		return;
 
-	tHeader* page = stack.back().page;
-	currentPageOffset = stack.back().offset;
+#if !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
+	tHeader* page = mStack.back().page;
+	currentPageOffset = mStack.back().offset;
 
 	while (inUseList != page) {
 		// invoke destructor to free allocation list
@@ -197,7 +217,13 @@
 		inUseList = nextInUse;
 	}
 
-	stack.pop_back();
+	mStack.pop_back();
+#else  // !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
+	for (auto alloc : mStack.back()) {
+		free(alloc);
+	}
+	mStack.pop_back();
+#endif
 }
 
 //
@@ -206,12 +232,13 @@
 //
 void TPoolAllocator::popAll()
 {
-	while (stack.size() > 0)
+	while (mStack.size() > 0)
 		pop();
 }
 
 void* TPoolAllocator::allocate(size_t numBytes)
 {
+#if !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
 	//
 	// Just keep some interesting statistics.
 	//
@@ -288,6 +315,14 @@
 	currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
 
 	return initializeAllocation(inUseList, ret, numBytes);
+#else  // !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
+	void *alloc = malloc(numBytes + alignmentMask);
+	mStack.back().push_back(alloc);
+
+	intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc);
+	intAlloc = (intAlloc + alignmentMask) & ~alignmentMask;
+	return reinterpret_cast<void *>(intAlloc);
+#endif
 }
 
 
diff --git a/src/OpenGL/compiler/PoolAlloc.h b/src/OpenGL/compiler/PoolAlloc.h
index 1aca1c9..d645a04 100644
--- a/src/OpenGL/compiler/PoolAlloc.h
+++ b/src/OpenGL/compiler/PoolAlloc.h
@@ -160,7 +160,12 @@
 	// by calling pop(), and to not have to solve memory leak problems.
 	//
 
-protected:
+private:
+	size_t alignment; // all returned allocations will be aligned at
+                      // this granularity, which will be a power of 2
+	size_t alignmentMask;
+
+#if !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
 	friend struct tHeader;
 
 	struct tHeader {
@@ -203,20 +208,21 @@
 	}
 
 	size_t pageSize;        // granularity of allocation from the OS
-	size_t alignment;       // all returned allocations will be aligned at
-							// this granularity, which will be a power of 2
-	size_t alignmentMask;
 	size_t headerSkip;      // amount of memory to skip to make room for the
 							//      header (basically, size of header, rounded
 							//      up to make it aligned
 	size_t currentPageOffset;  // next offset in top of inUseList to allocate from
 	tHeader* freeList;      // list of popped memory
 	tHeader* inUseList;     // list of all memory currently being used
-	tAllocStack stack;      // stack of where to allocate from, to partition pool
+	tAllocStack mStack;     // stack of where to allocate from, to partition pool
 
 	int numCalls;           // just an interesting statistic
 	size_t totalBytes;      // just an interesting statistic
-private:
+
+#else  // !defined(SWIFTSHADER_TRANSLATOR_DISABLE_POOL_ALLOC)
+	std::vector<std::vector<void *>> mStack;
+#endif
+
 	TPoolAllocator& operator=(const TPoolAllocator&);  // dont allow assignment operator
 	TPoolAllocator(const TPoolAllocator&);  // dont allow default copy constructor
 };
diff --git a/src/OpenGL/compiler/SymbolTable.cpp b/src/OpenGL/compiler/SymbolTable.cpp
index b2e48e8..3e6cae8 100644
--- a/src/OpenGL/compiler/SymbolTable.cpp
+++ b/src/OpenGL/compiler/SymbolTable.cpp
@@ -27,21 +27,20 @@
 #include <limits.h>
 #include <algorithm>
 
-#if defined(_MSC_VER) && MSC_VER < 1900

-#define snprintf _snprintf

+#if defined(_MSC_VER) && MSC_VER < 1900
+#define snprintf _snprintf
 #endif
 
 int TSymbolTableLevel::uniqueId = 0;
 
 TType::TType(const TPublicType &p) :
-	type(p.type), precision(p.precision), qualifier(p.qualifier), invariant(p.invariant), layoutQualifier(p.layoutQualifier),
+	type(p.type), precision(p.precision), qualifier(p.qualifier),
 	primarySize(p.primarySize), secondarySize(p.secondarySize), array(p.array), arraySize(p.arraySize), maxArraySize(0),
-	arrayInformationType(0), interfaceBlock(0), structure(0), deepestStructNesting(0), mangled(0)
+	arrayInformationType(0), interfaceBlock(0), layoutQualifier(p.layoutQualifier), structure(0), mangled(0)
 {
 	if (p.userDef)
 	{
 		structure = p.userDef->getStruct();
-		computeDeepestStructNesting();
 	}
 }
 
@@ -64,6 +63,7 @@
 	case EbtSampler3D:          mangledName += "s3";     break;
 	case EbtSamplerCube:        mangledName += "sC";     break;
 	case EbtSampler2DArray:		mangledName += "s2a";    break;
+	case EbtSampler2DRect:      mangledName += "s2r";    break;
 	case EbtSamplerExternalOES: mangledName += "sext";   break;
 	case EbtISampler2D:  		mangledName += "is2";    break;
 	case EbtISampler3D: 		mangledName += "is3";    break;
@@ -105,16 +105,11 @@
 	return getStruct()->objectSize();
 }
 
-void TType::computeDeepestStructNesting()
-{
-	deepestStructNesting = structure ? structure->deepestNesting() : 0;
-}
-
 bool TStructure::containsArrays() const
 {
-	for(size_t i = 0; i < mFields->size(); ++i)
+	for(const auto& field : *mFields)
 	{
-		const TType *fieldType = (*mFields)[i]->type();
+		const TType *fieldType = field->type();
 		if(fieldType->isArray() || fieldType->isStructureContainingArrays())
 			return true;
 	}
@@ -123,9 +118,9 @@
 
 bool TStructure::containsType(TBasicType type) const
 {
-	for(size_t i = 0; i < mFields->size(); ++i)
+	for(const auto& field : *mFields)
 	{
-		const TType *fieldType = (*mFields)[i]->type();
+		const TType *fieldType = field->type();
 		if(fieldType->getBasicType() == type || fieldType->isStructureContainingType(type))
 			return true;
 	}
@@ -134,23 +129,31 @@
 
 bool TStructure::containsSamplers() const
 {
-	for(size_t i = 0; i < mFields->size(); ++i)
+	for(const auto& field : *mFields)
 	{
-		const TType *fieldType = (*mFields)[i]->type();
+		const TType *fieldType = field->type();
 		if(IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers())
 			return true;
 	}
 	return false;
 }
 
+void TStructure::setMatrixPackingIfUnspecified(TLayoutMatrixPacking matrixPacking)
+{
+	for(auto& field : *mFields)
+	{
+		field->type()->setMatrixPackingIfUnspecified(matrixPacking);
+	}
+}
+
 TString TFieldListCollection::buildMangledName() const
 {
 	TString mangledName(mangledNamePrefix());
 	mangledName += *mName;
-	for(size_t i = 0; i < mFields->size(); ++i)
+	for(const auto& field : *mFields)
 	{
 		mangledName += '-';
-		mangledName += (*mFields)[i]->type()->getMangledName();
+		mangledName += field->type()->getMangledName();
 	}
 	return mangledName;
 }
@@ -158,9 +161,9 @@
 size_t TFieldListCollection::calculateObjectSize() const
 {
 	size_t size = 0;
-	for(size_t i = 0; i < mFields->size(); ++i)
+	for(const auto& field : *mFields)
 	{
-		size_t fieldSize = (*mFields)[i]->type()->getObjectSize();
+		size_t fieldSize = field->type()->getObjectSize();
 		if(fieldSize > INT_MAX - size)
 			size = INT_MAX;
 		else
@@ -172,8 +175,8 @@
 int TStructure::calculateDeepestNesting() const
 {
 	int maxNesting = 0;
-	for(size_t i = 0; i < mFields->size(); ++i)
-		maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting());
+	for(const auto& field : *mFields)
+		maxNesting = std::max(maxNesting, field->type()->getDeepestStructNesting());
 	return 1 + maxNesting;
 }
 
@@ -195,6 +198,35 @@
 		delete (*it).second;
 }
 
+bool TSymbolTableLevel::insert(TSymbol *symbol)
+{
+	symbol->setUniqueId(nextUniqueId());
+
+	// returning true means symbol was added to the table
+	tInsertResult result = level.insert(tLevelPair(symbol->getMangledName(), symbol));
+
+	return result.second;
+}
+
+bool TSymbolTableLevel::insertUnmangled(TFunction *function)
+{
+	function->setUniqueId(nextUniqueId());
+
+	// returning true means symbol was added to the table
+	tInsertResult result = level.insert(tLevelPair(function->getName(), function));
+
+	return result.second;
+}
+
+TSymbol *TSymbolTableLevel::find(const TString &name) const
+{
+	tLevel::const_iterator it = level.find(name);
+	if (it == level.end())
+		return 0;
+	else
+		return (*it).second;
+}
+
 TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, bool *builtIn, bool *sameScope) const
 {
 	int level = currentLevel();
diff --git a/src/OpenGL/compiler/SymbolTable.h b/src/OpenGL/compiler/SymbolTable.h
index c4fdbfe..3466f2f 100644
--- a/src/OpenGL/compiler/SymbolTable.h
+++ b/src/OpenGL/compiler/SymbolTable.h
@@ -206,27 +206,12 @@
 	TSymbolTableLevel() { }
 	~TSymbolTableLevel();
 
-	bool insert(TSymbol &symbol)
-	{
-		symbol.setUniqueId(nextUniqueId());
+	bool insert(TSymbol *symbol);
 
-		//
-		// returning true means symbol was added to the table
-		//
-		tInsertResult result;
-		result = level.insert(tLevelPair(symbol.getMangledName(), &symbol));
+	// Insert a function using its unmangled name as the key.
+	bool insertUnmangled(TFunction *function);
 
-		return result.second;
-	}
-
-	TSymbol* find(const TString& name) const
-	{
-		tLevel::const_iterator it = level.find(name);
-		if (it == level.end())
-			return 0;
-		else
-			return (*it).second;
-	}
+	TSymbol *find(const TString &name) const;
 
 	static int nextUniqueId()
 	{
@@ -348,12 +333,12 @@
 		precisionStack.pop_back();
 	}
 
-	bool declare(TSymbol &symbol)
+	bool declare(TSymbol *symbol)
 	{
 		return insert(currentLevel(), symbol);
 	}
 
-	bool insert(ESymbolLevel level, TSymbol &symbol)
+	bool insert(ESymbolLevel level, TSymbol *symbol)
 	{
 		return table[level]->insert(symbol);
 	}
@@ -362,7 +347,7 @@
 	{
 		TVariable *constant = new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConstExpr, 1));
 		constant->getConstPointer()->setIConst(value);
-		return insert(level, *constant);
+		return insert(level, constant);
 	}
 
 	void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
@@ -448,7 +433,7 @@
 			}
 
 			ASSERT(hasUnmangledBuiltIn(name));
-			insert(level, *function);
+			insert(level, function);
 		}
 	}
 
diff --git a/src/OpenGL/compiler/Types.h b/src/OpenGL/compiler/Types.h
index d4d98d0..5318e39 100644
--- a/src/OpenGL/compiler/Types.h
+++ b/src/OpenGL/compiler/Types.h
@@ -137,6 +137,8 @@
 
 	bool equals(const TStructure &other) const;
 
+	void setMatrixPackingIfUnspecified(TLayoutMatrixPacking matrixPacking);
+
 	void setUniqueId(int uniqueId)
 	{
 		mUniqueId = uniqueId;
@@ -238,36 +240,38 @@
 {
 public:
 	POOL_ALLOCATOR_NEW_DELETE();
-	TType() {}
+
 	TType(TBasicType t, int s0 = 1, int s1 = 1) :
-		type(t), precision(EbpUndefined), qualifier(EvqGlobal), invariant(false), layoutQualifier(TLayoutQualifier::create()),
-		primarySize(s0), secondarySize(s1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0),
-		structure(0), deepestStructNesting(0), mangled(0)
+		type(t), precision(EbpUndefined), qualifier(EvqGlobal),
+		primarySize(s0), secondarySize(s1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0), layoutQualifier(TLayoutQualifier::create()),
+		structure(0), mangled(0)
 	{
 	}
+
 	TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s0 = 1, int s1 = 1, bool a = false) :
-		type(t), precision(p), qualifier(q), invariant(false), layoutQualifier(TLayoutQualifier::create()),
-		primarySize(s0), secondarySize(s1), array(a), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0),
-		structure(0), deepestStructNesting(0), mangled(0)
+		type(t), precision(p), qualifier(q),
+		primarySize(s0), secondarySize(s1), array(a), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0), layoutQualifier(TLayoutQualifier::create()),
+		structure(0), mangled(0)
 	{
 	}
-	explicit TType(const TPublicType &p);
+
 	TType(TStructure* userDef, TPrecision p = EbpUndefined) :
-		type(EbtStruct), precision(p), qualifier(EvqTemporary), invariant(false), layoutQualifier(TLayoutQualifier::create()),
-		primarySize(1), secondarySize(1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0),
-		structure(userDef), deepestStructNesting(0), mangled(0)
+		type(EbtStruct), precision(p), qualifier(EvqTemporary),
+		primarySize(1), secondarySize(1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0), layoutQualifier(TLayoutQualifier::create()),
+		structure(userDef), mangled(0)
 	{
 	}
 
 	TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn,
 		TLayoutQualifier layoutQualifierIn, int arraySizeIn)
 		: type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn),
-		invariant(false), layoutQualifier(layoutQualifierIn),
 		primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn), maxArraySize(0), arrayInformationType(0),
-		interfaceBlock(interfaceBlockIn), structure(0), deepestStructNesting(0), mangled(0)
+		interfaceBlock(interfaceBlockIn), layoutQualifier(layoutQualifierIn), structure(0), mangled(0)
 	{
 	}
 
+	explicit TType(const TPublicType &p);
+
 	TBasicType getBasicType() const { return type; }
 	void setBasicType(TBasicType t) { type = t; }
 
@@ -277,11 +281,24 @@
 	TQualifier getQualifier() const { return qualifier; }
 	void setQualifier(TQualifier q) { qualifier = q; }
 
-	bool isInvariant() const { return invariant; }
-
 	TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; }
 	void setLayoutQualifier(TLayoutQualifier lq) { layoutQualifier = lq; }
 
+	void setMatrixPackingIfUnspecified(TLayoutMatrixPacking matrixPacking)
+	{
+		if(isStruct())
+		{
+			// If the structure's matrix packing is specified, it overrules the block's matrix packing
+			structure->setMatrixPackingIfUnspecified((layoutQualifier.matrixPacking == EmpUnspecified) ?
+			                                         matrixPacking : layoutQualifier.matrixPacking);
+		}
+		// If the member's matrix packing is specified, it overrules any higher level matrix packing
+		if(layoutQualifier.matrixPacking == EmpUnspecified)
+		{
+			layoutQualifier.matrixPacking = matrixPacking;
+		}
+	}
+
 	// One-dimensional size of single instance type
 	int getNominalSize() const { return primarySize; }
 	void setNominalSize(int s) { primarySize = s; }
@@ -318,6 +335,24 @@
 		}
 	}
 
+	int samplerRegisterCount() const
+	{
+		if(structure)
+		{
+			int registerCount = 0;
+
+			const TFieldList& fields = isInterfaceBlock() ? interfaceBlock->fields() : structure->fields();
+			for(size_t i = 0; i < fields.size(); i++)
+			{
+				registerCount += fields[i]->type()->totalSamplerRegisterCount();
+			}
+
+			return registerCount;
+		}
+
+		return IsSampler(getBasicType()) ? 1 : 0;
+	}
+
 	int elementRegisterCount() const
 	{
 		if(structure || isInterfaceBlock())
@@ -360,6 +395,18 @@
 		return totalRegisterCount();
 	}
 
+	int totalSamplerRegisterCount() const
+	{
+		if(array)
+		{
+			return arraySize * samplerRegisterCount();
+		}
+		else
+		{
+			return samplerRegisterCount();
+		}
+	}
+
 	int totalRegisterCount() const
 	{
 		if(array)
@@ -403,7 +450,7 @@
 	bool isScalarInt() const { return isScalar() && IsInteger(type); }
 
 	TStructure* getStruct() const { return structure; }
-	void setStruct(TStructure* s) { structure = s; computeDeepestStructNesting(); }
+	void setStruct(TStructure* s) { structure = s; }
 
 	TString& getMangledName() {
 		if (!mangled) {
@@ -483,27 +530,24 @@
 protected:
 	void buildMangledName(TString&);
 	size_t getStructSize() const;
-	void computeDeepestStructNesting();
 
-	TBasicType type;
-	TPrecision precision;
-	TQualifier qualifier;
-	bool invariant;
+	TBasicType type = EbtVoid;
+	TPrecision precision = EbpUndefined;
+	TQualifier qualifier = EvqTemporary;
+	unsigned char primarySize = 0;     // size of vector or matrix, not size of array
+	unsigned char secondarySize = 0;   // 1 for vectors, > 1 for matrices
+	bool array = false;
+	int arraySize = 0;
+	int maxArraySize = 0;
+	TType *arrayInformationType = nullptr;
+
+	// null unless this is an interface block, or interface block member variable
+	TInterfaceBlock *interfaceBlock = nullptr;
 	TLayoutQualifier layoutQualifier;
-	unsigned char primarySize;   // size of vector or matrix, not size of array
-	unsigned char secondarySize; // secondarySize: 1 for vectors, >1 for matrices
-	bool array;
-	int arraySize;
-	int maxArraySize;
-	TType *arrayInformationType;
 
-	// 0 unless this is an interface block, or interface block member variable
-	TInterfaceBlock *interfaceBlock;
+	TStructure *structure = nullptr;   // null unless this is a struct
 
-	TStructure *structure;      // 0 unless this is a struct
-	int deepestStructNesting;
-
-	TString *mangled;
+	TString *mangled = nullptr;
 };
 
 //
diff --git a/src/OpenGL/compiler/glslang.l b/src/OpenGL/compiler/glslang.l
index 663db3b..fdc3977 100644
--- a/src/OpenGL/compiler/glslang.l
+++ b/src/OpenGL/compiler/glslang.l
@@ -171,6 +171,7 @@
 
 "sampler2D"          { context->lexAfterType = true; return SAMPLER2D; }
 "samplerCube"        { context->lexAfterType = true; return SAMPLERCUBE; }
+"sampler2DRect"      { context->lexAfterType = true; return SAMPLER2DRECT; }
 "samplerExternalOES" { context->lexAfterType = true; return SAMPLER_EXTERNAL_OES; }
 "sampler3D"          { context->lexAfterType = true; return SAMPLER3D; }
 "sampler3DRect"      { return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); }
@@ -312,7 +313,6 @@
 
 "sampler1D"    |
 "sampler1DShadow" |
-"sampler2DRect" |
 "sampler2DRectShadow" |
 
 "sizeof"       |
@@ -492,7 +492,7 @@
         return 0;
     }
 
-    if (!atoi_clamp(yytext, &(yylval->lex.i)))
+    if (!atou_clamp(yytext, &(yylval->lex.u)))
         yyextra->warning(*yylloc, "Integer overflow", yytext, "");
 
     return UINTCONSTANT;
diff --git a/src/OpenGL/compiler/glslang.y b/src/OpenGL/compiler/glslang.y
index c7e8f28..cd0daff 100644
--- a/src/OpenGL/compiler/glslang.y
+++ b/src/OpenGL/compiler/glslang.y
@@ -233,8 +233,9 @@
         // don't delete $1.string, it's used by error recovery, and the pool
         // pop will reclaim the memory
 
+        // Constants which aren't indexable arrays can be propagated by value.
         ConstantUnion *constArray = variable->getConstPointer();
-        if (constArray) {
+        if (constArray && variable->getType().getArraySize() <= 1) {
             TType t(variable->getType());
             $$ = context->intermediate.addConstantUnion(constArray, t, @1);
         } else
@@ -1221,7 +1222,7 @@
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         $$.setBasic(EbtSamplerCube, qual, @1);
     }
-	| SAMPLER_EXTERNAL_OES {
+    | SAMPLER_EXTERNAL_OES {
         if (!context->supportsExtension("GL_OES_EGL_image_external")) {
             context->error(@1, "unsupported type", "samplerExternalOES", "");
             context->recover();
@@ -1230,6 +1231,15 @@
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         $$.setBasic(EbtSamplerExternalOES, qual, @1);
     }
+    | SAMPLER2DRECT {
+        if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
+            context->error(@1, "unsupported type", "sampler2DRect", "");
+            context->recover();
+        }
+        FRAG_VERT_ONLY("sampler2DRect", @1);
+        TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+        $$.setBasic(EbtSampler2DRect, qual, @1);
+    }
     | SAMPLER3D {
         FRAG_VERT_ONLY("sampler3D", @1);
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
diff --git a/src/OpenGL/compiler/glslang_lex.cpp b/src/OpenGL/compiler/glslang_lex.cpp
index 2316c51..0cf1555 100644
--- a/src/OpenGL/compiler/glslang_lex.cpp
+++ b/src/OpenGL/compiler/glslang_lex.cpp
@@ -29,20 +29,84 @@
 
 
 
-#line 33 "./glslang_lex.cpp"
-
 #define  YY_INT_ALIGNED short int
 
 /* A lexical scanner generated by flex */
 
+
+
+
+
+
+
+
+
+
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 6
-#define YY_FLEX_SUBMINOR_VERSION 0
+#define YY_FLEX_SUBMINOR_VERSION 4
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    
+#ifdef yyget_lval
+#define yyget_lval_ALREADY_DEFINED
+#else
+#define yyget_lval yyget_lval
+#endif
+
+    
+#ifdef yyset_lval
+#define yyset_lval_ALREADY_DEFINED
+#else
+#define yyset_lval yyset_lval
+#endif
+
+
+
+
+    
+#ifdef yyget_lloc
+#define yyget_lloc_ALREADY_DEFINED
+#else
+#define yyget_lloc yyget_lloc
+#endif
+
+    
+#ifdef yyset_lloc
+#define yyset_lloc_ALREADY_DEFINED
+#else
+#define yyset_lloc yyset_lloc
+#endif
+
+
+
+
+
+
+
+
+
+
+
 /* First, we deal with  platform-specific or compiler-specific issues. */
 
 /* begin standard C headers. */
@@ -113,40 +177,38 @@
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#ifndef SIZE_MAX
+#define SIZE_MAX               (~(size_t)0)
+#endif
+
 #endif /* ! C99 */
 
 #endif /* ! FLEXINT_H */
 
-#ifdef __cplusplus
 
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
+/* begin standard C++ headers. */
 
-#else	/* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif	/* defined (__STDC__) */
-#endif	/* ! __cplusplus */
-
-#ifdef YY_USE_CONST
+/* TODO: this is always defined, so inline it */
 #define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
 #else
-#define yyconst
+#define yynoreturn
 #endif
 
 /* Returned upon end-of-file. */
 #define YY_NULL 0
 
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index.  If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
+
+/* Promotes a possibly negative, possibly signed char to an
+ *   integer in range [0..255] for use as an array index.
  */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+
+
+
 
 /* An opaque pointer. */
 #ifndef YY_TYPEDEF_YY_SCANNER_T
@@ -154,6 +216,22 @@
 typedef void* yyscan_t;
 #endif
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 /* For convenience, these vars (plus the bison vars far below)
    are macros in the reentrant scanner. */
 #define yyin yyg->yyin_r
@@ -165,27 +243,36 @@
 #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
 #define yy_flex_debug yyg->yy_flex_debug_r
 
+
+
+
+
+
+
+
+
+
+
+
+
 /* Enter a start condition.  This macro really ought to take a parameter,
  * but we do it the disgusting crufty way forced on us by the ()-less
  * definition of BEGIN.
  */
 #define BEGIN yyg->yy_start = 1 + 2 *
-
 /* Translate the current start state into a value that can be later handed
  * to BEGIN to return to the state.  The YYSTATE alias is for lex
  * compatibility.
  */
 #define YY_START ((yyg->yy_start - 1) / 2)
 #define YYSTATE YY_START
-
 /* Action number for EOF rule of a given start state. */
 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
 /* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart(yyin ,yyscanner )
-
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
 #define YY_END_OF_BUFFER_CHAR 0
 
+
 /* Size of default input buffer. */
 #ifndef YY_BUF_SIZE
 #ifdef __ia64__
@@ -199,10 +286,13 @@
 #endif /* __ia64__ */
 #endif
 
+
 /* The state buf must be large enough to hold one state per character in the main buffer.
  */
 #define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
 
+
+
 #ifndef YY_TYPEDEF_YY_BUFFER_STATE
 #define YY_TYPEDEF_YY_BUFFER_STATE
 typedef struct yy_buffer_state *YY_BUFFER_STATE;
@@ -213,13 +303,16 @@
 typedef size_t yy_size_t;
 #endif
 
+
+
+
 #define EOB_ACT_CONTINUE_SCAN 0
 #define EOB_ACT_END_OF_FILE 1
 #define EOB_ACT_LAST_MATCH 2
-
+    
     /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
      *       access to the local variable yy_act. Since yyless() is a macro, it would break
-     *       existing scanners that call yyless() from OUTSIDE yylex. 
+     *       existing scanners that call yyless() from OUTSIDE yylex.
      *       One obvious solution it to make yy_act a global. I tried that, and saw
      *       a 5% performance hit in a non-yylineno scanner, because yy_act is
      *       normally declared as a register variable-- so it is not worth it.
@@ -252,27 +345,29 @@
 		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
 		} \
 	while ( 0 )
-
 #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
 
+
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 struct yy_buffer_state
 	{
 	FILE *yy_input_file;
 
+
+
 	char *yy_ch_buf;		/* input buffer */
 	char *yy_buf_pos;		/* current position in input buffer */
 
 	/* Size of input buffer in bytes, not including room for EOB
 	 * characters.
 	 */
-	yy_size_t yy_buf_size;
+	int yy_buf_size;
 
 	/* Number of characters read into yy_ch_buf, not including EOB
 	 * characters.
 	 */
-	yy_size_t yy_n_chars;
+	int yy_n_chars;
 
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	 * and can realloc() it to grow it, and should free() it to
@@ -295,7 +390,8 @@
 
     int yy_bs_lineno; /**< The line count. */
     int yy_bs_column; /**< The column count. */
-    
+
+
 	/* Whether to try to fill the input buffer when we reach the
 	 * end of it.
 	 */
@@ -320,6 +416,9 @@
 	};
 #endif /* !YY_STRUCT_YY_BUFFER_STATE */
 
+
+
+
 /* We provide macros for accessing buffer states in case in the
  * future we want to put the buffer states in a more general
  * "scanner state".
@@ -329,87 +428,95 @@
 #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
                           ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
                           : NULL)
-
 /* Same as previous macro, but useful when we know that the buffer stack is not
  * NULL or when we need an lvalue. For internal use only.
  */
 #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
 
-void yyrestart (FILE *input_file ,yyscan_t yyscanner );
-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
-void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-void yypop_buffer_state (yyscan_t yyscanner );
 
-static void yyensure_buffer_stack (yyscan_t yyscanner );
-static void yy_load_buffer_state (yyscan_t yyscanner );
-static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
 
-#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
 
-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
 
-void *yyalloc (yy_size_t ,yyscan_t yyscanner );
-void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
-void yyfree (void * ,yyscan_t yyscanner );
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
 
 #define yy_new_buffer yy_create_buffer
-
 #define yy_set_interactive(is_interactive) \
 	{ \
 	if ( ! YY_CURRENT_BUFFER ){ \
         yyensure_buffer_stack (yyscanner); \
 		YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
 	} \
 	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
 	}
-
 #define yy_set_bol(at_bol) \
 	{ \
 	if ( ! YY_CURRENT_BUFFER ){\
         yyensure_buffer_stack (yyscanner); \
 		YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
 	} \
 	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
 	}
-
 #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
 
+
 /* Begin user sect3 */
 
 #define yywrap(yyscanner) (/*CONSTCOND*/1)
 #define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
 
-typedef unsigned char YY_CHAR;
 
 typedef int yy_state_type;
 
 #define yytext_ptr yytext_r
 
-static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
-static int yy_get_next_buffer (yyscan_t yyscanner );
-#if defined(__GNUC__) && __GNUC__ >= 3
-__attribute__((__noreturn__))
-#endif
-static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+
+
+
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state  , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+
+
 
 /* Done after the current pattern has been matched and before the
  * corresponding action - sets up yytext.
  */
 #define YY_DO_BEFORE_ACTION \
 	yyg->yytext_ptr = yy_bp; \
-	yyleng = (size_t) (yy_cp - yy_bp); \
+	yyleng = (int) (yy_cp - yy_bp); \
 	yyg->yy_hold_char = *yy_cp; \
 	*yy_cp = '\0'; \
 	yyg->yy_c_buf_p = yy_cp;
-
 #define YY_NUM_RULES 239
 #define YY_END_OF_BUFFER 240
 /* This struct is not used in this scanner,
@@ -419,7 +526,7 @@
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[821] =
+static const flex_int16_t yy_accept[821] =
     {   0,
         0,    0,    0,    0,    0,    0,  240,  238,  237,  237,
       222,  228,  233,  217,  218,  226,  225,  214,  223,  221,
@@ -438,7 +545,7 @@
       177,  177,  177,  177,  177,  177,  177,  177,  177,  177,
       177,  177,  177,  177,  177,  177,  177,  177,  177,  177,
       177,  177,  199,  203,  235,    0,  189,  185,    0,  188,
-      182,    0,  184,  178,  195,  196,  177,  135,  177,  177,
+      182,    0,  184,  178,  195,  196,  177,  136,  177,  177,
       177,  177,  177,  177,  177,  177,  177,  177,  177,  177,
       177,  177,  177,  177,  177,  177,  177,  177,  177,  177,
       177,   13,  177,  177,  177,  177,  177,  177,  177,  177,
@@ -450,70 +557,70 @@
       177,  177,  177,  177,  177,  177,  177,  177,  177,    0,
       186,    0,  185,  187,  181,  177,  177,  177,   30,  177,
       177,   18,  174,  177,  177,  177,  177,  177,  177,  177,
-      177,  177,  177,   16,  138,  177,  177,  177,  177,   21,
-      177,  177,  142,  154,  177,  177,  177,  177,  177,  177,
-      177,  177,  177,  177,  177,  177,  151,    4,   35,   36,
+      177,  177,  177,   16,  139,  177,  177,  177,  177,   21,
+      177,  177,  143,  155,  177,  177,  177,  177,  177,  177,
+      177,  177,  177,  177,  177,  177,  152,    4,   35,   36,
 
        37,  177,  177,  177,  177,  177,  177,  177,  177,  177,
       177,  177,  177,  177,  177,  177,  177,  177,  177,  177,
-      177,  177,  177,  177,  177,  141,   31,  177,  177,   28,
+      177,  177,  177,  177,  177,  142,   31,  177,  177,   28,
       177,  177,  177,  177,  177,  177,  177,   47,   48,   49,
        29,  177,  177,  177,  177,  177,  177,   10,   56,   57,
-       58,  177,  136,  177,  177,    7,  177,  177,  177,  177,
-      163,  164,  165,  177,   32,  177,  155,   26,  166,  167,
-      168,    2,  160,  161,  162,  177,  177,  177,   25,  158,
+       58,  177,  137,  177,  177,    7,  177,  177,  177,  177,
+      164,  165,  166,  177,   32,  177,  156,   26,  167,  168,
+      169,    2,  161,  162,  163,  177,  177,  177,   25,  159,
       177,  177,  177,   50,   51,   52,  177,  177,  177,  177,
-      177,  177,  177,  177,  177,  177,  177,   85,  177,  177,
+      177,  177,  177,  177,  177,  177,  177,   86,  177,  177,
 
-      177,  177,  177,  177,  177,  152,  177,  177,  177,  177,
-      177,  177,  177,  177,  177,  177,  177,  137,  177,  177,
-      176,   53,   54,   55,  177,  177,   14,  177,   90,  177,
-      177,  177,  177,   88,  177,  177,  177,  153,  148,   91,
-      177,  177,  177,  177,  177,  177,  143,  177,  177,  177,
-       77,   38,   41,   43,   42,   39,   45,   44,   46,   40,
-      177,  177,  177,  177,  159,  134,  177,  177,  146,  177,
-      177,  177,   34,   86,  173,   22,  147,   76,  177,  157,
+      177,  177,  177,  177,  177,  153,  177,  177,  177,  177,
+      177,  177,  177,  177,  177,  177,  177,  138,  177,  177,
+      176,   53,   54,   55,  177,  177,   14,  177,   91,  177,
+      177,  177,  177,   89,  177,  177,  177,  154,  149,   92,
+      177,  177,  177,  177,  177,  177,  144,  177,  177,  177,
+       78,   38,   41,   43,   42,   39,   45,   44,   46,   40,
+      177,  177,  177,  177,  160,  135,  177,  177,  147,  177,
+      177,  177,   34,   87,  173,   22,  148,   77,  177,  158,
        17,  177,  177,  177,  177,  177,  177,  177,  177,  177,
       177,  177,  177,  177,  177,   19,   33,  177,  177,  177,
 
-      177,  177,  177,   92,   93,   94,  177,  177,  177,  177,
+      177,  177,  177,   93,   94,   95,  177,  177,  177,  177,
       177,    3,  177,  177,  177,  177,  177,  177,  177,  177,
-      177,  177,  177,  139,  177,  177,  177,  177,  177,    8,
-      177,  177,    9,  177,  177,  177,  177,   20,   78,   11,
-      149,   96,   97,   98,  177,  177,  177,  177,  177,  177,
-      177,  177,  177,  177,  177,  177,  144,  177,  177,  177,
-       80,   82,   79,  177,  177,  177,  177,  177,  177,  177,
-      140,  100,  101,  102,  177,  177,  156,  177,  145,  177,
+      177,  177,  177,  140,  177,  177,  177,  177,  177,    8,
+      177,  177,    9,  177,  177,  177,  177,   20,   79,   11,
+      150,   97,   98,   99,  177,  177,  177,  177,  177,  177,
+      177,  177,  177,  177,  177,  177,  145,  177,  177,  177,
+       81,   83,   80,  177,  177,  177,  177,  177,  177,  177,
+      141,  101,  102,  103,  177,  177,  157,  177,  146,  177,
       177,    6,  177,  177,  177,  177,  177,  177,  177,  177,
-      177,   95,  150,    1,  177,  177,  177,  177,  177,  175,
+      177,   96,  151,    1,  177,  177,  177,  177,  177,  175,
 
-      177,   89,    5,  169,   59,   62,  177,  177,  177,  177,
-      177,  177,  177,  177,  177,  177,  177,  177,  177,   81,
-      177,  177,  177,  177,   99,  177,  177,  177,  177,  177,
-      119,   65,   66,  177,  177,  177,  177,  177,  177,  177,
-      177,  177,  177,  177,  177,  177,   87,  177,  177,  177,
-      103,  121,   69,   70,  177,  177,   83,  177,  177,  177,
-      177,  177,  177,  177,  114,  177,  177,  177,  177,  177,
-      177,  177,  177,  177,  177,  128,  177,  177,  177,  177,
+      177,   90,    5,  170,   59,   63,  177,  177,  177,  177,
+      177,  177,  177,  177,  177,  177,  177,  177,  177,   82,
+      177,  177,  177,  177,  100,  177,  177,  177,  177,  177,
+      120,   66,   67,  177,  177,  177,  177,  177,  177,  177,
+      177,  177,  177,  177,  177,  177,   88,  177,  177,  177,
+      104,  122,   70,   71,  177,  177,   84,  177,  177,  177,
+      177,  177,  177,  177,  115,  177,  177,  177,  177,  177,
+      177,  177,  177,  177,  177,  129,  177,  177,  177,  177,
        60,  177,  177,  177,  177,  177,  177,  177,  177,  177,
-      177,  177,  177,  115,  104,  177,  105,  177,  177,  177,
+      177,  177,  177,  116,  105,  177,  106,  177,  177,  177,
 
-      129,  177,  177,   67,  177,  177,  177,  177,  177,  177,
-      177,  177,  177,  177,  177,  177,  177,  116,  177,  177,
-      130,  177,  177,   71,  106,  107,  177,  110,  177,  111,
-      177,  177,  177,  177,  177,   84,  177,  177,  177,  177,
-      171,  177,   63,  125,  177,  177,  108,  109,  177,  177,
-      177,  177,  177,  177,  177,  177,  177,  177,  123,  126,
-      117,  177,   64,  177,  177,  177,  177,  177,  177,  177,
-      177,  124,  127,  177,  177,  120,   68,  177,  177,  170,
-      177,  177,  177,   73,  177,  177,  122,   72,  177,  177,
-      177,  177,  177,  177,  131,  177,  177,  177,  177,  177,
+      130,  177,  177,   68,  177,  177,  177,  177,  177,  177,
+      177,  177,  177,  177,  177,  177,  177,  117,  177,  177,
+      131,  177,  177,   72,  107,  108,  177,  111,  177,  112,
+      177,  177,  177,  177,  177,   85,  177,  177,  177,  177,
+       61,  177,   64,  126,  177,  177,  109,  110,  177,  177,
+      177,  177,  177,  177,  177,  177,  177,  177,  124,  127,
+      118,  177,   65,  177,  177,  177,  177,  177,  177,  177,
+      177,  125,  128,  177,  177,  121,   69,  177,  177,  171,
+      177,  177,  177,   74,  177,  177,  123,   73,  177,  177,
+      177,  177,  177,  177,  132,  177,  177,  177,  177,  177,
 
-      177,  132,  177,  177,  177,   74,  177,  133,  112,  113,
-      177,  177,  177,   61,  177,  177,  172,  118,   75,    0
+      177,  133,  177,  177,  177,   75,  177,  134,  113,  114,
+      177,  177,  177,   62,  177,  177,  172,  119,   76,    0
     } ;
 
-static yyconst YY_CHAR yy_ec[256] =
+static const YY_CHAR yy_ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         2,    2,    2,    1,    1,    1,    1,    1,    1,    1,
@@ -545,7 +652,7 @@
         1,    1,    1,    1,    1
     } ;
 
-static yyconst YY_CHAR yy_meta[73] =
+static const YY_CHAR yy_meta[73] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    2,    2,    2,    2,    2,    2,
@@ -557,7 +664,7 @@
         1,    1
     } ;
 
-static yyconst flex_uint16_t yy_base[827] =
+static const flex_int16_t yy_base[827] =
     {   0,
         0,    0, 1019, 1018,   72,    0, 1020, 1023, 1023, 1023,
       994,  120,  141, 1023, 1023,  993,  138, 1023,  137,  135,
@@ -652,7 +759,7 @@
       509,  512,  515,  518,  519,  520
     } ;
 
-static yyconst flex_int16_t yy_def[827] =
+static const flex_int16_t yy_def[827] =
     {   0,
       820,    1,  821,  821,  820,    5,  820,  820,  820,  820,
       820,  820,  820,  820,  820,  820,  820,  820,  820,  820,
@@ -747,7 +854,7 @@
       820,  820,  820,  820,  820,  820
     } ;
 
-static yyconst flex_uint16_t yy_nxt[1096] =
+static const flex_int16_t yy_nxt[1096] =
     {   0,
         8,    9,   10,   11,   12,   13,   14,   15,   16,   17,
        18,   19,   20,   21,   22,   23,   23,   23,   23,   23,
@@ -872,7 +979,7 @@
 
     } ;
 
-static yyconst flex_int16_t yy_chk[1096] =
+static const flex_int16_t yy_chk[1096] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -997,8 +1104,9 @@
 
     } ;
 
+
 /* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[240] =
+static const flex_int32_t yy_rule_can_match_eol[240] =
     {   0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
@@ -1073,12 +1181,23 @@
 static int float_constant(yyscan_t yyscanner);
 static int floatsuffix_check(TParseContext* context);
 
+
+
+
 #define INITIAL 0
 #define COMMENT 1
 #define FIELDS 2
 
+
+
+
+
+
 #define YY_EXTRA_TYPE TParseContext*
 
+
+
+
 /* Holds the entire state of the reentrant scanner. */
 struct yyguts_t
     {
@@ -1092,8 +1211,8 @@
     size_t yy_buffer_stack_max; /**< capacity of stack. */
     YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
     char yy_hold_char;
-    yy_size_t yy_n_chars;
-    yy_size_t yyleng_r;
+    int yy_n_chars;
+    int yyleng_r;
     char *yy_c_buf_p;
     int yy_init;
     int yy_start;
@@ -1107,78 +1226,141 @@
     int yylineno_r;
     int yy_flex_debug_r;
 
+
+
+
     char *yytext_r;
     int yy_more_flag;
     int yy_more_len;
 
+
+
     YYSTYPE * yylval_r;
 
+
+
     YYLTYPE * yylloc_r;
 
+
     }; /* end struct yyguts_t */
 
-static int yy_init_globals (yyscan_t yyscanner );
 
+
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+
+
+
+    
     /* This must go here because YYSTYPE and YYLTYPE are included
      * from bison output in section 1.*/
     #    define yylval yyg->yylval_r
     
+
+    
     #    define yylloc yyg->yylloc_r
     
+
+
 int yylex_init (yyscan_t* scanner);
 
-int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+
 
 /* Accessor methods to globals.
    These are made visible to non-reentrant scanners for convenience. */
 
-int yylex_destroy (yyscan_t yyscanner );
 
-int yyget_debug (yyscan_t yyscanner );
+int yylex_destroy ( yyscan_t yyscanner );
 
-void yyset_debug (int debug_flag ,yyscan_t yyscanner );
 
-YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner );
 
-void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+int yyget_debug ( yyscan_t yyscanner );
 
-FILE *yyget_in (yyscan_t yyscanner );
 
-void yyset_in  (FILE * _in_str ,yyscan_t yyscanner );
 
-FILE *yyget_out (yyscan_t yyscanner );
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
 
-void yyset_out  (FILE * _out_str ,yyscan_t yyscanner );
 
-yy_size_t yyget_leng (yyscan_t yyscanner );
 
-char *yyget_text (yyscan_t yyscanner );
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
 
-int yyget_lineno (yyscan_t yyscanner );
 
-void yyset_lineno (int _line_number ,yyscan_t yyscanner );
 
-int yyget_column  (yyscan_t yyscanner );
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
 
-void yyset_column (int _column_no ,yyscan_t yyscanner );
 
-YYSTYPE * yyget_lval (yyscan_t yyscanner );
 
-void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+FILE *yyget_in ( yyscan_t yyscanner );
 
-       YYLTYPE *yyget_lloc (yyscan_t yyscanner );
+
+
+void yyset_in  ( FILE * _in_str , yyscan_t yyscanner );
+
+
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+
+
+void yyset_out  ( FILE * _out_str , yyscan_t yyscanner );
+
+
+
+			int yyget_leng ( yyscan_t yyscanner );
+
+
+
+char *yyget_text ( yyscan_t yyscanner );
+
+
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+
+
+
+int yyget_column  ( yyscan_t yyscanner );
+
+
+
+
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+
+
+
+YYSTYPE * yyget_lval ( yyscan_t yyscanner );
+
+
+void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
+
+
     
-        void yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+       YYLTYPE *yyget_lloc ( yyscan_t yyscanner );
     
+
+    
+        void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner );
+    
+
+
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
  */
 
 #ifndef YY_SKIP_YYWRAP
 #ifdef __cplusplus
-extern "C" int yywrap (yyscan_t yyscanner );
+extern "C" int yywrap ( yyscan_t yyscanner );
 #else
-extern int yywrap (yyscan_t yyscanner );
+extern int yywrap ( yyscan_t yyscanner );
 #endif
 #endif
 
@@ -1186,24 +1368,31 @@
     
 #endif
 
+
 #ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
 #endif
 
 #ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
 #endif
 
 #ifndef YY_NO_INPUT
-
 #ifdef __cplusplus
-static int yyinput (yyscan_t yyscanner );
+static int yyinput ( yyscan_t yyscanner );
 #else
-static int input (yyscan_t yyscanner );
+static int input ( yyscan_t yyscanner );
 #endif
 
 #endif
 
+
+
+
+
+
+
+
 /* Amount of stuff to slurp up with each read. */
 #ifndef YY_READ_BUF_SIZE
 #ifdef __ia64__
@@ -1214,14 +1403,17 @@
 #endif /* __ia64__ */
 #endif
 
+
 /* Copy whatever the last rule matched to the standard output. */
 #ifndef ECHO
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
 #endif
 
+
+
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
  * is returned in "result".
  */
@@ -1230,7 +1422,7 @@
 	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
 		{ \
 		int c = '*'; \
-		size_t n; \
+		int n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -1243,7 +1435,7 @@
 	else \
 		{ \
 		errno=0; \
-		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+		while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
 			{ \
 			if( errno != EINTR) \
 				{ \
@@ -1258,6 +1450,8 @@
 
 #endif
 
+
+
 /* No semi-colon after return; correct usage is to write "yyterminate();" -
  * we don't want an extra ';' after the "return" because that will cause
  * some compilers to complain about unreachable statements.
@@ -1266,31 +1460,54 @@
 #define yyterminate() return YY_NULL
 #endif
 
+
 /* Number of entries by which start-condition stack grows. */
 #ifndef YY_START_STACK_INCR
 #define YY_START_STACK_INCR 25
 #endif
 
+
 /* Report a fatal error. */
 #ifndef YY_FATAL_ERROR
 #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
 #endif
 
+
+
 /* end tables serialization structures and prototypes */
 
+
+
 /* Default declaration of generated scanner - a define so the user can
  * easily add parameters.
  */
 #ifndef YY_DECL
 #define YY_DECL_IS_OURS 1
 
+
+
+
+
+
+        
+    
+    
+
+
+
+    
+    
+    
+
+
 extern int yylex \
-               (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+               (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner);
 
 #define YY_DECL int yylex \
                (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
 #endif /* !YY_DECL */
 
+
 /* Code executed at the beginning of each rule, after yytext and yyleng
  * have been set up.
  */
@@ -1298,14 +1515,19 @@
 #define YY_USER_ACTION
 #endif
 
+
+
 /* Code executed at the end of each rule. */
 #ifndef YY_BREAK
 #define YY_BREAK /*LINTED*/break;
 #endif
 
+
+
 #define YY_RULE_SETUP \
 	YY_USER_ACTION
 
+
 /** The main scanner function which does all the work.
  */
 YY_DECL
@@ -1315,10 +1537,16 @@
 	int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
+
+
+
     yylval = yylval_param;
 
+
+
     yylloc = yylloc_param;
 
+
 	if ( !yyg->yy_init )
 		{
 		yyg->yy_init = 1;
@@ -1327,6 +1555,8 @@
 		YY_USER_INIT;
 #endif
 
+
+
 		if ( ! yyg->yy_start )
 			yyg->yy_start = 1;	/* first start state */
 
@@ -1339,16 +1569,20 @@
 		if ( ! YY_CURRENT_BUFFER ) {
 			yyensure_buffer_stack (yyscanner);
 			YY_CURRENT_BUFFER_LVALUE =
-				yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+				yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
 		}
 
-		yy_load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 		}
 
 	{
 
+
+
     TParseContext* context = yyextra;
 
+
+
 	while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
 		{
 		yy_cp = yyg->yy_c_buf_p;
@@ -1375,9 +1609,9 @@
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
 				if ( yy_current_state >= 821 )
-					yy_c = yy_meta[(unsigned int) yy_c];
+					yy_c = yy_meta[yy_c];
 				}
-			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 			++yy_cp;
 			}
 		while ( yy_current_state != 820 );
@@ -1389,20 +1623,23 @@
 
 		YY_DO_BEFORE_ACTION;
 
+
 		if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
 			{
-			yy_size_t yyl;
+			int yyl;
 			for ( yyl = 0; yyl < yyleng; ++yyl )
 				if ( yytext[yyl] == '\n' )
-					   
+					
     do{ yylineno++;
         yycolumn=0;
     }while(0)
 ;
 			}
 
+
 do_action:	/* This label is used only to access EOF actions. */
 
+
 		switch ( yy_act )
 	{ /* beginning of action switch */
 			case 0: /* must back up */
@@ -1654,74 +1891,77 @@
 	YY_BREAK
 case 61:
 YY_RULE_SETUP
-{ context->lexAfterType = true; return SAMPLER_EXTERNAL_OES; }
+{ context->lexAfterType = true; return SAMPLER2DRECT; }
 	YY_BREAK
 case 62:
 YY_RULE_SETUP
-{ context->lexAfterType = true; return SAMPLER3D; }
+{ context->lexAfterType = true; return SAMPLER_EXTERNAL_OES; }
 	YY_BREAK
 case 63:
 YY_RULE_SETUP
-{ return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); }
+{ context->lexAfterType = true; return SAMPLER3D; }
 	YY_BREAK
 case 64:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, SAMPLER2DARRAY); }
+{ return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); }
 	YY_BREAK
 case 65:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, ISAMPLER2D); }
+{ return  ES2_identifier_ES3_keyword(context, SAMPLER2DARRAY); }
 	YY_BREAK
 case 66:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, ISAMPLER3D); }
+{ return  ES2_identifier_ES3_keyword(context, ISAMPLER2D); }
 	YY_BREAK
 case 67:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, ISAMPLERCUBE); }
+{ return  ES2_identifier_ES3_keyword(context, ISAMPLER3D); }
 	YY_BREAK
 case 68:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, ISAMPLER2DARRAY); }
+{ return  ES2_identifier_ES3_keyword(context, ISAMPLERCUBE); }
 	YY_BREAK
 case 69:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, USAMPLER2D); }
+{ return  ES2_identifier_ES3_keyword(context, ISAMPLER2DARRAY); }
 	YY_BREAK
 case 70:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, USAMPLER3D); }
+{ return  ES2_identifier_ES3_keyword(context, USAMPLER2D); }
 	YY_BREAK
 case 71:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, USAMPLERCUBE); }
+{ return  ES2_identifier_ES3_keyword(context, USAMPLER3D); }
 	YY_BREAK
 case 72:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, USAMPLER2DARRAY); }
+{ return  ES2_identifier_ES3_keyword(context, USAMPLERCUBE); }
 	YY_BREAK
 case 73:
 YY_RULE_SETUP
-{ return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); }
+{ return  ES2_identifier_ES3_keyword(context, USAMPLER2DARRAY); }
 	YY_BREAK
 case 74:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, SAMPLERCUBESHADOW); }
+{ return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); }
 	YY_BREAK
 case 75:
 YY_RULE_SETUP
-{ return  ES2_identifier_ES3_keyword(context, SAMPLER2DARRAYSHADOW); }
+{ return  ES2_identifier_ES3_keyword(context, SAMPLERCUBESHADOW); }
 	YY_BREAK
 case 76:
 YY_RULE_SETUP
-{ context->lexAfterType = true; return(STRUCT); }
+{ return  ES2_identifier_ES3_keyword(context, SAMPLER2DARRAYSHADOW); }
 	YY_BREAK
 case 77:
 YY_RULE_SETUP
+{ context->lexAfterType = true; return(STRUCT); }
+	YY_BREAK
+case 78:
+YY_RULE_SETUP
 { return ES2_identifier_ES3_keyword(context, LAYOUT); }
 	YY_BREAK
 /* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */
-case 78:
 case 79:
 case 80:
 case 81:
@@ -1777,6 +2017,7 @@
 case 131:
 case 132:
 case 133:
+case 134:
 YY_RULE_SETUP
 { 
     if (context->getShaderVersion() < 300) {
@@ -1787,7 +2028,7 @@
 }
 	YY_BREAK
 /* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */
-case 134:
+case 135:
 YY_RULE_SETUP
 {
     if (context->getShaderVersion() >= 300)
@@ -1800,7 +2041,6 @@
 }
 	YY_BREAK
 /* Reserved keywords */
-case 135:
 case 136:
 case 137:
 case 138:
@@ -2186,7 +2426,7 @@
 				{
 				yyg->yy_did_buffer_switch_on_eof = 0;
 
-				if ( yywrap(yyscanner ) )
+				if ( yywrap( yyscanner ) )
 					{
 					/* Note: because we've taken care in
 					 * yy_get_next_buffer() to have set up
@@ -2242,6 +2482,10 @@
 	} /* end of user's declarations */
 } /* end of yylex */
 
+
+
+
+
 /* yy_get_next_buffer - try to read in a new buffer
  *
  * Returns a code representing an action:
@@ -2254,7 +2498,7 @@
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
 	char *source = yyg->yytext_ptr;
-	yy_size_t number_to_move, i;
+	int number_to_move, i;
 	int ret_val;
 
 	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
@@ -2283,7 +2527,7 @@
 	/* Try to read more data. */
 
 	/* First move last chars to start of buffer. */
-	number_to_move = (yy_size_t) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
 
 	for ( i = 0; i < number_to_move; ++i )
 		*(dest++) = *(source++);
@@ -2296,7 +2540,7 @@
 
 	else
 		{
-			yy_size_t num_to_read =
+			int num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
 
 		while ( num_to_read <= 0 )
@@ -2310,7 +2554,7 @@
 
 			if ( b->yy_is_our_buffer )
 				{
-				yy_size_t new_size = b->yy_buf_size * 2;
+				int new_size = b->yy_buf_size * 2;
 
 				if ( new_size <= 0 )
 					b->yy_buf_size += b->yy_buf_size / 8;
@@ -2319,11 +2563,12 @@
 
 				b->yy_ch_buf = (char *)
 					/* Include room in for 2 EOB chars. */
-					yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+					yyrealloc( (void *) b->yy_ch_buf,
+							 (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
 				}
 			else
 				/* Can't grow it, we don't own it. */
-				b->yy_ch_buf = 0;
+				b->yy_ch_buf = NULL;
 
 			if ( ! b->yy_ch_buf )
 				YY_FATAL_ERROR(
@@ -2351,7 +2596,7 @@
 		if ( number_to_move == YY_MORE_ADJ )
 			{
 			ret_val = EOB_ACT_END_OF_FILE;
-			yyrestart(yyin  ,yyscanner);
+			yyrestart( yyin  , yyscanner);
 			}
 
 		else
@@ -2365,12 +2610,15 @@
 	else
 		ret_val = EOB_ACT_CONTINUE_SCAN;
 
-	if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+	if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
 		/* Extend the array by 50%, plus the number we really need. */
-		yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
-		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+			(void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
 		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
 			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+		/* "- 2" to take care of EOB's */
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
 	}
 
 	yyg->yy_n_chars += number_to_move;
@@ -2382,6 +2630,7 @@
 	return ret_val;
 }
 
+
 /* yy_get_previous_state - get the state just before the EOB char was reached */
 
     static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
@@ -2404,14 +2653,15 @@
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
 			if ( yy_current_state >= 821 )
-				yy_c = yy_meta[(unsigned int) yy_c];
+				yy_c = yy_meta[yy_c];
 			}
-		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 		}
 
 	return yy_current_state;
 }
 
+
 /* yy_try_NUL_trans - try to make a transition on the NUL character
  *
  * synopsis
@@ -2433,15 +2683,16 @@
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
 		if ( yy_current_state >= 821 )
-			yy_c = yy_meta[(unsigned int) yy_c];
+			yy_c = yy_meta[yy_c];
 		}
-	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 	yy_is_jam = (yy_current_state == 820);
 
 	(void)yyg;
 	return yy_is_jam ? 0 : yy_current_state;
 }
 
+
 #ifndef YY_NO_UNPUT
 
 #endif
@@ -2471,7 +2722,7 @@
 
 		else
 			{ /* need more input */
-			yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
 			++yyg->yy_c_buf_p;
 
 			switch ( yy_get_next_buffer( yyscanner ) )
@@ -2488,14 +2739,14 @@
 					 */
 
 					/* Reset buffer status. */
-					yyrestart(yyin ,yyscanner);
+					yyrestart( yyin , yyscanner);
 
 					/*FALLTHROUGH*/
 
 				case EOB_ACT_END_OF_FILE:
 					{
-					if ( yywrap(yyscanner ) )
-						return EOF;
+					if ( yywrap( yyscanner ) )
+						return 0;
 
 					if ( ! yyg->yy_did_buffer_switch_on_eof )
 						YY_NEW_FILE;
@@ -2518,7 +2769,7 @@
 	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
 
 	if ( c == '\n' )
-		   
+		
     do{ yylineno++;
         yycolumn=0;
     }while(0)
@@ -2540,13 +2791,14 @@
 	if ( ! YY_CURRENT_BUFFER ){
         yyensure_buffer_stack (yyscanner);
 		YY_CURRENT_BUFFER_LVALUE =
-            yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
 	}
 
-	yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
-	yy_load_buffer_state(yyscanner );
+	yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+	yy_load_buffer_state( yyscanner );
 }
 
+
 /** Switch to a different input buffer.
  * @param new_buffer The new input buffer.
  * @param yyscanner The scanner object.
@@ -2573,7 +2825,7 @@
 		}
 
 	YY_CURRENT_BUFFER_LVALUE = new_buffer;
-	yy_load_buffer_state(yyscanner );
+	yy_load_buffer_state( yyscanner );
 
 	/* We don't actually know whether we did this switch during
 	 * EOF (yywrap()) processing, but the only time this flag
@@ -2583,6 +2835,7 @@
 	yyg->yy_did_buffer_switch_on_eof = 1;
 }
 
+
 static void yy_load_buffer_state  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
@@ -2602,26 +2855,27 @@
 {
 	YY_BUFFER_STATE b;
     
-	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
 	if ( ! b )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
-	b->yy_buf_size = (yy_size_t)size;
+	b->yy_buf_size = size;
 
 	/* yy_ch_buf has to be 2 characters longer than the size given because
 	 * we need to put in 2 end-of-buffer characters.
 	 */
-	b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner );
+	b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
 	if ( ! b->yy_ch_buf )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
 	b->yy_is_our_buffer = 1;
 
-	yy_init_buffer(b,file ,yyscanner);
+	yy_init_buffer( b, file , yyscanner);
 
 	return b;
 }
 
+
 /** Destroy the buffer.
  * @param b a buffer created with yy_create_buffer()
  * @param yyscanner The scanner object.
@@ -2637,11 +2891,12 @@
 		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
 
 	if ( b->yy_is_our_buffer )
-		yyfree((void *) b->yy_ch_buf ,yyscanner );
+		yyfree( (void *) b->yy_ch_buf , yyscanner );
 
-	yyfree((void *) b ,yyscanner );
+	yyfree( (void *) b , yyscanner );
 }
 
+
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
  * such as during a yyrestart() or at EOF.
@@ -2652,7 +2907,7 @@
 	int oerrno = errno;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-	yy_flush_buffer(b ,yyscanner);
+	yy_flush_buffer( b , yyscanner);
 
 	b->yy_input_file = file;
 	b->yy_fill_buffer = 1;
@@ -2666,8 +2921,11 @@
         b->yy_bs_column = 0;
     }
 
+
+    
         b->yy_is_interactive = 0;
     
+
 	errno = oerrno;
 }
 
@@ -2696,7 +2954,7 @@
 	b->yy_buffer_status = YY_BUFFER_NEW;
 
 	if ( b == YY_CURRENT_BUFFER )
-		yy_load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 }
 
 /** Pushes the new state onto the stack. The new state becomes
@@ -2728,10 +2986,11 @@
 	YY_CURRENT_BUFFER_LVALUE = new_buffer;
 
 	/* copied from yy_switch_to_buffer. */
-	yy_load_buffer_state(yyscanner );
+	yy_load_buffer_state( yyscanner );
 	yyg->yy_did_buffer_switch_on_eof = 1;
 }
 
+
 /** Removes and deletes the top of the stack, if present.
  *  The next element becomes the new top.
  *  @param yyscanner The scanner object.
@@ -2742,17 +3001,18 @@
 	if (!YY_CURRENT_BUFFER)
 		return;
 
-	yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
 	YY_CURRENT_BUFFER_LVALUE = NULL;
 	if (yyg->yy_buffer_stack_top > 0)
 		--yyg->yy_buffer_stack_top;
 
 	if (YY_CURRENT_BUFFER) {
-		yy_load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 		yyg->yy_did_buffer_switch_on_eof = 1;
 	}
 }
 
+
 /* Allocates the stack if it does not exist.
  *  Guarantees space for at least one push.
  */
@@ -2767,15 +3027,16 @@
 		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
 		 * immediate realloc on the next call.
          */
-		num_to_alloc = 1; // After all that talk, this was set to 1 anyways...
+      num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
 		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
 								(num_to_alloc * sizeof(struct yy_buffer_state*)
 								, yyscanner);
 		if ( ! yyg->yy_buffer_stack )
 			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-								  
+
+
 		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-				
+
 		yyg->yy_buffer_stack_max = num_to_alloc;
 		yyg->yy_buffer_stack_top = 0;
 		return;
@@ -2800,11 +3061,15 @@
 	}
 }
 
+
+
+
+
 /** Setup the input buffer state to scan directly from a user-specified character buffer.
  * @param base the character buffer
  * @param size the size in bytes of the character buffer
  * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object. 
+ * @return the newly allocated buffer state object.
  */
 YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
 {
@@ -2814,27 +3079,30 @@
 	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
 	     base[size-1] != YY_END_OF_BUFFER_CHAR )
 		/* They forgot to leave room for the EOB's. */
-		return 0;
+		return NULL;
 
-	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
 	if ( ! b )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
 
-	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_size = (int) (size - 2);	/* "- 2" to take care of EOB's */
 	b->yy_buf_pos = b->yy_ch_buf = base;
 	b->yy_is_our_buffer = 0;
-	b->yy_input_file = 0;
+	b->yy_input_file = NULL;
 	b->yy_n_chars = b->yy_buf_size;
 	b->yy_is_interactive = 0;
 	b->yy_at_bol = 1;
 	b->yy_fill_buffer = 0;
 	b->yy_buffer_status = YY_BUFFER_NEW;
 
-	yy_switch_to_buffer(b ,yyscanner );
+	yy_switch_to_buffer( b , yyscanner );
 
 	return b;
 }
 
+
+
+
 /** Setup the input buffer state to scan a string. The next call to yylex() will
  * scan from a @e copy of @a str.
  * @param yystr a NUL-terminated string to scan
@@ -2843,12 +3111,15 @@
  * @note If you want to scan bytes that may contain NUL values, then use
  *       yy_scan_bytes() instead.
  */
-YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
 {
     
-	return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+	return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
 }
 
+
+
+
 /** Setup the input buffer state to scan the given bytes. The next call to yylex() will
  * scan from a @e copy of @a bytes.
  * @param yybytes the byte buffer to scan
@@ -2856,16 +3127,16 @@
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_bytes  (const char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
 {
 	YY_BUFFER_STATE b;
 	char *buf;
 	yy_size_t n;
-	yy_size_t i;
+	int i;
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
-	n = _yybytes_len + 2;
-	buf = (char *) yyalloc(n ,yyscanner );
+	n = (yy_size_t) (_yybytes_len + 2);
+	buf = (char *) yyalloc( n , yyscanner );
 	if ( ! buf )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
 
@@ -2874,7 +3145,7 @@
 
 	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
 
-	b = yy_scan_buffer(buf,n ,yyscanner);
+	b = yy_scan_buffer( buf, n , yyscanner);
 	if ( ! b )
 		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
 
@@ -2886,15 +3157,25 @@
 	return b;
 }
 
+
+
+
+
+
+
+
+
+
+
 #ifndef YY_EXIT_FAILURE
 #define YY_EXIT_FAILURE 2
 #endif
 
-static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
-	(void) fprintf( stderr, "%s\n", msg );
+	fprintf( stderr, "%s\n", msg );
 	exit( YY_EXIT_FAILURE );
 }
 
@@ -2915,8 +3196,11 @@
 		} \
 	while ( 0 )
 
+
+
 /* Accessor  methods (get/set functions) to struct members. */
 
+
 /** Get the user-defined data for this scanner.
  * @param yyscanner The scanner object.
  */
@@ -2926,12 +3210,15 @@
     return yyextra;
 }
 
+
+
 /** Get the current line number.
  * @param yyscanner The scanner object.
  */
 int yyget_lineno  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
     
         if (! YY_CURRENT_BUFFER)
             return 0;
@@ -2939,12 +3226,16 @@
     return yylineno;
 }
 
+
+
+
 /** Get the current column number.
  * @param yyscanner The scanner object.
  */
 int yyget_column  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
     
         if (! YY_CURRENT_BUFFER)
             return 0;
@@ -2952,6 +3243,9 @@
     return yycolumn;
 }
 
+
+
+
 /** Get the input stream.
  * @param yyscanner The scanner object.
  */
@@ -2961,6 +3255,8 @@
     return yyin;
 }
 
+
+
 /** Get the output stream.
  * @param yyscanner The scanner object.
  */
@@ -2970,15 +3266,18 @@
     return yyout;
 }
 
+
+
 /** Get the length of the current token.
  * @param yyscanner The scanner object.
  */
-yy_size_t yyget_leng  (yyscan_t yyscanner)
+int yyget_leng  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyleng;
 }
 
+
 /** Get the current token.
  * @param yyscanner The scanner object.
  */
@@ -2989,6 +3288,8 @@
     return yytext;
 }
 
+
+
 /** Set the user-defined data. This data is never touched by the scanner.
  * @param user_defined The data to be associated with this scanner.
  * @param yyscanner The scanner object.
@@ -2999,6 +3300,8 @@
     yyextra = user_defined ;
 }
 
+
+
 /** Set the current line number.
  * @param _line_number line number
  * @param yyscanner The scanner object.
@@ -3007,6 +3310,7 @@
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
+    
         /* lineno is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
            YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
@@ -3014,6 +3318,9 @@
     yylineno = _line_number;
 }
 
+
+
+
 /** Set the current column.
  * @param _column_no column number
  * @param yyscanner The scanner object.
@@ -3022,6 +3329,7 @@
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
+    
         /* column is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
            YY_FATAL_ERROR( "yyset_column called with no buffer" );
@@ -3029,6 +3337,10 @@
     yycolumn = _column_no;
 }
 
+
+
+
+
 /** Set the input stream. This does not discard the current
  * input buffer.
  * @param _in_str A readable stream.
@@ -3041,59 +3353,77 @@
     yyin = _in_str ;
 }
 
+
+
 void yyset_out (FILE *  _out_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyout = _out_str ;
 }
 
+
+
+
 int yyget_debug  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yy_flex_debug;
 }
 
+
+
 void yyset_debug (int  _bdebug , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yy_flex_debug = _bdebug ;
 }
 
+
 /* Accessor methods for yylval and yylloc */
 
+
 YYSTYPE * yyget_lval  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yylval;
 }
 
+
+
 void yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yylval = yylval_param;
 }
 
+
+
+    
 YYLTYPE *yyget_lloc  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yylloc;
 }
     
+
+    
 void yyset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yylloc = yylloc_param;
 }
     
+
+
+
+
 /* User-visible API */
 
 /* yylex_init is special because it creates the scanner itself, so it is
  * the ONLY reentrant function that doesn't take the scanner as the last argument.
  * That's why we explicitly handle the declaration, instead of using our macros.
  */
-
 int yylex_init(yyscan_t* ptr_yy_globals)
-
 {
     if (ptr_yy_globals == NULL){
         errno = EINVAL;
@@ -3113,6 +3443,7 @@
     return yy_init_globals ( *ptr_yy_globals );
 }
 
+
 /* yylex_init_extra has the same functionality as yylex_init, but follows the
  * convention of taking the scanner as the last argument. Note however, that
  * this is a *pointer* to a scanner, as it will be allocated by this call (and
@@ -3120,9 +3451,7 @@
  * The user defined value in the first argument will be available to yyalloc in
  * the yyextra field.
  */
-
-int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
-
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
 {
     struct yyguts_t dummy_yyguts;
 
@@ -3132,23 +3461,24 @@
         errno = EINVAL;
         return 1;
     }
-	
+
     *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-	
+
     if (*ptr_yy_globals == NULL){
         errno = ENOMEM;
         return 1;
     }
-    
+
     /* By setting to 0xAA, we expose bugs in
     yy_init_globals. Leave at 0x00 for releases. */
     memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-    
+
     yyset_extra (yy_user_defined, *ptr_yy_globals);
-    
+
     return yy_init_globals ( *ptr_yy_globals );
 }
 
+
 static int yy_init_globals (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
@@ -3156,24 +3486,33 @@
      * This function is called from yylex_destroy(), so don't allocate here.
      */
 
-    yyg->yy_buffer_stack = 0;
+
+    
+
+    yyg->yy_buffer_stack = NULL;
     yyg->yy_buffer_stack_top = 0;
     yyg->yy_buffer_stack_max = 0;
-    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_c_buf_p = NULL;
     yyg->yy_init = 0;
     yyg->yy_start = 0;
 
+
     yyg->yy_start_stack_ptr = 0;
     yyg->yy_start_stack_depth = 0;
     yyg->yy_start_stack =  NULL;
 
+
+
+
+
+
 /* Defined in main.c */
 #ifdef YY_STDINIT
     yyin = stdin;
     yyout = stdout;
 #else
-    yyin = (FILE *) 0;
-    yyout = (FILE *) 0;
+    yyin = NULL;
+    yyout = NULL;
 #endif
 
     /* For future reference: Set errno on error, since we are called by
@@ -3182,6 +3521,7 @@
     return 0;
 }
 
+
 /* yylex_destroy is for both reentrant and non-reentrant scanners. */
 int yylex_destroy  (yyscan_t yyscanner)
 {
@@ -3189,19 +3529,23 @@
 
     /* Pop the buffer stack, destroying each element. */
 	while(YY_CURRENT_BUFFER){
-		yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
 		YY_CURRENT_BUFFER_LVALUE = NULL;
 		yypop_buffer_state(yyscanner);
 	}
 
 	/* Destroy the stack itself. */
-	yyfree(yyg->yy_buffer_stack ,yyscanner);
+	yyfree(yyg->yy_buffer_stack , yyscanner);
 	yyg->yy_buffer_stack = NULL;
 
+
     /* Destroy the start condition stack. */
-        yyfree(yyg->yy_start_stack ,yyscanner );
+        yyfree( yyg->yy_start_stack , yyscanner );
         yyg->yy_start_stack = NULL;
 
+
+
+
     /* Reset the globals. This is important in a non-reentrant scanner so the next time
      * yylex() is called, initialization will occur. */
     yy_init_globals( yyscanner);
@@ -3212,12 +3556,16 @@
     return 0;
 }
 
+
+
 /*
  * Internal utility routines.
  */
 
+
+
 #ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
@@ -3228,8 +3576,10 @@
 }
 #endif
 
+
+
 #ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
 {
 	int n;
 	for ( n = 0; s[n]; ++n )
@@ -3239,13 +3589,17 @@
 }
 #endif
 
+
+
 void *yyalloc (yy_size_t  size , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
-	return (void *) malloc( size );
+	return malloc(size);
 }
 
+
+
 void *yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
@@ -3258,9 +3612,11 @@
 	 * any pointer type to void*, and deal with argument conversions
 	 * as though doing an assignment.
 	 */
-	return (void *) realloc( (char *) ptr, size );
+	return realloc(ptr, size);
 }
 
+
+
 void yyfree (void * ptr , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
@@ -3268,16 +3624,24 @@
 	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
 }
 
+
 #define YYTABLES_NAME "yytables"
 
+
+
+
+
+
+
+
 yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) {
     pp::Token token;
     yyget_extra(yyscanner)->getPreprocessor().lex(&token);
     yy_size_t len = token.type == pp::Token::LAST ? 0 : token.text.size();
     if (len < max_size)
         memcpy(buf, token.text.c_str(), len);
-    yyset_column(token.location.file,yyscanner);
-    yyset_lineno(token.location.line,yyscanner);
+    yyset_column(token.location.file, yyscanner);
+    yyset_lineno(token.location.line, yyscanner);
 
     if (len >= max_size)
         YY_FATAL_ERROR("Input buffer overflow");
@@ -3360,7 +3724,7 @@
         return 0;
     }
 
-    if (!atoi_clamp(yytext, &(yylval->lex.i)))
+    if (!atou_clamp(yytext, &(yylval->lex.u)))
         yyextra->warning(*yylloc, "Integer overflow", yytext, "");
 
     return UINTCONSTANT;
@@ -3412,7 +3776,7 @@
 
 int glslang_initialize(TParseContext* context) {
     yyscan_t scanner = NULL;
-    if (yylex_init_extra(context,&scanner))
+    if (yylex_init_extra(context, &scanner))
         return 1;
 
     context->setScanner(scanner);
@@ -3431,9 +3795,9 @@
 
 int glslang_scan(size_t count, const char* const string[], const int length[],
                  TParseContext* context) {
-    yyrestart(NULL,context->getScanner());
-    yyset_column(0,context->getScanner());
-    yyset_lineno(1,context->getScanner());
+    yyrestart(NULL, context->getScanner());
+    yyset_column(0, context->getScanner());
+    yyset_lineno(1, context->getScanner());
     context->AfterEOF = false;
 
     // Initialize preprocessor.
@@ -3453,3 +3817,4 @@
     return 0;
 }
 
+
diff --git a/src/OpenGL/compiler/glslang_tab.cpp b/src/OpenGL/compiler/glslang_tab.cpp
index ea821d3..811da14 100644
--- a/src/OpenGL/compiler/glslang_tab.cpp
+++ b/src/OpenGL/compiler/glslang_tab.cpp
@@ -634,18 +634,18 @@
 #endif /* !YYCOPY_NEEDED */
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  112
+#define YYFINAL  113
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   2525
+#define YYLAST   2530
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  128
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  93
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  272
+#define YYNRULES  273
 /* YYNSTATES -- Number of states.  */
-#define YYNSTATES  413
+#define YYNSTATES  414
 
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
@@ -704,34 +704,34 @@
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   229,   229,   248,   251,   256,   261,   266,   271,   277,
-     280,   283,   286,   289,   292,   298,   306,   317,   321,   329,
-     332,   338,   342,   349,   355,   364,   372,   378,   385,   395,
-     398,   401,   404,   414,   415,   416,   417,   425,   426,   430,
-     434,   442,   443,   446,   452,   453,   457,   464,   465,   468,
-     471,   474,   480,   481,   484,   490,   491,   498,   499,   506,
-     507,   514,   515,   521,   522,   528,   529,   535,   536,   542,
-     543,   551,   552,   553,   554,   556,   557,   558,   561,   564,
-     567,   570,   576,   579,   590,   598,   606,   609,   615,   622,
-     626,   630,   634,   641,   647,   650,   657,   665,   686,   712,
-     722,   750,   755,   765,   770,   780,   783,   786,   789,   795,
-     802,   805,   809,   813,   818,   823,   830,   834,   838,   842,
-     847,   852,   856,   863,   873,   879,   882,   888,   894,   901,
-     910,   919,   927,   930,   937,   941,   945,   950,   958,   961,
-     965,   969,   978,   987,   995,  1005,  1017,  1020,  1023,  1029,
-    1036,  1039,  1045,  1048,  1051,  1057,  1060,  1065,  1080,  1084,
-    1088,  1092,  1096,  1100,  1105,  1110,  1115,  1120,  1125,  1130,
-    1135,  1140,  1145,  1150,  1155,  1160,  1166,  1172,  1178,  1184,
-    1190,  1196,  1202,  1208,  1214,  1219,  1224,  1233,  1238,  1243,
-    1248,  1253,  1258,  1263,  1268,  1273,  1278,  1283,  1288,  1293,
-    1298,  1303,  1316,  1316,  1319,  1319,  1325,  1328,  1344,  1347,
-    1356,  1360,  1366,  1373,  1388,  1392,  1396,  1397,  1403,  1404,
-    1405,  1406,  1407,  1408,  1409,  1413,  1414,  1414,  1414,  1424,
-    1425,  1429,  1429,  1430,  1430,  1435,  1438,  1448,  1451,  1457,
-    1458,  1462,  1470,  1474,  1481,  1481,  1488,  1491,  1498,  1503,
-    1518,  1518,  1523,  1523,  1530,  1530,  1538,  1541,  1547,  1550,
-    1556,  1560,  1567,  1570,  1573,  1576,  1579,  1588,  1592,  1599,
-    1602,  1608,  1608
+       0,   229,   229,   249,   252,   257,   262,   267,   272,   278,
+     281,   284,   287,   290,   293,   299,   307,   318,   322,   330,
+     333,   339,   343,   350,   356,   365,   373,   379,   386,   396,
+     399,   402,   405,   415,   416,   417,   418,   426,   427,   431,
+     435,   443,   444,   447,   453,   454,   458,   465,   466,   469,
+     472,   475,   481,   482,   485,   491,   492,   499,   500,   507,
+     508,   515,   516,   522,   523,   529,   530,   536,   537,   543,
+     544,   552,   553,   554,   555,   557,   558,   559,   562,   565,
+     568,   571,   577,   580,   591,   599,   607,   610,   616,   623,
+     627,   631,   635,   642,   648,   651,   658,   666,   687,   713,
+     723,   751,   756,   766,   771,   781,   784,   787,   790,   796,
+     803,   806,   810,   814,   819,   824,   831,   835,   839,   843,
+     848,   853,   857,   864,   874,   880,   883,   889,   895,   902,
+     911,   920,   928,   931,   938,   942,   946,   951,   959,   962,
+     966,   970,   979,   988,   996,  1006,  1018,  1021,  1024,  1030,
+    1037,  1040,  1046,  1049,  1052,  1058,  1061,  1066,  1081,  1085,
+    1089,  1093,  1097,  1101,  1106,  1111,  1116,  1121,  1126,  1131,
+    1136,  1141,  1146,  1151,  1156,  1161,  1167,  1173,  1179,  1185,
+    1191,  1197,  1203,  1209,  1215,  1220,  1225,  1234,  1243,  1248,
+    1253,  1258,  1263,  1268,  1273,  1278,  1283,  1288,  1293,  1298,
+    1303,  1308,  1313,  1326,  1326,  1329,  1329,  1335,  1338,  1354,
+    1357,  1366,  1370,  1376,  1383,  1398,  1402,  1406,  1407,  1413,
+    1414,  1415,  1416,  1417,  1418,  1419,  1423,  1424,  1424,  1424,
+    1434,  1435,  1439,  1439,  1440,  1440,  1445,  1448,  1458,  1461,
+    1467,  1468,  1472,  1480,  1484,  1491,  1491,  1498,  1501,  1508,
+    1513,  1528,  1528,  1533,  1533,  1540,  1540,  1548,  1551,  1557,
+    1560,  1566,  1570,  1577,  1580,  1583,  1586,  1589,  1598,  1602,
+    1609,  1612,  1618,  1618
 };
 #endif
 
@@ -820,12 +820,12 @@
 };
 # endif
 
-#define YYPACT_NINF -334
+#define YYPACT_NINF -344
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-334)))
+  (!!((Yystate) == (-344)))
 
-#define YYTABLE_NINF -232
+#define YYTABLE_NINF -233
 
 #define yytable_value_is_error(Yytable_value) \
   0
@@ -834,48 +834,48 @@
      STATE-NUM.  */
 static const yytype_int16 yypact[] =
 {
-    2163,    10,  -334,  -334,  -334,   169,  -334,  -334,  -334,  -334,
-    -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,
-    -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,
-    -334,  -334,  -334,  -334,  -334,  -334,  -334,    69,  -334,  -334,
-     -48,  -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,
-    -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,   -82,  -334,
-    -334,   -78,   -73,   -71,     1,   -59,  -334,   -32,   113,  1182,
-    -334,  -334,  2448,   113,  -334,   -23,  -334,  2088,  -334,  -334,
-    -334,  -334,   113,  -334,  2448,  -334,  -334,    11,  -334,     9,
-    -334,    20,  -334,   121,  -334,  -334,  -334,  -334,  -334,  2312,
-     150,    22,  -334,   -79,  -334,    37,  -334,  2238,  -334,  -334,
-    -334,  1252,  -334,  -334,  -334,    62,  -334,  2238,    44,   -41,
-    -334,   410,  -334,  -334,  -334,  -334,   105,  2312,   -76,  -334,
-    1350,  1641,  -334,   107,  2312,   117,  1833,  -334,    91,  -334,
-    -334,  -334,  -334,  -334,  1641,  1641,  1641,  -334,  -334,  -334,
-    -334,  -334,  -334,  -334,    19,  -334,  -334,  -334,   103,   -24,
-    1736,   120,  -334,  1641,    80,   -42,   -36,    15,    43,    99,
-     108,   104,   141,   142,   -69,  -334,   127,  -334,  -334,  2238,
-    1918,    87,  -334,     9,   122,   124,  -334,   135,   136,   129,
-    1448,   140,  1641,   133,   143,   137,  -334,  -334,   118,  -334,
-    -334,    12,  -334,   -78,   145,  -334,  -334,  -334,  -334,   526,
-    -334,  -334,  -334,  -334,  -334,  -334,   144,  -334,  -334,  1543,
-    1641,   138,   148,  -334,  -334,   117,   146,    28,  -334,   -58,
-    -334,  -334,  -334,   -15,  -334,  -334,  1641,  2380,  -334,  -334,
-    1641,   154,  -334,  -334,  -334,  1641,  1641,  1641,  1641,  1641,
-    1641,  1641,  1641,  1641,  1641,  1641,  1641,  1641,  1641,  1641,
-    1641,  1641,  1641,  1641,  1641,  -334,  2003,  -334,  -334,  -334,
-    -334,  -334,  -334,   152,  -334,  1641,  -334,  -334,    41,  1641,
-     149,  -334,  -334,  -334,   642,  -334,  -334,  -334,  -334,  -334,
-    -334,  -334,  -334,  -334,  -334,  -334,  1641,  1641,  -334,  -334,
-    -334,  1641,   151,   155,  -334,  1641,   157,    57,  1641,   117,
-    -334,   -85,  -334,  -334,   156,   160,  -334,   161,  -334,  -334,
-    -334,  -334,  -334,    80,    80,   -42,   -42,   -36,   -36,   -36,
-     -36,    15,    15,    43,    99,   108,   104,   141,   142,    72,
-    -334,   211,    20,   874,   990,   -10,  -334,     3,  -334,  1087,
-     642,  -334,  -334,   165,  1641,   163,  -334,  1641,  -334,   166,
-    -334,  1641,  -334,  -334,  1641,   164,  -334,  -334,  -334,  -334,
-    1087,   152,  -334,   160,   198,  2312,   172,   170,  -334,  -334,
-    1641,  -334,  -334,   171,  -334,  1641,  -334,   167,   175,   265,
-    -334,   178,   174,   758,  -334,  -334,   176,    13,  1641,   758,
-     152,  -334,  1641,  -334,  -334,  -334,  -334,   177,   160,  -334,
-    -334,  -334,  -334
+    2168,   120,  -344,  -344,  -344,   146,  -344,  -344,  -344,  -344,
+    -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,
+    -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,
+    -344,  -344,  -344,  -344,  -344,  -344,  -344,   127,  -344,  -344,
+     -41,  -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,
+    -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,   -84,
+    -344,  -344,   -68,   -57,   -39,     1,   -89,  -344,    41,    14,
+    1187,  -344,  -344,  2453,    14,  -344,    15,  -344,  2093,  -344,
+    -344,  -344,  -344,    14,  -344,  2453,  -344,  -344,    18,  -344,
+      47,  -344,    26,  -344,    10,  -344,  -344,  -344,  -344,  -344,
+    2317,   113,    60,  -344,   -66,  -344,    31,  -344,  2243,  -344,
+    -344,  -344,  1257,  -344,  -344,  -344,   -45,  -344,  2243,    46,
+     -21,  -344,   415,  -344,  -344,  -344,  -344,    68,  2317,   -42,
+    -344,  1355,  1646,  -344,   188,  2317,    89,  1838,  -344,    85,
+    -344,  -344,  -344,  -344,  -344,  1646,  1646,  1646,  -344,  -344,
+    -344,  -344,  -344,  -344,  -344,    39,  -344,  -344,  -344,    74,
+     -17,  1741,    96,  -344,  1646,    37,   -37,    91,   -61,    87,
+      65,    81,    71,   116,   115,   -64,  -344,   102,  -344,  -344,
+    2243,  1923,   105,  -344,    47,    97,    99,  -344,   110,   131,
+     124,  1453,   138,  1646,   132,   142,   140,  -344,  -344,   123,
+    -344,  -344,   -77,  -344,   -68,   143,  -344,  -344,  -344,  -344,
+     531,  -344,  -344,  -344,  -344,  -344,  -344,   144,  -344,  -344,
+    1548,  1646,   141,   148,  -344,  -344,    89,   145,    -9,  -344,
+     -58,  -344,  -344,  -344,   -13,  -344,  -344,  1646,  2385,  -344,
+    -344,  1646,   152,  -344,  -344,  -344,  1646,  1646,  1646,  1646,
+    1646,  1646,  1646,  1646,  1646,  1646,  1646,  1646,  1646,  1646,
+    1646,  1646,  1646,  1646,  1646,  1646,  -344,  2008,  -344,  -344,
+    -344,  -344,  -344,  -344,   150,  -344,  1646,  -344,  -344,    -7,
+    1646,   147,  -344,  -344,  -344,   647,  -344,  -344,  -344,  -344,
+    -344,  -344,  -344,  -344,  -344,  -344,  -344,  1646,  1646,  -344,
+    -344,  -344,  1646,   149,   153,  -344,  1646,   151,     5,  1646,
+      89,  -344,   -70,  -344,  -344,   158,   157,  -344,   165,  -344,
+    -344,  -344,  -344,  -344,    37,    37,   -37,   -37,    91,    91,
+      91,    91,   -61,   -61,    87,    65,    81,    71,   116,   115,
+      75,  -344,   214,    26,   879,   995,    -8,  -344,     4,  -344,
+    1092,   647,  -344,  -344,   164,  1646,   159,  -344,  1646,  -344,
+     166,  -344,  1646,  -344,  -344,  1646,   170,  -344,  -344,  -344,
+    -344,  1092,   150,  -344,   157,   200,  2317,   172,   169,  -344,
+    -344,  1646,  -344,  -344,   173,  -344,  1646,  -344,   167,   174,
+     265,  -344,   175,   171,   763,  -344,  -344,   177,     9,  1646,
+     763,   150,  -344,  1646,  -344,  -344,  -344,  -344,   178,   157,
+    -344,  -344,  -344,  -344
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -887,74 +887,74 @@
      160,   161,   166,   167,   168,   169,   170,   171,   163,   164,
      165,   172,   173,   174,   175,   176,   177,   139,   140,   143,
      129,   178,   179,   180,   181,   182,   183,     0,   126,   125,
-       0,   158,   184,   185,   186,   188,   189,   190,   191,   192,
-     193,   194,   195,   196,   187,   197,   198,   199,     0,   201,
-     270,   271,     0,    95,   105,     0,   110,   116,   133,     0,
-     131,   123,     0,   134,   144,   155,   200,     0,   267,   269,
-     130,   122,     0,   136,     0,   141,   142,     0,   204,     0,
-      86,     0,    93,   105,   127,   106,   107,   108,    96,     0,
-     105,     0,    87,   117,   132,     0,    92,     0,   124,   145,
-     135,     0,     1,   268,   137,     0,   202,     0,   152,     0,
-     150,     0,   272,    97,   102,   104,   109,     0,   111,    98,
-       0,     0,    85,     0,     0,     0,     0,   206,     2,     6,
-       4,     5,     7,    28,     0,     0,     0,   156,    35,    34,
-      36,    33,     3,     9,    29,    11,    16,    17,     0,     0,
-      22,     0,    37,     0,    41,    44,    47,    52,    55,    57,
-      59,    61,    63,    65,    67,    84,     0,    26,    88,     0,
-       0,     0,   149,     0,     0,     0,   252,     0,     0,     0,
-       0,     0,     0,     0,     0,   226,   235,   239,    37,    69,
-      82,     0,   215,     0,   144,   218,   237,   217,   216,     0,
-     219,   220,   221,   222,   223,   224,    99,   101,   103,     0,
-       0,     0,     0,   214,   121,     0,   212,     0,   210,     0,
-     207,    30,    31,     0,    13,    14,     0,     0,    20,    19,
-       0,   158,    23,    25,    32,     0,     0,     0,     0,     0,
+       0,   158,   184,   185,   186,   187,   189,   190,   191,   192,
+     193,   194,   195,   196,   197,   188,   198,   199,   200,     0,
+     202,   271,   272,     0,    95,   105,     0,   110,   116,   133,
+       0,   131,   123,     0,   134,   144,   155,   201,     0,   268,
+     270,   130,   122,     0,   136,     0,   141,   142,     0,   205,
+       0,    86,     0,    93,   105,   127,   106,   107,   108,    96,
+       0,   105,     0,    87,   117,   132,     0,    92,     0,   124,
+     145,   135,     0,     1,   269,   137,     0,   203,     0,   152,
+       0,   150,     0,   273,    97,   102,   104,   109,     0,   111,
+      98,     0,     0,    85,     0,     0,     0,     0,   207,     2,
+       6,     4,     5,     7,    28,     0,     0,     0,   156,    35,
+      34,    36,    33,     3,     9,    29,    11,    16,    17,     0,
+       0,    22,     0,    37,     0,    41,    44,    47,    52,    55,
+      57,    59,    61,    63,    65,    67,    84,     0,    26,    88,
+       0,     0,     0,   149,     0,     0,     0,   253,     0,     0,
+       0,     0,     0,     0,     0,     0,   227,   236,   240,    37,
+      69,    82,     0,   216,     0,   144,   219,   238,   218,   217,
+       0,   220,   221,   222,   223,   224,   225,    99,   101,   103,
+       0,     0,     0,     0,   215,   121,     0,   213,     0,   211,
+       0,   208,    30,    31,     0,    13,    14,     0,     0,    20,
+      19,     0,   158,    23,    25,    32,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   157,     0,   205,   153,   154,
-     151,   263,   262,   233,   254,     0,   266,   264,     0,     0,
-       0,   247,   250,   225,     0,    72,    73,    75,    74,    77,
-      78,    79,    80,    81,    76,    71,     0,     0,   240,   236,
-     238,     0,     0,     0,   115,     0,   118,     0,     0,     0,
-     208,     0,    89,     8,     0,    15,    27,    12,    18,    24,
-      38,    39,    40,    43,    42,    45,    46,    50,    51,    48,
-      49,    53,    54,    56,    58,    60,    62,    64,    66,     0,
-     203,     0,     0,     0,     0,     0,   265,     0,   246,     0,
-     227,    70,    83,     0,     0,   112,   119,     0,   209,     0,
-     211,     0,    90,    10,     0,     0,   232,   234,   257,   256,
-     259,   233,   244,   248,     0,     0,     0,     0,   100,   113,
-       0,   120,   213,     0,    68,     0,   258,     0,     0,   243,
-     241,     0,     0,     0,   228,   114,     0,     0,   260,     0,
-     233,   245,     0,   230,   251,   229,    91,     0,   261,   255,
-     242,   249,   253
+       0,     0,     0,     0,     0,     0,   157,     0,   206,   153,
+     154,   151,   264,   263,   234,   255,     0,   267,   265,     0,
+       0,     0,   248,   251,   226,     0,    72,    73,    75,    74,
+      77,    78,    79,    80,    81,    76,    71,     0,     0,   241,
+     237,   239,     0,     0,     0,   115,     0,   118,     0,     0,
+       0,   209,     0,    89,     8,     0,    15,    27,    12,    18,
+      24,    38,    39,    40,    43,    42,    45,    46,    50,    51,
+      48,    49,    53,    54,    56,    58,    60,    62,    64,    66,
+       0,   204,     0,     0,     0,     0,     0,   266,     0,   247,
+       0,   228,    70,    83,     0,     0,   112,   119,     0,   210,
+       0,   212,     0,    90,    10,     0,     0,   233,   235,   258,
+     257,   260,   234,   245,   249,     0,     0,     0,     0,   100,
+     113,     0,   120,   214,     0,    68,     0,   259,     0,     0,
+     244,   242,     0,     0,     0,   229,   114,     0,     0,   261,
+       0,   234,   246,     0,   231,   252,   230,    91,     0,   262,
+     256,   243,   250,   254
 };
 
   /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -334,  -334,  -334,  -334,  -334,  -334,  -334,    46,  -334,  -334,
-    -334,  -334,    66,  -334,   -46,   -44,   -67,   -34,    30,    33,
-      29,    32,    34,    31,  -334,  -104,  -127,  -334,  -144,  -119,
-    -334,    14,    17,  -334,  -334,  -334,   168,   204,   199,   173,
-    -334,  -334,  -325,     8,  -334,  -101,     7,   -68,   293,  -334,
-    -334,   119,     0,  -334,  -334,  -334,  -334,   -97,  -123,    76,
-      -6,  -208,   -40,  -206,  -328,   -83,  -334,  -334,   -94,  -333,
-    -334,  -334,   -86,    25,   -38,  -334,  -334,  -334,  -334,  -334,
-     -60,  -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,  -334,
-     253,  -334,  -334
+    -344,  -344,  -344,  -344,  -344,  -344,  -344,    48,  -344,  -344,
+    -344,  -344,    70,  -344,   -56,   -49,  -123,   -53,    28,    29,
+      27,    32,    30,    33,  -344,  -110,  -128,  -344,  -138,  -119,
+    -344,    11,    17,  -344,  -344,  -344,   168,   201,   197,   176,
+    -344,  -344,  -326,     7,  -344,  -105,    13,   -69,   294,  -344,
+    -344,   117,     0,  -344,  -344,  -344,  -344,  -103,  -121,    76,
+     -10,  -215,   -40,  -203,  -314,   -86,  -344,  -344,   -97,  -343,
+    -344,  -344,   -87,    23,   -36,  -344,  -344,  -344,  -344,  -344,
+     -60,  -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,  -344,
+     232,  -344,  -344
 };
 
   /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,   152,   153,   154,   314,   155,   156,   157,   158,   159,
-     160,   161,   198,   163,   164,   165,   166,   167,   168,   169,
-     170,   171,   172,   173,   174,   199,   200,   296,   201,   176,
-     107,   202,   203,    62,    63,    64,   124,    98,    99,   125,
-      65,    66,    67,    68,   100,    69,    70,    71,    72,    73,
-     119,   120,   177,    75,    76,   179,   117,   136,   137,   227,
-     228,   224,   205,   206,   207,   208,   284,   377,   404,   341,
-     342,   343,   405,   209,   210,   211,   390,   212,   391,   213,
-     376,   214,   349,   273,   344,   370,   387,   388,   215,    77,
-      78,    79,    91
+      -1,   153,   154,   155,   315,   156,   157,   158,   159,   160,
+     161,   162,   199,   164,   165,   166,   167,   168,   169,   170,
+     171,   172,   173,   174,   175,   200,   201,   297,   202,   177,
+     108,   203,   204,    63,    64,    65,   125,    99,   100,   126,
+      66,    67,    68,    69,   101,    70,    71,    72,    73,    74,
+     120,   121,   178,    76,    77,   180,   118,   137,   138,   228,
+     229,   225,   206,   207,   208,   209,   285,   378,   405,   342,
+     343,   344,   406,   210,   211,   212,   391,   213,   392,   214,
+     377,   215,   350,   274,   345,   371,   388,   389,   216,    78,
+      79,    80,    92
 };
 
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
@@ -962,461 +962,454 @@
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_int16 yytable[] =
 {
-      74,   108,   233,   300,   223,   122,   134,   175,    83,    82,
-      94,   222,   304,   230,    60,   367,   134,    61,   311,     7,
-     180,   361,    89,   263,   374,   129,   175,   130,    87,   362,
-     219,   126,    92,   242,   131,   134,    90,   220,   389,   135,
-      93,    95,    96,    97,   103,   374,   278,   250,   251,   135,
-      27,    28,   101,    29,    80,   102,   312,   230,   264,   126,
-      88,    37,    38,    39,   182,   403,   225,   410,   135,    74,
-     183,   403,   109,   280,   248,   104,   249,    74,   134,   134,
-     110,   239,   266,   111,   115,   118,    81,   240,   175,   114,
-     313,    60,   315,   223,    61,   371,   297,   356,   128,    74,
-     303,   297,   252,   253,   234,   235,   -94,    74,   372,    85,
-      86,   135,   135,   319,   297,   175,     7,    74,   407,   116,
-     339,   204,     7,   297,   297,   236,   298,    74,   121,   237,
-      94,   345,   256,   257,    74,   347,    74,   254,   255,   309,
-      83,    82,   310,   230,   300,   132,   379,    27,    28,   381,
-      29,    80,   297,    27,    28,   346,    29,   181,    37,    38,
-      39,    95,    96,    97,    37,   134,   268,   269,   309,   351,
-     352,   358,   395,     2,     3,     4,   178,   162,   223,    74,
-      74,   216,   353,   297,   364,   327,   328,   329,   330,   359,
-      95,    96,    97,   226,   411,   -27,   162,   175,   135,   245,
-     246,   247,   323,   324,   175,   373,   325,   326,   238,   204,
-     231,   232,   285,   286,   287,   288,   289,   290,   291,   292,
-     293,   294,   331,   332,   243,   258,   373,   223,   260,   244,
-     223,   295,   261,   259,   265,   262,   271,   384,   272,   274,
-     275,   397,   383,   276,   279,   281,   283,   282,   375,   -26,
-     301,   305,   308,   223,   408,   306,   366,   175,   162,   -21,
-    -231,   348,   355,   363,   354,   -28,    74,   365,   385,   375,
-     357,   297,   378,   382,   392,   223,   380,   393,   396,   394,
-     399,   398,   400,   318,   204,   162,   195,   402,   333,   335,
-     406,   412,   334,   336,   338,   217,   337,   123,    84,   127,
-     218,   307,   270,   360,   368,   409,   369,   108,   401,   350,
-     386,   320,   321,   322,   162,   162,   162,   162,   162,   162,
-     162,   162,   162,   162,   162,   162,   162,   162,   162,   162,
-     113,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   204,   204,     0,     0,     0,     0,   204,
-     204,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   162,     0,     0,
-     204,     0,     0,     0,   162,    74,     0,     0,     0,     0,
+      75,   109,   176,   135,   224,   123,   305,   301,    83,   234,
+      95,    61,   223,   135,    84,   181,   231,    62,   312,    95,
+      90,   176,   102,     7,   375,   103,   253,   254,   264,   390,
+     368,   127,   135,   243,   298,    88,   362,   299,   130,   136,
+     131,    96,    97,    98,   363,   375,    91,   132,    93,   136,
+      96,    97,    98,   279,    27,    28,   313,    29,   411,   127,
+     231,   255,   256,   265,   220,    37,   226,    89,   136,   179,
+      75,   221,    94,   110,   281,   135,   135,   267,    75,   249,
+     404,   250,   105,   176,   183,   116,   404,   111,   240,    61,
+     184,   357,   314,   224,   241,    62,   115,   372,   298,   316,
+      75,   304,   310,   298,   298,   311,   -94,   347,    75,   373,
+     176,   136,   136,   320,   408,   298,   310,   104,    75,   359,
+     298,   112,   205,   119,   235,   236,   117,   340,    75,     7,
+     328,   329,   330,   331,   122,    75,   129,    75,   346,   133,
+     380,    83,   348,   382,   217,   237,   231,    84,   301,   238,
+       2,     3,     4,    96,    97,    98,   246,   247,   248,   182,
+      27,    28,   135,    29,    81,   227,   396,    86,    87,   352,
+     353,    37,    38,    39,   251,   252,   257,   258,   224,   239,
+      75,    75,   163,   354,   269,   270,   298,   365,   412,   -27,
+     360,   259,   176,   324,   325,   261,    82,     7,   136,   176,
+     244,   163,   326,   327,   332,   333,   260,   262,   263,   266,
+     205,   272,   374,   273,   275,   232,   233,   286,   287,   288,
+     289,   290,   291,   292,   293,   294,   295,   224,    27,    28,
+     224,    29,    81,   374,   245,   276,   296,   385,   277,    37,
+      38,    39,   280,   384,   282,   376,   283,   -26,   398,   284,
+     302,   309,   176,   224,   306,   307,   367,   -21,  -232,   349,
+     356,   409,   355,   163,   358,   364,   376,    75,   298,   -28,
+     366,   379,   381,   383,   386,   224,   393,   394,   395,   400,
+     397,   399,   401,   196,   403,   205,   319,   334,   336,   335,
+     163,   407,   413,   338,   337,   124,   218,   339,   128,    85,
+     361,   271,   308,   410,   219,   369,   402,   109,   351,   370,
+     114,   387,     0,     0,     0,     0,   321,   322,   323,   163,
+     163,   163,   163,   163,   163,   163,   163,   163,   163,   163,
+     163,   163,   163,   163,   163,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   205,   205,     0,     0,     0,     0,
+     205,   205,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   204,     0,     0,     0,     0,     0,   204,
+       0,   205,   163,     0,     0,     0,    75,     0,     0,   163,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     1,     2,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,   184,   185,   186,   162,   187,   188,
-     189,   190,   191,   192,   193,    12,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-      27,    28,     0,    29,    30,    31,    32,    33,    34,    35,
-      36,    37,    38,    39,    40,    41,   194,    42,    43,    44,
-       0,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-      54,     0,    55,    56,    57,    58,   138,    59,   139,   140,
-     141,   142,   143,     0,     0,   144,   145,     0,     0,     0,
+       0,     0,     0,     0,   205,     0,     0,     0,     0,     0,
+     205,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     1,     2,
+       3,     4,     5,     6,     7,     8,     9,    10,    11,   185,
+     186,   187,   163,   188,   189,   190,   191,   192,   193,   194,
+      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,    24,    25,    26,    27,    28,     0,    29,    30,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+      41,   195,    42,    43,    44,    45,    46,    47,    48,    49,
+      50,    51,    52,    53,    54,    55,     0,    56,    57,    58,
+      59,   139,    60,   140,   141,   142,   143,   144,     0,     0,
+     145,   146,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   147,
+       0,     0,     0,   196,   197,     0,     0,     0,     0,   198,
+     149,   150,   151,   152,     1,     2,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,   185,   186,   187,     0,   188,
+     189,   190,   191,   192,   193,   194,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,     0,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,   195,    42,    43,
+      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+      54,    55,     0,    56,    57,    58,    59,   139,    60,   140,
+     141,   142,   143,   144,     0,     0,   145,   146,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   146,     0,     0,     0,   195,   196,
-       0,     0,     0,     0,   197,   148,   149,   150,   151,     1,
-       2,     3,     4,     5,     6,     7,     8,     9,    10,    11,
-     184,   185,   186,     0,   187,   188,   189,   190,   191,   192,
-     193,    12,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,    23,    24,    25,    26,    27,    28,     0,    29,
-      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
-      40,    41,   194,    42,    43,    44,     0,    45,    46,    47,
-      48,    49,    50,    51,    52,    53,    54,     0,    55,    56,
-      57,    58,   138,    59,   139,   140,   141,   142,   143,     0,
-       0,   144,   145,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     146,     0,     0,     0,   195,   299,     0,     0,     0,     0,
-     197,   148,   149,   150,   151,     1,     2,     3,     4,     5,
-       6,     7,     8,     9,    10,    11,   184,   185,   186,     0,
-     187,   188,   189,   190,   191,   192,   193,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,     0,    29,    30,    31,    32,    33,
-      34,    35,    36,    37,    38,    39,    40,    41,   194,    42,
-      43,    44,     0,    45,    46,    47,    48,    49,    50,    51,
-      52,    53,    54,     0,    55,    56,    57,    58,   138,    59,
-     139,   140,   141,   142,   143,     0,     0,   144,   145,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   146,     0,     0,     0,
-     195,     0,     0,     0,     0,     0,   197,   148,   149,   150,
-     151,     1,     2,     3,     4,     5,     6,     7,     8,     9,
-      10,    11,   184,   185,   186,     0,   187,   188,   189,   190,
-     191,   192,   193,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-       0,    29,    30,    31,    32,    33,    34,    35,    36,    37,
-      38,    39,    40,    41,   194,    42,    43,    44,     0,    45,
-      46,    47,    48,    49,    50,    51,    52,    53,    54,     0,
-      55,    56,    57,    58,   138,    59,   139,   140,   141,   142,
-     143,     0,     0,   144,   145,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   146,     0,     0,     0,   121,     0,     0,     0,
-       0,     0,   197,   148,   149,   150,   151,     1,     2,     3,
-       4,     5,     6,     7,     8,     9,    10,    11,   184,   185,
-     186,     0,   187,   188,   189,   190,   191,   192,   193,    12,
-      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,     0,    29,    30,    31,
-      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
-     194,    42,    43,    44,     0,    45,    46,    47,    48,    49,
-      50,    51,    52,    53,    54,     0,    55,    56,    57,    58,
-     138,    59,   139,   140,   141,   142,   143,     0,     0,   144,
-     145,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   146,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   197,   148,
-     149,   150,   151,     1,     2,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    12,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-      27,    28,     0,    29,    30,    31,    32,    33,    34,    35,
-      36,    37,    38,    39,    40,    41,     0,    42,    43,    44,
-       0,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-      54,     0,    55,    56,    57,    58,   138,    59,   139,   140,
-     141,   142,   143,     0,     0,   144,   145,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     133,     2,     3,     4,   146,     6,     7,     8,     9,    10,
-      11,     0,     0,     0,   197,   148,   149,   150,   151,     0,
-       0,     0,    12,    13,    14,    15,    16,    17,    18,    19,
+       0,     0,     0,     0,     0,   147,     0,     0,     0,   196,
+     300,     0,     0,     0,     0,   198,   149,   150,   151,   152,
+       1,     2,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,   185,   186,   187,     0,   188,   189,   190,   191,   192,
+     193,   194,    12,    13,    14,    15,    16,    17,    18,    19,
       20,    21,    22,    23,    24,    25,    26,    27,    28,     0,
       29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
-      39,    40,    41,     0,    42,    43,    44,     0,    45,    46,
-      47,    48,    49,    50,    51,    52,    53,    54,     0,    55,
-      56,    57,    58,   138,    59,   139,   140,   141,   142,   143,
-       0,     0,   144,   145,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     2,     3,     4,     0,
-       0,   146,     8,     9,    10,    11,     0,     0,     0,     0,
-       0,     0,   148,   149,   150,   151,     0,    12,    13,    14,
+      39,    40,    41,   195,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,     0,    56,
+      57,    58,    59,   139,    60,   140,   141,   142,   143,   144,
+       0,     0,   145,   146,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   147,     0,     0,     0,   196,     0,     0,     0,     0,
+       0,   198,   149,   150,   151,   152,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,   185,   186,   187,
+       0,   188,   189,   190,   191,   192,   193,   194,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,     0,    29,    30,    31,    32,
+      33,    34,    35,    36,    37,    38,    39,    40,    41,   195,
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,     0,    56,    57,    58,    59,   139,
+      60,   140,   141,   142,   143,   144,     0,     0,   145,   146,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   147,     0,     0,
+       0,   122,     0,     0,     0,     0,     0,   198,   149,   150,
+     151,   152,     1,     2,     3,     4,     5,     6,     7,     8,
+       9,    10,    11,   185,   186,   187,     0,   188,   189,   190,
+     191,   192,   193,   194,    12,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,     0,    29,    30,    31,    32,    33,    34,    35,    36,
+      37,    38,    39,    40,    41,   195,    42,    43,    44,    45,
+      46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
+       0,    56,    57,    58,    59,   139,    60,   140,   141,   142,
+     143,   144,     0,     0,   145,   146,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   147,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   198,   149,   150,   151,   152,     1,     2,
+       3,     4,     5,     6,     7,     8,     9,    10,    11,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,    24,    25,    26,    27,    28,     0,    29,    30,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+      41,     0,    42,    43,    44,    45,    46,    47,    48,    49,
+      50,    51,    52,    53,    54,    55,     0,    56,    57,    58,
+      59,   139,    60,   140,   141,   142,   143,   144,     0,     0,
+     145,   146,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   134,     2,     3,     4,   147,
+       6,     7,     8,     9,    10,    11,     0,     0,     0,   198,
+     149,   150,   151,   152,     0,     0,     0,    12,    13,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,     0,     0,     0,     0,     0,    31,    32,    33,
-      34,    35,    36,     0,     0,     0,    40,    41,     0,    42,
-      43,    44,     0,    45,    46,    47,    48,    49,    50,    51,
-      52,    53,    54,     0,    55,    56,    57,     0,   105,    59,
-       0,     0,     8,     9,    10,    11,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,     0,     0,     0,     0,   106,    31,    32,    33,
-      34,    35,    36,     0,     0,     0,    40,    41,     0,    42,
-      43,    44,     0,    45,    46,    47,    48,    49,    50,    51,
-      52,    53,    54,     0,    55,    56,    57,     0,   138,    59,
-     139,   140,   141,   142,   143,     0,     0,   144,   145,     0,
+      25,    26,    27,    28,     0,    29,    30,    31,    32,    33,
+      34,    35,    36,    37,    38,    39,    40,    41,     0,    42,
+      43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
+      53,    54,    55,     0,    56,    57,    58,    59,   139,    60,
+     140,   141,   142,   143,   144,     0,     0,   145,   146,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   146,     0,     0,   147,
-       8,     9,    10,    11,     0,     0,     0,   148,   149,   150,
-     151,     0,     0,     0,     0,    12,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-       0,     0,     0,     0,     0,    31,    32,    33,    34,    35,
-      36,     0,     0,     0,    40,    41,     0,    42,    43,    44,
-       0,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-      54,     0,    55,    56,    57,     0,   138,    59,   139,   140,
-     141,   142,   143,     0,     0,   144,   145,     0,     0,     0,
+       0,     2,     3,     4,     0,     0,   147,     8,     9,    10,
+      11,     0,     0,     0,     0,     0,     0,   149,   150,   151,
+     152,     0,    12,    13,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,    25,    26,     0,     0,     0,
+       0,     0,    31,    32,    33,    34,    35,    36,     0,     0,
+       0,    40,    41,     0,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,     0,    56,
+      57,    58,     0,   106,    60,     0,     0,     8,     9,    10,
+      11,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    12,    13,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,    25,    26,     0,     0,     0,
+       0,   107,    31,    32,    33,    34,    35,    36,     0,     0,
+       0,    40,    41,     0,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,     0,    56,
+      57,    58,     0,   139,    60,   140,   141,   142,   143,   144,
+       0,     0,   145,   146,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   146,     0,     0,   221,     8,     9,
-      10,    11,     0,     0,     0,   148,   149,   150,   151,     0,
-       0,     0,     0,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,    24,    25,    26,     0,     0,
-       0,     0,     0,    31,    32,    33,    34,    35,    36,     0,
-       0,     0,    40,    41,     0,    42,    43,    44,     0,    45,
-      46,    47,    48,    49,    50,    51,    52,    53,    54,     0,
-      55,    56,    57,     0,   138,    59,   139,   140,   141,   142,
-     143,     0,     0,   144,   145,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   146,     8,     9,    10,    11,     0,     0,     0,
-       0,     0,   277,   148,   149,   150,   151,     0,    12,    13,
+       0,   147,     0,     0,   148,     8,     9,    10,    11,     0,
+       0,     0,   149,   150,   151,   152,     0,     0,     0,     0,
+      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,    24,    25,    26,     0,     0,     0,     0,     0,
+      31,    32,    33,    34,    35,    36,     0,     0,     0,    40,
+      41,     0,    42,    43,    44,    45,    46,    47,    48,    49,
+      50,    51,    52,    53,    54,    55,     0,    56,    57,    58,
+       0,   139,    60,   140,   141,   142,   143,   144,     0,     0,
+     145,   146,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   147,
+       0,     0,   222,     8,     9,    10,    11,     0,     0,     0,
+     149,   150,   151,   152,     0,     0,     0,     0,    12,    13,
       14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
       24,    25,    26,     0,     0,     0,     0,     0,    31,    32,
       33,    34,    35,    36,     0,     0,     0,    40,    41,     0,
-      42,    43,    44,     0,    45,    46,    47,    48,    49,    50,
-      51,    52,    53,    54,     0,    55,    56,    57,     0,   138,
-      59,   139,   140,   141,   142,   143,     0,     0,   144,   145,
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,     0,    56,    57,    58,     0,   139,
+      60,   140,   141,   142,   143,   144,     0,     0,   145,   146,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   146,     0,     0,
-     302,     8,     9,    10,    11,     0,     0,     0,   148,   149,
-     150,   151,     0,     0,     0,     0,    12,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
-      26,     0,     0,     0,     0,     0,    31,    32,    33,    34,
-      35,    36,     0,     0,     0,    40,    41,     0,    42,    43,
-      44,     0,    45,    46,    47,    48,    49,    50,    51,    52,
-      53,    54,     0,    55,    56,    57,     0,   138,    59,   139,
-     140,   141,   142,   143,     0,     0,   144,   145,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   147,     8,     9,
+      10,    11,     0,     0,     0,     0,     0,   278,   149,   150,
+     151,   152,     0,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,     0,     0,
+       0,     0,     0,    31,    32,    33,    34,    35,    36,     0,
+       0,     0,    40,    41,     0,    42,    43,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    54,    55,     0,
+      56,    57,    58,     0,   139,    60,   140,   141,   142,   143,
+     144,     0,     0,   145,   146,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   146,     8,     9,    10,    11,
-       0,     0,     0,     0,     0,     0,   148,   149,   150,   151,
+       0,     0,   147,     0,     0,   303,     8,     9,    10,    11,
+       0,     0,     0,   149,   150,   151,   152,     0,     0,     0,
        0,    12,    13,    14,    15,    16,    17,    18,    19,    20,
       21,    22,    23,    24,    25,    26,     0,     0,     0,     0,
        0,    31,    32,    33,    34,    35,    36,     0,     0,     0,
-      40,   241,     0,    42,    43,    44,     0,    45,    46,    47,
-      48,    49,    50,    51,    52,    53,    54,     0,    55,    56,
-      57,     0,   138,    59,   139,   140,   141,   142,   143,     0,
-       0,   144,   145,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   133,     2,     3,     4,
-     146,     6,     7,     8,     9,    10,    11,     0,     0,     0,
-       0,   148,   149,   150,   151,     0,     0,     0,    12,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-      24,    25,    26,    27,    28,     0,    29,    30,    31,    32,
-      33,    34,    35,    36,    37,    38,    39,    40,    41,     0,
-      42,    43,    44,     0,    45,    46,    47,    48,    49,    50,
-      51,    52,    53,    54,     0,    55,    56,    57,    58,     0,
-      59,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,   133,     2,     3,     4,     0,     6,     7,     8,     9,
-      10,    11,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   229,    12,    13,    14,    15,    16,    17,    18,
+      40,    41,     0,    42,    43,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    54,    55,     0,    56,    57,
+      58,     0,   139,    60,   140,   141,   142,   143,   144,     0,
+       0,   145,   146,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     147,     8,     9,    10,    11,     0,     0,     0,     0,     0,
+       0,   149,   150,   151,   152,     0,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,     0,     0,     0,     0,     0,    31,    32,    33,    34,
+      35,    36,     0,     0,     0,    40,   242,     0,    42,    43,
+      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+      54,    55,     0,    56,    57,    58,     0,   139,    60,   140,
+     141,   142,   143,   144,     0,     0,   145,   146,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   134,     2,     3,     4,   147,     6,     7,     8,     9,
+      10,    11,     0,     0,     0,     0,   149,   150,   151,   152,
+       0,     0,     0,    12,    13,    14,    15,    16,    17,    18,
       19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
        0,    29,    30,    31,    32,    33,    34,    35,    36,    37,
-      38,    39,    40,    41,     0,    42,    43,    44,     0,    45,
-      46,    47,    48,    49,    50,    51,    52,    53,    54,     0,
-      55,    56,    57,    58,     0,    59,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   133,     2,     3,     4,
+      38,    39,    40,    41,     0,    42,    43,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    54,    55,     0,
+      56,    57,    58,    59,     0,    60,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   134,     2,     3,     4,
        0,     6,     7,     8,     9,    10,    11,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   267,    12,    13,
+       0,     0,     0,     0,     0,     0,     0,   230,    12,    13,
       14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
       24,    25,    26,    27,    28,     0,    29,    30,    31,    32,
       33,    34,    35,    36,    37,    38,    39,    40,    41,     0,
-      42,    43,    44,     0,    45,    46,    47,    48,    49,    50,
-      51,    52,    53,    54,     0,    55,    56,    57,    58,     0,
-      59,     0,     0,     0,     0,     0,     0,     0,   112,     0,
-       0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,     0,    56,    57,    58,    59,     0,
+      60,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   134,     2,     3,     4,     0,     6,     7,     8,     9,
       10,    11,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   340,    12,    13,    14,    15,    16,    17,    18,
+       0,     0,   268,    12,    13,    14,    15,    16,    17,    18,
       19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
        0,    29,    30,    31,    32,    33,    34,    35,    36,    37,
-      38,    39,    40,    41,     0,    42,    43,    44,     0,    45,
-      46,    47,    48,    49,    50,    51,    52,    53,    54,     0,
-      55,    56,    57,    58,     0,    59,     1,     2,     3,     4,
+      38,    39,    40,    41,     0,    42,    43,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    54,    55,     0,
+      56,    57,    58,    59,     0,    60,     0,     0,     0,     0,
+       0,     0,     0,   113,     0,     0,     1,     2,     3,     4,
        5,     6,     7,     8,     9,    10,    11,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   341,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,     0,    29,    30,    31,    32,
+      33,    34,    35,    36,    37,    38,    39,    40,    41,     0,
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,     0,    56,    57,    58,    59,     0,
+      60,     1,     2,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+       0,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+      38,    39,    40,    41,     0,    42,    43,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    54,    55,     0,
+      56,    57,    58,    59,     0,    60,   134,     2,     3,     4,
+       0,     6,     7,     8,     9,    10,    11,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,    12,    13,
       14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
       24,    25,    26,    27,    28,     0,    29,    30,    31,    32,
       33,    34,    35,    36,    37,    38,    39,    40,    41,     0,
-      42,    43,    44,     0,    45,    46,    47,    48,    49,    50,
-      51,    52,    53,    54,     0,    55,    56,    57,    58,     0,
-      59,   133,     2,     3,     4,     0,     6,     7,     8,     9,
-      10,    11,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-       0,    29,    30,    31,    32,    33,    34,    35,    36,    37,
-      38,    39,    40,    41,     0,    42,    43,    44,     0,    45,
-      46,    47,    48,    49,    50,    51,    52,    53,    54,     0,
-      55,    56,    57,    58,     0,    59,     2,     3,     4,     0,
-       0,     0,     8,     9,    10,    11,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,     0,     0,     0,     0,     0,    31,    32,    33,
-      34,    35,    36,     0,     0,     0,    40,    41,     0,    42,
-      43,    44,     0,    45,    46,    47,    48,    49,    50,    51,
-      52,    53,    54,     0,    55,    56,    57,     0,     0,    59,
-       8,     9,    10,    11,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    12,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-       0,     0,     0,     0,     0,    31,    32,    33,    34,    35,
-      36,     0,     0,     0,    40,    41,     0,    42,    43,    44,
-       0,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-      54,     0,    55,    56,    57,     0,   316,    59,     8,     9,
-      10,    11,   317,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,    24,    25,    26,     0,     0,
-       0,     0,     0,    31,    32,    33,    34,    35,    36,     0,
-       0,     0,    40,    41,     0,    42,    43,    44,     0,    45,
-      46,    47,    48,    49,    50,    51,    52,    53,    54,     0,
-      55,    56,    57,     0,     0,    59
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,     0,    56,    57,    58,    59,     0,
+      60,     2,     3,     4,     0,     0,     0,     8,     9,    10,
+      11,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    12,    13,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,    25,    26,     0,     0,     0,
+       0,     0,    31,    32,    33,    34,    35,    36,     0,     0,
+       0,    40,    41,     0,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,     0,    56,
+      57,    58,     0,     0,    60,     8,     9,    10,    11,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,    24,    25,    26,     0,     0,     0,     0,     0,
+      31,    32,    33,    34,    35,    36,     0,     0,     0,    40,
+      41,     0,    42,    43,    44,    45,    46,    47,    48,    49,
+      50,    51,    52,    53,    54,    55,     0,    56,    57,    58,
+       0,   317,    60,     8,     9,    10,    11,   318,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,     0,     0,     0,     0,     0,    31,    32,
+      33,    34,    35,    36,     0,     0,     0,    40,    41,     0,
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,    53,    54,    55,     0,    56,    57,    58,     0,     0,
+      60
 };
 
 static const yytype_int16 yycheck[] =
 {
-       0,    69,   146,   209,   131,    91,   107,   111,     1,     1,
-       9,   130,   220,   136,     0,   343,   117,     0,    76,     9,
-     117,   106,   104,    92,   349,   104,   130,   106,    76,   114,
-     106,    99,   105,   160,   113,   136,   114,   113,   371,   107,
-     111,    40,    41,    42,    76,   370,   190,    83,    84,   117,
-      40,    41,   111,    43,    44,   114,   114,   180,   127,   127,
-     108,    51,    52,    53,   105,   393,   134,   400,   136,    69,
-     111,   399,    72,   192,   116,    68,   118,    77,   179,   180,
-      73,   105,   179,   106,    84,    76,    76,   111,   192,    82,
-     105,    77,   236,   220,    77,   105,   111,   305,    76,    99,
-     219,   111,    87,    88,    85,    86,   105,   107,   105,    40,
-      41,   179,   180,   240,   111,   219,     9,   117,   105,   108,
-     264,   121,     9,   111,   111,   106,   114,   127,   108,   110,
-       9,   275,    89,    90,   134,   279,   136,   122,   123,   111,
-     133,   133,   114,   266,   350,   108,   354,    40,    41,   357,
-      43,    44,   111,    40,    41,   114,    43,   113,    51,    52,
-      53,    40,    41,    42,    51,   266,    79,    80,   111,   296,
-     297,   114,   380,     4,     5,     6,   114,   111,   305,   179,
-     180,    76,   301,   111,   112,   252,   253,   254,   255,   308,
-      40,    41,    42,    76,   402,   104,   130,   301,   266,   119,
-     120,   121,   248,   249,   308,   349,   250,   251,   105,   209,
-     144,   145,    94,    95,    96,    97,    98,    99,   100,   101,
-     102,   103,   256,   257,   104,   126,   370,   354,   124,   163,
-     357,   113,    91,   125,   107,    93,   114,   364,   114,   104,
-     104,   385,   361,   114,   104,   112,   109,   104,   349,   104,
-     106,   113,   106,   380,   398,   107,   342,   361,   192,   105,
-     108,   112,   107,   107,   113,   104,   266,    56,   104,   370,
-     113,   111,   107,   107,    76,   402,   113,   105,   107,   109,
-     105,   114,    17,   237,   284,   219,   108,   113,   258,   260,
-     114,   114,   259,   261,   263,   127,   262,    93,     5,   100,
-     127,   225,   183,   309,   344,   399,   344,   375,   391,   284,
-     370,   245,   246,   247,   248,   249,   250,   251,   252,   253,
-     254,   255,   256,   257,   258,   259,   260,   261,   262,   263,
-      77,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,   343,   344,    -1,    -1,    -1,    -1,   349,
-     350,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,   301,    -1,    -1,
-     370,    -1,    -1,    -1,   308,   375,    -1,    -1,    -1,    -1,
+       0,    70,   112,   108,   132,    92,   221,   210,     1,   147,
+       9,     0,   131,   118,     1,   118,   137,     0,    76,     9,
+     104,   131,   111,     9,   350,   114,    87,    88,    92,   372,
+     344,   100,   137,   161,   111,    76,   106,   114,   104,   108,
+     106,    40,    41,    42,   114,   371,   114,   113,   105,   118,
+      40,    41,    42,   191,    40,    41,   114,    43,   401,   128,
+     181,   122,   123,   127,   106,    51,   135,   108,   137,   114,
+      70,   113,   111,    73,   193,   180,   181,   180,    78,   116,
+     394,   118,    69,   193,   105,    85,   400,    74,   105,    78,
+     111,   306,   105,   221,   111,    78,    83,   105,   111,   237,
+     100,   220,   111,   111,   111,   114,   105,   114,   108,   105,
+     220,   180,   181,   241,   105,   111,   111,    76,   118,   114,
+     111,   106,   122,    76,    85,    86,   108,   265,   128,     9,
+     253,   254,   255,   256,   108,   135,    76,   137,   276,   108,
+     355,   134,   280,   358,    76,   106,   267,   134,   351,   110,
+       4,     5,     6,    40,    41,    42,   119,   120,   121,   113,
+      40,    41,   267,    43,    44,    76,   381,    40,    41,   297,
+     298,    51,    52,    53,    83,    84,    89,    90,   306,   105,
+     180,   181,   112,   302,    79,    80,   111,   112,   403,   104,
+     309,   126,   302,   249,   250,   124,    76,     9,   267,   309,
+     104,   131,   251,   252,   257,   258,   125,    91,    93,   107,
+     210,   114,   350,   114,   104,   145,   146,    94,    95,    96,
+      97,    98,    99,   100,   101,   102,   103,   355,    40,    41,
+     358,    43,    44,   371,   164,   104,   113,   365,   114,    51,
+      52,    53,   104,   362,   112,   350,   104,   104,   386,   109,
+     106,   106,   362,   381,   113,   107,   343,   105,   108,   112,
+     107,   399,   113,   193,   113,   107,   371,   267,   111,   104,
+      56,   107,   113,   107,   104,   403,    76,   105,   109,   105,
+     107,   114,    17,   108,   113,   285,   238,   259,   261,   260,
+     220,   114,   114,   263,   262,    94,   128,   264,   101,     5,
+     310,   184,   226,   400,   128,   345,   392,   376,   285,   345,
+      78,   371,    -1,    -1,    -1,    -1,   246,   247,   248,   249,
+     250,   251,   252,   253,   254,   255,   256,   257,   258,   259,
+     260,   261,   262,   263,   264,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   344,   345,    -1,    -1,    -1,    -1,
+     350,   351,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,   393,    -1,    -1,    -1,    -1,    -1,   399,
+      -1,   371,   302,    -1,    -1,    -1,   376,    -1,    -1,   309,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,     3,     4,     5,     6,     7,     8,     9,
-      10,    11,    12,    13,    14,    15,    16,   361,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
-      40,    41,    -1,    43,    44,    45,    46,    47,    48,    49,
-      50,    51,    52,    53,    54,    55,    56,    57,    58,    59,
-      -1,    61,    62,    63,    64,    65,    66,    67,    68,    69,
-      70,    -1,    72,    73,    74,    75,    76,    77,    78,    79,
-      80,    81,    82,    -1,    -1,    85,    86,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   394,    -1,    -1,    -1,    -1,    -1,
+     400,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,   362,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,    -1,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    -1,    72,    73,    74,
+      75,    76,    77,    78,    79,    80,    81,    82,    -1,    -1,
+      85,    86,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   104,
+      -1,    -1,    -1,   108,   109,    -1,    -1,    -1,    -1,   114,
+     115,   116,   117,   118,     3,     4,     5,     6,     7,     8,
+       9,    10,    11,    12,    13,    14,    15,    16,    -1,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    40,    41,    -1,    43,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,    60,    61,    62,    63,    64,    65,    66,    67,    68,
+      69,    70,    -1,    72,    73,    74,    75,    76,    77,    78,
+      79,    80,    81,    82,    -1,    -1,    85,    86,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,   104,    -1,    -1,    -1,   108,   109,
-      -1,    -1,    -1,    -1,   114,   115,   116,   117,   118,     3,
-       4,     5,     6,     7,     8,     9,    10,    11,    12,    13,
-      14,    15,    16,    -1,    18,    19,    20,    21,    22,    23,
-      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
-      34,    35,    36,    37,    38,    39,    40,    41,    -1,    43,
-      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-      54,    55,    56,    57,    58,    59,    -1,    61,    62,    63,
-      64,    65,    66,    67,    68,    69,    70,    -1,    72,    73,
-      74,    75,    76,    77,    78,    79,    80,    81,    82,    -1,
-      -1,    85,    86,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-     104,    -1,    -1,    -1,   108,   109,    -1,    -1,    -1,    -1,
-     114,   115,   116,   117,   118,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    13,    14,    15,    16,    -1,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
-      38,    39,    40,    41,    -1,    43,    44,    45,    46,    47,
-      48,    49,    50,    51,    52,    53,    54,    55,    56,    57,
-      58,    59,    -1,    61,    62,    63,    64,    65,    66,    67,
-      68,    69,    70,    -1,    72,    73,    74,    75,    76,    77,
-      78,    79,    80,    81,    82,    -1,    -1,    85,    86,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   104,    -1,    -1,    -1,
-     108,    -1,    -1,    -1,    -1,    -1,   114,   115,   116,   117,
-     118,     3,     4,     5,     6,     7,     8,     9,    10,    11,
-      12,    13,    14,    15,    16,    -1,    18,    19,    20,    21,
-      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
-      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
-      -1,    43,    44,    45,    46,    47,    48,    49,    50,    51,
-      52,    53,    54,    55,    56,    57,    58,    59,    -1,    61,
-      62,    63,    64,    65,    66,    67,    68,    69,    70,    -1,
-      72,    73,    74,    75,    76,    77,    78,    79,    80,    81,
-      82,    -1,    -1,    85,    86,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   104,    -1,    -1,    -1,   108,    -1,    -1,    -1,
-      -1,    -1,   114,   115,   116,   117,   118,     3,     4,     5,
-       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      16,    -1,    18,    19,    20,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
-      36,    37,    38,    39,    40,    41,    -1,    43,    44,    45,
-      46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
-      56,    57,    58,    59,    -1,    61,    62,    63,    64,    65,
-      66,    67,    68,    69,    70,    -1,    72,    73,    74,    75,
-      76,    77,    78,    79,    80,    81,    82,    -1,    -1,    85,
-      86,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   104,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   114,   115,
-     116,   117,   118,     3,     4,     5,     6,     7,     8,     9,
-      10,    11,    12,    13,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    25,    26,    27,    28,    29,
-      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
-      40,    41,    -1,    43,    44,    45,    46,    47,    48,    49,
-      50,    51,    52,    53,    54,    55,    -1,    57,    58,    59,
-      -1,    61,    62,    63,    64,    65,    66,    67,    68,    69,
-      70,    -1,    72,    73,    74,    75,    76,    77,    78,    79,
-      80,    81,    82,    -1,    -1,    85,    86,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-       3,     4,     5,     6,   104,     8,     9,    10,    11,    12,
-      13,    -1,    -1,    -1,   114,   115,   116,   117,   118,    -1,
-      -1,    -1,    25,    26,    27,    28,    29,    30,    31,    32,
+      -1,    -1,    -1,    -1,    -1,   104,    -1,    -1,    -1,   108,
+     109,    -1,    -1,    -1,    -1,   114,   115,   116,   117,   118,
+       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
+      13,    14,    15,    16,    -1,    18,    19,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
       33,    34,    35,    36,    37,    38,    39,    40,    41,    -1,
       43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
-      53,    54,    55,    -1,    57,    58,    59,    -1,    61,    62,
+      53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
       63,    64,    65,    66,    67,    68,    69,    70,    -1,    72,
       73,    74,    75,    76,    77,    78,    79,    80,    81,    82,
       -1,    -1,    85,    86,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,     4,     5,     6,    -1,
-      -1,   104,    10,    11,    12,    13,    -1,    -1,    -1,    -1,
-      -1,    -1,   115,   116,   117,   118,    -1,    25,    26,    27,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,   104,    -1,    -1,    -1,   108,    -1,    -1,    -1,    -1,
+      -1,   114,   115,   116,   117,   118,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
+      -1,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+      37,    38,    39,    40,    41,    -1,    43,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    54,    55,    56,
+      57,    58,    59,    60,    61,    62,    63,    64,    65,    66,
+      67,    68,    69,    70,    -1,    72,    73,    74,    75,    76,
+      77,    78,    79,    80,    81,    82,    -1,    -1,    85,    86,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   104,    -1,    -1,
+      -1,   108,    -1,    -1,    -1,    -1,    -1,   114,   115,   116,
+     117,   118,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    13,    14,    15,    16,    -1,    18,    19,    20,
+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+      41,    -1,    43,    44,    45,    46,    47,    48,    49,    50,
+      51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+      61,    62,    63,    64,    65,    66,    67,    68,    69,    70,
+      -1,    72,    73,    74,    75,    76,    77,    78,    79,    80,
+      81,    82,    -1,    -1,    85,    86,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   104,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   114,   115,   116,   117,   118,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,    -1,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    -1,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    -1,    72,    73,    74,
+      75,    76,    77,    78,    79,    80,    81,    82,    -1,    -1,
+      85,    86,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,     3,     4,     5,     6,   104,
+       8,     9,    10,    11,    12,    13,    -1,    -1,    -1,   114,
+     115,   116,   117,   118,    -1,    -1,    -1,    25,    26,    27,
       28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
-      38,    39,    -1,    -1,    -1,    -1,    -1,    45,    46,    47,
-      48,    49,    50,    -1,    -1,    -1,    54,    55,    -1,    57,
-      58,    59,    -1,    61,    62,    63,    64,    65,    66,    67,
-      68,    69,    70,    -1,    72,    73,    74,    -1,    76,    77,
-      -1,    -1,    10,    11,    12,    13,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    25,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
-      38,    39,    -1,    -1,    -1,    -1,   114,    45,    46,    47,
-      48,    49,    50,    -1,    -1,    -1,    54,    55,    -1,    57,
-      58,    59,    -1,    61,    62,    63,    64,    65,    66,    67,
-      68,    69,    70,    -1,    72,    73,    74,    -1,    76,    77,
+      38,    39,    40,    41,    -1,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,    -1,    57,
+      58,    59,    60,    61,    62,    63,    64,    65,    66,    67,
+      68,    69,    70,    -1,    72,    73,    74,    75,    76,    77,
       78,    79,    80,    81,    82,    -1,    -1,    85,    86,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   104,    -1,    -1,   107,
-      10,    11,    12,    13,    -1,    -1,    -1,   115,   116,   117,
-     118,    -1,    -1,    -1,    -1,    25,    26,    27,    28,    29,
-      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
-      -1,    -1,    -1,    -1,    -1,    45,    46,    47,    48,    49,
-      50,    -1,    -1,    -1,    54,    55,    -1,    57,    58,    59,
-      -1,    61,    62,    63,    64,    65,    66,    67,    68,    69,
-      70,    -1,    72,    73,    74,    -1,    76,    77,    78,    79,
-      80,    81,    82,    -1,    -1,    85,    86,    -1,    -1,    -1,
+      -1,     4,     5,     6,    -1,    -1,   104,    10,    11,    12,
+      13,    -1,    -1,    -1,    -1,    -1,    -1,   115,   116,   117,
+     118,    -1,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    34,    35,    36,    37,    38,    39,    -1,    -1,    -1,
+      -1,    -1,    45,    46,    47,    48,    49,    50,    -1,    -1,
+      -1,    54,    55,    -1,    57,    58,    59,    60,    61,    62,
+      63,    64,    65,    66,    67,    68,    69,    70,    -1,    72,
+      73,    74,    -1,    76,    77,    -1,    -1,    10,    11,    12,
+      13,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    34,    35,    36,    37,    38,    39,    -1,    -1,    -1,
+      -1,   114,    45,    46,    47,    48,    49,    50,    -1,    -1,
+      -1,    54,    55,    -1,    57,    58,    59,    60,    61,    62,
+      63,    64,    65,    66,    67,    68,    69,    70,    -1,    72,
+      73,    74,    -1,    76,    77,    78,    79,    80,    81,    82,
+      -1,    -1,    85,    86,    -1,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,   104,    -1,    -1,   107,    10,    11,
-      12,    13,    -1,    -1,    -1,   115,   116,   117,   118,    -1,
-      -1,    -1,    -1,    25,    26,    27,    28,    29,    30,    31,
+      -1,   104,    -1,    -1,   107,    10,    11,    12,    13,    -1,
+      -1,    -1,   115,   116,   117,   118,    -1,    -1,    -1,    -1,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    -1,    -1,    -1,    -1,    -1,
+      45,    46,    47,    48,    49,    50,    -1,    -1,    -1,    54,
+      55,    -1,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    -1,    72,    73,    74,
+      -1,    76,    77,    78,    79,    80,    81,    82,    -1,    -1,
+      85,    86,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   104,
+      -1,    -1,   107,    10,    11,    12,    13,    -1,    -1,    -1,
+     115,   116,   117,   118,    -1,    -1,    -1,    -1,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+      37,    38,    39,    -1,    -1,    -1,    -1,    -1,    45,    46,
+      47,    48,    49,    50,    -1,    -1,    -1,    54,    55,    -1,
+      57,    58,    59,    60,    61,    62,    63,    64,    65,    66,
+      67,    68,    69,    70,    -1,    72,    73,    74,    -1,    76,
+      77,    78,    79,    80,    81,    82,    -1,    -1,    85,    86,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   104,    10,    11,
+      12,    13,    -1,    -1,    -1,    -1,    -1,   114,   115,   116,
+     117,   118,    -1,    25,    26,    27,    28,    29,    30,    31,
       32,    33,    34,    35,    36,    37,    38,    39,    -1,    -1,
       -1,    -1,    -1,    45,    46,    47,    48,    49,    50,    -1,
-      -1,    -1,    54,    55,    -1,    57,    58,    59,    -1,    61,
+      -1,    -1,    54,    55,    -1,    57,    58,    59,    60,    61,
       62,    63,    64,    65,    66,    67,    68,    69,    70,    -1,
       72,    73,    74,    -1,    76,    77,    78,    79,    80,    81,
       82,    -1,    -1,    85,    86,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   104,    10,    11,    12,    13,    -1,    -1,    -1,
-      -1,    -1,   114,   115,   116,   117,   118,    -1,    25,    26,
-      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
-      37,    38,    39,    -1,    -1,    -1,    -1,    -1,    45,    46,
-      47,    48,    49,    50,    -1,    -1,    -1,    54,    55,    -1,
-      57,    58,    59,    -1,    61,    62,    63,    64,    65,    66,
-      67,    68,    69,    70,    -1,    72,    73,    74,    -1,    76,
-      77,    78,    79,    80,    81,    82,    -1,    -1,    85,    86,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,   104,    -1,    -1,
-     107,    10,    11,    12,    13,    -1,    -1,    -1,   115,   116,
-     117,   118,    -1,    -1,    -1,    -1,    25,    26,    27,    28,
-      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
-      39,    -1,    -1,    -1,    -1,    -1,    45,    46,    47,    48,
-      49,    50,    -1,    -1,    -1,    54,    55,    -1,    57,    58,
-      59,    -1,    61,    62,    63,    64,    65,    66,    67,    68,
-      69,    70,    -1,    72,    73,    74,    -1,    76,    77,    78,
-      79,    80,    81,    82,    -1,    -1,    85,    86,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,   104,    10,    11,    12,    13,
-      -1,    -1,    -1,    -1,    -1,    -1,   115,   116,   117,   118,
+      -1,    -1,   104,    -1,    -1,   107,    10,    11,    12,    13,
+      -1,    -1,    -1,   115,   116,   117,   118,    -1,    -1,    -1,
       -1,    25,    26,    27,    28,    29,    30,    31,    32,    33,
       34,    35,    36,    37,    38,    39,    -1,    -1,    -1,    -1,
       -1,    45,    46,    47,    48,    49,    50,    -1,    -1,    -1,
-      54,    55,    -1,    57,    58,    59,    -1,    61,    62,    63,
+      54,    55,    -1,    57,    58,    59,    60,    61,    62,    63,
       64,    65,    66,    67,    68,    69,    70,    -1,    72,    73,
       74,    -1,    76,    77,    78,    79,    80,    81,    82,    -1,
       -1,    85,    86,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,     3,     4,     5,     6,
-     104,     8,     9,    10,    11,    12,    13,    -1,    -1,    -1,
-      -1,   115,   116,   117,   118,    -1,    -1,    -1,    25,    26,
-      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
-      37,    38,    39,    40,    41,    -1,    43,    44,    45,    46,
-      47,    48,    49,    50,    51,    52,    53,    54,    55,    -1,
-      57,    58,    59,    -1,    61,    62,    63,    64,    65,    66,
-      67,    68,    69,    70,    -1,    72,    73,    74,    75,    -1,
-      77,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,     3,     4,     5,     6,    -1,     8,     9,    10,    11,
-      12,    13,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   109,    25,    26,    27,    28,    29,    30,    31,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     104,    10,    11,    12,    13,    -1,    -1,    -1,    -1,    -1,
+      -1,   115,   116,   117,   118,    -1,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    -1,    -1,    -1,    -1,    -1,    45,    46,    47,    48,
+      49,    50,    -1,    -1,    -1,    54,    55,    -1,    57,    58,
+      59,    60,    61,    62,    63,    64,    65,    66,    67,    68,
+      69,    70,    -1,    72,    73,    74,    -1,    76,    77,    78,
+      79,    80,    81,    82,    -1,    -1,    85,    86,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,     3,     4,     5,     6,   104,     8,     9,    10,    11,
+      12,    13,    -1,    -1,    -1,    -1,   115,   116,   117,   118,
+      -1,    -1,    -1,    25,    26,    27,    28,    29,    30,    31,
       32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
       -1,    43,    44,    45,    46,    47,    48,    49,    50,    51,
-      52,    53,    54,    55,    -1,    57,    58,    59,    -1,    61,
+      52,    53,    54,    55,    -1,    57,    58,    59,    60,    61,
       62,    63,    64,    65,    66,    67,    68,    69,    70,    -1,
       72,    73,    74,    75,    -1,    77,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,     3,     4,     5,     6,
@@ -1425,53 +1418,62 @@
       27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
       37,    38,    39,    40,    41,    -1,    43,    44,    45,    46,
       47,    48,    49,    50,    51,    52,    53,    54,    55,    -1,
-      57,    58,    59,    -1,    61,    62,    63,    64,    65,    66,
+      57,    58,    59,    60,    61,    62,    63,    64,    65,    66,
       67,    68,    69,    70,    -1,    72,    73,    74,    75,    -1,
-      77,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     0,    -1,
-      -1,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+      77,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,     3,     4,     5,     6,    -1,     8,     9,    10,    11,
       12,    13,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,   109,    25,    26,    27,    28,    29,    30,    31,
       32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
       -1,    43,    44,    45,    46,    47,    48,    49,    50,    51,
-      52,    53,    54,    55,    -1,    57,    58,    59,    -1,    61,
+      52,    53,    54,    55,    -1,    57,    58,    59,    60,    61,
       62,    63,    64,    65,    66,    67,    68,    69,    70,    -1,
-      72,    73,    74,    75,    -1,    77,     3,     4,     5,     6,
+      72,    73,    74,    75,    -1,    77,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,     0,    -1,    -1,     3,     4,     5,     6,
        7,     8,     9,    10,    11,    12,    13,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    25,    26,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   109,    25,    26,
       27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
       37,    38,    39,    40,    41,    -1,    43,    44,    45,    46,
       47,    48,    49,    50,    51,    52,    53,    54,    55,    -1,
-      57,    58,    59,    -1,    61,    62,    63,    64,    65,    66,
+      57,    58,    59,    60,    61,    62,    63,    64,    65,    66,
       67,    68,    69,    70,    -1,    72,    73,    74,    75,    -1,
-      77,     3,     4,     5,     6,    -1,     8,     9,    10,    11,
+      77,     3,     4,     5,     6,     7,     8,     9,    10,    11,
       12,    13,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    25,    26,    27,    28,    29,    30,    31,
       32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
       -1,    43,    44,    45,    46,    47,    48,    49,    50,    51,
-      52,    53,    54,    55,    -1,    57,    58,    59,    -1,    61,
+      52,    53,    54,    55,    -1,    57,    58,    59,    60,    61,
       62,    63,    64,    65,    66,    67,    68,    69,    70,    -1,
-      72,    73,    74,    75,    -1,    77,     4,     5,     6,    -1,
-      -1,    -1,    10,    11,    12,    13,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    25,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
-      38,    39,    -1,    -1,    -1,    -1,    -1,    45,    46,    47,
-      48,    49,    50,    -1,    -1,    -1,    54,    55,    -1,    57,
-      58,    59,    -1,    61,    62,    63,    64,    65,    66,    67,
-      68,    69,    70,    -1,    72,    73,    74,    -1,    -1,    77,
-      10,    11,    12,    13,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    25,    26,    27,    28,    29,
-      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
-      -1,    -1,    -1,    -1,    -1,    45,    46,    47,    48,    49,
-      50,    -1,    -1,    -1,    54,    55,    -1,    57,    58,    59,
-      -1,    61,    62,    63,    64,    65,    66,    67,    68,    69,
-      70,    -1,    72,    73,    74,    -1,    76,    77,    10,    11,
-      12,    13,    82,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    25,    26,    27,    28,    29,    30,    31,
-      32,    33,    34,    35,    36,    37,    38,    39,    -1,    -1,
-      -1,    -1,    -1,    45,    46,    47,    48,    49,    50,    -1,
-      -1,    -1,    54,    55,    -1,    57,    58,    59,    -1,    61,
-      62,    63,    64,    65,    66,    67,    68,    69,    70,    -1,
-      72,    73,    74,    -1,    -1,    77
+      72,    73,    74,    75,    -1,    77,     3,     4,     5,     6,
+      -1,     8,     9,    10,    11,    12,    13,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+      37,    38,    39,    40,    41,    -1,    43,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    54,    55,    -1,
+      57,    58,    59,    60,    61,    62,    63,    64,    65,    66,
+      67,    68,    69,    70,    -1,    72,    73,    74,    75,    -1,
+      77,     4,     5,     6,    -1,    -1,    -1,    10,    11,    12,
+      13,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    34,    35,    36,    37,    38,    39,    -1,    -1,    -1,
+      -1,    -1,    45,    46,    47,    48,    49,    50,    -1,    -1,
+      -1,    54,    55,    -1,    57,    58,    59,    60,    61,    62,
+      63,    64,    65,    66,    67,    68,    69,    70,    -1,    72,
+      73,    74,    -1,    -1,    77,    10,    11,    12,    13,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    -1,    -1,    -1,    -1,    -1,
+      45,    46,    47,    48,    49,    50,    -1,    -1,    -1,    54,
+      55,    -1,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    -1,    72,    73,    74,
+      -1,    76,    77,    10,    11,    12,    13,    82,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+      37,    38,    39,    -1,    -1,    -1,    -1,    -1,    45,    46,
+      47,    48,    49,    50,    -1,    -1,    -1,    54,    55,    -1,
+      57,    58,    59,    60,    61,    62,    63,    64,    65,    66,
+      67,    68,    69,    70,    -1,    72,    73,    74,    -1,    -1,
+      77
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -1482,44 +1484,44 @@
       12,    13,    25,    26,    27,    28,    29,    30,    31,    32,
       33,    34,    35,    36,    37,    38,    39,    40,    41,    43,
       44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-      54,    55,    57,    58,    59,    61,    62,    63,    64,    65,
-      66,    67,    68,    69,    70,    72,    73,    74,    75,    77,
-     159,   160,   161,   162,   163,   168,   169,   170,   171,   173,
-     174,   175,   176,   177,   180,   181,   182,   217,   218,   219,
-      44,    76,   171,   174,   176,    40,    41,    76,   108,   104,
-     114,   220,   105,   111,     9,    40,    41,    42,   165,   166,
-     172,   111,   114,    76,   174,    76,   114,   158,   175,   180,
-     174,   106,     0,   218,   174,   180,   108,   184,    76,   178,
-     179,   108,   200,   165,   164,   167,   175,   166,    76,   104,
-     106,   113,   108,     3,   173,   175,   185,   186,    76,    78,
-      79,    80,    81,    82,    85,    86,   104,   107,   115,   116,
-     117,   118,   129,   130,   131,   133,   134,   135,   136,   137,
-     138,   139,   140,   141,   142,   143,   144,   145,   146,   147,
-     148,   149,   150,   151,   152,   153,   157,   180,   114,   183,
-     185,   113,   105,   111,    14,    15,    16,    18,    19,    20,
-      21,    22,    23,    24,    56,   108,   109,   114,   140,   153,
-     154,   156,   159,   160,   180,   190,   191,   192,   193,   201,
-     202,   203,   205,   207,   209,   216,    76,   164,   167,   106,
-     113,   107,   157,   154,   189,   175,    76,   187,   188,   109,
-     186,   140,   140,   156,    85,    86,   106,   110,   105,   105,
-     111,    55,   154,   104,   140,   119,   120,   121,   116,   118,
-      83,    84,    87,    88,   122,   123,    89,    90,   126,   125,
-     124,    91,    93,    92,   127,   107,   185,   109,    79,    80,
-     179,   114,   114,   211,   104,   104,   114,   114,   156,   104,
-     157,   112,   104,   109,   194,    94,    95,    96,    97,    98,
-      99,   100,   101,   102,   103,   113,   155,   111,   114,   109,
-     191,   106,   107,   157,   189,   113,   107,   187,   106,   111,
-     114,    76,   114,   105,   132,   156,    76,    82,   135,   154,
-     140,   140,   140,   142,   142,   143,   143,   144,   144,   144,
-     144,   145,   145,   146,   147,   148,   149,   150,   151,   156,
-     109,   197,   198,   199,   212,   156,   114,   156,   112,   210,
-     201,   154,   154,   157,   113,   107,   189,   113,   114,   157,
-     188,   106,   114,   107,   112,    56,   200,   192,   190,   202,
-     213,   105,   105,   156,   170,   173,   208,   195,   107,   189,
-     113,   189,   107,   157,   154,   104,   208,   214,   215,   197,
-     204,   206,    76,   105,   109,   189,   107,   156,   114,   105,
-      17,   193,   113,   192,   196,   200,   114,   105,   156,   196,
-     197,   189,   114
+      54,    55,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    72,    73,    74,    75,
+      77,   159,   160,   161,   162,   163,   168,   169,   170,   171,
+     173,   174,   175,   176,   177,   180,   181,   182,   217,   218,
+     219,    44,    76,   171,   174,   176,    40,    41,    76,   108,
+     104,   114,   220,   105,   111,     9,    40,    41,    42,   165,
+     166,   172,   111,   114,    76,   174,    76,   114,   158,   175,
+     180,   174,   106,     0,   218,   174,   180,   108,   184,    76,
+     178,   179,   108,   200,   165,   164,   167,   175,   166,    76,
+     104,   106,   113,   108,     3,   173,   175,   185,   186,    76,
+      78,    79,    80,    81,    82,    85,    86,   104,   107,   115,
+     116,   117,   118,   129,   130,   131,   133,   134,   135,   136,
+     137,   138,   139,   140,   141,   142,   143,   144,   145,   146,
+     147,   148,   149,   150,   151,   152,   153,   157,   180,   114,
+     183,   185,   113,   105,   111,    14,    15,    16,    18,    19,
+      20,    21,    22,    23,    24,    56,   108,   109,   114,   140,
+     153,   154,   156,   159,   160,   180,   190,   191,   192,   193,
+     201,   202,   203,   205,   207,   209,   216,    76,   164,   167,
+     106,   113,   107,   157,   154,   189,   175,    76,   187,   188,
+     109,   186,   140,   140,   156,    85,    86,   106,   110,   105,
+     105,   111,    55,   154,   104,   140,   119,   120,   121,   116,
+     118,    83,    84,    87,    88,   122,   123,    89,    90,   126,
+     125,   124,    91,    93,    92,   127,   107,   185,   109,    79,
+      80,   179,   114,   114,   211,   104,   104,   114,   114,   156,
+     104,   157,   112,   104,   109,   194,    94,    95,    96,    97,
+      98,    99,   100,   101,   102,   103,   113,   155,   111,   114,
+     109,   191,   106,   107,   157,   189,   113,   107,   187,   106,
+     111,   114,    76,   114,   105,   132,   156,    76,    82,   135,
+     154,   140,   140,   140,   142,   142,   143,   143,   144,   144,
+     144,   144,   145,   145,   146,   147,   148,   149,   150,   151,
+     156,   109,   197,   198,   199,   212,   156,   114,   156,   112,
+     210,   201,   154,   154,   157,   113,   107,   189,   113,   114,
+     157,   188,   106,   114,   107,   112,    56,   200,   192,   190,
+     202,   213,   105,   105,   156,   170,   173,   208,   195,   107,
+     189,   113,   189,   107,   157,   154,   104,   208,   214,   215,
+     197,   204,   206,    76,   105,   109,   189,   107,   156,   114,
+     105,    17,   193,   113,   192,   196,   200,   114,   105,   156,
+     196,   197,   189,   114
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
@@ -1545,14 +1547,14 @@
      181,   181,   181,   181,   181,   181,   181,   181,   181,   181,
      181,   181,   181,   181,   181,   181,   181,   181,   181,   181,
      181,   181,   181,   181,   181,   181,   181,   181,   181,   181,
-     181,   181,   183,   182,   184,   182,   185,   185,   186,   186,
-     187,   187,   188,   188,   189,   190,   191,   191,   192,   192,
-     192,   192,   192,   192,   192,   193,   194,   195,   193,   196,
-     196,   198,   197,   199,   197,   200,   200,   201,   201,   202,
-     202,   203,   204,   204,   206,   205,   207,   207,   208,   208,
-     210,   209,   211,   209,   212,   209,   213,   213,   214,   214,
-     215,   215,   216,   216,   216,   216,   216,   217,   217,   218,
-     218,   220,   219
+     181,   181,   181,   183,   182,   184,   182,   185,   185,   186,
+     186,   187,   187,   188,   188,   189,   190,   191,   191,   192,
+     192,   192,   192,   192,   192,   192,   193,   194,   195,   193,
+     196,   196,   198,   197,   199,   197,   200,   200,   201,   201,
+     202,   202,   203,   204,   204,   206,   205,   207,   207,   208,
+     208,   210,   209,   211,   209,   212,   209,   213,   213,   214,
+     214,   215,   215,   216,   216,   216,   216,   216,   217,   217,
+     218,   218,   220,   219
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
@@ -1578,14 +1580,14 @@
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     1,     0,     6,     0,     5,     1,     2,     3,     4,
-       1,     3,     1,     4,     1,     1,     1,     1,     1,     1,
-       1,     1,     1,     1,     1,     2,     0,     0,     5,     1,
-       1,     0,     2,     0,     2,     2,     3,     1,     2,     1,
-       2,     5,     3,     1,     0,     6,     3,     2,     1,     4,
-       0,     6,     0,     8,     0,     7,     1,     1,     1,     0,
-       2,     3,     2,     2,     2,     3,     2,     1,     2,     1,
-       1,     0,     3
+       1,     1,     1,     0,     6,     0,     5,     1,     2,     3,
+       4,     1,     3,     1,     4,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     2,     0,     0,     5,
+       1,     1,     0,     2,     0,     2,     2,     3,     1,     2,
+       1,     2,     5,     3,     1,     0,     6,     3,     2,     1,
+       4,     0,     6,     0,     8,     0,     7,     1,     1,     1,
+       0,     2,     3,     2,     2,     2,     3,     2,     1,     2,
+       1,     1,     0,     3
 };
 
 
@@ -2373,8 +2375,9 @@
         // don't delete $1.string, it's used by error recovery, and the pool
         // pop will reclaim the memory
 
+        // Constants which aren't indexable arrays can be propagated by value.
         ConstantUnion *constArray = variable->getConstPointer();
-        if (constArray) {
+        if (constArray && variable->getType().getArraySize() <= 1) {
             TType t(variable->getType());
             (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yylsp[0]));
         } else
@@ -4123,6 +4126,20 @@
   case 187:
 
     {
+        if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
+            context->error((yylsp[0]), "unsupported type", "sampler2DRect", "");
+            context->recover();
+        }
+        FRAG_VERT_ONLY("sampler2DRect", (yylsp[0]));
+        TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+        (yyval.interm.type).setBasic(EbtSampler2DRect, qual, (yylsp[0]));
+    }
+
+    break;
+
+  case 188:
+
+    {
         FRAG_VERT_ONLY("sampler3D", (yylsp[0]));
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         (yyval.interm.type).setBasic(EbtSampler3D, qual, (yylsp[0]));
@@ -4130,7 +4147,7 @@
 
     break;
 
-  case 188:
+  case 189:
 
     {
         FRAG_VERT_ONLY("sampler2DArray", (yylsp[0]));
@@ -4140,7 +4157,7 @@
 
     break;
 
-  case 189:
+  case 190:
 
     {
         FRAG_VERT_ONLY("isampler2D", (yylsp[0]));
@@ -4150,7 +4167,7 @@
 
     break;
 
-  case 190:
+  case 191:
 
     {
         FRAG_VERT_ONLY("isampler3D", (yylsp[0]));
@@ -4160,7 +4177,7 @@
 
     break;
 
-  case 191:
+  case 192:
 
     {
         FRAG_VERT_ONLY("isamplerCube", (yylsp[0]));
@@ -4170,7 +4187,7 @@
 
     break;
 
-  case 192:
+  case 193:
 
     {
         FRAG_VERT_ONLY("isampler2DArray", (yylsp[0]));
@@ -4180,7 +4197,7 @@
 
     break;
 
-  case 193:
+  case 194:
 
     {
         FRAG_VERT_ONLY("usampler2D", (yylsp[0]));
@@ -4190,7 +4207,7 @@
 
     break;
 
-  case 194:
+  case 195:
 
     {
         FRAG_VERT_ONLY("usampler3D", (yylsp[0]));
@@ -4200,7 +4217,7 @@
 
     break;
 
-  case 195:
+  case 196:
 
     {
         FRAG_VERT_ONLY("usamplerCube", (yylsp[0]));
@@ -4210,7 +4227,7 @@
 
     break;
 
-  case 196:
+  case 197:
 
     {
         FRAG_VERT_ONLY("usampler2DArray", (yylsp[0]));
@@ -4220,7 +4237,7 @@
 
     break;
 
-  case 197:
+  case 198:
 
     {
         FRAG_VERT_ONLY("sampler2DShadow", (yylsp[0]));
@@ -4230,7 +4247,7 @@
 
     break;
 
-  case 198:
+  case 199:
 
     {
         FRAG_VERT_ONLY("samplerCubeShadow", (yylsp[0]));
@@ -4240,7 +4257,7 @@
 
     break;
 
-  case 199:
+  case 200:
 
     {
         FRAG_VERT_ONLY("sampler2DArrayShadow", (yylsp[0]));
@@ -4250,7 +4267,7 @@
 
     break;
 
-  case 200:
+  case 201:
 
     {
         FRAG_VERT_ONLY("struct", (yylsp[0]));
@@ -4260,7 +4277,7 @@
 
     break;
 
-  case 201:
+  case 202:
 
     {
         //
@@ -4275,13 +4292,13 @@
 
     break;
 
-  case 202:
+  case 203:
 
     { if (context->enterStructDeclaration((yylsp[-1]), *(yyvsp[-1].lex).string)) context->recover(); }
 
     break;
 
-  case 203:
+  case 204:
 
     {
         (yyval.interm.type) = context->addStructure((yylsp[-5]), (yylsp[-4]), (yyvsp[-4].lex).string, (yyvsp[-1].interm.fieldList));
@@ -4289,13 +4306,13 @@
 
     break;
 
-  case 204:
+  case 205:
 
     { if (context->enterStructDeclaration((yylsp[0]), *(yyvsp[0].lex).string)) context->recover(); }
 
     break;
 
-  case 205:
+  case 206:
 
     {
         (yyval.interm.type) = context->addStructure((yylsp[-4]), (yylsp[-4]), NewPoolTString(""), (yyvsp[-1].interm.fieldList));
@@ -4303,7 +4320,7 @@
 
     break;
 
-  case 206:
+  case 207:
 
     {
         (yyval.interm.fieldList) = (yyvsp[0].interm.fieldList);
@@ -4311,7 +4328,7 @@
 
     break;
 
-  case 207:
+  case 208:
 
     {
         (yyval.interm.fieldList) = (yyvsp[-1].interm.fieldList);
@@ -4329,7 +4346,7 @@
 
     break;
 
-  case 208:
+  case 209:
 
     {
         (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[-2].interm.type), (yyvsp[-1].interm.fieldList));
@@ -4337,7 +4354,7 @@
 
     break;
 
-  case 209:
+  case 210:
 
     {
         // ES3 Only, but errors should be handled elsewhere
@@ -4348,7 +4365,7 @@
 
     break;
 
-  case 210:
+  case 211:
 
     {
         (yyval.interm.fieldList) = NewPoolTFieldList();
@@ -4357,7 +4374,7 @@
 
     break;
 
-  case 211:
+  case 212:
 
     {
         (yyval.interm.fieldList)->push_back((yyvsp[0].interm.field));
@@ -4365,7 +4382,7 @@
 
     break;
 
-  case 212:
+  case 213:
 
     {
         if (context->reservedErrorCheck((yylsp[0]), *(yyvsp[0].lex).string))
@@ -4377,7 +4394,7 @@
 
     break;
 
-  case 213:
+  case 214:
 
     {
         if (context->reservedErrorCheck((yylsp[-3]), *(yyvsp[-3].lex).string))
@@ -4394,27 +4411,21 @@
 
     break;
 
-  case 214:
+  case 215:
 
     { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); }
 
     break;
 
-  case 215:
-
-    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
-
-    break;
-
   case 216:
 
-    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); }
+    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
 
     break;
 
   case 217:
 
-    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); }
 
     break;
 
@@ -4438,19 +4449,19 @@
 
   case 221:
 
-    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermSwitch); }
+    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
 
     break;
 
   case 222:
 
-    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermCase); }
+    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermSwitch); }
 
     break;
 
   case 223:
 
-    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermCase); }
 
     break;
 
@@ -4462,24 +4473,30 @@
 
   case 225:
 
-    { (yyval.interm.intermAggregate) = 0; }
+    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
 
     break;
 
   case 226:
 
-    { context->symbolTable.push(); }
+    { (yyval.interm.intermAggregate) = 0; }
 
     break;
 
   case 227:
 
-    { context->symbolTable.pop(); }
+    { context->symbolTable.push(); }
 
     break;
 
   case 228:
 
+    { context->symbolTable.pop(); }
+
+    break;
+
+  case 229:
+
     {
         if ((yyvsp[-2].interm.intermAggregate) != 0) {
             (yyvsp[-2].interm.intermAggregate)->setOp(EOpSequence);
@@ -4490,51 +4507,51 @@
 
     break;
 
-  case 229:
+  case 230:
 
     { (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); }
 
     break;
 
-  case 230:
+  case 231:
 
     { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
 
     break;
 
-  case 231:
-
-    { context->symbolTable.push(); }
-
-    break;
-
   case 232:
 
-    { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); }
+    { context->symbolTable.push(); }
 
     break;
 
   case 233:
 
-    { context->symbolTable.push(); }
+    { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); }
 
     break;
 
   case 234:
 
-    { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+    { context->symbolTable.push(); }
 
     break;
 
   case 235:
 
+    { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); }
+
+    break;
+
+  case 236:
+
     {
         (yyval.interm.intermAggregate) = 0;
     }
 
     break;
 
-  case 236:
+  case 237:
 
     {
         if ((yyvsp[-1].interm.intermAggregate)) {
@@ -4546,7 +4563,7 @@
 
     break;
 
-  case 237:
+  case 238:
 
     {
         (yyval.interm.intermAggregate) = context->intermediate.makeAggregate((yyvsp[0].interm.intermNode), (yyloc));
@@ -4554,7 +4571,7 @@
 
     break;
 
-  case 238:
+  case 239:
 
     {
         (yyval.interm.intermAggregate) = context->intermediate.growAggregate((yyvsp[-1].interm.intermAggregate), (yyvsp[0].interm.intermNode), (yyloc));
@@ -4562,19 +4579,19 @@
 
     break;
 
-  case 239:
+  case 240:
 
     { (yyval.interm.intermNode) = 0; }
 
     break;
 
-  case 240:
+  case 241:
 
     { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[-1].interm.intermTypedNode)); }
 
     break;
 
-  case 241:
+  case 242:
 
     {
         if (context->boolErrorCheck((yylsp[-4]), (yyvsp[-2].interm.intermTypedNode)))
@@ -4584,7 +4601,7 @@
 
     break;
 
-  case 242:
+  case 243:
 
     {
         (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode);
@@ -4593,7 +4610,7 @@
 
     break;
 
-  case 243:
+  case 244:
 
     {
         (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode);
@@ -4602,13 +4619,13 @@
 
     break;
 
-  case 244:
+  case 245:
 
     { context->incrSwitchNestingLevel(); }
 
     break;
 
-  case 245:
+  case 246:
 
     {
         (yyval.interm.intermSwitch) = context->addSwitch((yyvsp[-3].interm.intermTypedNode), (yyvsp[0].interm.intermAggregate), (yylsp[-5]));
@@ -4617,7 +4634,7 @@
 
     break;
 
-  case 246:
+  case 247:
 
     {
         (yyval.interm.intermCase) = context->addCase((yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
@@ -4625,7 +4642,7 @@
 
     break;
 
-  case 247:
+  case 248:
 
     {
         (yyval.interm.intermCase) = context->addDefault((yylsp[-1]));
@@ -4633,7 +4650,7 @@
 
     break;
 
-  case 248:
+  case 249:
 
     {
         (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
@@ -4643,7 +4660,7 @@
 
     break;
 
-  case 249:
+  case 250:
 
     {
         TIntermNode *intermNode;
@@ -4660,13 +4677,13 @@
 
     break;
 
-  case 250:
+  case 251:
 
     { context->symbolTable.push(); context->incrLoopNestingLevel(); }
 
     break;
 
-  case 251:
+  case 252:
 
     {
         context->symbolTable.pop();
@@ -4676,13 +4693,13 @@
 
     break;
 
-  case 252:
+  case 253:
 
     { context->incrLoopNestingLevel(); }
 
     break;
 
-  case 253:
+  case 254:
 
     {
         if (context->boolErrorCheck((yylsp[0]), (yyvsp[-2].interm.intermTypedNode)))
@@ -4694,26 +4711,18 @@
 
     break;
 
-  case 254:
-
-    { context->symbolTable.push(); context->incrLoopNestingLevel(); }
-
-    break;
-
   case 255:
 
-    {
-        context->symbolTable.pop();
-        (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[-3].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node2), (yyvsp[0].interm.intermNode), (yylsp[-6]));
-        context->decrLoopNestingLevel();
-    }
+    { context->symbolTable.push(); context->incrLoopNestingLevel(); }
 
     break;
 
   case 256:
 
     {
-        (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+        context->symbolTable.pop();
+        (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[-3].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node2), (yyvsp[0].interm.intermNode), (yylsp[-6]));
+        context->decrLoopNestingLevel();
     }
 
     break;
@@ -4729,7 +4738,7 @@
   case 258:
 
     {
-        (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
+        (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
     }
 
     break;
@@ -4737,7 +4746,7 @@
   case 259:
 
     {
-        (yyval.interm.intermTypedNode) = 0;
+        (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode);
     }
 
     break;
@@ -4745,13 +4754,21 @@
   case 260:
 
     {
+        (yyval.interm.intermTypedNode) = 0;
+    }
+
+    break;
+
+  case 261:
+
+    {
         (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermTypedNode);
         (yyval.interm.nodePair).node2 = 0;
     }
 
     break;
 
-  case 261:
+  case 262:
 
     {
         (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermTypedNode);
@@ -4760,7 +4777,7 @@
 
     break;
 
-  case 262:
+  case 263:
 
     {
         (yyval.interm.intermNode) = context->addBranch(EOpContinue, (yylsp[-1]));
@@ -4768,7 +4785,7 @@
 
     break;
 
-  case 263:
+  case 264:
 
     {
         (yyval.interm.intermNode) = context->addBranch(EOpBreak, (yylsp[-1]));
@@ -4776,7 +4793,7 @@
 
     break;
 
-  case 264:
+  case 265:
 
     {
         (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yylsp[-1]));
@@ -4784,7 +4801,7 @@
 
     break;
 
-  case 265:
+  case 266:
 
     {
         (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
@@ -4792,7 +4809,7 @@
 
     break;
 
-  case 266:
+  case 267:
 
     {
         FRAG_ONLY("discard", (yylsp[-1]));
@@ -4801,19 +4818,10 @@
 
     break;
 
-  case 267:
-
-    {
-        (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
-        context->setTreeRoot((yyval.interm.intermNode));
-    }
-
-    break;
-
   case 268:
 
     {
-        (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode), (yyloc));
+        (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
         context->setTreeRoot((yyval.interm.intermNode));
     }
 
@@ -4822,7 +4830,8 @@
   case 269:
 
     {
-        (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
+        (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode), (yyloc));
+        context->setTreeRoot((yyval.interm.intermNode));
     }
 
     break;
@@ -4838,7 +4847,7 @@
   case 271:
 
     {
-        context->parseFunctionPrototype((yylsp[0]), (yyvsp[0].interm).function, &(yyvsp[0].interm).intermAggregate);
+        (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
     }
 
     break;
@@ -4846,6 +4855,14 @@
   case 272:
 
     {
+        context->parseFunctionPrototype((yylsp[0]), (yyvsp[0].interm).function, &(yyvsp[0].interm).intermAggregate);
+    }
+
+    break;
+
+  case 273:
+
+    {
         (yyval.interm.intermNode) = context->addFunctionDefinition(*((yyvsp[-2].interm).function), (yyvsp[-2].interm).intermAggregate, (yyvsp[0].interm.intermAggregate), (yylsp[-2]));
     }
 
diff --git a/src/OpenGL/compiler/intermediate.h b/src/OpenGL/compiler/intermediate.h
index 7757d89..d277255 100644
--- a/src/OpenGL/compiler/intermediate.h
+++ b/src/OpenGL/compiler/intermediate.h
@@ -330,7 +330,7 @@
 	TString getCompleteString() const { return type.getCompleteString(); }
 
 	int totalRegisterCount() const { return type.totalRegisterCount(); }
-	int blockRegisterCount() const { return type.blockRegisterCount(); }
+	int blockRegisterCount(bool samplersOnly) const { return samplersOnly ? type.totalSamplerRegisterCount() : type.blockRegisterCount(); }
 	int elementRegisterCount() const { return type.elementRegisterCount(); }
 	int registerSize() const { return type.registerSize(); }
 	int getArraySize() const { return type.getArraySize(); }
diff --git a/src/OpenGL/compiler/osinclude.h b/src/OpenGL/compiler/osinclude.h
index 650f871..54d4c75 100644
--- a/src/OpenGL/compiler/osinclude.h
+++ b/src/OpenGL/compiler/osinclude.h
@@ -26,7 +26,7 @@
       defined(__FreeBSD__) || defined(__OpenBSD__) || \
       defined(__sun) || defined(ANDROID) || \
       defined(__GLIBC__) || defined(__GNU__) || \
-      defined(__QNX__)
+      defined(__QNX__) || defined(__Fuchsia__)
 #define ANGLE_OS_POSIX
 #else
 #error Unsupported platform.
diff --git a/src/OpenGL/compiler/preprocessor/BUILD.gn b/src/OpenGL/compiler/preprocessor/BUILD.gn
index 7c8c2e4..e947c31 100644
--- a/src/OpenGL/compiler/preprocessor/BUILD.gn
+++ b/src/OpenGL/compiler/preprocessor/BUILD.gn
@@ -27,8 +27,8 @@
 
 swiftshader_source_set("swiftshader_opengl_preprocessor") {
   sources = [
-    "Diagnostics.cpp",
-    "DirectiveHandler.cpp",
+    "DiagnosticsBase.cpp",
+    "DirectiveHandlerBase.cpp",
     "DirectiveParser.cpp",
     "ExpressionParser.cpp",
     "Input.cpp",
diff --git a/src/OpenGL/compiler/preprocessor/Diagnostics.cpp b/src/OpenGL/compiler/preprocessor/Diagnostics.cpp
deleted file mode 100644
index 767edd9..0000000
--- a/src/OpenGL/compiler/preprocessor/Diagnostics.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "Diagnostics.h"
-
-#include <cassert>
-
-namespace pp
-{
-
-Diagnostics::~Diagnostics()
-{
-}
-
-void Diagnostics::report(ID id,
-                         const SourceLocation& loc,
-                         const std::string& text)
-{
-	// TODO(alokp): Keep a count of errors and warnings.
-	print(id, loc, text);
-}
-
-Diagnostics::Severity Diagnostics::severity(ID id)
-{
-	if ((id > ERROR_BEGIN) && (id < ERROR_END))
-		return PP_ERROR;
-
-	if ((id > WARNING_BEGIN) && (id < WARNING_END))
-		return PP_WARNING;
-
-	assert(false);
-	return PP_ERROR;
-}
-
-std::string Diagnostics::message(ID id)
-{
-	switch (id)
-	{
-	// Errors begin.
-	case INTERNAL_ERROR:
-		  return "internal error";
-	case OUT_OF_MEMORY:
-		  return "out of memory";
-	case INVALID_CHARACTER:
-		  return "invalid character";
-	case INVALID_NUMBER:
-		  return "invalid number";
-	case INTEGER_OVERFLOW:
-		  return "integer overflow";
-	case FLOAT_OVERFLOW:
-		  return "float overflow";
-	case TOKEN_TOO_LONG:
-		  return "token too long";
-	case INVALID_EXPRESSION:
-		  return "invalid expression";
-	case DIVISION_BY_ZERO:
-		  return "division by zero";
-	case EOF_IN_COMMENT:
-		  return "unexpected end of file found in comment";
-	case UNEXPECTED_TOKEN:
-		  return "unexpected token";
-	case DIRECTIVE_INVALID_NAME:
-		  return "invalid directive name";
-	case MACRO_NAME_RESERVED:
-		  return "macro name is reserved";
-	case MACRO_REDEFINED:
-		  return "macro redefined";
-	case MACRO_PREDEFINED_REDEFINED:
-		  return "predefined macro redefined";
-	case MACRO_PREDEFINED_UNDEFINED:
-		  return "predefined macro undefined";
-	case MACRO_UNTERMINATED_INVOCATION:
-		  return "unterminated macro invocation";
-	case MACRO_TOO_FEW_ARGS:
-		  return "Not enough arguments for macro";
-	case MACRO_TOO_MANY_ARGS:
-		  return "Too many arguments for macro";
-	case MACRO_DUPLICATE_PARAMETER_NAMES:
-		  return "duplicate macro parameter name";
-	case CONDITIONAL_ENDIF_WITHOUT_IF:
-		  return "unexpected #endif found without a matching #if";
-	case CONDITIONAL_ELSE_WITHOUT_IF:
-		  return "unexpected #else found without a matching #if";
-	case CONDITIONAL_ELSE_AFTER_ELSE:
-		  return "unexpected #else found after another #else";
-	case CONDITIONAL_ELIF_WITHOUT_IF:
-		  return "unexpected #elif found without a matching #if";
-	case CONDITIONAL_ELIF_AFTER_ELSE:
-		  return "unexpected #elif found after #else";
-	case CONDITIONAL_UNTERMINATED:
-		  return "unexpected end of file found in conditional block";
-	case INVALID_EXTENSION_NAME:
-		  return "invalid extension name";
-	case INVALID_EXTENSION_BEHAVIOR:
-		  return "invalid extension behavior";
-	case INVALID_EXTENSION_DIRECTIVE:
-		  return "invalid extension directive";
-	case INVALID_VERSION_NUMBER:
-		  return "invalid version number";
-	case INVALID_VERSION_DIRECTIVE:
-		  return "invalid version directive";
-	case VERSION_NOT_FIRST_STATEMENT:
-		return "#version directive must occur before anything else, "
-		       "except for comments and white space";
-	case INVALID_LINE_NUMBER:
-		  return "invalid line number";
-	case INVALID_FILE_NUMBER:
-		  return "invalid file number";
-	case INVALID_LINE_DIRECTIVE:
-		  return "invalid line directive";
-	case UNDEFINED_IDENTIFIER:
-		  return "undefined identifier";
-	// Errors end.
-	// Warnings begin.
-	case EOF_IN_DIRECTIVE:
-		  return "unexpected end of file found in directive";
-	case CONDITIONAL_UNEXPECTED_TOKEN:
-		  return "unexpected token after conditional expression";
-	case UNRECOGNIZED_PRAGMA:
-		  return "unrecognized pragma";
-	// Warnings end.
-	default:
-		  assert(false);
-		  return "";
-	}
-}
-
-}  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/Diagnostics.h b/src/OpenGL/compiler/preprocessor/Diagnostics.h
deleted file mode 100644
index 1f4cfc4..0000000
--- a/src/OpenGL/compiler/preprocessor/Diagnostics.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
-#define COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
-
-#include <string>
-
-namespace pp
-{
-
-struct SourceLocation;
-
-// Base class for reporting diagnostic messages.
-// Derived classes are responsible for formatting and printing the messages.
-class Diagnostics
-{
-public:
-	enum Severity
-	{
-		PP_ERROR,
-		PP_WARNING
-	};
-	enum ID
-	{
-		ERROR_BEGIN,
-		INTERNAL_ERROR,
-		OUT_OF_MEMORY,
-		INVALID_CHARACTER,
-		INVALID_NUMBER,
-		INTEGER_OVERFLOW,
-		FLOAT_OVERFLOW,
-		TOKEN_TOO_LONG,
-		INVALID_EXPRESSION,
-		DIVISION_BY_ZERO,
-		EOF_IN_COMMENT,
-		UNEXPECTED_TOKEN,
-		DIRECTIVE_INVALID_NAME,
-		MACRO_NAME_RESERVED,
-		MACRO_REDEFINED,
-		MACRO_PREDEFINED_REDEFINED,
-		MACRO_PREDEFINED_UNDEFINED,
-		MACRO_UNTERMINATED_INVOCATION,
-		MACRO_TOO_FEW_ARGS,
-		MACRO_TOO_MANY_ARGS,
-		MACRO_DUPLICATE_PARAMETER_NAMES,
-		CONDITIONAL_ENDIF_WITHOUT_IF,
-		CONDITIONAL_ELSE_WITHOUT_IF,
-		CONDITIONAL_ELSE_AFTER_ELSE,
-		CONDITIONAL_ELIF_WITHOUT_IF,
-		CONDITIONAL_ELIF_AFTER_ELSE,
-		CONDITIONAL_UNTERMINATED,
-		CONDITIONAL_UNEXPECTED_TOKEN,
-		INVALID_EXTENSION_NAME,
-		INVALID_EXTENSION_BEHAVIOR,
-		INVALID_EXTENSION_DIRECTIVE,
-		INVALID_VERSION_NUMBER,
-		INVALID_VERSION_DIRECTIVE,
-		VERSION_NOT_FIRST_STATEMENT,
-		INVALID_LINE_NUMBER,
-		INVALID_FILE_NUMBER,
-		INVALID_LINE_DIRECTIVE,
-		UNDEFINED_IDENTIFIER,
-		ERROR_END,
-
-		WARNING_BEGIN,
-		EOF_IN_DIRECTIVE,
-		UNRECOGNIZED_PRAGMA,
-		WARNING_END
-	};
-
-	virtual ~Diagnostics();
-
-	void report(ID id, const SourceLocation& loc, const std::string& text);
-
-protected:
-	Severity severity(ID id);
-	std::string message(ID id);
-
-	virtual void print(ID id,
-	                   const SourceLocation& loc,
-	                   const std::string& text) = 0;
-};
-
-}  // namespace pp
-#endif  // COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
diff --git a/src/OpenGL/compiler/preprocessor/DiagnosticsBase.cpp b/src/OpenGL/compiler/preprocessor/DiagnosticsBase.cpp
new file mode 100644
index 0000000..0cea776
--- /dev/null
+++ b/src/OpenGL/compiler/preprocessor/DiagnosticsBase.cpp
@@ -0,0 +1,163 @@
+// Copyright 2017 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "DiagnosticsBase.h"
+
+#include <cassert>
+
+namespace pp
+{
+
+Diagnostics::~Diagnostics()
+{
+}
+
+void Diagnostics::report(ID id, const SourceLocation &loc, const std::string &text)
+{
+	print(id, loc, text);
+}
+
+bool Diagnostics::isError(ID id)
+{
+	if ((id > PP_ERROR_BEGIN) && (id < PP_ERROR_END))
+		return true;
+
+	if ((id > PP_WARNING_BEGIN) && (id < PP_WARNING_END))
+		return false;
+
+	assert(false);
+	return true;
+}
+
+Diagnostics::Severity Diagnostics::severity(ID id)
+{
+	if((id > PP_ERROR_BEGIN) && (id < PP_ERROR_END))
+		return PP_ERROR;
+
+	if((id > PP_WARNING_BEGIN) && (id < PP_WARNING_END))
+		return PP_WARNING;
+
+	assert(false);
+	return PP_ERROR;
+}
+
+const char *Diagnostics::message(ID id)
+{
+	switch (id)
+	{
+	// Errors begin.
+	case PP_INTERNAL_ERROR:
+		return "internal error";
+	case PP_OUT_OF_MEMORY:
+		return "out of memory";
+	case PP_INVALID_CHARACTER:
+		return "invalid character";
+	case PP_INVALID_NUMBER:
+		return "invalid number";
+	case PP_INTEGER_OVERFLOW:
+		return "integer overflow";
+	case PP_FLOAT_OVERFLOW:
+		return "float overflow";
+	case PP_TOKEN_TOO_LONG:
+		return "token too long";
+	case PP_INVALID_EXPRESSION:
+		return "invalid expression";
+	case PP_DIVISION_BY_ZERO:
+		return "division by zero";
+	case PP_EOF_IN_COMMENT:
+		return "unexpected end of file found in comment";
+	case PP_UNEXPECTED_TOKEN:
+		return "unexpected token";
+	case PP_DIRECTIVE_INVALID_NAME:
+		return "invalid directive name";
+	case PP_MACRO_NAME_RESERVED:
+		return "macro name is reserved";
+	case PP_MACRO_REDEFINED:
+		return "macro redefined";
+	case PP_MACRO_PREDEFINED_REDEFINED:
+		return "predefined macro redefined";
+	case PP_MACRO_PREDEFINED_UNDEFINED:
+		return "predefined macro undefined";
+	case PP_MACRO_UNTERMINATED_INVOCATION:
+		return "unterminated macro invocation";
+	case PP_MACRO_UNDEFINED_WHILE_INVOKED:
+		return "macro undefined while being invoked";
+	case PP_MACRO_TOO_FEW_ARGS:
+		return "Not enough arguments for macro";
+	case PP_MACRO_TOO_MANY_ARGS:
+		return "Too many arguments for macro";
+	case PP_MACRO_DUPLICATE_PARAMETER_NAMES:
+		return "duplicate macro parameter name";
+	case PP_MACRO_INVOCATION_CHAIN_TOO_DEEP:
+		return "macro invocation chain too deep";
+	case PP_CONDITIONAL_ENDIF_WITHOUT_IF:
+		return "unexpected #endif found without a matching #if";
+	case PP_CONDITIONAL_ELSE_WITHOUT_IF:
+		return "unexpected #else found without a matching #if";
+	case PP_CONDITIONAL_ELSE_AFTER_ELSE:
+		return "unexpected #else found after another #else";
+	case PP_CONDITIONAL_ELIF_WITHOUT_IF:
+		return "unexpected #elif found without a matching #if";
+	case PP_CONDITIONAL_ELIF_AFTER_ELSE:
+		return "unexpected #elif found after #else";
+	case PP_CONDITIONAL_UNTERMINATED:
+		return "unexpected end of file found in conditional block";
+	case PP_INVALID_EXTENSION_NAME:
+		return "invalid extension name";
+	case PP_INVALID_EXTENSION_BEHAVIOR:
+		return "invalid extension behavior";
+	case PP_INVALID_EXTENSION_DIRECTIVE:
+		return "invalid extension directive";
+	case PP_INVALID_VERSION_NUMBER:
+		return "invalid version number";
+	case PP_INVALID_VERSION_DIRECTIVE:
+		return "invalid version directive";
+	case PP_VERSION_NOT_FIRST_STATEMENT:
+		return "#version directive must occur before anything else, "
+		       "except for comments and white space";
+	case PP_VERSION_NOT_FIRST_LINE_ESSL3:
+		return "#version directive must occur on the first line of the shader";
+	case PP_INVALID_LINE_NUMBER:
+		return "invalid line number";
+	case PP_INVALID_FILE_NUMBER:
+		return "invalid file number";
+	case PP_INVALID_LINE_DIRECTIVE:
+		return "invalid line directive";
+	case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3:
+		return "extension directive must occur before any non-preprocessor tokens in ESSL3";
+	case PP_UNDEFINED_SHIFT:
+		return "shift exponent is negative or undefined";
+	case PP_TOKENIZER_ERROR:
+		return "internal tokenizer error";
+	// Errors end.
+	// Warnings begin.
+	case PP_EOF_IN_DIRECTIVE:
+		return "unexpected end of file found in directive";
+	case PP_CONDITIONAL_UNEXPECTED_TOKEN:
+		return "unexpected token after conditional expression";
+	case PP_UNRECOGNIZED_PRAGMA:
+		return "unrecognized pragma";
+	case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1:
+		return "extension directive should occur before any non-preprocessor tokens";
+	case PP_WARNING_MACRO_NAME_RESERVED:
+		return "macro name with a double underscore is reserved - unintented behavior is "
+		       "possible";
+	// Warnings end.
+	default:
+		assert(false);
+		return "";
+	}
+}
+
+}  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/DiagnosticsBase.h b/src/OpenGL/compiler/preprocessor/DiagnosticsBase.h
new file mode 100644
index 0000000..16e6881
--- /dev/null
+++ b/src/OpenGL/compiler/preprocessor/DiagnosticsBase.h
@@ -0,0 +1,106 @@
+// Copyright 2017 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_
+#define COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_
+
+#include <string>
+
+namespace pp
+{
+
+struct SourceLocation;
+
+// Base class for reporting diagnostic messages.
+// Derived classes are responsible for formatting and printing the messages.
+class Diagnostics
+{
+public:
+	// Severity is used to classify info log messages.
+	enum Severity
+	{
+		PP_WARNING,
+		PP_ERROR
+	};
+
+	enum ID
+	{
+		PP_ERROR_BEGIN,
+		PP_INTERNAL_ERROR,
+		PP_OUT_OF_MEMORY,
+		PP_INVALID_CHARACTER,
+		PP_INVALID_NUMBER,
+		PP_INTEGER_OVERFLOW,
+		PP_FLOAT_OVERFLOW,
+		PP_TOKEN_TOO_LONG,
+		PP_INVALID_EXPRESSION,
+		PP_DIVISION_BY_ZERO,
+		PP_EOF_IN_COMMENT,
+		PP_UNEXPECTED_TOKEN,
+		PP_DIRECTIVE_INVALID_NAME,
+		PP_MACRO_NAME_RESERVED,
+		PP_MACRO_REDEFINED,
+		PP_MACRO_PREDEFINED_REDEFINED,
+		PP_MACRO_PREDEFINED_UNDEFINED,
+		PP_MACRO_UNTERMINATED_INVOCATION,
+		PP_MACRO_UNDEFINED_WHILE_INVOKED,
+		PP_MACRO_TOO_FEW_ARGS,
+		PP_MACRO_TOO_MANY_ARGS,
+		PP_MACRO_DUPLICATE_PARAMETER_NAMES,
+		PP_MACRO_INVOCATION_CHAIN_TOO_DEEP,
+		PP_CONDITIONAL_ENDIF_WITHOUT_IF,
+		PP_CONDITIONAL_ELSE_WITHOUT_IF,
+		PP_CONDITIONAL_ELSE_AFTER_ELSE,
+		PP_CONDITIONAL_ELIF_WITHOUT_IF,
+		PP_CONDITIONAL_ELIF_AFTER_ELSE,
+		PP_CONDITIONAL_UNTERMINATED,
+		PP_CONDITIONAL_UNEXPECTED_TOKEN,
+		PP_INVALID_EXTENSION_NAME,
+		PP_INVALID_EXTENSION_BEHAVIOR,
+		PP_INVALID_EXTENSION_DIRECTIVE,
+		PP_INVALID_VERSION_NUMBER,
+		PP_INVALID_VERSION_DIRECTIVE,
+		PP_VERSION_NOT_FIRST_STATEMENT,
+		PP_VERSION_NOT_FIRST_LINE_ESSL3,
+		PP_INVALID_LINE_NUMBER,
+		PP_INVALID_FILE_NUMBER,
+		PP_INVALID_LINE_DIRECTIVE,
+		PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
+		PP_UNDEFINED_SHIFT,
+		PP_TOKENIZER_ERROR,
+		PP_ERROR_END,
+
+		PP_WARNING_BEGIN,
+		PP_EOF_IN_DIRECTIVE,
+		PP_UNRECOGNIZED_PRAGMA,
+		PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
+		PP_WARNING_MACRO_NAME_RESERVED,
+		PP_WARNING_END
+	};
+
+	virtual ~Diagnostics();
+
+	void report(ID id, const SourceLocation &loc, const std::string &text);
+
+protected:
+	bool isError(ID id);
+	const char *message(ID id);
+	Severity severity(ID id);
+
+	virtual void print(ID id, const SourceLocation &loc, const std::string &text) = 0;
+};
+
+}  // namespace pp
+
+#endif  // COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_
diff --git a/src/OpenGL/compiler/preprocessor/DirectiveHandler.h b/src/OpenGL/compiler/preprocessor/DirectiveHandler.h
deleted file mode 100644
index f7b3784..0000000
--- a/src/OpenGL/compiler/preprocessor/DirectiveHandler.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
-#define COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
-
-#include <string>
-
-namespace pp
-{
-
-struct SourceLocation;
-
-// Base class for handling directives.
-// Preprocessor uses this class to notify the clients about certain
-// preprocessor directives. Derived classes are responsible for
-// handling them in an appropriate manner.
-class DirectiveHandler
-{
-public:
-	virtual ~DirectiveHandler();
-
-	virtual void handleError(const SourceLocation& loc,
-	                         const std::string& msg) = 0;
-
-	// Handle pragma of form: #pragma name[(value)]
-	virtual void handlePragma(const SourceLocation& loc,
-	                          const std::string& name,
-	                          const std::string& value) = 0;
-
-	virtual void handleExtension(const SourceLocation& loc,
-	                             const std::string& name,
-	                             const std::string& behavior) = 0;
-
-	virtual void handleVersion(const SourceLocation& loc,
-	                           int version) = 0;
-};
-
-}  // namespace pp
-#endif  // COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
diff --git a/src/OpenGL/compiler/preprocessor/DirectiveHandler.cpp b/src/OpenGL/compiler/preprocessor/DirectiveHandlerBase.cpp
similarity index 86%
rename from src/OpenGL/compiler/preprocessor/DirectiveHandler.cpp
rename to src/OpenGL/compiler/preprocessor/DirectiveHandlerBase.cpp
index ac26c83..e1f1015 100644
--- a/src/OpenGL/compiler/preprocessor/DirectiveHandler.cpp
+++ b/src/OpenGL/compiler/preprocessor/DirectiveHandlerBase.cpp
@@ -1,4 +1,4 @@
-// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+// Copyright 2017 The SwiftShader Authors. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "DirectiveHandler.h"
+#include "DirectiveHandlerBase.h"
 
 namespace pp
 {
diff --git a/src/OpenGL/compiler/preprocessor/DirectiveHandlerBase.h b/src/OpenGL/compiler/preprocessor/DirectiveHandlerBase.h
new file mode 100644
index 0000000..54ddc9d
--- /dev/null
+++ b/src/OpenGL/compiler/preprocessor/DirectiveHandlerBase.h
@@ -0,0 +1,51 @@
+// Copyright 2017 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_
+#define COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_
+
+#include <string>
+
+namespace pp
+{
+
+struct SourceLocation;
+
+// Base class for handling directives.
+// Preprocessor uses this class to notify the clients about certain
+// preprocessor directives. Derived classes are responsible for
+// handling them in an appropriate manner.
+class DirectiveHandler
+{
+  public:
+	virtual ~DirectiveHandler();
+
+	virtual void handleError(const SourceLocation &loc, const std::string &msg) = 0;
+
+	// Handle pragma of form: #pragma name[(value)]
+	virtual void handlePragma(const SourceLocation &loc,
+	                          const std::string &name,
+	                          const std::string &value,
+	                          bool stdgl) = 0;
+
+	virtual void handleExtension(const SourceLocation &loc,
+	                             const std::string &name,
+	                             const std::string &behavior) = 0;
+
+	virtual void handleVersion(const SourceLocation &loc, int version) = 0;
+};
+
+}  // namespace pp
+
+#endif  // COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_
diff --git a/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp b/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
index ec77c21..9eb044e 100644
--- a/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
+++ b/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
@@ -14,12 +14,13 @@
 
 #include "DirectiveParser.h"
 
+#include <algorithm>
 #include <cassert>
 #include <cstdlib>
 #include <sstream>
 
-#include "Diagnostics.h"
-#include "DirectiveHandler.h"
+#include "DiagnosticsBase.h"
+#include "DirectiveHandlerBase.h"
 #include "ExpressionParser.h"
 #include "MacroExpander.h"
 #include "Token.h"
@@ -45,7 +46,7 @@
 };
 }  // namespace
 
-static DirectiveType getDirective(const pp::Token* token)
+static DirectiveType getDirective(const pp::Token *token)
 {
 	static const std::string kDirectiveDefine("define");
 	static const std::string kDirectiveUndef("undef");
@@ -111,12 +112,12 @@
 }
 
 // Returns true if the token represents End Of Directive.
-static bool isEOD(const pp::Token* token)
+static bool isEOD(const pp::Token *token)
 {
 	return (token->type == '\n') || (token->type == pp::Token::LAST);
 }
 
-static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
+static void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
 {
 	while(!isEOD(token))
 	{
@@ -127,39 +128,105 @@
 static bool isMacroNameReserved(const std::string& name)
 {
 	// Names prefixed with "GL_" are reserved.
-	if (name.substr(0, 3) == "GL_")
-		return true;
+	return (name.substr(0, 3) == "GL_");
+}
 
-	// Names containing two consecutive underscores are reserved.
-	if (name.find("__") != std::string::npos)
-		return true;
-
-	return false;
+bool hasDoubleUnderscores(const std::string &name)
+{
+	return (name.find("__") != std::string::npos);
 }
 
 static bool isMacroPredefined(const std::string& name,
                               const pp::MacroSet& macroSet)
 {
 	pp::MacroSet::const_iterator iter = macroSet.find(name);
-	return iter != macroSet.end() ? iter->second.predefined : false;
+	return iter != macroSet.end() ? iter->second->predefined : false;
 }
 
 namespace pp
 {
 
-DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
-                                 MacroSet* macroSet,
-                                 Diagnostics* diagnostics,
-                                 DirectiveHandler* directiveHandler) :
-	mPastFirstStatement(false),
-	mTokenizer(tokenizer),
-	mMacroSet(macroSet),
-	mDiagnostics(diagnostics),
-	mDirectiveHandler(directiveHandler)
+class DefinedParser : public Lexer
+{
+public:
+	DefinedParser(Lexer *lexer, const MacroSet *macroSet, Diagnostics *diagnostics)
+		: mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
+	{
+	}
+
+protected:
+	void lex(Token *token) override
+	{
+		const char kDefined[] = "defined";
+
+		mLexer->lex(token);
+		if (token->type != Token::IDENTIFIER)
+			return;
+		if (token->text != kDefined)
+			return;
+
+		bool paren = false;
+		mLexer->lex(token);
+		if (token->type == '(')
+		{
+			paren = true;
+			mLexer->lex(token);
+		}
+
+		if (token->type != Token::IDENTIFIER)
+		{
+			mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
+			skipUntilEOD(mLexer, token);
+			return;
+		}
+		MacroSet::const_iterator iter = mMacroSet->find(token->text);
+		std::string expression = iter != mMacroSet->end() ? "1" : "0";
+
+		if (paren)
+		{
+			mLexer->lex(token);
+			if (token->type != ')')
+			{
+				mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
+				                     token->location, token->text);
+				skipUntilEOD(mLexer, token);
+				return;
+			}
+		}
+
+		// We have a valid defined operator.
+		// Convert the current token into a CONST_INT token.
+		token->type = Token::CONST_INT;
+		token->text = expression;
+	}
+
+private:
+	Lexer *mLexer;
+	const MacroSet *mMacroSet;
+	Diagnostics *mDiagnostics;
+};
+
+DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
+                                 MacroSet *macroSet,
+                                 Diagnostics *diagnostics,
+                                 DirectiveHandler *directiveHandler,
+                                 int maxMacroExpansionDepth)
+    : mPastFirstStatement(false),
+      mSeenNonPreprocessorToken(false),
+      mTokenizer(tokenizer),
+      mMacroSet(macroSet),
+      mDiagnostics(diagnostics),
+      mDirectiveHandler(directiveHandler),
+      mShaderVersion(100),
+      mMaxMacroExpansionDepth(maxMacroExpansionDepth)
 {
 }
 
-void DirectiveParser::lex(Token* token)
+DirectiveParser::~DirectiveParser()
+{
+}
+
+void DirectiveParser::lex(Token *token)
 {
 	do
 	{
@@ -170,13 +237,17 @@
 			parseDirective(token);
 			mPastFirstStatement = true;
 		}
+		else if (!isEOD(token))
+		{
+			mSeenNonPreprocessorToken = true;
+		}
 
 		if (token->type == Token::LAST)
 		{
 			if (!mConditionalStack.empty())
 			{
-				const ConditionalBlock& block = mConditionalStack.back();
-				mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,
+				const ConditionalBlock &block = mConditionalStack.back();
+				mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
 				                     block.location, block.type);
 			}
 			break;
@@ -187,7 +258,7 @@
 	mPastFirstStatement = true;
 }
 
-void DirectiveParser::parseDirective(Token* token)
+void DirectiveParser::parseDirective(Token *token)
 {
 	assert(token->type == Token::PP_HASH);
 
@@ -211,7 +282,7 @@
 	switch(directive)
 	{
 	case DIRECTIVE_NONE:
-		mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,
+		mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		break;
@@ -262,64 +333,74 @@
 	skipUntilEOD(mTokenizer, token);
 	if (token->type == Token::LAST)
 	{
-		mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
+		mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
 		                     token->location, token->text);
 	}
 }
 
-void DirectiveParser::parseDefine(Token* token)
+void DirectiveParser::parseDefine(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_DEFINE);
 
 	mTokenizer->lex(token);
 	if (token->type != Token::IDENTIFIER)
 	{
-		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		return;
 	}
 	if (isMacroPredefined(token->text, *mMacroSet))
 	{
-		mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
+		mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
 		                     token->location, token->text);
 		return;
 	}
 	if (isMacroNameReserved(token->text))
 	{
-		mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
+		mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
 		                     token->location, token->text);
 		return;
 	}
+	// Using double underscores is allowed, but may result in unintended
+	// behavior, so a warning is issued. At the time of writing this was
+	// specified in ESSL 3.10, but the intent judging from Khronos
+	// discussions and dEQP tests was that double underscores should be
+	// allowed in earlier ESSL versions too.
+	if (hasDoubleUnderscores(token->text))
+	{
+		mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
+		                     token->text);
+	}
 
-	Macro macro;
-	macro.type = Macro::kTypeObj;
-	macro.name = token->text;
+	std::shared_ptr<Macro> macro = std::make_shared<Macro>();
+	macro->type = Macro::kTypeObj;
+	macro->name = token->text;
 
 	mTokenizer->lex(token);
 	if (token->type == '(' && !token->hasLeadingSpace())
 	{
 		// Function-like macro. Collect arguments.
-		macro.type = Macro::kTypeFunc;
+		macro->type = Macro::kTypeFunc;
 		do {
 			mTokenizer->lex(token);
 			if (token->type != Token::IDENTIFIER)
 				break;
 
-			if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
+			if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) != macro->parameters.end())
 			{
-				mDiagnostics->report(Diagnostics::MACRO_DUPLICATE_PARAMETER_NAMES,
+				mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
 				                     token->location, token->text);
 				return;
 			}
 
-			macro.parameters.push_back(token->text);
+			macro->parameters.push_back(token->text);
 
 			mTokenizer->lex(token);  // Get ','.
 		} while (token->type == ',');
 
 		if (token->type != ')')
 		{
-			mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+			mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 			                     token->location,
 			                     token->text);
 			return;
@@ -333,36 +414,34 @@
 		// list. Resetting it also allows us to reuse Token::equals() to
 		// compare macros.
 		token->location = SourceLocation();
-		macro.replacements.push_back(*token);
+		macro->replacements.push_back(*token);
 		mTokenizer->lex(token);
 	}
-	if (!macro.replacements.empty())
+	if (!macro->replacements.empty())
 	{
 		// Whitespace preceding the replacement list is not considered part of
 		// the replacement list for either form of macro.
-		macro.replacements.front().setHasLeadingSpace(false);
+		macro->replacements.front().setHasLeadingSpace(false);
 	}
 
 	// Check for macro redefinition.
-	MacroSet::const_iterator iter = mMacroSet->find(macro.name);
-	if (iter != mMacroSet->end() && !macro.equals(iter->second))
+	MacroSet::const_iterator iter = mMacroSet->find(macro->name);
+	if (iter != mMacroSet->end() && !macro->equals(*iter->second))
 	{
-		mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
-		                     token->location,
-		                     macro.name);
+		mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);
 		return;
 	}
-	mMacroSet->insert(std::make_pair(macro.name, macro));
+	mMacroSet->insert(std::make_pair(macro->name, macro));
 }
 
-void DirectiveParser::parseUndef(Token* token)
+void DirectiveParser::parseUndef(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_UNDEF);
 
 	mTokenizer->lex(token);
 	if (token->type != Token::IDENTIFIER)
 	{
-		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		return;
 	}
@@ -370,10 +449,17 @@
 	MacroSet::iterator iter = mMacroSet->find(token->text);
 	if (iter != mMacroSet->end())
 	{
-		if (iter->second.predefined)
+		if (iter->second->predefined)
 		{
-			mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+			mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
 			                     token->location, token->text);
+			return;
+		}
+		else if (iter->second->expansionCount > 0)
+		{
+			mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED,
+			                     token->location, token->text);
+			return;
 		}
 		else
 		{
@@ -382,39 +468,44 @@
 	}
 
 	mTokenizer->lex(token);
+	if (!isEOD(token))
+	{
+		mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+	}
 }
 
-void DirectiveParser::parseIf(Token* token)
+void DirectiveParser::parseIf(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_IF);
 	parseConditionalIf(token);
 }
 
-void DirectiveParser::parseIfdef(Token* token)
+void DirectiveParser::parseIfdef(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_IFDEF);
 	parseConditionalIf(token);
 }
 
-void DirectiveParser::parseIfndef(Token* token)
+void DirectiveParser::parseIfndef(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_IFNDEF);
 	parseConditionalIf(token);
 }
 
-void DirectiveParser::parseElse(Token* token)
+void DirectiveParser::parseElse(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_ELSE);
 
 	if (mConditionalStack.empty())
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
 	}
 
-	ConditionalBlock& block = mConditionalStack.back();
+	ConditionalBlock &block = mConditionalStack.back();
 	if (block.skipBlock)
 	{
 		// No diagnostics. Just skip the whole line.
@@ -423,7 +514,7 @@
 	}
 	if (block.foundElseGroup)
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
@@ -437,25 +528,25 @@
 	mTokenizer->lex(token);
 	if (!isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 	}
 }
 
-void DirectiveParser::parseElif(Token* token)
+void DirectiveParser::parseElif(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_ELIF);
 
 	if (mConditionalStack.empty())
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
 	}
 
-	ConditionalBlock& block = mConditionalStack.back();
+	ConditionalBlock &block = mConditionalStack.back();
 	if (block.skipBlock)
 	{
 		// No diagnostics. Just skip the whole line.
@@ -464,7 +555,7 @@
 	}
 	if (block.foundElseGroup)
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
@@ -483,13 +574,13 @@
 	block.foundValidGroup = expression != 0;
 }
 
-void DirectiveParser::parseEndif(Token* token)
+void DirectiveParser::parseEndif(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_ENDIF);
 
 	if (mConditionalStack.empty())
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
@@ -501,13 +592,13 @@
 	mTokenizer->lex(token);
 	if (!isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 	}
 }
 
-void DirectiveParser::parseError(Token* token)
+void DirectiveParser::parseError(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_ERROR);
 
@@ -522,7 +613,7 @@
 }
 
 // Parses pragma of form: #pragma name[(value)].
-void DirectiveParser::parsePragma(Token* token)
+void DirectiveParser::parsePragma(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_PRAGMA);
 
@@ -539,6 +630,11 @@
 	int state = PRAGMA_NAME;
 
 	mTokenizer->lex(token);
+	bool stdgl = token->text == "STDGL";
+	if (stdgl)
+	{
+		mTokenizer->lex(token);
+	}
 	while ((token->type != '\n') && (token->type != Token::LAST))
 	{
 		switch(state++)
@@ -569,16 +665,15 @@
 	                  (state == RIGHT_PAREN + 1));  // With value.
 	if (!valid)
 	{
-		mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,
-		                     token->location, name);
+		mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
 	}
 	else if (state > PRAGMA_NAME)  // Do not notify for empty pragma.
 	{
-		mDirectiveHandler->handlePragma(token->location, name, value);
+		mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
 	}
 }
 
-void DirectiveParser::parseExtension(Token* token)
+void DirectiveParser::parseExtension(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_EXTENSION);
 
@@ -598,61 +693,77 @@
 	{
 		switch (state++)
 		{
-		case EXT_NAME:
-			if (valid && (token->type != Token::IDENTIFIER))
-			{
-				mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,
-				                     token->location, token->text);
-				valid = false;
-			}
-			if (valid) name = token->text;
-			break;
-		case COLON:
-			if (valid && (token->type != ':'))
-			{
-				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
-		case EXT_BEHAVIOR:
-			if (valid && (token->type != Token::IDENTIFIER))
-			{
-				mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,
-				                     token->location, token->text);
-				valid = false;
-			}
-			if (valid) behavior = token->text;
-			break;
-		default:
-			if (valid)
-			{
-				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
+			case EXT_NAME:
+				if (valid && (token->type != Token::IDENTIFIER))
+				{
+					mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
+					                     token->text);
+					valid = false;
+				}
+				if (valid)
+					name = token->text;
+				break;
+			case COLON:
+				if (valid && (token->type != ':'))
+				{
+					mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
+					                     token->text);
+					valid = false;
+				}
+				break;
+			case EXT_BEHAVIOR:
+				if (valid && (token->type != Token::IDENTIFIER))
+				{
+					mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
+					                     token->location, token->text);
+					valid = false;
+				}
+				if (valid)
+					behavior = token->text;
+				break;
+			default:
+				if (valid)
+				{
+					mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
+					                     token->text);
+					valid = false;
+				}
+				break;
 		}
 		mTokenizer->lex(token);
 	}
 	if (valid && (state != EXT_BEHAVIOR + 1))
 	{
-		mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,
-		                     token->location, token->text);
+		mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
+		                     token->text);
 		valid = false;
 	}
+	if (valid && mSeenNonPreprocessorToken)
+	{
+		if (mShaderVersion >= 300)
+		{
+			mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
+			                     token->location, token->text);
+			valid = false;
+		}
+		else
+		{
+			mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
+			                     token->location, token->text);
+		}
+	}
 	if (valid)
 		mDirectiveHandler->handleExtension(token->location, name, behavior);
 }
 
-void DirectiveParser::parseVersion(Token* token)
+void DirectiveParser::parseVersion(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_VERSION);
 
 	if (mPastFirstStatement)
 	{
-		mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT,
-		                     token->location, token->text);
+		mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
+		                     token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
 	}
@@ -676,13 +787,13 @@
 		case VERSION_NUMBER:
 			if (token->type != Token::CONST_INT)
 			{
-				mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,
+				mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
 				                     token->location, token->text);
 				valid = false;
 			}
 			if (valid && !token->iValue(&version))
 			{
-				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+				mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
 				                     token->location, token->text);
 				valid = false;
 			}
@@ -694,14 +805,14 @@
 		case VERSION_PROFILE:
 			if (token->type != Token::IDENTIFIER || token->text != "es")
 			{
-				mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
+				mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
 				                     token->location, token->text);
 				valid = false;
 			}
 			state = VERSION_ENDLINE;
 			break;
 		default:
-			mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+			mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 			                     token->location, token->text);
 			valid = false;
 			break;
@@ -712,99 +823,98 @@
 
 	if (valid && (state != VERSION_ENDLINE))
 	{
-		mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
+		mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
 		                     token->location, token->text);
 		valid = false;
 	}
 
+	if (valid && version >= 300 && token->location.line > 1)
+	{
+		mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
+		                     token->text);
+		valid = false;
+	}
+
 	if (valid)
 	{
 		mDirectiveHandler->handleVersion(token->location, version);
+		mShaderVersion = version;
+		PredefineMacro(mMacroSet, "__VERSION__", version);
 	}
 }
 
-void DirectiveParser::parseLine(Token* token)
+void DirectiveParser::parseLine(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_LINE);
 
-	enum State
-	{
-		LINE_NUMBER,
-		FILE_NUMBER
-	};
-
 	bool valid = true;
+	bool parsedFileNumber = false;
 	int line = 0, file = 0;
-	int state = LINE_NUMBER;
 
-	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);
+	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false, mMaxMacroExpansionDepth);
+
+	// Lex the first token after "#line" so we can check it for EOD.
 	macroExpander.lex(token);
-	while ((token->type != '\n') && (token->type != Token::LAST))
-	{
-		switch (state++)
-		{
-		case LINE_NUMBER:
-			if (valid && (token->type != Token::CONST_INT))
-			{
-				mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,
-				                     token->location, token->text);
-				valid = false;
-			}
-			if (valid && !token->iValue(&line))
-			{
-				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
-		case FILE_NUMBER:
-			if (valid && (token->type != Token::CONST_INT))
-			{
-				mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,
-				                     token->location, token->text);
-				valid = false;
-			}
-			if (valid && !token->iValue(&file))
-			{
-				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
-		default:
-			if (valid)
-			{
-				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
-		}
-		macroExpander.lex(token);
-	}
 
-	if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
+	if (isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,
-		                     token->location, token->text);
+		mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
 		valid = false;
 	}
+	else
+	{
+		ExpressionParser expressionParser(&macroExpander, mDiagnostics);
+		ExpressionParser::ErrorSettings errorSettings;
+
+		// See GLES3 section 12.42
+		errorSettings.integerLiteralsMustFit32BitSignedRange = true;
+
+		errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
+		// The first token was lexed earlier to check if it was EOD. Include
+		// the token in parsing for a second time by setting the
+		// parsePresetToken flag to true.
+		expressionParser.parse(token, &line, true, errorSettings, &valid);
+		if (!isEOD(token) && valid)
+		{
+			errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
+			// After parsing the line expression expressionParser has also
+			// advanced to the first token of the file expression - this is the
+			// token that makes the parser reduce the "input" rule for the line
+			// expression and stop. So we're using parsePresetToken = true here
+			// as well.
+			expressionParser.parse(token, &file, true, errorSettings, &valid);
+			parsedFileNumber = true;
+		}
+		if (!isEOD(token))
+		{
+			if (valid)
+			{
+				mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
+				                     token->location, token->text);
+				valid = false;
+			}
+			skipUntilEOD(mTokenizer, token);
+		}
+	}
+
 	if (valid)
 	{
 		mTokenizer->setLineNumber(line);
-		if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
+		if (parsedFileNumber)
+			mTokenizer->setFileNumber(file);
 	}
 }
 
 bool DirectiveParser::skipping() const
 {
-	if (mConditionalStack.empty()) return false;
+	if (mConditionalStack.empty())
+		return false;
 
-	const ConditionalBlock& block = mConditionalStack.back();
+	const ConditionalBlock &block = mConditionalStack.back();
 	return block.skipBlock || block.skipGroup;
 }
 
-void DirectiveParser::parseConditionalIf(Token* token)
+void DirectiveParser::parseConditionalIf(Token *token)
 {
 	ConditionalBlock block;
 	block.type = token->text;
@@ -845,22 +955,26 @@
 	mConditionalStack.push_back(block);
 }
 
-int DirectiveParser::parseExpressionIf(Token* token)
+int DirectiveParser::parseExpressionIf(Token *token)
 {
-	assert((getDirective(token) == DIRECTIVE_IF) ||
-	       (getDirective(token) == DIRECTIVE_ELIF));
+	assert((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
 
-	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);
+	DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
+	MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, true, mMaxMacroExpansionDepth);
 	ExpressionParser expressionParser(&macroExpander, mDiagnostics);
 
 	int expression = 0;
-	macroExpander.lex(token);
-	expressionParser.parse(token, &expression);
+	ExpressionParser::ErrorSettings errorSettings;
+	errorSettings.integerLiteralsMustFit32BitSignedRange = false;
+	errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
+
+	bool valid = true;
+	expressionParser.parse(token, &expression, false, errorSettings, &valid);
 
 	// Check if there are tokens after #if expression.
 	if (!isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 	}
@@ -876,7 +990,7 @@
 	mTokenizer->lex(token);
 	if (token->type != Token::IDENTIFIER)
 	{
-		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return 0;
@@ -889,7 +1003,7 @@
 	mTokenizer->lex(token);
 	if (!isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 	}
diff --git a/src/OpenGL/compiler/preprocessor/DirectiveParser.h b/src/OpenGL/compiler/preprocessor/DirectiveParser.h
index b23a99e..d1e1135 100644
--- a/src/OpenGL/compiler/preprocessor/DirectiveParser.h
+++ b/src/OpenGL/compiler/preprocessor/DirectiveParser.h
@@ -30,35 +30,37 @@
 class DirectiveParser : public Lexer
 {
 public:
-	DirectiveParser(Tokenizer* tokenizer,
-	                MacroSet* macroSet,
-	                Diagnostics* diagnostics,
-	                DirectiveHandler* directiveHandler);
+	DirectiveParser(Tokenizer *tokenizer,
+	                MacroSet *macroSet,
+	                Diagnostics *diagnostics,
+	                DirectiveHandler *directiveHandler,
+	                int maxMacroExpansionDepth);
+	~DirectiveParser() override;
 
-	virtual void lex(Token* token);
+	void lex(Token *token) override;
 
 private:
 	PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser);
 
-	void parseDirective(Token* token);
-	void parseDefine(Token* token);
-	void parseUndef(Token* token);
-	void parseIf(Token* token);
-	void parseIfdef(Token* token);
-	void parseIfndef(Token* token);
-	void parseElse(Token* token);
-	void parseElif(Token* token);
-	void parseEndif(Token* token);
-	void parseError(Token* token);
-	void parsePragma(Token* token);
-	void parseExtension(Token* token);
-	void parseVersion(Token* token);
-	void parseLine(Token* token);
+	void parseDirective(Token *token);
+	void parseDefine(Token *token);
+	void parseUndef(Token *token);
+	void parseIf(Token *token);
+	void parseIfdef(Token *token);
+	void parseIfndef(Token *token);
+	void parseElse(Token *token);
+	void parseElif(Token *token);
+	void parseEndif(Token *token);
+	void parseError(Token *token);
+	void parsePragma(Token *token);
+	void parseExtension(Token *token);
+	void parseVersion(Token *token);
+	void parseLine(Token *token);
 
 	bool skipping() const;
-	void parseConditionalIf(Token* token);
-	int parseExpressionIf(Token* token);
-	int parseExpressionIfdef(Token* token);
+	void parseConditionalIf(Token *token);
+	int parseExpressionIf(Token *token);
+	int parseExpressionIfdef(Token *token);
 
 	struct ConditionalBlock
 	{
@@ -78,11 +80,16 @@
 		}
 	};
 	bool mPastFirstStatement;
+	bool mSeenNonPreprocessorToken;  // Tracks if a non-preprocessor token has been seen yet.  Some
+	                                 // macros, such as
+	                                 // #extension must be declared before all shader code.
 	std::vector<ConditionalBlock> mConditionalStack;
-	Tokenizer* mTokenizer;
-	MacroSet* mMacroSet;
-	Diagnostics* mDiagnostics;
-	DirectiveHandler* mDirectiveHandler;
+	Tokenizer *mTokenizer;
+	MacroSet *mMacroSet;
+	Diagnostics *mDiagnostics;
+	DirectiveHandler *mDirectiveHandler;
+	int mShaderVersion;
+	int mMaxMacroExpansionDepth;
 };
 
 }  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/ExpressionParser.cpp b/src/OpenGL/compiler/preprocessor/ExpressionParser.cpp
index b2aa9d7..752252b 100644
--- a/src/OpenGL/compiler/preprocessor/ExpressionParser.cpp
+++ b/src/OpenGL/compiler/preprocessor/ExpressionParser.cpp
@@ -88,26 +88,38 @@
 
 #if defined(__GNUC__)
 // Triggered by the auto-generated pplval variable.
+#if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#else
 #pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
 #elif defined(_MSC_VER)
-#pragma warning(disable: 4065 4701)
+#pragma warning(disable: 4065 4244 4701 4702)
 #endif
 
 #include "ExpressionParser.h"
 
+#if defined(_MSC_VER)
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+
+#include <limits>
 #include <cassert>
 #include <sstream>
+#include <stdint.h>
 
-#include "Diagnostics.h"
+#include "DiagnosticsBase.h"
 #include "Lexer.h"
 #include "Token.h"
+#include "../../common/debug.h"
 
-#if defined(_MSC_VER)
-typedef __int64 YYSTYPE;
-#else
-#include <stdint.h>
-typedef intmax_t YYSTYPE;
-#endif  // _MSC_VER
+typedef int32_t YYSTYPE;
+typedef uint32_t UNSIGNED_TYPE;
+
+#define YYENABLE_NLS 0
+#define YYLTYPE_IS_TRIVIAL 1
 #define YYSTYPE_IS_TRIVIAL 1
 #define YYSTYPE_IS_DECLARED 1
 
@@ -118,7 +130,17 @@
     pp::Lexer* lexer;
     pp::Token* token;
     int* result;
-    int shortCircuited;   // Don't produce errors when > 0
+    bool parsePresetToken;
+
+    pp::ExpressionParser::ErrorSettings errorSettings;
+    bool *valid;
+
+    void startIgnoreErrors() { ++ignoreErrors; }
+    void endIgnoreErrors() { --ignoreErrors; }
+
+    bool isIgnoringErrors() { return ignoreErrors > 0; }
+
+    int ignoreErrors;
 };
 }  // namespace
 
@@ -159,15 +181,16 @@
   enum yytokentype
   {
     TOK_CONST_INT = 258,
-    TOK_OP_OR = 259,
-    TOK_OP_AND = 260,
-    TOK_OP_EQ = 261,
-    TOK_OP_NE = 262,
-    TOK_OP_LE = 263,
-    TOK_OP_GE = 264,
-    TOK_OP_LEFT = 265,
-    TOK_OP_RIGHT = 266,
-    TOK_UNARY = 267
+    TOK_IDENTIFIER = 259,
+    TOK_OP_OR = 260,
+    TOK_OP_AND = 261,
+    TOK_OP_EQ = 262,
+    TOK_OP_NE = 263,
+    TOK_OP_LE = 264,
+    TOK_OP_GE = 265,
+    TOK_OP_LEFT = 266,
+    TOK_OP_RIGHT = 267,
+    TOK_UNARY = 268
   };
 #endif
 
@@ -426,23 +449,23 @@
 #endif /* !YYCOPY_NEEDED */
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  14
+#define YYFINAL  15
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   178
+#define YYLAST   176
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  27
+#define YYNTOKENS  28
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  5
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  28
+#define YYNRULES  29
 /* YYNSTATES -- Number of states.  */
-#define YYNSTATES  54
+#define YYNSTATES  55
 
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   267
+#define YYMAXUTOK   268
 
 #define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -454,16 +477,16 @@
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    23,     2,     2,     2,    21,     8,     2,
-      25,    26,    19,    17,     2,    18,     2,    20,     2,     2,
+       2,     2,     2,    24,     2,     2,     2,    22,     9,     2,
+      26,    27,    20,    18,     2,    19,     2,    21,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      11,     2,    12,     2,     2,     2,     2,     2,     2,     2,
+      12,     2,    13,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     7,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     8,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     6,     2,    24,     2,     2,     2,
+       2,     2,     2,     2,     7,     2,    25,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -477,16 +500,16 @@
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     9,    10,    13,    14,    15,    16,    22
+       5,     6,    10,    11,    14,    15,    16,    17,    23
 };
 
 #if YYDEBUG
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
-static const yytype_uint8 yyrline[] =
+static const yytype_uint16 yyrline[] =
 {
-       0,    86,    86,    93,    94,    94,   110,   110,   126,   129,
-     132,   135,   138,   141,   144,   147,   150,   153,   156,   159,
-     162,   165,   184,   203,   206,   209,   212,   215,   218
+       0,   125,   125,   132,   133,   144,   144,   165,   165,   186,
+     189,   192,   195,   198,   201,   204,   207,   210,   213,   238,
+     260,   263,   266,   292,   319,   322,   325,   328,   340,   343
 };
 #endif
 
@@ -495,11 +518,11 @@
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "TOK_CONST_INT", "TOK_OP_OR",
-  "TOK_OP_AND", "'|'", "'^'", "'&'", "TOK_OP_EQ", "TOK_OP_NE", "'<'",
-  "'>'", "TOK_OP_LE", "TOK_OP_GE", "TOK_OP_LEFT", "TOK_OP_RIGHT", "'+'",
-  "'-'", "'*'", "'/'", "'%'", "TOK_UNARY", "'!'", "'~'", "'('", "')'",
-  "$accept", "input", "expression", "$@1", "$@2", YY_NULLPTR
+  "$end", "error", "$undefined", "TOK_CONST_INT", "TOK_IDENTIFIER",
+  "TOK_OP_OR", "TOK_OP_AND", "'|'", "'^'", "'&'", "TOK_OP_EQ", "TOK_OP_NE",
+  "'<'", "'>'", "TOK_OP_LE", "TOK_OP_GE", "TOK_OP_LEFT", "TOK_OP_RIGHT",
+  "'+'", "'-'", "'*'", "'/'", "'%'", "TOK_UNARY", "'!'", "'~'", "'('",
+  "')'", "$accept", "input", "expression", "$@1", "$@2", YY_NULLPTR
 };
 #endif
 
@@ -508,16 +531,16 @@
    (internal) symbol number NUM (which must be that of a token).  */
 static const yytype_uint16 yytoknum[] =
 {
-       0,   256,   257,   258,   259,   260,   124,    94,    38,   261,
-     262,    60,    62,   263,   264,   265,   266,    43,    45,    42,
-      47,    37,   267,    33,   126,    40,    41
+       0,   256,   257,   258,   259,   260,   261,   124,    94,    38,
+     262,   263,    60,    62,   264,   265,   266,   267,    43,    45,
+      42,    47,    37,   268,    33,   126,    40,    41
 };
 # endif
 
-#define YYPACT_NINF -11
+#define YYPACT_NINF -12
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-11)))
+  (!!((Yystate) == (-12)))
 
 #define YYTABLE_NINF -1
 
@@ -528,12 +551,12 @@
      STATE-NUM.  */
 static const yytype_int16 yypact[] =
 {
-      49,   -11,    49,    49,    49,    49,    49,    31,    71,   -11,
-     -11,   -11,   -11,    30,   -11,   -11,   -11,    49,    49,    49,
-      49,    49,    49,    49,    49,    49,    49,    49,    49,    49,
-      49,    49,    49,   -11,    49,    49,   119,   133,   146,   157,
-     157,   -10,   -10,   -10,   -10,    40,    40,    -7,    -7,   -11,
-     -11,   -11,    88,   104
+      31,   -12,   -12,    31,    31,    31,    31,    31,    51,    76,
+     -12,   -12,   -12,   -12,    53,   -12,   -12,   -12,    31,    31,
+      31,    31,    31,    31,    31,    31,    31,    31,    31,    31,
+      31,    31,    31,    31,   -12,    31,    31,   124,   138,    26,
+     149,   149,   -11,   -11,   -11,   -11,   154,   154,    -8,    -8,
+     -12,   -12,   -12,    93,   109
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -541,24 +564,24 @@
      means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     3,     0,     0,     0,     0,     0,     0,     2,    27,
-      26,    24,    25,     0,     1,     4,     6,     0,     0,     0,
+       0,     3,     4,     0,     0,     0,     0,     0,     0,     2,
+      28,    27,    25,    26,     0,     1,     5,     7,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,    28,     0,     0,     8,     9,    10,    12,
-      11,    16,    15,    14,    13,    18,    17,    20,    19,    23,
-      22,    21,     5,     7
+       0,     0,     0,     0,    29,     0,     0,     9,    10,    11,
+      13,    12,    17,    16,    15,    14,    19,    18,    21,    20,
+      24,    23,    22,     6,     8
 };
 
   /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -11,   -11,    -2,   -11,   -11
+     -12,   -12,    -3,   -12,   -12
 };
 
   /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
-      -1,     7,     8,    34,    35
+      -1,     8,     9,    35,    36
 };
 
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
@@ -566,74 +589,74 @@
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_uint8 yytable[] =
 {
-       9,    10,    11,    12,    13,    26,    27,    28,    29,    30,
-      31,    32,    30,    31,    32,    36,    37,    38,    39,    40,
-      41,    42,    43,    44,    45,    46,    47,    48,    49,    50,
-      51,    14,    52,    53,    15,    16,    17,    18,    19,    20,
-      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,     1,     0,     0,     0,    33,    28,    29,    30,
-      31,    32,     0,     0,     0,     0,     2,     3,     0,     0,
-       0,     0,     4,     5,     6,    15,    16,    17,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      30,    31,    32,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-      27,    28,    29,    30,    31,    32,    18,    19,    20,    21,
+      10,    11,    12,    13,    14,    27,    28,    29,    30,    31,
+      32,    33,    31,    32,    33,    37,    38,    39,    40,    41,
+      42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+      52,     0,    53,    54,     1,     2,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,     3,
+       4,    15,     0,     0,     0,     5,     6,     7,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,     0,     0,     0,     0,
+      34,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,    18,    19,    20,    21,
       22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
-      32,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    32,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    22,    23,
-      24,    25,    26,    27,    28,    29,    30,    31,    32
+      32,    33,    19,    20,    21,    22,    23,    24,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+      32,    33,    29,    30,    31,    32,    33
 };
 
 static const yytype_int8 yycheck[] =
 {
-       2,     3,     4,     5,     6,    15,    16,    17,    18,    19,
-      20,    21,    19,    20,    21,    17,    18,    19,    20,    21,
-      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
-      32,     0,    34,    35,     4,     5,     6,     7,     8,     9,
-      10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
-      20,    21,     3,    -1,    -1,    -1,    26,    17,    18,    19,
-      20,    21,    -1,    -1,    -1,    -1,    17,    18,    -1,    -1,
-      -1,    -1,    23,    24,    25,     4,     5,     6,     7,     8,
-       9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,     5,     6,     7,     8,     9,    10,    11,
-      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,     7,     8,     9,    10,
+       3,     4,     5,     6,     7,    16,    17,    18,    19,    20,
+      21,    22,    20,    21,    22,    18,    19,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    -1,    35,    36,     3,     4,    10,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    18,
+      19,     0,    -1,    -1,    -1,    24,    25,    26,     5,     6,
+       7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    -1,    -1,    -1,    -1,
+      27,     5,     6,     7,     8,     9,    10,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,     6,
+       7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,     7,     8,     9,    10,
       11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,     8,     9,    10,    11,    12,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,     9,    10,    11,    12,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    11,    12,
-      13,    14,    15,    16,    17,    18,    19,    20,    21
+      21,    22,     8,     9,    10,    11,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,     9,    10,    11,
+      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    12,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    18,    19,    20,    21,    22
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,     3,    17,    18,    23,    24,    25,    28,    29,    29,
-      29,    29,    29,    29,     0,     4,     5,     6,     7,     8,
+       0,     3,     4,    18,    19,    24,    25,    26,    29,    30,
+      30,    30,    30,    30,    30,     0,     5,     6,     7,     8,
        9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    26,    30,    31,    29,    29,    29,    29,
-      29,    29,    29,    29,    29,    29,    29,    29,    29,    29,
-      29,    29,    29,    29
+      19,    20,    21,    22,    27,    31,    32,    30,    30,    30,
+      30,    30,    30,    30,    30,    30,    30,    30,    30,    30,
+      30,    30,    30,    30,    30
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    27,    28,    29,    30,    29,    31,    29,    29,    29,
-      29,    29,    29,    29,    29,    29,    29,    29,    29,    29,
-      29,    29,    29,    29,    29,    29,    29,    29,    29
+       0,    28,    29,    30,    30,    31,    30,    32,    30,    30,
+      30,    30,    30,    30,    30,    30,    30,    30,    30,    30,
+      30,    30,    30,    30,    30,    30,    30,    30,    30,    30
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     1,     1,     0,     4,     0,     4,     3,     3,
+       0,     2,     1,     1,     1,     0,     4,     0,     4,     3,
        3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
-       3,     3,     3,     3,     2,     2,     2,     2,     3
+       3,     3,     3,     3,     3,     2,     2,     2,     2,     3
 };
 
 
@@ -1327,10 +1350,15 @@
   case 4:
 
     {
-        if ((yyvsp[-1]) != 0)
+        if (!context->isIgnoringErrors())
         {
-            context->shortCircuited++;
+            // This rule should be applied right after the token is lexed, so we can
+            // refer to context->token in the error message.
+            context->diagnostics->report(context->errorSettings.unexpectedIdentifier,
+                                         context->token->location, context->token->text);
+            *(context->valid) = false;
         }
+        (yyval) = (yyvsp[0]);
     }
 
     break;
@@ -1338,10 +1366,26 @@
   case 5:
 
     {
+        if ((yyvsp[-1]) != 0)
+        {
+            // Ignore errors in the short-circuited part of the expression.
+            // ESSL3.00 section 3.4:
+            // If an operand is not evaluated, the presence of undefined identifiers
+            // in the operand will not cause an error.
+            // Unevaluated division by zero should not cause an error either.
+            context->startIgnoreErrors();
+        }
+    }
+
+    break;
+
+  case 6:
+
+    {
         if ((yyvsp[-3]) != 0)
         {
-            context->shortCircuited--;
-            (yyval) = 1;
+            context->endIgnoreErrors();
+            (yyval) = static_cast<YYSTYPE>(1);
         }
         else
         {
@@ -1351,24 +1395,29 @@
 
     break;
 
-  case 6:
+  case 7:
 
     {
         if ((yyvsp[-1]) == 0)
         {
-            context->shortCircuited++;
+            // Ignore errors in the short-circuited part of the expression.
+            // ESSL3.00 section 3.4:
+            // If an operand is not evaluated, the presence of undefined identifiers
+            // in the operand will not cause an error.
+            // Unevaluated division by zero should not cause an error either.
+            context->startIgnoreErrors();
         }
     }
 
     break;
 
-  case 7:
+  case 8:
 
     {
         if ((yyvsp[-3]) == 0)
         {
-            context->shortCircuited--;
-            (yyval) = 0;
+            context->endIgnoreErrors();
+            (yyval) = static_cast<YYSTYPE>(0);
         }
         else
         {
@@ -1378,7 +1427,7 @@
 
     break;
 
-  case 8:
+  case 9:
 
     {
         (yyval) = (yyvsp[-2]) | (yyvsp[0]);
@@ -1386,7 +1435,7 @@
 
     break;
 
-  case 9:
+  case 10:
 
     {
         (yyval) = (yyvsp[-2]) ^ (yyvsp[0]);
@@ -1394,7 +1443,7 @@
 
     break;
 
-  case 10:
+  case 11:
 
     {
         (yyval) = (yyvsp[-2]) & (yyvsp[0]);
@@ -1402,7 +1451,7 @@
 
     break;
 
-  case 11:
+  case 12:
 
     {
         (yyval) = (yyvsp[-2]) != (yyvsp[0]);
@@ -1410,7 +1459,7 @@
 
     break;
 
-  case 12:
+  case 13:
 
     {
         (yyval) = (yyvsp[-2]) == (yyvsp[0]);
@@ -1418,7 +1467,7 @@
 
     break;
 
-  case 13:
+  case 14:
 
     {
         (yyval) = (yyvsp[-2]) >= (yyvsp[0]);
@@ -1426,7 +1475,7 @@
 
     break;
 
-  case 14:
+  case 15:
 
     {
         (yyval) = (yyvsp[-2]) <= (yyvsp[0]);
@@ -1434,7 +1483,7 @@
 
     break;
 
-  case 15:
+  case 16:
 
     {
         (yyval) = (yyvsp[-2]) > (yyvsp[0]);
@@ -1442,7 +1491,7 @@
 
     break;
 
-  case 16:
+  case 17:
 
     {
         (yyval) = (yyvsp[-2]) < (yyvsp[0]);
@@ -1450,18 +1499,32 @@
 
     break;
 
-  case 17:
-
-    {
-        (yyval) = (yyvsp[-2]) >> (yyvsp[0]);
-    }
-
-    break;
-
   case 18:
 
     {
-        (yyval) = (yyvsp[-2]) << (yyvsp[0]);
+        if ((yyvsp[0]) < 0 || (yyvsp[0]) > 31)
+        {
+            if (!context->isIgnoringErrors())
+            {
+                std::ostringstream stream;
+                stream << (yyvsp[-2]) << " >> " << (yyvsp[0]);
+                std::string text = stream.str();
+                context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
+                                             context->token->location,
+                                             text.c_str());
+                *(context->valid) = false;
+            }
+            (yyval) = static_cast<YYSTYPE>(0);
+        }
+        else if ((yyvsp[-2]) < 0)
+        {
+            // Logical shift right.
+            (yyval) = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>((yyvsp[-2])) >> (yyvsp[0]));
+        }
+        else
+        {
+            (yyval) = (yyvsp[-2]) >> (yyvsp[0]);
+        }
     }
 
     break;
@@ -1469,7 +1532,26 @@
   case 19:
 
     {
-        (yyval) = (yyvsp[-2]) - (yyvsp[0]);
+        if ((yyvsp[0]) < 0 || (yyvsp[0]) > 31)
+        {
+            if (!context->isIgnoringErrors())
+            {
+                std::ostringstream stream;
+                stream << (yyvsp[-2]) << " << " << (yyvsp[0]);
+                std::string text = stream.str();
+                context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
+                                             context->token->location,
+                                             text.c_str());
+                *(context->valid) = false;
+            }
+            (yyval) = static_cast<YYSTYPE>(0);
+        }
+        else
+        {
+            // Logical shift left. Casting to unsigned is needed to ensure there's no signed integer
+            // overflow, which some tools treat as an error.
+            (yyval) = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>((yyvsp[-2])) << (yyvsp[0]));
+        }
     }
 
     break;
@@ -1477,7 +1559,7 @@
   case 20:
 
     {
-        (yyval) = (yyvsp[-2]) + (yyvsp[0]);
+        (yyval) = (yyvsp[-2]) - (yyvsp[0]);
     }
 
     break;
@@ -1485,23 +1567,7 @@
   case 21:
 
     {
-        if ((yyvsp[0]) == 0)
-        {
-            if (!context->shortCircuited)
-            {
-                context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
-                                             context->token->location, "");
-                YYABORT;
-            }
-            else
-            {
-                (yyval) = 0;
-            }
-        }
-        else
-        {
-            (yyval) = (yyvsp[-2]) % (yyvsp[0]);
-        }
+        (yyval) = (yyvsp[-2]) + (yyvsp[0]);
     }
 
     break;
@@ -1511,16 +1577,55 @@
     {
         if ((yyvsp[0]) == 0)
         {
-            if (!context->shortCircuited)
+            if (!context->isIgnoringErrors())
             {
-                context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
-                                             context->token->location, "");
-                YYABORT;
+                std::ostringstream stream;
+                stream << (yyvsp[-2]) << " % " << (yyvsp[0]);
+                std::string text = stream.str();
+                context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+                                             context->token->location,
+                                             text.c_str());
+                *(context->valid) = false;
             }
-            else
+            (yyval) = static_cast<YYSTYPE>(0);
+        }
+        else if (((yyvsp[-2]) == std::numeric_limits<YYSTYPE>::min()) && ((yyvsp[0]) == -1))
+        {
+            // Check for the special case where the minimum representable number is
+            // divided by -1. If left alone this has undefined results.
+            (yyval) = 0;
+        }
+        else
+        {
+            (yyval) = (yyvsp[-2]) % (yyvsp[0]);
+        }
+    }
+
+    break;
+
+  case 23:
+
+    {
+        if ((yyvsp[0]) == 0)
+        {
+            if (!context->isIgnoringErrors())
             {
-                (yyval) = 0;
+                std::ostringstream stream;
+                stream << (yyvsp[-2]) << " / " << (yyvsp[0]);
+                std::string text = stream.str();
+                context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+                                            context->token->location,
+                                            text.c_str());
+                *(context->valid) = false;
             }
+            (yyval) = static_cast<YYSTYPE>(0);
+        }
+        else if (((yyvsp[-2]) == std::numeric_limits<YYSTYPE>::min()) && ((yyvsp[0]) == -1))
+        {
+            // Check for the special case where the minimum representable number is
+            // divided by -1. If left alone this leads to integer overflow in C++, which
+            // has undefined results.
+            (yyval) = std::numeric_limits<YYSTYPE>::max();
         }
         else
         {
@@ -1530,7 +1635,7 @@
 
     break;
 
-  case 23:
+  case 24:
 
     {
         (yyval) = (yyvsp[-2]) * (yyvsp[0]);
@@ -1538,7 +1643,7 @@
 
     break;
 
-  case 24:
+  case 25:
 
     {
         (yyval) = ! (yyvsp[0]);
@@ -1546,7 +1651,7 @@
 
     break;
 
-  case 25:
+  case 26:
 
     {
         (yyval) = ~ (yyvsp[0]);
@@ -1554,15 +1659,24 @@
 
     break;
 
-  case 26:
+  case 27:
 
     {
-        (yyval) = - (yyvsp[0]);
+        // Check for negation of minimum representable integer to prevent undefined signed int
+        // overflow.
+        if ((yyvsp[0]) == std::numeric_limits<YYSTYPE>::min())
+        {
+            (yyval) = std::numeric_limits<YYSTYPE>::min();
+        }
+        else
+        {
+            (yyval) = -(yyvsp[0]);
+        }
     }
 
     break;
 
-  case 27:
+  case 28:
 
     {
         (yyval) = + (yyvsp[0]);
@@ -1570,7 +1684,7 @@
 
     break;
 
-  case 28:
+  case 29:
 
     {
         (yyval) = (yyvsp[-1]);
@@ -1810,93 +1924,115 @@
 
 
 
-int yylex(YYSTYPE* lvalp, Context* context)
+int yylex(YYSTYPE *lvalp, Context *context)
 {
+    pp::Token *token = context->token;
+    if (!context->parsePresetToken)
+    {
+        context->lexer->lex(token);
+    }
+    context->parsePresetToken = false;
+
     int type = 0;
 
-    pp::Token* token = context->token;
     switch (token->type)
     {
-      case pp::Token::CONST_INT:
-      {
+      case pp::Token::CONST_INT: {
         unsigned int val = 0;
-        if (!token->uValue(&val))
+        int testVal = 0;
+        if (!token->uValue(&val) || (!token->iValue(&testVal) &&
+                                     context->errorSettings.integerLiteralsMustFit32BitSignedRange))
         {
-            context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
+            context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW,
                                          token->location, token->text);
+            *(context->valid) = false;
         }
         *lvalp = static_cast<YYSTYPE>(val);
         type = TOK_CONST_INT;
         break;
       }
       case pp::Token::IDENTIFIER:
-        if (!context->shortCircuited)
-        {
-            // Defined identifiers should have been expanded already.
-            // Unlike the C/C++ preprocessor, it does not default to 0.
-            // Use of such identifiers causes an error.
-            context->diagnostics->report(pp::Diagnostics::UNDEFINED_IDENTIFIER,
-                                         token->location, token->text);
-        }
-
-        *lvalp = 0;
-        type = TOK_CONST_INT;
+        *lvalp = static_cast<YYSTYPE>(-1);
+        type = TOK_IDENTIFIER;
         break;
-      case pp::Token::OP_OR: type = TOK_OP_OR; break;
-      case pp::Token::OP_AND: type = TOK_OP_AND; break;
-      case pp::Token::OP_NE: type = TOK_OP_NE; break;
-      case pp::Token::OP_EQ: type = TOK_OP_EQ; break;
-      case pp::Token::OP_GE: type = TOK_OP_GE; break;
-      case pp::Token::OP_LE: type = TOK_OP_LE; break;
-      case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break;
-      case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break;
-      case '|': type = '|'; break;
-      case '^': type = '^'; break;
-      case '&': type = '&'; break;
-      case '>': type = '>'; break;
-      case '<': type = '<'; break;
-      case '-': type = '-'; break;
-      case '+': type = '+'; break;
-      case '%': type = '%'; break;
-      case '/': type = '/'; break;
-      case '*': type = '*'; break;
-      case '!': type = '!'; break;
-      case '~': type = '~'; break;
-      case '(': type = '('; break;
-      case ')': type = ')'; break;
+      case pp::Token::OP_OR:
+        type = TOK_OP_OR;
+        break;
+      case pp::Token::OP_AND:
+        type = TOK_OP_AND;
+        break;
+      case pp::Token::OP_NE:
+        type = TOK_OP_NE;
+        break;
+      case pp::Token::OP_EQ:
+        type = TOK_OP_EQ;
+        break;
+      case pp::Token::OP_GE:
+        type = TOK_OP_GE;
+        break;
+      case pp::Token::OP_LE:
+        type = TOK_OP_LE;
+        break;
+      case pp::Token::OP_RIGHT:
+        type = TOK_OP_RIGHT;
+        break;
+      case pp::Token::OP_LEFT:
+        type = TOK_OP_LEFT;
+        break;
+      case '|':
+      case '^':
+      case '&':
+      case '>':
+      case '<':
+      case '-':
+      case '+':
+      case '%':
+      case '/':
+      case '*':
+      case '!':
+      case '~':
+      case '(':
+      case ')':
+        type = token->type;
+        break;
 
-      default: break;
+      default:
+        break;
     }
 
-    // Advance to the next token if the current one is valid.
-    if (type != 0) context->lexer->lex(token);
-
     return type;
 }
 
-void yyerror(Context* context, const char* reason)
+void yyerror(Context *context, const char *reason)
 {
-    context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION,
+    context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION,
                                  context->token->location,
                                  reason);
 }
 
 namespace pp {
 
-ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) :
-    mLexer(lexer),
-    mDiagnostics(diagnostics)
+ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
+    : mLexer(lexer),
+      mDiagnostics(diagnostics)
 {
 }
 
-bool ExpressionParser::parse(Token* token, int* result)
+bool ExpressionParser::parse(Token *token,
+                             int *result,
+                             bool parsePresetToken,
+                             const ErrorSettings &errorSettings,
+                             bool *valid)
 {
     Context context;
     context.diagnostics = mDiagnostics;
     context.lexer = mLexer;
     context.token = token;
     context.result = result;
-    context.shortCircuited = 0;
+    context.ignoreErrors = 0;
+    context.parsePresetToken = parsePresetToken;
+    context.errorSettings    = errorSettings;
+    context.valid            = valid;
     int ret = yyparse(&context);
     switch (ret)
     {
@@ -1905,12 +2041,12 @@
         break;
 
       case 2:
-        mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, "");
+        mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, "");
         break;
 
       default:
         assert(false);
-        mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, "");
+        mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, "");
         break;
     }
 
diff --git a/src/OpenGL/compiler/preprocessor/ExpressionParser.h b/src/OpenGL/compiler/preprocessor/ExpressionParser.h
index c28f4bb..47bd477 100644
--- a/src/OpenGL/compiler/preprocessor/ExpressionParser.h
+++ b/src/OpenGL/compiler/preprocessor/ExpressionParser.h
@@ -15,27 +15,34 @@
 #ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
 #define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
 
-#include "pp_utils.h"
+#include "DiagnosticsBase.h"
 
 namespace pp
 {
 
-class Diagnostics;
 class Lexer;
 struct Token;
 
 class ExpressionParser
 {
 public:
-	ExpressionParser(Lexer* lexer, Diagnostics* diagnostics);
+	struct ErrorSettings
+	{
+		Diagnostics::ID unexpectedIdentifier;
+		bool integerLiteralsMustFit32BitSignedRange;
+	};
 
-	bool parse(Token* token, int* result);
+	ExpressionParser(Lexer *lexer, Diagnostics *diagnostics);
+
+	bool parse(Token *token,
+	           int *result,
+	           bool parsePresetToken,
+	           const ErrorSettings &errorSettings,
+	           bool *valid);
 
 private:
-	PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser);
-
-	Lexer* mLexer;
-	Diagnostics* mDiagnostics;
+	Lexer *mLexer;
+	Diagnostics *mDiagnostics;
 };
 
 }  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/ExpressionParser.y b/src/OpenGL/compiler/preprocessor/ExpressionParser.y
index 09e86aa..5342935 100644
--- a/src/OpenGL/compiler/preprocessor/ExpressionParser.y
+++ b/src/OpenGL/compiler/preprocessor/ExpressionParser.y
@@ -38,26 +38,38 @@
 
 #if defined(__GNUC__)
 // Triggered by the auto-generated pplval variable.
+#if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#else
 #pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
 #elif defined(_MSC_VER)
-#pragma warning(disable: 4065 4701)
+#pragma warning(disable: 4065 4244 4701 4702)
 #endif
 
 #include "ExpressionParser.h"
 
+#if defined(_MSC_VER)
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+
+#include <limits>
 #include <cassert>
 #include <sstream>
+#include <stdint.h>
 
-#include "Diagnostics.h"
+#include "DiagnosticsBase.h"
 #include "Lexer.h"
 #include "Token.h"
+#include "../../common/debug.h"
 
-#if defined(_MSC_VER)
-typedef __int64 YYSTYPE;
-#else
-#include <stdint.h>
-typedef intmax_t YYSTYPE;
-#endif  // _MSC_VER
+typedef int32_t YYSTYPE;
+typedef uint32_t UNSIGNED_TYPE;
+
+#define YYENABLE_NLS 0
+#define YYLTYPE_IS_TRIVIAL 1
 #define YYSTYPE_IS_TRIVIAL 1
 #define YYSTYPE_IS_DECLARED 1
 
@@ -68,7 +80,17 @@
     pp::Lexer* lexer;
     pp::Token* token;
     int* result;
-    int shortCircuited;   // Don't produce errors when > 0
+    bool parsePresetToken;
+
+    pp::ExpressionParser::ErrorSettings errorSettings;
+    bool *valid;
+
+    void startIgnoreErrors() { ++ignoreErrors; }
+    void endIgnoreErrors() { --ignoreErrors; }
+
+    bool isIgnoringErrors() { return ignoreErrors > 0; }
+
+    int ignoreErrors;
 };
 }  // namespace
 %}
@@ -84,6 +106,7 @@
 %}
 
 %token TOK_CONST_INT
+%token TOK_IDENTIFIER
 %left TOK_OP_OR
 %left TOK_OP_AND
 %left '|'
@@ -107,16 +130,32 @@
 
 expression
     : TOK_CONST_INT
+    | TOK_IDENTIFIER {
+        if (!context->isIgnoringErrors())
+        {
+            // This rule should be applied right after the token is lexed, so we can
+            // refer to context->token in the error message.
+            context->diagnostics->report(context->errorSettings.unexpectedIdentifier,
+                                         context->token->location, context->token->text);
+            *(context->valid) = false;
+        }
+        $$ = $1;
+    }
     | expression TOK_OP_OR {
         if ($1 != 0)
         {
-            context->shortCircuited++;
+            // Ignore errors in the short-circuited part of the expression.
+            // ESSL3.00 section 3.4:
+            // If an operand is not evaluated, the presence of undefined identifiers
+            // in the operand will not cause an error.
+            // Unevaluated division by zero should not cause an error either.
+            context->startIgnoreErrors();
         }
     } expression {
         if ($1 != 0)
         {
-            context->shortCircuited--;
-            $$ = 1;
+            context->endIgnoreErrors();
+            $$ = static_cast<YYSTYPE>(1);
         }
         else
         {
@@ -126,13 +165,18 @@
     | expression TOK_OP_AND {
         if ($1 == 0)
         {
-            context->shortCircuited++;
+            // Ignore errors in the short-circuited part of the expression.
+            // ESSL3.00 section 3.4:
+            // If an operand is not evaluated, the presence of undefined identifiers
+            // in the operand will not cause an error.
+            // Unevaluated division by zero should not cause an error either.
+            context->startIgnoreErrors();
         }
     } expression {
         if ($1 == 0)
         {
-            context->shortCircuited--;
-            $$ = 0;
+            context->endIgnoreErrors();
+            $$ = static_cast<YYSTYPE>(0);
         }
         else
         {
@@ -167,10 +211,51 @@
         $$ = $1 < $3;
     }
     | expression TOK_OP_RIGHT expression {
-        $$ = $1 >> $3;
+        if ($3 < 0 || $3 > 31)
+        {
+            if (!context->isIgnoringErrors())
+            {
+                std::ostringstream stream;
+                stream << $1 << " >> " << $3;
+                std::string text = stream.str();
+                context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
+                                             context->token->location,
+                                             text.c_str());
+                *(context->valid) = false;
+            }
+            $$ = static_cast<YYSTYPE>(0);
+        }
+        else if ($1 < 0)
+        {
+            // Logical shift right.
+            $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) >> $3);
+        }
+        else
+        {
+            $$ = $1 >> $3;
+        }
     }
     | expression TOK_OP_LEFT expression {
-        $$ = $1 << $3;
+        if ($3 < 0 || $3 > 31)
+        {
+            if (!context->isIgnoringErrors())
+            {
+                std::ostringstream stream;
+                stream << $1 << " << " << $3;
+                std::string text = stream.str();
+                context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
+                                             context->token->location,
+                                             text.c_str());
+                *(context->valid) = false;
+            }
+            $$ = static_cast<YYSTYPE>(0);
+        }
+        else
+        {
+            // Logical shift left. Casting to unsigned is needed to ensure there's no signed integer
+            // overflow, which some tools treat as an error.
+            $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) << $3);
+        }
     }
     | expression '-' expression {
         $$ = $1 - $3;
@@ -181,16 +266,23 @@
     | expression '%' expression {
         if ($3 == 0)
         {
-            if (!context->shortCircuited)
+            if (!context->isIgnoringErrors())
             {
-                context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
-                                             context->token->location, "");
-                YYABORT;
+                std::ostringstream stream;
+                stream << $1 << " % " << $3;
+                std::string text = stream.str();
+                context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+                                             context->token->location,
+                                             text.c_str());
+                *(context->valid) = false;
             }
-            else
-            {
-                $$ = 0;
-            }
+            $$ = static_cast<YYSTYPE>(0);
+        }
+        else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
+        {
+            // Check for the special case where the minimum representable number is
+            // divided by -1. If left alone this has undefined results.
+            $$ = 0;
         }
         else
         {
@@ -200,16 +292,24 @@
     | expression '/' expression {
         if ($3 == 0)
         {
-            if (!context->shortCircuited)
+            if (!context->isIgnoringErrors())
             {
-                context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
-                                             context->token->location, "");
-                YYABORT;
+                std::ostringstream stream;
+                stream << $1 << " / " << $3;
+                std::string text = stream.str();
+                context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+                                            context->token->location,
+                                            text.c_str());
+                *(context->valid) = false;
             }
-            else
-            {
-                $$ = 0;
-            }
+            $$ = static_cast<YYSTYPE>(0);
+        }
+        else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
+        {
+            // Check for the special case where the minimum representable number is
+            // divided by -1. If left alone this leads to integer overflow in C++, which
+            // has undefined results.
+            $$ = std::numeric_limits<YYSTYPE>::max();
         }
         else
         {
@@ -226,7 +326,16 @@
         $$ = ~ $2;
     }
     | '-' expression %prec TOK_UNARY {
-        $$ = - $2;
+        // Check for negation of minimum representable integer to prevent undefined signed int
+        // overflow.
+        if ($2 == std::numeric_limits<YYSTYPE>::min())
+        {
+            $$ = std::numeric_limits<YYSTYPE>::min();
+        }
+        else
+        {
+            $$ = -$2;
+        }
     }
     | '+' expression %prec TOK_UNARY {
         $$ = + $2;
@@ -238,93 +347,115 @@
 
 %%
 
-int yylex(YYSTYPE* lvalp, Context* context)
+int yylex(YYSTYPE *lvalp, Context *context)
 {
+    pp::Token *token = context->token;
+    if (!context->parsePresetToken)
+    {
+        context->lexer->lex(token);
+    }
+    context->parsePresetToken = false;
+
     int type = 0;
 
-    pp::Token* token = context->token;
     switch (token->type)
     {
-      case pp::Token::CONST_INT:
-      {
+      case pp::Token::CONST_INT: {
         unsigned int val = 0;
-        if (!token->uValue(&val))
+        int testVal = 0;
+        if (!token->uValue(&val) || (!token->iValue(&testVal) &&
+                                     context->errorSettings.integerLiteralsMustFit32BitSignedRange))
         {
-            context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
+            context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW,
                                          token->location, token->text);
+            *(context->valid) = false;
         }
         *lvalp = static_cast<YYSTYPE>(val);
         type = TOK_CONST_INT;
         break;
       }
       case pp::Token::IDENTIFIER:
-        if (!context->shortCircuited)
-        {
-            // Defined identifiers should have been expanded already.
-            // Unlike the C/C++ preprocessor, it does not default to 0.
-            // Use of such identifiers causes an error.
-            context->diagnostics->report(pp::Diagnostics::UNDEFINED_IDENTIFIER,
-                                         token->location, token->text);
-        }
-
-        *lvalp = 0;
-        type = TOK_CONST_INT;
+        *lvalp = static_cast<YYSTYPE>(-1);
+        type = TOK_IDENTIFIER;
         break;
-      case pp::Token::OP_OR: type = TOK_OP_OR; break;
-      case pp::Token::OP_AND: type = TOK_OP_AND; break;
-      case pp::Token::OP_NE: type = TOK_OP_NE; break;
-      case pp::Token::OP_EQ: type = TOK_OP_EQ; break;
-      case pp::Token::OP_GE: type = TOK_OP_GE; break;
-      case pp::Token::OP_LE: type = TOK_OP_LE; break;
-      case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break;
-      case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break;
-      case '|': type = '|'; break;
-      case '^': type = '^'; break;
-      case '&': type = '&'; break;
-      case '>': type = '>'; break;
-      case '<': type = '<'; break;
-      case '-': type = '-'; break;
-      case '+': type = '+'; break;
-      case '%': type = '%'; break;
-      case '/': type = '/'; break;
-      case '*': type = '*'; break;
-      case '!': type = '!'; break;
-      case '~': type = '~'; break;
-      case '(': type = '('; break;
-      case ')': type = ')'; break;
+      case pp::Token::OP_OR:
+        type = TOK_OP_OR;
+        break;
+      case pp::Token::OP_AND:
+        type = TOK_OP_AND;
+        break;
+      case pp::Token::OP_NE:
+        type = TOK_OP_NE;
+        break;
+      case pp::Token::OP_EQ:
+        type = TOK_OP_EQ;
+        break;
+      case pp::Token::OP_GE:
+        type = TOK_OP_GE;
+        break;
+      case pp::Token::OP_LE:
+        type = TOK_OP_LE;
+        break;
+      case pp::Token::OP_RIGHT:
+        type = TOK_OP_RIGHT;
+        break;
+      case pp::Token::OP_LEFT:
+        type = TOK_OP_LEFT;
+        break;
+      case '|':
+      case '^':
+      case '&':
+      case '>':
+      case '<':
+      case '-':
+      case '+':
+      case '%':
+      case '/':
+      case '*':
+      case '!':
+      case '~':
+      case '(':
+      case ')':
+        type = token->type;
+        break;
 
-      default: break;
+      default:
+        break;
     }
 
-    // Advance to the next token if the current one is valid.
-    if (type != 0) context->lexer->lex(token);
-
     return type;
 }
 
-void yyerror(Context* context, const char* reason)
+void yyerror(Context *context, const char *reason)
 {
-    context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION,
+    context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION,
                                  context->token->location,
                                  reason);
 }
 
 namespace pp {
 
-ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) :
-    mLexer(lexer),
-    mDiagnostics(diagnostics)
+ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
+    : mLexer(lexer),
+      mDiagnostics(diagnostics)
 {
 }
 
-bool ExpressionParser::parse(Token* token, int* result)
+bool ExpressionParser::parse(Token *token,
+                             int *result,
+                             bool parsePresetToken,
+                             const ErrorSettings &errorSettings,
+                             bool *valid)
 {
     Context context;
     context.diagnostics = mDiagnostics;
     context.lexer = mLexer;
     context.token = token;
     context.result = result;
-    context.shortCircuited = 0;
+    context.ignoreErrors = 0;
+    context.parsePresetToken = parsePresetToken;
+    context.errorSettings    = errorSettings;
+    context.valid            = valid;
     int ret = yyparse(&context);
     switch (ret)
     {
@@ -333,12 +464,12 @@
         break;
 
       case 2:
-        mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, "");
+        mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, "");
         break;
 
       default:
         assert(false);
-        mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, "");
+        mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, "");
         break;
     }
 
diff --git a/src/OpenGL/compiler/preprocessor/Input.cpp b/src/OpenGL/compiler/preprocessor/Input.cpp
index c22622a..0626af7 100644
--- a/src/OpenGL/compiler/preprocessor/Input.cpp
+++ b/src/OpenGL/compiler/preprocessor/Input.cpp
@@ -25,27 +25,101 @@
 {
 }
 
-Input::Input(int count, const char* const string[], const int length[]) :
-	mCount(count),
-	mString(string)
+Input::~Input()
 {
-	assert(mCount >= 0);
+}
+
+Input::Input(size_t count, const char *const string[], const int length[])
+	: mCount(count), mString(string)
+{
 	mLength.reserve(mCount);
-	for (int i = 0; i < mCount; ++i)
+	for (size_t i = 0; i < mCount; ++i)
 	{
 		int len = length ? length[i] : -1;
-		mLength.push_back(len < 0 ? strlen(mString[i]) : len);
+		mLength.push_back(len < 0 ? std::strlen(mString[i]) : len);
 	}
 }
 
-int Input::read(char* buf, int maxSize)
+const char *Input::skipChar()
 {
-	int nRead = 0;
-	while ((nRead < maxSize) && (mReadLoc.sIndex < mCount))
+	// This function should only be called when there is a character to skip.
+	assert(mReadLoc.cIndex < mLength[mReadLoc.sIndex]);
+	++mReadLoc.cIndex;
+	if (mReadLoc.cIndex == mLength[mReadLoc.sIndex])
 	{
-		int size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex;
-		size = std::min(size, maxSize);
-		memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size);
+		++mReadLoc.sIndex;
+		mReadLoc.cIndex = 0;
+	}
+	if (mReadLoc.sIndex >= mCount)
+	{
+		return nullptr;
+	}
+	return mString[mReadLoc.sIndex] + mReadLoc.cIndex;
+}
+
+size_t Input::read(char *buf, size_t maxSize, int *lineNo)
+{
+	size_t nRead = 0;
+	// The previous call to read might have stopped copying the string when encountering a line
+	// continuation. Check for this possibility first.
+	if (mReadLoc.sIndex < mCount && maxSize > 0)
+	{
+		const char *c = mString[mReadLoc.sIndex] + mReadLoc.cIndex;
+		if ((*c) == '\\')
+		{
+			c = skipChar();
+			if (c != nullptr && (*c) == '\n')
+			{
+				// Line continuation of backslash + newline.
+				skipChar();
+				// Fake an EOF if the line number would overflow.
+				if (*lineNo == INT_MAX)
+				{
+					return 0;
+				}
+				++(*lineNo);
+			}
+			else if (c != nullptr && (*c) == '\r')
+			{
+				// Line continuation. Could be backslash + '\r\n' or just backslash + '\r'.
+				c = skipChar();
+				if (c != nullptr && (*c) == '\n')
+				{
+					skipChar();
+				}
+				// Fake an EOF if the line number would overflow.
+				if (*lineNo == INT_MAX)
+				{
+					return 0;
+				}
+				++(*lineNo);
+			}
+			else
+			{
+				// Not line continuation, so write the skipped backslash to buf.
+				*buf = '\\';
+				++nRead;
+			}
+		}
+	}
+
+	size_t maxRead = maxSize;
+	while ((nRead < maxRead) && (mReadLoc.sIndex < mCount))
+	{
+		size_t size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex;
+		size		= std::min(size, maxSize);
+		for (size_t i = 0; i < size; ++i)
+		{
+			// Stop if a possible line continuation is encountered.
+			// It will be processed on the next call on input, which skips it
+			// and increments line number if necessary.
+			if (*(mString[mReadLoc.sIndex] + mReadLoc.cIndex + i) == '\\')
+			{
+				size	= i;
+				maxRead = nRead + size;  // Stop reading right before the backslash.
+			}
+		}
+		std::memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size);
 		nRead += size;
 		mReadLoc.cIndex += size;
 
diff --git a/src/OpenGL/compiler/preprocessor/Input.h b/src/OpenGL/compiler/preprocessor/Input.h
index 35776e7..59083bf 100644
--- a/src/OpenGL/compiler/preprocessor/Input.h
+++ b/src/OpenGL/compiler/preprocessor/Input.h
@@ -15,7 +15,9 @@
 #ifndef COMPILER_PREPROCESSOR_INPUT_H_
 #define COMPILER_PREPROCESSOR_INPUT_H_
 
+#include <cstddef>
 #include <vector>
+#include <climits>
 
 namespace pp
 {
@@ -25,28 +27,33 @@
 {
 public:
 	Input();
-	Input(int count, const char* const string[], const int length[]);
+	~Input();
+	Input(size_t count, const char *const string[], const int length[]);
 
-	int count() const { return mCount; }
-	const char* string(int index) const { return mString[index]; }
-	int length(int index) const { return mLength[index]; }
+	size_t count() const { return mCount; }
+	const char *string(size_t index) const { return mString[index]; }
+	size_t length(size_t index) const { return mLength[index]; }
 
-	int read(char* buf, int maxSize);
+	size_t read(char *buf, size_t maxSize, int *lineNo);
 
 	struct Location
 	{
-		int sIndex;  // String index;
-		int cIndex;  // Char index.
+		size_t sIndex;  // String index;
+		size_t cIndex;  // Char index.
 
-		Location() : sIndex(0), cIndex(0) { }
+		Location() : sIndex(0), cIndex(0) {}
 	};
-	const Location& readLoc() const { return mReadLoc; }
+	const Location &readLoc() const { return mReadLoc; }
 
 private:
+	// Skip a character and return the next character after the one that was skipped.
+	// Return nullptr if data runs out.
+	const char *skipChar();
+
 	// Input.
-	int mCount;
-	const char* const* mString;
-	std::vector<int> mLength;
+	size_t mCount;
+	const char *const *mString;
+	std::vector<size_t> mLength;
 
 	Location mReadLoc;
 };
diff --git a/src/OpenGL/compiler/preprocessor/Lexer.h b/src/OpenGL/compiler/preprocessor/Lexer.h
index 558fc98..54de516 100644
--- a/src/OpenGL/compiler/preprocessor/Lexer.h
+++ b/src/OpenGL/compiler/preprocessor/Lexer.h
@@ -25,7 +25,7 @@
 public:
 	virtual ~Lexer();
 
-	virtual void lex(Token* token) = 0;
+	virtual void lex(Token *token) = 0;
 };
 
 }  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/Macro.cpp b/src/OpenGL/compiler/preprocessor/Macro.cpp
index 9024f8a..d3b419c 100644
--- a/src/OpenGL/compiler/preprocessor/Macro.cpp
+++ b/src/OpenGL/compiler/preprocessor/Macro.cpp
@@ -19,12 +19,33 @@
 namespace pp
 {
 
-bool Macro::equals(const Macro& other) const
+Macro::Macro() : predefined(false), disabled(false), expansionCount(0), type(kTypeObj)
 {
-    return (type == other.type) &&
-           (name == other.name) &&
-           (parameters == other.parameters) &&
-           (replacements == other.replacements);
+}
+
+Macro::~Macro()
+{
+}
+
+bool Macro::equals(const Macro &other) const
+{
+	return (type == other.type) && (name == other.name) && (parameters == other.parameters) &&
+	       (replacements == other.replacements);
+}
+
+void PredefineMacro(MacroSet *macroSet, const char *name, int value)
+{
+	Token token;
+	token.type = Token::CONST_INT;
+	token.text = std::to_string(value);
+
+	std::shared_ptr<Macro> macro = std::make_shared<Macro>();
+	macro->predefined = true;
+	macro->type = Macro::kTypeObj;
+	macro->name = name;
+	macro->replacements.push_back(token);
+
+	(*macroSet)[name] = macro;
 }
 
 }  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/Macro.h b/src/OpenGL/compiler/preprocessor/Macro.h
index bad8db3..c2daeca 100644
--- a/src/OpenGL/compiler/preprocessor/Macro.h
+++ b/src/OpenGL/compiler/preprocessor/Macro.h
@@ -16,6 +16,7 @@
 #define COMPILER_PREPROCESSOR_MACRO_H_
 
 #include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -34,11 +35,13 @@
     typedef std::vector<std::string> Parameters;
     typedef std::vector<Token> Replacements;
 
-    Macro() : predefined(false), disabled(false), type(kTypeObj) { }
-    bool equals(const Macro& other) const;
+    Macro();
+    ~Macro();
+    bool equals(const Macro &other) const;
 
     bool predefined;
     mutable bool disabled;
+    mutable int expansionCount;
 
     Type type;
     std::string name;
@@ -46,7 +49,9 @@
     Replacements replacements;
 };
 
-typedef std::map<std::string, Macro> MacroSet;
+typedef std::map<std::string, std::shared_ptr<Macro>> MacroSet;
+
+void PredefineMacro(MacroSet *macroSet, const char *name, int value);
 
 }  // namespace pp
 #endif  // COMPILER_PREPROCESSOR_MACRO_H_
diff --git a/src/OpenGL/compiler/preprocessor/MacroExpander.cpp b/src/OpenGL/compiler/preprocessor/MacroExpander.cpp
index df0e495..a235112 100644
--- a/src/OpenGL/compiler/preprocessor/MacroExpander.cpp
+++ b/src/OpenGL/compiler/preprocessor/MacroExpander.cpp
@@ -15,26 +15,32 @@
 #include "MacroExpander.h"
 
 #include <algorithm>
-#include <sstream>
+#include <cassert>
 
-#include "Diagnostics.h"
+#include "DiagnosticsBase.h"
+#include "pp_utils.h"
 #include "Token.h"
 
 namespace pp
 {
 
+namespace
+{
+
+const size_t kMaxContextTokens = 10000;
+
 class TokenLexer : public Lexer
 {
  public:
 	typedef std::vector<Token> TokenVector;
 
-	TokenLexer(TokenVector* tokens)
+	TokenLexer(TokenVector *tokens)
 	{
 		tokens->swap(mTokens);
 		mIter = mTokens.begin();
 	}
 
-	virtual void lex(Token* token)
+	void lex(Token *token) override
 	{
 		if (mIter == mTokens.end())
 		{
@@ -54,26 +60,64 @@
 	TokenVector::const_iterator mIter;
 };
 
-MacroExpander::MacroExpander(Lexer* lexer,
-                             MacroSet* macroSet,
-                             Diagnostics* diagnostics,
-                             bool parseDefined) :
-	mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mParseDefined(parseDefined)
+}  // anonymous namespace
+
+class MacroExpander::ScopedMacroReenabler final
 {
-	mReserveToken = nullptr;
+ public:
+	ScopedMacroReenabler(MacroExpander *expander);
+	~ScopedMacroReenabler();
+
+  private:
+	PP_DISALLOW_COPY_AND_ASSIGN(ScopedMacroReenabler);
+
+	MacroExpander *mExpander;
+};
+
+MacroExpander::ScopedMacroReenabler::ScopedMacroReenabler(MacroExpander *expander)
+	: mExpander(expander)
+{
+	mExpander->mDeferReenablingMacros = true;
+}
+
+MacroExpander::ScopedMacroReenabler::~ScopedMacroReenabler()
+{
+	mExpander->mDeferReenablingMacros = false;
+	for (auto macro : mExpander->mMacrosToReenable)
+	{
+		// Copying the string here by using substr is a check for use-after-free. It detects
+		// use-after-free more reliably than just toggling the disabled flag.
+		assert(macro->name.substr() != "");
+		macro->disabled = false;
+	}
+	mExpander->mMacrosToReenable.clear();
+}
+
+MacroExpander::MacroExpander(Lexer *lexer,
+                             MacroSet *macroSet,
+                             Diagnostics *diagnostics,
+                             bool parseDefined,
+                             int allowedMacroExpansionDepth)
+    : mLexer(lexer),
+      mMacroSet(macroSet),
+      mDiagnostics(diagnostics),
+      mParseDefined(parseDefined),
+      mTotalTokensInContexts(0),
+      mAllowedMacroExpansionDepth(allowedMacroExpansionDepth),
+      mDeferReenablingMacros(false)
+{
 }
 
 MacroExpander::~MacroExpander()
 {
-	for (size_t i = 0; i < mContextStack.size(); ++i)
+	assert(mMacrosToReenable.empty());
+	for (MacroContext *context : mContextStack)
 	{
-		delete mContextStack[i];
+		delete context;
 	}
-
-	delete mReserveToken;
 }
 
-void MacroExpander::lex(Token* token)
+void MacroExpander::lex(Token *token)
 {
 	while (true)
 	{
@@ -98,7 +142,7 @@
 			}
 			if (token->type != Token::IDENTIFIER)
 			{
-				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,
+				mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
 				                     token->text);
 				break;
 			}
@@ -110,7 +154,7 @@
 				getToken(token);
 				if (token->type != ')')
 				{
-					mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,
+					mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
 					                     token->text);
 					break;
 				}
@@ -130,17 +174,22 @@
 		if (iter == mMacroSet->end())
 			break;
 
-		const Macro& macro = iter->second;
-		if (macro.disabled)
+		std::shared_ptr<Macro> macro = iter->second;
+		if (macro->disabled)
 		{
 			// If a particular token is not expanded, it is never expanded.
 			token->setExpansionDisabled(true);
 			break;
 		}
-		if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen())
+
+		// Bump the expansion count before peeking if the next token is a '('
+		// otherwise there could be a #undef of the macro before the next token.
+		macro->expansionCount++;
+		if ((macro->type == Macro::kTypeFunc) && !isNextTokenLeftParen())
 		{
 			// If the token immediately after the macro name is not a '(',
 			// this macro should not be expanded.
+			macro->expansionCount--;
 			break;
 		}
 
@@ -148,13 +197,12 @@
 	}
 }
 
-void MacroExpander::getToken(Token* token)
+void MacroExpander::getToken(Token *token)
 {
-	if (mReserveToken)
+	if (mReserveToken.get())
 	{
 		*token = *mReserveToken;
-		delete mReserveToken;
-		mReserveToken = nullptr;
+		mReserveToken.reset();
 		return;
 	}
 
@@ -170,22 +218,23 @@
 	}
 	else
 	{
+		assert(mTotalTokensInContexts == 0);
 		mLexer->lex(token);
 	}
 }
 
-void MacroExpander::ungetToken(const Token& token)
+void MacroExpander::ungetToken(const Token &token)
 {
 	if (!mContextStack.empty())
 	{
-		MacroContext* context = mContextStack.back();
+		MacroContext *context = mContextStack.back();
 		context->unget();
 		assert(context->replacements[context->index] == token);
 	}
 	else
 	{
-		assert(!mReserveToken);
-		mReserveToken = new Token(token);
+		assert(!mReserveToken.get());
+		mReserveToken.reset(new Token(token));
 	}
 }
 
@@ -200,24 +249,25 @@
 	return lparen;
 }
 
-bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier)
+bool MacroExpander::pushMacro(std::shared_ptr<Macro> macro, const Token &identifier)
 {
-	assert(!macro.disabled);
+	assert(!macro->disabled);
 	assert(!identifier.expansionDisabled());
 	assert(identifier.type == Token::IDENTIFIER);
-	assert(identifier.text == macro.name);
+	assert(identifier.text == macro->name);
 
 	std::vector<Token> replacements;
-	if (!expandMacro(macro, identifier, &replacements))
+	if (!expandMacro(*macro, identifier, &replacements))
 		return false;
 
 	// Macro is disabled for expansion until it is popped off the stack.
-	macro.disabled = true;
+	macro->disabled = true;
 
-	MacroContext* context = new MacroContext;
-	context->macro = &macro;
+	MacroContext *context = new MacroContext;
+	context->macro = macro;
 	context->replacements.swap(replacements);
 	mContextStack.push_back(context);
+	mTotalTokensInContexts += context->replacements.size();
 	return true;
 }
 
@@ -225,43 +275,54 @@
 {
 	assert(!mContextStack.empty());
 
-	MacroContext* context = mContextStack.back();
+	MacroContext *context = mContextStack.back();
 	mContextStack.pop_back();
 
 	assert(context->empty());
 	assert(context->macro->disabled);
-	context->macro->disabled = false;
+	assert(context->macro->expansionCount > 0);
+	if (mDeferReenablingMacros)
+	{
+		mMacrosToReenable.push_back(context->macro);
+	}
+	else
+	{
+		context->macro->disabled = false;
+	}
+	context->macro->expansionCount--;
+	mTotalTokensInContexts -= context->replacements.size();
 	delete context;
 }
 
-bool MacroExpander::expandMacro(const Macro& macro,
-                                const Token& identifier,
-                                std::vector<Token>* replacements)
+bool MacroExpander::expandMacro(const Macro &macro,
+                                const Token &identifier,
+                                std::vector<Token> *replacements)
 {
 	replacements->clear();
+
+	// In the case of an object-like macro, the replacement list gets its location
+	// from the identifier, but in the case of a function-like macro, the replacement
+	// list gets its location from the closing parenthesis of the macro invocation.
+	// This is tested by dEQP-GLES3.functional.shaders.preprocessor.predefined_macros.*
+	SourceLocation replacementLocation = identifier.location;
 	if (macro.type == Macro::kTypeObj)
 	{
-		replacements->assign(macro.replacements.begin(),
-		                     macro.replacements.end());
+		replacements->assign(macro.replacements.begin(), macro.replacements.end());
 
 		if (macro.predefined)
 		{
-			static const std::string kLine = "__LINE__";
-			static const std::string kFile = "__FILE__";
+			const char kLine[] = "__LINE__";
+			const char kFile[] = "__FILE__";
 
 			assert(replacements->size() == 1);
-			Token& repl = replacements->front();
+			Token &repl = replacements->front();
 			if (macro.name == kLine)
 			{
-				std::ostringstream stream;
-				stream << identifier.location.line;
-				repl.text = stream.str();
+				repl.text = std::to_string(identifier.location.line);
 			}
 			else if (macro.name == kFile)
 			{
-				std::ostringstream stream;
-				stream << identifier.location.file;
-				repl.text = stream.str();
+				repl.text = std::to_string(identifier.location.file);
 			}
 		}
 	}
@@ -270,15 +331,15 @@
 		assert(macro.type == Macro::kTypeFunc);
 		std::vector<MacroArg> args;
 		args.reserve(macro.parameters.size());
-		if (!collectMacroArgs(macro, identifier, &args))
+		if (!collectMacroArgs(macro, identifier, &args, &replacementLocation))
 			return false;
 
 		replaceMacroParams(macro, args, replacements);
 	}
 
-	for (size_t i = 0; i < replacements->size(); ++i)
+	for (std::size_t i = 0; i < replacements->size(); ++i)
 	{
-		Token& repl = replacements->at(i);
+		Token &repl = replacements->at(i);
 		if (i == 0)
 		{
 			// The first token in the replacement list inherits the padding
@@ -286,34 +347,42 @@
 			repl.setAtStartOfLine(identifier.atStartOfLine());
 			repl.setHasLeadingSpace(identifier.hasLeadingSpace());
 		}
-		repl.location = identifier.location;
+		repl.location = replacementLocation;
 	}
 	return true;
 }
 
-bool MacroExpander::collectMacroArgs(const Macro& macro,
-                                     const Token& identifier,
-                                     std::vector<MacroArg>* args)
+bool MacroExpander::collectMacroArgs(const Macro &macro,
+                                     const Token &identifier,
+                                     std::vector<MacroArg> *args,
+                                     SourceLocation *closingParenthesisLocation)
 {
 	Token token;
 	getToken(&token);
 	assert(token.type == '(');
 
 	args->push_back(MacroArg());
-	for (int openParens = 1; openParens != 0; )
+
+	// Defer reenabling macros until args collection is finished to avoid the possibility of
+	// infinite recursion. Otherwise infinite recursion might happen when expanding the args after
+	// macros have been popped from the context stack when parsing the args.
+	ScopedMacroReenabler deferReenablingMacros(this);
+
+	int openParens = 1;
+	while (openParens != 0)
 	{
 		getToken(&token);
 
 		if (token.type == Token::LAST)
 		{
-			mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION,
-			                     identifier.location, identifier.text);
+			mDiagnostics->report(Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION, identifier.location,
+			                     identifier.text);
 			// Do not lose EOF token.
 			ungetToken(token);
 			return false;
 		}
 
-		bool isArg = false; // True if token is part of the current argument.
+		bool isArg = false;  // True if token is part of the current argument.
 		switch (token.type)
 		{
 		case '(':
@@ -323,12 +392,14 @@
 		case ')':
 			--openParens;
 			isArg = openParens != 0;
+			*closingParenthesisLocation = token.location;
 			break;
 		case ',':
 			// The individual arguments are separated by comma tokens, but
 			// the comma tokens between matching inner parentheses do not
 			// seperate arguments.
-			if (openParens == 1) args->push_back(MacroArg());
+			if (openParens == 1)
+				args->push_back(MacroArg());
 			isArg = openParens != 1;
 			break;
 		default:
@@ -337,14 +408,15 @@
 		}
 		if (isArg)
 		{
-			MacroArg& arg = args->back();
+			MacroArg &arg = args->back();
 			// Initial whitespace is not part of the argument.
-			if (arg.empty()) token.setHasLeadingSpace(false);
+			if (arg.empty())
+				token.setHasLeadingSpace(false);
 			arg.push_back(token);
 		}
 	}
 
-	const Macro::Parameters& params = macro.parameters;
+	const Macro::Parameters &params = macro.parameters;
 	// If there is only one empty argument, it is equivalent to no argument.
 	if (params.empty() && (args->size() == 1) && args->front().empty())
 	{
@@ -354,8 +426,8 @@
 	if (args->size() != params.size())
 	{
 		Diagnostics::ID id = args->size() < macro.parameters.size() ?
-			Diagnostics::MACRO_TOO_FEW_ARGS :
-			Diagnostics::MACRO_TOO_MANY_ARGS;
+			Diagnostics::PP_MACRO_TOO_FEW_ARGS :
+			Diagnostics::PP_MACRO_TOO_MANY_ARGS;
 		mDiagnostics->report(id, identifier.location, identifier.text);
 		return false;
 	}
@@ -363,11 +435,17 @@
 	// Pre-expand each argument before substitution.
 	// This step expands each argument individually before they are
 	// inserted into the macro body.
-	for (size_t i = 0; i < args->size(); ++i)
+	size_t numTokens = 0;
+	for (auto &arg : *args)
 	{
-		MacroArg& arg = args->at(i);
 		TokenLexer lexer(&arg);
-		MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mParseDefined);
+		if (mAllowedMacroExpansionDepth < 1)
+		{
+			mDiagnostics->report(Diagnostics::PP_MACRO_INVOCATION_CHAIN_TOO_DEEP,
+			                     token.location, token.text);
+			return false;
+		}
+		MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mParseDefined, mAllowedMacroExpansionDepth - 1);
 
 		arg.clear();
 		expander.lex(&token);
@@ -375,18 +453,32 @@
 		{
 			arg.push_back(token);
 			expander.lex(&token);
+			numTokens++;
+			if (numTokens + mTotalTokensInContexts > kMaxContextTokens)
+			{
+				mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text);
+				return false;
+			}
 		}
 	}
 	return true;
 }
 
-void MacroExpander::replaceMacroParams(const Macro& macro,
-                                       const std::vector<MacroArg>& args,
-                                       std::vector<Token>* replacements)
+void MacroExpander::replaceMacroParams(const Macro &macro,
+                                       const std::vector<MacroArg> &args,
+                                       std::vector<Token> *replacements)
 {
-	for (size_t i = 0; i < macro.replacements.size(); ++i)
+	for (std::size_t i = 0; i < macro.replacements.size(); ++i)
 	{
-		const Token& repl = macro.replacements[i];
+		if (!replacements->empty() &&
+			replacements->size() + mTotalTokensInContexts > kMaxContextTokens)
+		{
+			const Token &token = replacements->back();
+			mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text);
+			return;
+		}
+
+		const Token &repl = macro.replacements[i];
 		if (repl.type != Token::IDENTIFIER)
 		{
 			replacements->push_back(repl);
@@ -396,21 +488,21 @@
 		// TODO(alokp): Optimize this.
 		// There is no need to search for macro params every time.
 		// The param index can be cached with the replacement token.
-		Macro::Parameters::const_iterator iter = std::find(
-			macro.parameters.begin(), macro.parameters.end(), repl.text);
+		Macro::Parameters::const_iterator iter =
+			std::find(macro.parameters.begin(), macro.parameters.end(), repl.text);
 		if (iter == macro.parameters.end())
 		{
 			replacements->push_back(repl);
 			continue;
 		}
 
-		size_t iArg = std::distance(macro.parameters.begin(), iter);
-		const MacroArg& arg = args[iArg];
+		std::size_t iArg = std::distance(macro.parameters.begin(), iter);
+		const MacroArg &arg = args[iArg];
 		if (arg.empty())
 		{
 			continue;
 		}
-		size_t iRepl = replacements->size();
+		std::size_t iRepl = replacements->size();
 		replacements->insert(replacements->end(), arg.begin(), arg.end());
 		// The replacement token inherits padding properties from
 		// macro replacement token.
@@ -418,5 +510,29 @@
 	}
 }
 
+MacroExpander::MacroContext::MacroContext() : macro(0), index(0)
+{
+}
+
+MacroExpander::MacroContext::~MacroContext()
+{
+}
+
+bool MacroExpander::MacroContext::empty() const
+{
+	return index == replacements.size();
+}
+
+const Token &MacroExpander::MacroContext::get()
+{
+	return replacements[index++];
+}
+
+void MacroExpander::MacroContext::unget()
+{
+	assert(index > 0);
+	--index;
+}
+
 }  // namespace pp
 
diff --git a/src/OpenGL/compiler/preprocessor/MacroExpander.h b/src/OpenGL/compiler/preprocessor/MacroExpander.h
index c8c3920..f7c1701 100644
--- a/src/OpenGL/compiler/preprocessor/MacroExpander.h
+++ b/src/OpenGL/compiler/preprocessor/MacroExpander.h
@@ -15,7 +15,6 @@
 #ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
 #define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
 
-#include <cassert>
 #include <memory>
 #include <vector>
 
@@ -27,58 +26,67 @@
 {
 
 class Diagnostics;
+struct SourceLocation;
 
 class MacroExpander : public Lexer
 {
 public:
-	MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics, bool parseDefined);
-	virtual ~MacroExpander();
+	MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics, bool parseDefined, int allowedMacroExpansionDepth);
+	~MacroExpander() override;
 
-	virtual void lex(Token* token);
+	void lex(Token *token) override;
 
 private:
 	PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander);
 
-	void getToken(Token* token);
-	void ungetToken(const Token& token);
+	void getToken(Token *token);
+	void ungetToken(const Token &token);
 	bool isNextTokenLeftParen();
 
-	bool pushMacro(const Macro& macro, const Token& identifier);
+	bool pushMacro(std::shared_ptr<Macro> macro, const Token &identifier);
 	void popMacro();
 
-	bool expandMacro(const Macro& macro,
-	                 const Token& identifier,
-	                 std::vector<Token>* replacements);
+	bool expandMacro(const Macro &macro, const Token &identifier, std::vector<Token> *replacements);
 
 	typedef std::vector<Token> MacroArg;
-	bool collectMacroArgs(const Macro& macro,
-	                      const Token& identifier,
-	                      std::vector<MacroArg>* args);
-	void replaceMacroParams(const Macro& macro,
-	                        const std::vector<MacroArg>& args,
-	                        std::vector<Token>* replacements);
+	bool collectMacroArgs(const Macro &macro,
+	                      const Token &identifier,
+	                      std::vector<MacroArg> *args,
+	                      SourceLocation *closingParenthesisLocation);
+	void replaceMacroParams(const Macro &macro,
+	                        const std::vector<MacroArg> &args,
+	                        std::vector<Token> *replacements);
 
 	struct MacroContext
 	{
-		const Macro* macro;
-		size_t index;
-		std::vector<Token> replacements;
+		MacroContext();
+		~MacroContext();
+		bool empty() const;
+		const Token &get();
+		void unget();
 
-		MacroContext() : macro(0), index(0) { }
-		bool empty() const { return index == replacements.size(); }
-		const Token& get() { return replacements[index++]; }
-		void unget() { assert(index > 0); --index; }
+		std::shared_ptr<Macro> macro;
+		std::size_t index;
+		std::vector<Token> replacements;
 	};
 
-	Lexer* mLexer;
-	MacroSet* mMacroSet;
-	Diagnostics* mDiagnostics;
+	Lexer *mLexer;
+	MacroSet *mMacroSet;
+	Diagnostics *mDiagnostics;
 	const bool mParseDefined;
 
-	Token* mReserveToken;
-	std::vector<MacroContext*> mContextStack;
+	std::unique_ptr<Token> mReserveToken;
+	std::vector<MacroContext *> mContextStack;
+	size_t mTotalTokensInContexts;
+
+	int mAllowedMacroExpansionDepth;
+
+	bool mDeferReenablingMacros;
+	std::vector<std::shared_ptr<Macro>> mMacrosToReenable;
+
+	class ScopedMacroReenabler;
 };
 
 }  // namespace pp
-#endif  // COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
+#endif  // COMPILER_PREPROCESSOR_MACROEXPANDER_H_
 
diff --git a/src/OpenGL/compiler/preprocessor/Preprocessor.cpp b/src/OpenGL/compiler/preprocessor/Preprocessor.cpp
index 4ce0bf4..e4e2b5e 100644
--- a/src/OpenGL/compiler/preprocessor/Preprocessor.cpp
+++ b/src/OpenGL/compiler/preprocessor/Preprocessor.cpp
@@ -15,9 +15,8 @@
 #include "Preprocessor.h"
 
 #include <cassert>
-#include <sstream>
 
-#include "Diagnostics.h"
+#include "DiagnosticsBase.h"
 #include "DirectiveParser.h"
 #include "Macro.h"
 #include "MacroExpander.h"
@@ -29,25 +28,28 @@
 
 struct PreprocessorImpl
 {
-	Diagnostics* diagnostics;
+	Diagnostics *diagnostics;
 	MacroSet macroSet;
 	Tokenizer tokenizer;
 	DirectiveParser directiveParser;
 	MacroExpander macroExpander;
 
-	PreprocessorImpl(Diagnostics* diag, DirectiveHandler* directiveHandler) :
-		diagnostics(diag),
-		tokenizer(diag),
-		directiveParser(&tokenizer, &macroSet, diag, directiveHandler),
-		macroExpander(&directiveParser, &macroSet, diag, false)
+	PreprocessorImpl(Diagnostics *diag,
+	                 DirectiveHandler *directiveHandler,
+	                 const PreprocessorSettings &settings)
+	    : diagnostics(diag),
+	      tokenizer(diag),
+	      directiveParser(&tokenizer, &macroSet, diag, directiveHandler,  settings.maxMacroExpansionDepth),
+	      macroExpander(&directiveParser, &macroSet, diag, false, settings.maxMacroExpansionDepth)
 	{
 	}
 };
 
-Preprocessor::Preprocessor(Diagnostics* diagnostics,
-                           DirectiveHandler* directiveHandler)
+Preprocessor::Preprocessor(Diagnostics *diagnostics,
+                           DirectiveHandler *directiveHandler,
+                           const PreprocessorSettings &settings)
 {
-	mImpl = new PreprocessorImpl(diagnostics, directiveHandler);
+	mImpl = new PreprocessorImpl(diagnostics, directiveHandler, settings);
 }
 
 Preprocessor::~Preprocessor()
@@ -55,40 +57,25 @@
 	delete mImpl;
 }
 
-bool Preprocessor::init(int count,
-                        const char* const string[],
-                        const int length[])
+bool Preprocessor::init(size_t count, const char *const string[], const int length[])
 {
-	static const int kGLSLVersion = 100;
+	static const int kDefaultGLSLVersion = 100;
 
 	// Add standard pre-defined macros.
 	predefineMacro("__LINE__", 0);
 	predefineMacro("__FILE__", 0);
-	predefineMacro("__VERSION__", kGLSLVersion);
+	predefineMacro("__VERSION__", kDefaultGLSLVersion);
 	predefineMacro("GL_ES", 1);
 
 	return mImpl->tokenizer.init(count, string, length);
 }
 
-void Preprocessor::predefineMacro(const char* name, int value)
+void Preprocessor::predefineMacro(const char *name, int value)
 {
-	std::ostringstream stream;
-	stream << value;
-
-	Token token;
-	token.type = Token::CONST_INT;
-	token.text = stream.str();
-
-	Macro macro;
-	macro.predefined = true;
-	macro.type = Macro::kTypeObj;
-	macro.name = name;
-	macro.replacements.push_back(token);
-
-	mImpl->macroSet[name] = macro;
+	PredefineMacro(&mImpl->macroSet, name, value);
 }
 
-void Preprocessor::lex(Token* token)
+void Preprocessor::lex(Token *token)
 {
 	bool validToken = false;
 	while (!validToken)
@@ -102,40 +89,12 @@
 		case Token::PP_HASH:
 			assert(false);
 			break;
-		case Token::CONST_INT:
-		  {
-			int val = 0;
-			if (!token->iValue(&val))
-			{
-				// Do not mark the token as invalid.
-				// Just emit the diagnostic and reset value to 0.
-				mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW,
-				                           token->location, token->text);
-				token->text.assign("0");
-			}
-			validToken = true;
-			break;
-		  }
-		case Token::CONST_FLOAT:
-		  {
-			float val = 0;
-			if (!token->fValue(&val))
-			{
-				// Do not mark the token as invalid.
-				// Just emit the diagnostic and reset value to 0.0.
-				mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW,
-				                           token->location, token->text);
-				token->text.assign("0.0");
-			}
-			validToken = true;
-			break;
-		  }
 		case Token::PP_NUMBER:
-			mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER,
+			mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER,
 			                           token->location, token->text);
 			break;
 		case Token::PP_OTHER:
-			mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER,
+			mImpl->diagnostics->report(Diagnostics::PP_INVALID_CHARACTER,
 			                           token->location, token->text);
 			break;
 		default:
@@ -145,5 +104,9 @@
 	}
 }
 
-}  // namespace pp
+void Preprocessor::setMaxTokenSize(size_t maxTokenSize)
+{
+	mImpl->tokenizer.setMaxTokenSize(maxTokenSize);
+}
 
+}  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/Preprocessor.h b/src/OpenGL/compiler/preprocessor/Preprocessor.h
index 62eca56..a8e139c 100644
--- a/src/OpenGL/compiler/preprocessor/Preprocessor.h
+++ b/src/OpenGL/compiler/preprocessor/Preprocessor.h
@@ -17,6 +17,8 @@
 
 #include "pp_utils.h"
 
+#include <cstddef>
+
 namespace pp
 {
 
@@ -25,10 +27,18 @@
 struct PreprocessorImpl;
 struct Token;
 
+struct PreprocessorSettings
+{
+	PreprocessorSettings() : maxMacroExpansionDepth(1000) {}
+	int maxMacroExpansionDepth;
+};
+
 class Preprocessor
 {
 public:
-	Preprocessor(Diagnostics* diagnostics, DirectiveHandler* directiveHandler);
+	Preprocessor(Diagnostics *diagnostics,
+	             DirectiveHandler *directiveHandler,
+	             const PreprocessorSettings &settings);
 	~Preprocessor();
 
 	// count: specifies the number of elements in the string and length arrays.
@@ -40,16 +50,19 @@
 	// Each element in the length array may contain the length of the
 	// corresponding string or a value less than 0 to indicate that the string
 	// is null terminated.
-	bool init(int count, const char* const string[], const int length[]);
+	bool init(size_t count, const char *const string[], const int length[]);
 	// Adds a pre-defined macro.
-	void predefineMacro(const char* name, int value);
+	void predefineMacro(const char *name, int value);
 
-	void lex(Token* token);
+	void lex(Token *token);
+
+	// Set maximum preprocessor token size
+	void setMaxTokenSize(size_t maxTokenSize);
 
 private:
 	PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor);
 
-	PreprocessorImpl* mImpl;
+	PreprocessorImpl *mImpl;
 };
 
 }  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/SourceLocation.h b/src/OpenGL/compiler/preprocessor/SourceLocation.h
index b01e73b..234d304 100644
--- a/src/OpenGL/compiler/preprocessor/SourceLocation.h
+++ b/src/OpenGL/compiler/preprocessor/SourceLocation.h
@@ -20,10 +20,10 @@
 
 struct SourceLocation
 {
-	SourceLocation() : file(0), line(0) { }
-	SourceLocation(int f, int l) : file(f), line(l) { }
+	SourceLocation() : file(0), line(0) {}
+	SourceLocation(int f, int l) : file(f), line(l) {}
 
-	bool equals(const SourceLocation& other) const
+	bool equals(const SourceLocation &other) const
 	{
 		return (file == other.file) && (line == other.line);
 	}
@@ -32,12 +32,12 @@
 	int line;
 };
 
-inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs)
+inline bool operator==(const SourceLocation &lhs, const SourceLocation &rhs)
 {
 	return lhs.equals(rhs);
 }
 
-inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs)
+inline bool operator!=(const SourceLocation &lhs, const SourceLocation &rhs)
 {
 	return !lhs.equals(rhs);
 }
diff --git a/src/OpenGL/compiler/preprocessor/Token.cpp b/src/OpenGL/compiler/preprocessor/Token.cpp
index 28d6f8c..731a592 100644
--- a/src/OpenGL/compiler/preprocessor/Token.cpp
+++ b/src/OpenGL/compiler/preprocessor/Token.cpp
@@ -29,7 +29,7 @@
 	text.clear();
 }
 
-bool Token::equals(const Token& other) const
+bool Token::equals(const Token &other) const
 {
 	return (type == other.type) &&
 	       (flags == other.flags) &&
@@ -61,25 +61,25 @@
 		flags &= ~EXPANSION_DISABLED;
 }
 
-bool Token::iValue(int* value) const
+bool Token::iValue(int *value) const
 {
 	assert(type == CONST_INT);
 	return numeric_lex_int(text, value);
 }
 
-bool Token::uValue(unsigned int* value) const
+bool Token::uValue(unsigned int *value) const
 {
 	assert(type == CONST_INT);
 	return numeric_lex_int(text, value);
 }
 
-bool Token::fValue(float* value) const
+bool Token::fValue(float *value) const
 {
 	assert(type == CONST_FLOAT);
 	return numeric_lex_float(text, value);
 }
 
-std::ostream& operator<<(std::ostream& out, const Token& token)
+std::ostream &operator<<(std::ostream &out, const Token &token)
 {
 	if (token.hasLeadingSpace())
 		out << " ";
diff --git a/src/OpenGL/compiler/preprocessor/Token.h b/src/OpenGL/compiler/preprocessor/Token.h
index ddd3aac..c0475a8 100644
--- a/src/OpenGL/compiler/preprocessor/Token.h
+++ b/src/OpenGL/compiler/preprocessor/Token.h
@@ -27,6 +27,8 @@
 {
 	enum Type
 	{
+		// Calling this ERROR causes a conflict with wingdi.h
+		GOT_ERROR = -1,
 		LAST = 0,  // EOF.
 
 		IDENTIFIER = 258,
@@ -70,10 +72,10 @@
 		EXPANSION_DISABLED = 1 << 2
 	};
 
-	Token() : type(0), flags(0) { }
+	Token() : type(0), flags(0) {}
 
 	void reset();
-	bool equals(const Token& other) const;
+	bool equals(const Token &other) const;
 
 	// Returns true if this is the first token on line.
 	// It disregards any leading whitespace.
@@ -88,9 +90,9 @@
 
 	// Converts text into numeric value for CONST_INT and CONST_FLOAT token.
 	// Returns false if the parsed value cannot fit into an int or float.
-	bool iValue(int* value) const;
-	bool uValue(unsigned int* value) const;
-	bool fValue(float* value) const;
+	bool iValue(int *value) const;
+	bool uValue(unsigned int *value) const;
+	bool fValue(float *value) const;
 
 	int type;
 	unsigned int flags;
@@ -98,17 +100,17 @@
 	std::string text;
 };
 
-inline bool operator==(const Token& lhs, const Token& rhs)
+inline bool operator==(const Token &lhs, const Token &rhs)
 {
 	return lhs.equals(rhs);
 }
 
-inline bool operator!=(const Token& lhs, const Token& rhs)
+inline bool operator!=(const Token &lhs, const Token &rhs)
 {
 	return !lhs.equals(rhs);
 }
 
-extern std::ostream& operator<<(std::ostream& out, const Token& token);
+std::ostream &operator<<(std::ostream &out, const Token &token);
 
 }  // namepsace pp
 #endif  // COMPILER_PREPROCESSOR_TOKEN_H_
diff --git a/src/OpenGL/compiler/preprocessor/Tokenizer.cpp b/src/OpenGL/compiler/preprocessor/Tokenizer.cpp
index 13e93ce..44025a9 100644
--- a/src/OpenGL/compiler/preprocessor/Tokenizer.cpp
+++ b/src/OpenGL/compiler/preprocessor/Tokenizer.cpp
@@ -1,4 +1,4 @@
-#line 16 "./Tokenizer.l"
+#line 24 "./Tokenizer.l"
 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,330 @@
 
 
 
-#line 13 "./Tokenizer.cpp"
-
 #define  YY_INT_ALIGNED short int
 
 /* A lexical scanner generated by flex */
 
+
+
+
+
+
+
+
+
+
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 6
-#define YY_FLEX_SUBMINOR_VERSION 0
+#define YY_FLEX_SUBMINOR_VERSION 4
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef yy_create_buffer
+#define pp_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer pp_create_buffer
+#endif
+
+    
+#ifdef yy_delete_buffer
+#define pp_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer pp_delete_buffer
+#endif
+
+    
+#ifdef yy_scan_buffer
+#define pp_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer pp_scan_buffer
+#endif
+
+    
+#ifdef yy_scan_string
+#define pp_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string pp_scan_string
+#endif
+
+    
+#ifdef yy_scan_bytes
+#define pp_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes pp_scan_bytes
+#endif
+
+    
+#ifdef yy_init_buffer
+#define pp_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer pp_init_buffer
+#endif
+
+    
+#ifdef yy_flush_buffer
+#define pp_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer pp_flush_buffer
+#endif
+
+    
+#ifdef yy_load_buffer_state
+#define pp_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state pp_load_buffer_state
+#endif
+
+    
+#ifdef yy_switch_to_buffer
+#define pp_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer pp_switch_to_buffer
+#endif
+
+    
+#ifdef yypush_buffer_state
+#define pppush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state pppush_buffer_state
+#endif
+
+    
+#ifdef yypop_buffer_state
+#define pppop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state pppop_buffer_state
+#endif
+
+    
+#ifdef yyensure_buffer_stack
+#define ppensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack ppensure_buffer_stack
+#endif
+
+    
+#ifdef yylex
+#define pplex_ALREADY_DEFINED
+#else
+#define yylex pplex
+#endif
+
+    
+#ifdef yyrestart
+#define pprestart_ALREADY_DEFINED
+#else
+#define yyrestart pprestart
+#endif
+
+    
+#ifdef yylex_init
+#define pplex_init_ALREADY_DEFINED
+#else
+#define yylex_init pplex_init
+#endif
+
+    
+#ifdef yylex_init_extra
+#define pplex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra pplex_init_extra
+#endif
+
+    
+#ifdef yylex_destroy
+#define pplex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy pplex_destroy
+#endif
+
+    
+#ifdef yyget_debug
+#define ppget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug ppget_debug
+#endif
+
+    
+#ifdef yyset_debug
+#define ppset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug ppset_debug
+#endif
+
+    
+#ifdef yyget_extra
+#define ppget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra ppget_extra
+#endif
+
+    
+#ifdef yyset_extra
+#define ppset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra ppset_extra
+#endif
+
+    
+#ifdef yyget_in
+#define ppget_in_ALREADY_DEFINED
+#else
+#define yyget_in ppget_in
+#endif
+
+    
+#ifdef yyset_in
+#define ppset_in_ALREADY_DEFINED
+#else
+#define yyset_in ppset_in
+#endif
+
+    
+#ifdef yyget_out
+#define ppget_out_ALREADY_DEFINED
+#else
+#define yyget_out ppget_out
+#endif
+
+    
+#ifdef yyset_out
+#define ppset_out_ALREADY_DEFINED
+#else
+#define yyset_out ppset_out
+#endif
+
+    
+#ifdef yyget_leng
+#define ppget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng ppget_leng
+#endif
+
+    
+#ifdef yyget_text
+#define ppget_text_ALREADY_DEFINED
+#else
+#define yyget_text ppget_text
+#endif
+
+    
+#ifdef yyget_lineno
+#define ppget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno ppget_lineno
+#endif
+
+    
+#ifdef yyset_lineno
+#define ppset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno ppset_lineno
+#endif
+
+    
+        
+#ifdef yyget_column
+#define ppget_column_ALREADY_DEFINED
+#else
+#define yyget_column ppget_column
+#endif
+
+        
+#ifdef yyset_column
+#define ppset_column_ALREADY_DEFINED
+#else
+#define yyset_column ppset_column
+#endif
+
+    
+    
+#ifdef yywrap
+#define ppwrap_ALREADY_DEFINED
+#else
+#define yywrap ppwrap
+#endif
+
+
+
+
+    
+#ifdef yyget_lval
+#define ppget_lval_ALREADY_DEFINED
+#else
+#define yyget_lval ppget_lval
+#endif
+
+    
+#ifdef yyset_lval
+#define ppset_lval_ALREADY_DEFINED
+#else
+#define yyset_lval ppset_lval
+#endif
+
+
+
+
+    
+#ifdef yyget_lloc
+#define ppget_lloc_ALREADY_DEFINED
+#else
+#define yyget_lloc ppget_lloc
+#endif
+
+    
+#ifdef yyset_lloc
+#define ppset_lloc_ALREADY_DEFINED
+#else
+#define yyset_lloc ppset_lloc
+#endif
+
+
+
+
+#ifdef yyalloc
+#define ppalloc_ALREADY_DEFINED
+#else
+#define yyalloc ppalloc
+#endif
+
+    
+#ifdef yyrealloc
+#define pprealloc_ALREADY_DEFINED
+#else
+#define yyrealloc pprealloc
+#endif
+
+    
+#ifdef yyfree
+#define ppfree_ALREADY_DEFINED
+#else
+#define yyfree ppfree
+#endif
+
+
+
+
+
+
+
+
+
 /* First, we deal with  platform-specific or compiler-specific issues. */
 
 /* begin standard C headers. */
@@ -101,40 +411,38 @@
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#ifndef SIZE_MAX
+#define SIZE_MAX               (~(size_t)0)
+#endif
+
 #endif /* ! C99 */
 
 #endif /* ! FLEXINT_H */
 
-#ifdef __cplusplus
 
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
+/* begin standard C++ headers. */
 
-#else	/* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif	/* defined (__STDC__) */
-#endif	/* ! __cplusplus */
-
-#ifdef YY_USE_CONST
+/* TODO: this is always defined, so inline it */
 #define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
 #else
-#define yyconst
+#define yynoreturn
 #endif
 
 /* Returned upon end-of-file. */
 #define YY_NULL 0
 
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index.  If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
+
+/* Promotes a possibly negative, possibly signed char to an
+ *   integer in range [0..255] for use as an array index.
  */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+
+
+
 
 /* An opaque pointer. */
 #ifndef YY_TYPEDEF_YY_SCANNER_T
@@ -142,6 +450,22 @@
 typedef void* yyscan_t;
 #endif
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 /* For convenience, these vars (plus the bison vars far below)
    are macros in the reentrant scanner. */
 #define yyin yyg->yyin_r
@@ -153,27 +477,36 @@
 #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
 #define yy_flex_debug yyg->yy_flex_debug_r
 
+
+
+
+
+
+
+
+
+
+
+
+
 /* Enter a start condition.  This macro really ought to take a parameter,
  * but we do it the disgusting crufty way forced on us by the ()-less
  * definition of BEGIN.
  */
 #define BEGIN yyg->yy_start = 1 + 2 *
-
 /* Translate the current start state into a value that can be later handed
  * to BEGIN to return to the state.  The YYSTATE alias is for lex
  * compatibility.
  */
 #define YY_START ((yyg->yy_start - 1) / 2)
 #define YYSTATE YY_START
-
 /* Action number for EOF rule of a given start state. */
 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
 /* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE pprestart(yyin ,yyscanner )
-
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
 #define YY_END_OF_BUFFER_CHAR 0
 
+
 /* Size of default input buffer. */
 #ifndef YY_BUF_SIZE
 #ifdef __ia64__
@@ -187,10 +520,13 @@
 #endif /* __ia64__ */
 #endif
 
+
 /* The state buf must be large enough to hold one state per character in the main buffer.
  */
 #define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
 
+
+
 #ifndef YY_TYPEDEF_YY_BUFFER_STATE
 #define YY_TYPEDEF_YY_BUFFER_STATE
 typedef struct yy_buffer_state *YY_BUFFER_STATE;
@@ -201,10 +537,13 @@
 typedef size_t yy_size_t;
 #endif
 
+
+
+
 #define EOB_ACT_CONTINUE_SCAN 0
 #define EOB_ACT_END_OF_FILE 1
 #define EOB_ACT_LAST_MATCH 2
-
+    
     #define YY_LESS_LINENO(n)
     #define YY_LINENO_REWIND_TO(ptr)
     
@@ -221,27 +560,29 @@
 		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
 		} \
 	while ( 0 )
-
 #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
 
+
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 struct yy_buffer_state
 	{
 	FILE *yy_input_file;
 
+
+
 	char *yy_ch_buf;		/* input buffer */
 	char *yy_buf_pos;		/* current position in input buffer */
 
 	/* Size of input buffer in bytes, not including room for EOB
 	 * characters.
 	 */
-	yy_size_t yy_buf_size;
+	int yy_buf_size;
 
 	/* Number of characters read into yy_ch_buf, not including EOB
 	 * characters.
 	 */
-	yy_size_t yy_n_chars;
+	int yy_n_chars;
 
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	 * and can realloc() it to grow it, and should free() it to
@@ -264,7 +605,8 @@
 
     int yy_bs_lineno; /**< The line count. */
     int yy_bs_column; /**< The column count. */
-    
+
+
 	/* Whether to try to fill the input buffer when we reach the
 	 * end of it.
 	 */
@@ -281,7 +623,7 @@
 	 * possible backing-up.
 	 *
 	 * When we actually see the EOF, we change the status to "new"
-	 * (via pprestart()), so that the user can continue scanning by
+	 * (via yyrestart()), so that the user can continue scanning by
 	 * just pointing yyin at a new input file.
 	 */
 #define YY_BUFFER_EOF_PENDING 2
@@ -289,6 +631,9 @@
 	};
 #endif /* !YY_STRUCT_YY_BUFFER_STATE */
 
+
+
+
 /* We provide macros for accessing buffer states in case in the
  * future we want to put the buffer states in a more general
  * "scanner state".
@@ -298,89 +643,97 @@
 #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
                           ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
                           : NULL)
-
 /* Same as previous macro, but useful when we know that the buffer stack is not
  * NULL or when we need an lvalue. For internal use only.
  */
 #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
 
-void pprestart (FILE *input_file ,yyscan_t yyscanner );
-void pp_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-YY_BUFFER_STATE pp_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
-void pp_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void pp_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void pppush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-void pppop_buffer_state (yyscan_t yyscanner );
 
-static void ppensure_buffer_stack (yyscan_t yyscanner );
-static void pp_load_buffer_state (yyscan_t yyscanner );
-static void pp_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
 
-#define YY_FLUSH_BUFFER pp_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
 
-YY_BUFFER_STATE pp_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
-YY_BUFFER_STATE pp_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
-YY_BUFFER_STATE pp_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
 
-void *ppalloc (yy_size_t ,yyscan_t yyscanner );
-void *pprealloc (void *,yy_size_t ,yyscan_t yyscanner );
-void ppfree (void * ,yyscan_t yyscanner );
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
 
-#define yy_new_buffer pp_create_buffer
 
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+
+#define yy_new_buffer yy_create_buffer
 #define yy_set_interactive(is_interactive) \
 	{ \
 	if ( ! YY_CURRENT_BUFFER ){ \
-        ppensure_buffer_stack (yyscanner); \
+        yyensure_buffer_stack (yyscanner); \
 		YY_CURRENT_BUFFER_LVALUE =    \
-            pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
 	} \
 	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
 	}
-
 #define yy_set_bol(at_bol) \
 	{ \
 	if ( ! YY_CURRENT_BUFFER ){\
-        ppensure_buffer_stack (yyscanner); \
+        yyensure_buffer_stack (yyscanner); \
 		YY_CURRENT_BUFFER_LVALUE =    \
-            pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
 	} \
 	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
 	}
-
 #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
 
+
 /* Begin user sect3 */
 
 #define ppwrap(yyscanner) (/*CONSTCOND*/1)
 #define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
 
-typedef unsigned char YY_CHAR;
 
 typedef int yy_state_type;
 
 #define yytext_ptr yytext_r
 
-static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
-static int yy_get_next_buffer (yyscan_t yyscanner );
-#if defined(__GNUC__) && __GNUC__ >= 3
-__attribute__((__noreturn__))
-#endif
-static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+
+
+
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state  , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+
+
 
 /* Done after the current pattern has been matched and before the
  * corresponding action - sets up yytext.
  */
 #define YY_DO_BEFORE_ACTION \
 	yyg->yytext_ptr = yy_bp; \
-	yyleng = (size_t) (yy_cp - yy_bp); \
+	yyleng = (int) (yy_cp - yy_bp); \
 	yyg->yy_hold_char = *yy_cp; \
 	*yy_cp = '\0'; \
 	yyg->yy_c_buf_p = yy_cp;
-
-#define YY_NUM_RULES 38
-#define YY_END_OF_BUFFER 39
+#define YY_NUM_RULES 37
+#define YY_END_OF_BUFFER 38
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -388,22 +741,22 @@
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[98] =
+static const flex_int16_t yy_accept[95] =
     {   0,
-        0,    0,    0,    0,   39,   37,   34,   35,   35,   33,
+        0,    0,    0,    0,   38,   36,   34,   35,   35,   33,
         7,   33,   33,   33,   33,   33,   33,   33,   33,    9,
-        9,   33,   33,   33,    8,   37,   33,   33,    3,    5,
-        5,    4,   34,   35,   19,   27,   20,   30,   25,   12,
-       23,   13,   24,   10,    2,    1,   26,   10,    9,   11,
-       11,   11,    9,   11,    9,    9,   14,   16,   18,   17,
-       15,    8,   36,   36,   31,   21,   32,   22,    3,    5,
-        6,   11,   10,   11,   10,    1,   10,   11,   10,    0,
-       10,    9,    9,    9,   28,   29,    0,   10,   10,   10,
-       10,    9,   10,   10,    9,   10,    0
+        9,   33,   33,   33,    8,   33,   33,    3,    5,    5,
+        4,   34,   35,   19,   27,   20,   30,   25,   12,   23,
+       13,   24,   10,    2,    1,   26,   10,    9,   11,   11,
+       11,    9,   11,    9,    9,   14,   16,   18,   17,   15,
+        8,   31,   21,   32,   22,    3,    5,    6,   11,   10,
+       11,   10,    1,   10,   11,   10,    0,   10,    9,    9,
+        9,   28,   29,    0,   10,   10,   10,   10,    9,   10,
+       10,    9,   10,    0
 
     } ;
 
-static yyconst YY_CHAR yy_ec[256] =
+static const YY_CHAR yy_ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         2,    2,    4,    1,    1,    1,    1,    1,    1,    1,
@@ -414,11 +767,11 @@
        19,   20,    9,    1,   21,   21,   21,   21,   22,   23,
        24,   24,   24,   24,   24,   24,   24,   24,   24,   24,
        24,   24,   24,   24,   25,   24,   24,   26,   24,   24,
-        9,   27,    9,   28,   24,    1,   21,   21,   21,   21,
+        9,    1,    9,   27,   24,    1,   21,   21,   21,   21,
 
        22,   23,   24,   24,   24,   24,   24,   24,   24,   24,
        24,   24,   24,   24,   24,   24,   25,   24,   24,   26,
-       24,   24,    9,   29,    9,    9,    1,    1,    1,    1,
+       24,   24,    9,   28,    9,    9,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -435,101 +788,99 @@
         1,    1,    1,    1,    1
     } ;
 
-static yyconst YY_CHAR yy_meta[30] =
+static const YY_CHAR yy_meta[29] =
     {   0,
         1,    1,    2,    2,    1,    1,    1,    1,    1,    3,
         1,    1,    4,    1,    5,    5,    5,    1,    1,    1,
-        5,    5,    5,    5,    5,    5,    1,    1,    1
+        5,    5,    5,    5,    5,    5,    1,    1
     } ;
 
-static yyconst flex_uint16_t yy_base[103] =
+static const flex_int16_t yy_base[100] =
     {   0,
-        0,    0,   27,   29,  137,  194,  133,  194,  117,  100,
-      194,   98,   26,  194,   94,   24,   28,   33,   32,   39,
-       51,   39,   80,   50,    0,   68,   25,   54,    0,  194,
-       88,   71,   80,  194,  194,  194,  194,  194,  194,  194,
-      194,  194,  194,   71,  194,    0,  194,   85,   55,   64,
-       99,  111,   53,  105,    0,   50,   55,  194,  194,  194,
-       40,    0,  194,   38,  194,  194,  194,  194,    0,  194,
-      194,  117,    0,  130,    0,    0,    0,  137,    0,   88,
-      113,    0,  131,    0,  194,  194,  143,  139,  152,  150,
-        0,   13,  153,  194,    0,  194,  194,  176,   31,  181,
+        0,    0,   26,   28,  133,  195,  130,  195,  128,  105,
+      195,  104,   25,  195,  100,   23,   27,   32,   31,   38,
+       50,   38,   93,   49,    0,   16,   51,    0,  195,  105,
+       87,   93,  195,  195,  195,  195,  195,  195,  195,  195,
+      195,  195,   67,  195,    0,  195,   81,   55,   84,   98,
+      110,   53,   61,    0,   52,   39,  195,  195,  195,   33,
+        0,  195,  195,  195,  195,    0,  195,  195,  113,    0,
+      126,    0,    0,    0,  133,    0,   56,  128,    0,  133,
+        0,  195,  195,  101,  141,  143,  145,    0,   15,  154,
+      195,    0,  195,  195,  177,   32,  182,  187,  189
 
-      186,  188
     } ;
 
-static yyconst flex_int16_t yy_def[103] =
+static const flex_int16_t yy_def[100] =
     {   0,
-       97,    1,   98,   98,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       20,   97,   97,   97,   99,   97,   97,   97,  100,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,  101,   97,   97,   20,   20,
-       50,   51,   51,  102,   21,   51,   97,   97,   97,   97,
-       97,   99,   97,   97,   97,   97,   97,   97,  100,   97,
-       97,   44,   44,   72,   72,  101,   48,   51,   51,   97,
-       52,   51,  102,   51,   97,   97,   97,   74,   78,   97,
-       51,   51,   97,   97,   51,   97,    0,   97,   97,   97,
+       94,    1,   95,   95,   94,   94,   94,   94,   94,   94,
+       94,   94,   94,   94,   94,   94,   94,   94,   94,   94,
+       20,   94,   94,   94,   96,   94,   94,   97,   94,   94,
+       94,   94,   94,   94,   94,   94,   94,   94,   94,   94,
+       94,   94,   94,   94,   98,   94,   94,   20,   20,   49,
+       50,   50,   99,   21,   50,   94,   94,   94,   94,   94,
+       96,   94,   94,   94,   94,   97,   94,   94,   43,   43,
+       69,   69,   98,   47,   50,   50,   94,   51,   50,   99,
+       50,   94,   94,   94,   71,   75,   94,   50,   50,   94,
+       94,   50,   94,    0,   94,   94,   94,   94,   94
 
-       97,   97
     } ;
 
-static yyconst flex_uint16_t yy_nxt[224] =
+static const flex_int16_t yy_nxt[224] =
     {   0,
         6,    7,    8,    9,   10,   11,   12,   13,   14,   15,
        16,   17,   18,   19,   20,   21,   21,   22,   23,   24,
-       25,   25,   25,   25,   25,   25,   26,   27,   28,   30,
-       31,   30,   31,   37,   40,   62,   32,   95,   32,   42,
-       63,   45,   41,   65,   38,   46,   43,   44,   44,   44,
-       47,   48,   66,   49,   49,   50,   57,   58,   86,   51,
-       52,   51,   51,   53,   54,   55,   55,   55,   60,   61,
-       63,   64,   67,   85,   84,   56,   51,   82,   50,   50,
-       51,   33,   68,   72,   71,   73,   73,   73,   51,   51,
-       70,   72,   74,   75,   72,   72,   72,   51,   59,   77,
+       25,   25,   25,   25,   25,   25,   26,   27,   29,   30,
+       29,   30,   36,   39,   62,   31,   61,   31,   41,   92,
+       44,   40,   63,   37,   45,   42,   43,   43,   43,   46,
+       47,   83,   48,   48,   49,   56,   57,   82,   50,   51,
+       50,   50,   52,   53,   54,   54,   54,   59,   60,   64,
+       87,   87,   87,   50,   55,   50,   81,   79,   65,   69,
+       50,   70,   70,   70,   50,   50,   50,   69,   71,   72,
+       69,   69,   69,   50,   32,   74,   74,   74,   49,   49,
 
-       77,   77,   90,   90,   90,   51,   78,   79,   51,   51,
-       51,   51,   39,   51,   51,   51,   36,   51,   35,   34,
-       51,   80,   80,   97,   97,   81,   81,   81,   51,   51,
-       51,   72,   72,   72,   33,   91,   97,   97,   72,   72,
-       87,   87,   97,   51,   88,   88,   88,   87,   87,   97,
-       97,   89,   89,   89,   51,   92,   51,   93,   93,   93,
-       97,   75,   97,   97,   90,   90,   90,   93,   93,   93,
-       97,   97,   94,   97,   79,   96,   29,   29,   29,   29,
-       29,   69,   97,   97,   69,   69,   76,   97,   76,   76,
-       76,   83,   83,    5,   97,   97,   97,   97,   97,   97,
+       68,   50,   75,   76,   50,   50,   50,   67,   50,   50,
+       50,   58,   50,   50,   50,   90,   90,   90,   38,   50,
+       77,   77,   35,   34,   78,   78,   78,   69,   69,   69,
+       33,   32,   94,   94,   69,   69,   84,   84,   94,   94,
+       85,   85,   85,   84,   84,   50,   94,   86,   86,   86,
+       88,   94,   94,   94,   94,   94,   50,   89,   50,   87,
+       87,   87,   94,   72,   94,   76,   94,   91,   90,   90,
+       90,   94,   94,   94,   94,   94,   93,   28,   28,   28,
+       28,   28,   66,   94,   94,   66,   66,   73,   94,   73,
+       73,   73,   80,   80,    5,   94,   94,   94,   94,   94,
 
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97
+       94,   94,   94,   94,   94,   94,   94,   94,   94,   94,
+       94,   94,   94,   94,   94,   94,   94,   94,   94,   94,
+       94,   94,   94
     } ;
 
-static yyconst flex_int16_t yy_chk[224] =
+static const flex_int16_t yy_chk[224] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    3,
-        3,    4,    4,   13,   16,   99,    3,   92,    4,   17,
-       64,   19,   16,   27,   13,   19,   17,   18,   18,   18,
-       19,   20,   27,   20,   20,   20,   22,   22,   61,   20,
-       20,   20,   20,   20,   20,   21,   21,   21,   24,   24,
-       26,   26,   28,   57,   56,   21,   21,   53,   50,   50,
-       49,   33,   28,   44,   32,   44,   44,   44,   50,   50,
-       31,   44,   44,   44,   44,   44,   44,   48,   23,   48,
+        1,    1,    1,    1,    1,    1,    1,    1,    3,    3,
+        4,    4,   13,   16,   26,    3,   96,    4,   17,   89,
+       19,   16,   26,   13,   19,   17,   18,   18,   18,   19,
+       20,   60,   20,   20,   20,   22,   22,   56,   20,   20,
+       20,   20,   20,   20,   21,   21,   21,   24,   24,   27,
+       77,   77,   77,   53,   21,   21,   55,   52,   27,   43,
+       48,   43,   43,   43,   53,   53,   53,   43,   43,   43,
+       43,   43,   43,   47,   32,   47,   47,   47,   49,   49,
 
-       48,   48,   80,   80,   80,   48,   48,   48,   48,   48,
-       48,   51,   15,   51,   51,   51,   12,   54,   10,    9,
-       51,   52,   52,   81,   81,   52,   52,   52,   54,   54,
-       54,   72,   72,   72,    7,   81,    5,    0,   72,   72,
-       74,   74,    0,   83,   74,   74,   74,   78,   78,   88,
-       88,   78,   78,   78,   83,   83,   83,   87,   87,   87,
-        0,   88,   89,   89,   90,   90,   90,   93,   93,   93,
-        0,    0,   90,    0,   89,   93,   98,   98,   98,   98,
-       98,  100,    0,    0,  100,  100,  101,    0,  101,  101,
-      101,  102,  102,   97,   97,   97,   97,   97,   97,   97,
+       31,   47,   47,   47,   47,   47,   47,   30,   49,   49,
+       50,   23,   50,   50,   50,   84,   84,   84,   15,   50,
+       51,   51,   12,   10,   51,   51,   51,   69,   69,   69,
+        9,    7,    5,    0,   69,   69,   71,   71,   78,   78,
+       71,   71,   71,   75,   75,   80,    0,   75,   75,   75,
+       78,   85,   85,   86,   86,    0,   80,   80,   80,   87,
+       87,   87,    0,   85,    0,   86,    0,   87,   90,   90,
+       90,    0,    0,    0,    0,    0,   90,   95,   95,   95,
+       95,   95,   97,    0,    0,   97,   97,   98,    0,   98,
+       98,   98,   99,   99,   94,   94,   94,   94,   94,   94,
 
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97
+       94,   94,   94,   94,   94,   94,   94,   94,   94,   94,
+       94,   94,   94,   94,   94,   94,   94,   94,   94,   94,
+       94,   94,   94
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -561,14 +912,27 @@
 IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
 */
 
+#if defined(_MSC_VER)
+#pragma warning(disable: 4005)
+#endif
+
 #include "Tokenizer.h"
 
-#include "Diagnostics.h"
+#include "DiagnosticsBase.h"
 #include "Token.h"
 
 #if defined(__GNUC__)
 // Triggered by the auto-generated yy_fatal_error function.
 #pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4244)
+#endif
+
+// Workaround for flex using the register keyword, deprecated in C++11.
+#ifdef __cplusplus
+#if __cplusplus > 199711L
+#define register
+#endif
 #endif
 
 typedef std::string YYSTYPE;
@@ -602,13 +966,25 @@
     } while(0);
 
 #define YY_INPUT(buf, result, maxSize) \
-    result = yyextra->input.read(buf, maxSize);
+    result = yyextra->input.read(buf, maxSize, &yylineno);
+
+
+
+
 
 #define INITIAL 0
 #define COMMENT 1
 
+
+
+
+
+
 #define YY_EXTRA_TYPE pp::Tokenizer::Context*
 
+
+
+
 /* Holds the entire state of the reentrant scanner. */
 struct yyguts_t
     {
@@ -622,8 +998,8 @@
     size_t yy_buffer_stack_max; /**< capacity of stack. */
     YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
     char yy_hold_char;
-    yy_size_t yy_n_chars;
-    yy_size_t yyleng_r;
+    int yy_n_chars;
+    int yyleng_r;
     char *yy_c_buf_p;
     int yy_init;
     int yy_start;
@@ -637,78 +1013,141 @@
     int yylineno_r;
     int yy_flex_debug_r;
 
+
+
+
     char *yytext_r;
     int yy_more_flag;
     int yy_more_len;
 
+
+
     YYSTYPE * yylval_r;
 
+
+
     YYLTYPE * yylloc_r;
 
+
     }; /* end struct yyguts_t */
 
-static int yy_init_globals (yyscan_t yyscanner );
 
+
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+
+
+
+    
     /* This must go here because YYSTYPE and YYLTYPE are included
      * from bison output in section 1.*/
     #    define yylval yyg->yylval_r
     
+
+    
     #    define yylloc yyg->yylloc_r
     
-int pplex_init (yyscan_t* scanner);
 
-int pplex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+
 
 /* Accessor methods to globals.
    These are made visible to non-reentrant scanners for convenience. */
 
-int pplex_destroy (yyscan_t yyscanner );
 
-int ppget_debug (yyscan_t yyscanner );
+int yylex_destroy ( yyscan_t yyscanner );
 
-void ppset_debug (int debug_flag ,yyscan_t yyscanner );
 
-YY_EXTRA_TYPE ppget_extra (yyscan_t yyscanner );
 
-void ppset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+int yyget_debug ( yyscan_t yyscanner );
 
-FILE *ppget_in (yyscan_t yyscanner );
 
-void ppset_in  (FILE * _in_str ,yyscan_t yyscanner );
 
-FILE *ppget_out (yyscan_t yyscanner );
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
 
-void ppset_out  (FILE * _out_str ,yyscan_t yyscanner );
 
-yy_size_t ppget_leng (yyscan_t yyscanner );
 
-char *ppget_text (yyscan_t yyscanner );
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
 
-int ppget_lineno (yyscan_t yyscanner );
 
-void ppset_lineno (int _line_number ,yyscan_t yyscanner );
 
-int ppget_column  (yyscan_t yyscanner );
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
 
-void ppset_column (int _column_no ,yyscan_t yyscanner );
 
-YYSTYPE * ppget_lval (yyscan_t yyscanner );
 
-void ppset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+FILE *yyget_in ( yyscan_t yyscanner );
 
-       YYLTYPE *ppget_lloc (yyscan_t yyscanner );
+
+
+void yyset_in  ( FILE * _in_str , yyscan_t yyscanner );
+
+
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+
+
+void yyset_out  ( FILE * _out_str , yyscan_t yyscanner );
+
+
+
+			int yyget_leng ( yyscan_t yyscanner );
+
+
+
+char *yyget_text ( yyscan_t yyscanner );
+
+
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+
+
+
+int yyget_column  ( yyscan_t yyscanner );
+
+
+
+
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+
+
+
+YYSTYPE * yyget_lval ( yyscan_t yyscanner );
+
+
+void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
+
+
     
-        void ppset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+       YYLTYPE *yyget_lloc ( yyscan_t yyscanner );
     
+
+    
+        void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner );
+    
+
+
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
  */
 
 #ifndef YY_SKIP_YYWRAP
 #ifdef __cplusplus
-extern "C" int ppwrap (yyscan_t yyscanner );
+extern "C" int yywrap ( yyscan_t yyscanner );
 #else
-extern int ppwrap (yyscan_t yyscanner );
+extern int yywrap ( yyscan_t yyscanner );
 #endif
 #endif
 
@@ -716,24 +1155,31 @@
     
 #endif
 
+
 #ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
 #endif
 
 #ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
 #endif
 
 #ifndef YY_NO_INPUT
-
 #ifdef __cplusplus
-static int yyinput (yyscan_t yyscanner );
+static int yyinput ( yyscan_t yyscanner );
 #else
-static int input (yyscan_t yyscanner );
+static int input ( yyscan_t yyscanner );
 #endif
 
 #endif
 
+
+
+
+
+
+
+
 /* Amount of stuff to slurp up with each read. */
 #ifndef YY_READ_BUF_SIZE
 #ifdef __ia64__
@@ -744,14 +1190,17 @@
 #endif /* __ia64__ */
 #endif
 
+
 /* Copy whatever the last rule matched to the standard output. */
 #ifndef ECHO
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
 #endif
 
+
+
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
  * is returned in "result".
  */
@@ -760,7 +1209,7 @@
 	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
 		{ \
 		int c = '*'; \
-		size_t n; \
+		int n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -773,7 +1222,7 @@
 	else \
 		{ \
 		errno=0; \
-		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+		while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
 			{ \
 			if( errno != EINTR) \
 				{ \
@@ -788,6 +1237,8 @@
 
 #endif
 
+
+
 /* No semi-colon after return; correct usage is to write "yyterminate();" -
  * we don't want an extra ';' after the "return" because that will cause
  * some compilers to complain about unreachable statements.
@@ -796,31 +1247,54 @@
 #define yyterminate() return YY_NULL
 #endif
 
+
 /* Number of entries by which start-condition stack grows. */
 #ifndef YY_START_STACK_INCR
 #define YY_START_STACK_INCR 25
 #endif
 
+
 /* Report a fatal error. */
 #ifndef YY_FATAL_ERROR
 #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
 #endif
 
+
+
 /* end tables serialization structures and prototypes */
 
+
+
 /* Default declaration of generated scanner - a define so the user can
  * easily add parameters.
  */
 #ifndef YY_DECL
 #define YY_DECL_IS_OURS 1
 
-extern int pplex \
-               (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
 
-#define YY_DECL int pplex \
+
+
+
+
+        
+    
+    
+
+
+
+    
+    
+    
+
+
+extern int yylex \
+               (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner);
+
+#define YY_DECL int yylex \
                (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
 #endif /* !YY_DECL */
 
+
 /* Code executed at the beginning of each rule, after yytext and yyleng
  * have been set up.
  */
@@ -828,14 +1302,19 @@
 #define YY_USER_ACTION
 #endif
 
+
+
 /* Code executed at the end of each rule. */
 #ifndef YY_BREAK
 #define YY_BREAK /*LINTED*/break;
 #endif
 
+
+
 #define YY_RULE_SETUP \
 	YY_USER_ACTION
 
+
 /** The main scanner function which does all the work.
  */
 YY_DECL
@@ -845,10 +1324,16 @@
 	int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
+
+
+
     yylval = yylval_param;
 
+
+
     yylloc = yylloc_param;
 
+
 	if ( !yyg->yy_init )
 		{
 		yyg->yy_init = 1;
@@ -857,6 +1342,8 @@
 		YY_USER_INIT;
 #endif
 
+
+
 		if ( ! yyg->yy_start )
 			yyg->yy_start = 1;	/* first start state */
 
@@ -867,16 +1354,17 @@
 			yyout = stdout;
 
 		if ( ! YY_CURRENT_BUFFER ) {
-			ppensure_buffer_stack (yyscanner);
+			yyensure_buffer_stack (yyscanner);
 			YY_CURRENT_BUFFER_LVALUE =
-				pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+				yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
 		}
 
-		pp_load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 		}
 
 	{
 
+
     /* Line comment */
 
 	while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
@@ -904,13 +1392,13 @@
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 98 )
-					yy_c = yy_meta[(unsigned int) yy_c];
+				if ( yy_current_state >= 95 )
+					yy_c = yy_meta[yy_c];
 				}
-			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 			++yy_cp;
 			}
-		while ( yy_current_state != 97 );
+		while ( yy_current_state != 94 );
 		yy_cp = yyg->yy_last_accepting_cpos;
 		yy_current_state = yyg->yy_last_accepting_state;
 
@@ -919,8 +1407,11 @@
 
 		YY_DO_BEFORE_ACTION;
 
+
+
 do_action:	/* This label is used only to access EOF actions. */
 
+
 		switch ( yy_act )
 	{ /* beginning of action switch */
 			case 0: /* must back up */
@@ -936,7 +1427,7 @@
 	YY_BREAK
 /* Block comment */
 /* Line breaks are just counted - not returned. */
-/* The comment is replaced by a single space. */ 
+/* The comment is replaced by a single space. */
 case 2:
 YY_RULE_SETUP
 { BEGIN(COMMENT); }
@@ -952,7 +1443,14 @@
 case 5:
 /* rule 5 can match eol */
 YY_RULE_SETUP
-{ ++yylineno; }
+{
+    if (yylineno == INT_MAX)
+    {
+        *yylval = "Integer overflow on line number";
+        return pp::Token::GOT_ERROR;
+    }
+    ++yylineno;
+}
 	YY_BREAK
 case 6:
 YY_RULE_SETUP
@@ -1161,17 +1659,17 @@
 /* rule 35 can match eol */
 YY_RULE_SETUP
 {
+    if (yylineno == INT_MAX)
+    {
+        *yylval = "Integer overflow on line number";
+        return pp::Token::GOT_ERROR;
+    }
     ++yylineno;
     yylval->assign(1, '\n');
     return '\n';
 }
 	YY_BREAK
 case 36:
-/* rule 36 can match eol */
-YY_RULE_SETUP
-{ ++yylineno; }
-	YY_BREAK
-case 37:
 YY_RULE_SETUP
 {
     yylval->assign(1, yytext[0]);
@@ -1185,28 +1683,35 @@
     // Set the location for EOF token manually.
     pp::Input* input = &yyextra->input;
     pp::Input::Location* scanLoc = &yyextra->scanLoc;
-    int sIndexMax = std::max(0, input->count() - 1);
+    yy_size_t sIndexMax = input->count() ? input->count() - 1 : 0;
     if (scanLoc->sIndex != sIndexMax)
     {
         // We can only reach here if there are empty strings at the
         // end of the input.
         scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
-        yyfileno = sIndexMax; yylineno = 1;
+        // FIXME: this is not 64-bit clean.
+        yyfileno = static_cast<int>(sIndexMax); yylineno = 1;
     }
     yylloc->file = yyfileno;
     yylloc->line = yylineno;
     yylval->clear();
 
-    if (YY_START == COMMENT)
+    // Line number overflows fake EOFs to exit early, check for this case.
+    if (yylineno == INT_MAX) {
+        yyextra->diagnostics->report(pp::Diagnostics::PP_TOKENIZER_ERROR,
+                pp::SourceLocation(yyfileno, yylineno),
+                "Integer overflow on line number");
+    }
+    else if (YY_START == COMMENT)
     {
-        yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT,
+        yyextra->diagnostics->report(pp::Diagnostics::PP_EOF_IN_COMMENT,
                                      pp::SourceLocation(yyfileno, yylineno),
-                                     "");
+                                     "EOF while in a comment");
     }
     yyterminate();
 }
 	YY_BREAK
-case 38:
+case 37:
 YY_RULE_SETUP
 ECHO;
 	YY_BREAK
@@ -1225,7 +1730,7 @@
 			/* We're scanning a new file or input source.  It's
 			 * possible that this happened because the user
 			 * just pointed yyin at a new source and called
-			 * pplex().  If so, then we have to assure
+			 * yylex().  If so, then we have to assure
 			 * consistency between YY_CURRENT_BUFFER and our
 			 * globals.  Here is the right place to do so, because
 			 * this is the first action (other than possibly a
@@ -1286,7 +1791,7 @@
 				{
 				yyg->yy_did_buffer_switch_on_eof = 0;
 
-				if ( ppwrap(yyscanner ) )
+				if ( yywrap( yyscanner ) )
 					{
 					/* Note: because we've taken care in
 					 * yy_get_next_buffer() to have set up
@@ -1340,7 +1845,11 @@
 	} /* end of action switch */
 		} /* end of scanning one token */
 	} /* end of user's declarations */
-} /* end of pplex */
+} /* end of yylex */
+
+
+
+
 
 /* yy_get_next_buffer - try to read in a new buffer
  *
@@ -1354,7 +1863,7 @@
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
 	char *source = yyg->yytext_ptr;
-	yy_size_t number_to_move, i;
+	int number_to_move, i;
 	int ret_val;
 
 	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
@@ -1383,7 +1892,7 @@
 	/* Try to read more data. */
 
 	/* First move last chars to start of buffer. */
-	number_to_move = (yy_size_t) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
 
 	for ( i = 0; i < number_to_move; ++i )
 		*(dest++) = *(source++);
@@ -1396,7 +1905,7 @@
 
 	else
 		{
-			yy_size_t num_to_read =
+			int num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
 
 		while ( num_to_read <= 0 )
@@ -1410,7 +1919,7 @@
 
 			if ( b->yy_is_our_buffer )
 				{
-				yy_size_t new_size = b->yy_buf_size * 2;
+				int new_size = b->yy_buf_size * 2;
 
 				if ( new_size <= 0 )
 					b->yy_buf_size += b->yy_buf_size / 8;
@@ -1419,11 +1928,12 @@
 
 				b->yy_ch_buf = (char *)
 					/* Include room in for 2 EOB chars. */
-					pprealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+					yyrealloc( (void *) b->yy_ch_buf,
+							 (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
 				}
 			else
 				/* Can't grow it, we don't own it. */
-				b->yy_ch_buf = 0;
+				b->yy_ch_buf = NULL;
 
 			if ( ! b->yy_ch_buf )
 				YY_FATAL_ERROR(
@@ -1451,7 +1961,7 @@
 		if ( number_to_move == YY_MORE_ADJ )
 			{
 			ret_val = EOB_ACT_END_OF_FILE;
-			pprestart(yyin  ,yyscanner);
+			yyrestart( yyin  , yyscanner);
 			}
 
 		else
@@ -1465,12 +1975,15 @@
 	else
 		ret_val = EOB_ACT_CONTINUE_SCAN;
 
-	if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+	if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
 		/* Extend the array by 50%, plus the number we really need. */
-		yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
-		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) pprealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+			(void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
 		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
 			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+		/* "- 2" to take care of EOB's */
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
 	}
 
 	yyg->yy_n_chars += number_to_move;
@@ -1482,6 +1995,7 @@
 	return ret_val;
 }
 
+
 /* yy_get_previous_state - get the state just before the EOB char was reached */
 
     static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
@@ -1503,15 +2017,16 @@
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 98 )
-				yy_c = yy_meta[(unsigned int) yy_c];
+			if ( yy_current_state >= 95 )
+				yy_c = yy_meta[yy_c];
 			}
-		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 		}
 
 	return yy_current_state;
 }
 
+
 /* yy_try_NUL_trans - try to make a transition on the NUL character
  *
  * synopsis
@@ -1532,16 +2047,17 @@
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 98 )
-			yy_c = yy_meta[(unsigned int) yy_c];
+		if ( yy_current_state >= 95 )
+			yy_c = yy_meta[yy_c];
 		}
-	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 97);
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+	yy_is_jam = (yy_current_state == 94);
 
 	(void)yyg;
 	return yy_is_jam ? 0 : yy_current_state;
 }
 
+
 #ifndef YY_NO_UNPUT
 
 #endif
@@ -1571,7 +2087,7 @@
 
 		else
 			{ /* need more input */
-			yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
 			++yyg->yy_c_buf_p;
 
 			switch ( yy_get_next_buffer( yyscanner ) )
@@ -1588,14 +2104,14 @@
 					 */
 
 					/* Reset buffer status. */
-					pprestart(yyin ,yyscanner);
+					yyrestart( yyin , yyscanner);
 
 					/*FALLTHROUGH*/
 
 				case EOB_ACT_END_OF_FILE:
 					{
-					if ( ppwrap(yyscanner ) )
-						return EOF;
+					if ( yywrap( yyscanner ) )
+						return 0;
 
 					if ( ! yyg->yy_did_buffer_switch_on_eof )
 						YY_NEW_FILE;
@@ -1617,6 +2133,7 @@
 	*yyg->yy_c_buf_p = '\0';	/* preserve yytext */
 	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
 
+
 	return c;
 }
 #endif	/* ifndef YY_NO_INPUT */
@@ -1626,34 +2143,35 @@
  * @param yyscanner The scanner object.
  * @note This function does not reset the start condition to @c INITIAL .
  */
-    void pprestart  (FILE * input_file , yyscan_t yyscanner)
+    void yyrestart  (FILE * input_file , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
 	if ( ! YY_CURRENT_BUFFER ){
-        ppensure_buffer_stack (yyscanner);
+        yyensure_buffer_stack (yyscanner);
 		YY_CURRENT_BUFFER_LVALUE =
-            pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
 	}
 
-	pp_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
-	pp_load_buffer_state(yyscanner );
+	yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+	yy_load_buffer_state( yyscanner );
 }
 
+
 /** Switch to a different input buffer.
  * @param new_buffer The new input buffer.
  * @param yyscanner The scanner object.
  */
-    void pp_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
 	/* TODO. We should be able to replace this entire function body
 	 * with
-	 *		pppop_buffer_state();
-	 *		pppush_buffer_state(new_buffer);
+	 *		yypop_buffer_state();
+	 *		yypush_buffer_state(new_buffer);
      */
-	ppensure_buffer_stack (yyscanner);
+	yyensure_buffer_stack (yyscanner);
 	if ( YY_CURRENT_BUFFER == new_buffer )
 		return;
 
@@ -1666,17 +2184,18 @@
 		}
 
 	YY_CURRENT_BUFFER_LVALUE = new_buffer;
-	pp_load_buffer_state(yyscanner );
+	yy_load_buffer_state( yyscanner );
 
 	/* We don't actually know whether we did this switch during
-	 * EOF (ppwrap()) processing, but the only time this flag
-	 * is looked at is after ppwrap() is called, so it's safe
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
 	 * to go ahead and always set it.
 	 */
 	yyg->yy_did_buffer_switch_on_eof = 1;
 }
 
-static void pp_load_buffer_state  (yyscan_t yyscanner)
+
+static void yy_load_buffer_state  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
@@ -1691,35 +2210,36 @@
  * @param yyscanner The scanner object.
  * @return the allocated buffer state.
  */
-    YY_BUFFER_STATE pp_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
 {
 	YY_BUFFER_STATE b;
     
-	b = (YY_BUFFER_STATE) ppalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
 	if ( ! b )
-		YY_FATAL_ERROR( "out of dynamic memory in pp_create_buffer()" );
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
-	b->yy_buf_size = (yy_size_t)size;
+	b->yy_buf_size = size;
 
 	/* yy_ch_buf has to be 2 characters longer than the size given because
 	 * we need to put in 2 end-of-buffer characters.
 	 */
-	b->yy_ch_buf = (char *) ppalloc(b->yy_buf_size + 2 ,yyscanner );
+	b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
 	if ( ! b->yy_ch_buf )
-		YY_FATAL_ERROR( "out of dynamic memory in pp_create_buffer()" );
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
 	b->yy_is_our_buffer = 1;
 
-	pp_init_buffer(b,file ,yyscanner);
+	yy_init_buffer( b, file , yyscanner);
 
 	return b;
 }
 
+
 /** Destroy the buffer.
- * @param b a buffer created with pp_create_buffer()
+ * @param b a buffer created with yy_create_buffer()
  * @param yyscanner The scanner object.
  */
-    void pp_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+    void yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
@@ -1730,28 +2250,29 @@
 		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
 
 	if ( b->yy_is_our_buffer )
-		ppfree((void *) b->yy_ch_buf ,yyscanner );
+		yyfree( (void *) b->yy_ch_buf , yyscanner );
 
-	ppfree((void *) b ,yyscanner );
+	yyfree( (void *) b , yyscanner );
 }
 
+
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
- * such as during a pprestart() or at EOF.
+ * such as during a yyrestart() or at EOF.
  */
-    static void pp_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
 
 {
 	int oerrno = errno;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-	pp_flush_buffer(b ,yyscanner);
+	yy_flush_buffer( b , yyscanner);
 
 	b->yy_input_file = file;
 	b->yy_fill_buffer = 1;
 
-    /* If b is the current buffer, then pp_init_buffer was _probably_
-     * called from pprestart() or through yy_get_next_buffer.
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
      * In that case, we don't want to reset the lineno or column.
      */
     if (b != YY_CURRENT_BUFFER){
@@ -1759,8 +2280,11 @@
         b->yy_bs_column = 0;
     }
 
+
+    
         b->yy_is_interactive = 0;
     
+
 	errno = oerrno;
 }
 
@@ -1768,7 +2292,7 @@
  * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
  * @param yyscanner The scanner object.
  */
-    void pp_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+    void yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	if ( ! b )
@@ -1789,7 +2313,7 @@
 	b->yy_buffer_status = YY_BUFFER_NEW;
 
 	if ( b == YY_CURRENT_BUFFER )
-		pp_load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 }
 
 /** Pushes the new state onto the stack. The new state becomes
@@ -1798,15 +2322,15 @@
  *  @param new_buffer The new state.
  *  @param yyscanner The scanner object.
  */
-void pppush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	if (new_buffer == NULL)
 		return;
 
-	ppensure_buffer_stack(yyscanner);
+	yyensure_buffer_stack(yyscanner);
 
-	/* This block is copied from pp_switch_to_buffer. */
+	/* This block is copied from yy_switch_to_buffer. */
 	if ( YY_CURRENT_BUFFER )
 		{
 		/* Flush out information for old buffer. */
@@ -1820,36 +2344,38 @@
 		yyg->yy_buffer_stack_top++;
 	YY_CURRENT_BUFFER_LVALUE = new_buffer;
 
-	/* copied from pp_switch_to_buffer. */
-	pp_load_buffer_state(yyscanner );
+	/* copied from yy_switch_to_buffer. */
+	yy_load_buffer_state( yyscanner );
 	yyg->yy_did_buffer_switch_on_eof = 1;
 }
 
+
 /** Removes and deletes the top of the stack, if present.
  *  The next element becomes the new top.
  *  @param yyscanner The scanner object.
  */
-void pppop_buffer_state (yyscan_t yyscanner)
+void yypop_buffer_state (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	if (!YY_CURRENT_BUFFER)
 		return;
 
-	pp_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
 	YY_CURRENT_BUFFER_LVALUE = NULL;
 	if (yyg->yy_buffer_stack_top > 0)
 		--yyg->yy_buffer_stack_top;
 
 	if (YY_CURRENT_BUFFER) {
-		pp_load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 		yyg->yy_did_buffer_switch_on_eof = 1;
 	}
 }
 
+
 /* Allocates the stack if it does not exist.
  *  Guarantees space for at least one push.
  */
-static void ppensure_buffer_stack (yyscan_t yyscanner)
+static void yyensure_buffer_stack (yyscan_t yyscanner)
 {
 	yy_size_t num_to_alloc;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
@@ -1860,15 +2386,16 @@
 		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
 		 * immediate realloc on the next call.
          */
-		num_to_alloc = 1; // After all that talk, this was set to 1 anyways...
-		yyg->yy_buffer_stack = (struct yy_buffer_state**)ppalloc
+      num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
 								(num_to_alloc * sizeof(struct yy_buffer_state*)
 								, yyscanner);
 		if ( ! yyg->yy_buffer_stack )
-			YY_FATAL_ERROR( "out of dynamic memory in ppensure_buffer_stack()" );
-								  
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+
 		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-				
+
 		yyg->yy_buffer_stack_max = num_to_alloc;
 		yyg->yy_buffer_stack_top = 0;
 		return;
@@ -1880,12 +2407,12 @@
 		yy_size_t grow_size = 8 /* arbitrary grow size */;
 
 		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
-		yyg->yy_buffer_stack = (struct yy_buffer_state**)pprealloc
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
 								(yyg->yy_buffer_stack,
 								num_to_alloc * sizeof(struct yy_buffer_state*)
 								, yyscanner);
 		if ( ! yyg->yy_buffer_stack )
-			YY_FATAL_ERROR( "out of dynamic memory in ppensure_buffer_stack()" );
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
 
 		/* zero only the new slots.*/
 		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
@@ -1893,13 +2420,17 @@
 	}
 }
 
+
+
+
+
 /** Setup the input buffer state to scan directly from a user-specified character buffer.
  * @param base the character buffer
  * @param size the size in bytes of the character buffer
  * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object. 
+ * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE pp_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
 {
 	YY_BUFFER_STATE b;
     
@@ -1907,69 +2438,75 @@
 	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
 	     base[size-1] != YY_END_OF_BUFFER_CHAR )
 		/* They forgot to leave room for the EOB's. */
-		return 0;
+		return NULL;
 
-	b = (YY_BUFFER_STATE) ppalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
 	if ( ! b )
-		YY_FATAL_ERROR( "out of dynamic memory in pp_scan_buffer()" );
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
 
-	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_size = (int) (size - 2);	/* "- 2" to take care of EOB's */
 	b->yy_buf_pos = b->yy_ch_buf = base;
 	b->yy_is_our_buffer = 0;
-	b->yy_input_file = 0;
+	b->yy_input_file = NULL;
 	b->yy_n_chars = b->yy_buf_size;
 	b->yy_is_interactive = 0;
 	b->yy_at_bol = 1;
 	b->yy_fill_buffer = 0;
 	b->yy_buffer_status = YY_BUFFER_NEW;
 
-	pp_switch_to_buffer(b ,yyscanner );
+	yy_switch_to_buffer( b , yyscanner );
 
 	return b;
 }
 
-/** Setup the input buffer state to scan a string. The next call to pplex() will
+
+
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
  * scan from a @e copy of @a str.
  * @param yystr a NUL-terminated string to scan
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  * @note If you want to scan bytes that may contain NUL values, then use
- *       pp_scan_bytes() instead.
+ *       yy_scan_bytes() instead.
  */
-YY_BUFFER_STATE pp_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
 {
     
-	return pp_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+	return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
 }
 
-/** Setup the input buffer state to scan the given bytes. The next call to pplex() will
+
+
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
  * scan from a @e copy of @a bytes.
  * @param yybytes the byte buffer to scan
  * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE pp_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_bytes  (const char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
 {
 	YY_BUFFER_STATE b;
 	char *buf;
 	yy_size_t n;
-	yy_size_t i;
+	int i;
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
-	n = _yybytes_len + 2;
-	buf = (char *) ppalloc(n ,yyscanner );
+	n = (yy_size_t) (_yybytes_len + 2);
+	buf = (char *) yyalloc( n , yyscanner );
 	if ( ! buf )
-		YY_FATAL_ERROR( "out of dynamic memory in pp_scan_bytes()" );
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
 
 	for ( i = 0; i < _yybytes_len; ++i )
 		buf[i] = yybytes[i];
 
 	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
 
-	b = pp_scan_buffer(buf,n ,yyscanner);
+	b = yy_scan_buffer( buf, n , yyscanner);
 	if ( ! b )
-		YY_FATAL_ERROR( "bad buffer in pp_scan_bytes()" );
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
 
 	/* It's okay to grow etc. this buffer, and we should throw it
 	 * away when we're done.
@@ -1979,15 +2516,25 @@
 	return b;
 }
 
+
+
+
+
+
+
+
+
+
+
 #ifndef YY_EXIT_FAILURE
 #define YY_EXIT_FAILURE 2
 #endif
 
-static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
-	(void) fprintf( stderr, "%s\n", msg );
+	fprintf( stderr, "%s\n", msg );
 	exit( YY_EXIT_FAILURE );
 }
 
@@ -2008,23 +2555,29 @@
 		} \
 	while ( 0 )
 
+
+
 /* Accessor  methods (get/set functions) to struct members. */
 
+
 /** Get the user-defined data for this scanner.
  * @param yyscanner The scanner object.
  */
-YY_EXTRA_TYPE ppget_extra  (yyscan_t yyscanner)
+YY_EXTRA_TYPE yyget_extra  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyextra;
 }
 
+
+
 /** Get the current line number.
  * @param yyscanner The scanner object.
  */
-int ppget_lineno  (yyscan_t yyscanner)
+int yyget_lineno  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
     
         if (! YY_CURRENT_BUFFER)
             return 0;
@@ -2032,12 +2585,16 @@
     return yylineno;
 }
 
+
+
+
 /** Get the current column number.
  * @param yyscanner The scanner object.
  */
-int ppget_column  (yyscan_t yyscanner)
+int yyget_column  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
     
         if (! YY_CURRENT_BUFFER)
             return 0;
@@ -2045,155 +2602,194 @@
     return yycolumn;
 }
 
+
+
+
 /** Get the input stream.
  * @param yyscanner The scanner object.
  */
-FILE *ppget_in  (yyscan_t yyscanner)
+FILE *yyget_in  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyin;
 }
 
+
+
 /** Get the output stream.
  * @param yyscanner The scanner object.
  */
-FILE *ppget_out  (yyscan_t yyscanner)
+FILE *yyget_out  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyout;
 }
 
+
+
 /** Get the length of the current token.
  * @param yyscanner The scanner object.
  */
-yy_size_t ppget_leng  (yyscan_t yyscanner)
+int yyget_leng  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyleng;
 }
 
+
 /** Get the current token.
  * @param yyscanner The scanner object.
  */
 
-char *ppget_text  (yyscan_t yyscanner)
+char *yyget_text  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yytext;
 }
 
+
+
 /** Set the user-defined data. This data is never touched by the scanner.
  * @param user_defined The data to be associated with this scanner.
  * @param yyscanner The scanner object.
  */
-void ppset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+void yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyextra = user_defined ;
 }
 
+
+
 /** Set the current line number.
  * @param _line_number line number
  * @param yyscanner The scanner object.
  */
-void ppset_lineno (int  _line_number , yyscan_t yyscanner)
+void yyset_lineno (int  _line_number , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
+    
         /* lineno is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           YY_FATAL_ERROR( "ppset_lineno called with no buffer" );
+           YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
     
     yylineno = _line_number;
 }
 
+
+
+
 /** Set the current column.
  * @param _column_no column number
  * @param yyscanner The scanner object.
  */
-void ppset_column (int  _column_no , yyscan_t yyscanner)
+void yyset_column (int  _column_no , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
+    
         /* column is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           YY_FATAL_ERROR( "ppset_column called with no buffer" );
+           YY_FATAL_ERROR( "yyset_column called with no buffer" );
     
     yycolumn = _column_no;
 }
 
+
+
+
+
 /** Set the input stream. This does not discard the current
  * input buffer.
  * @param _in_str A readable stream.
  * @param yyscanner The scanner object.
- * @see pp_switch_to_buffer
+ * @see yy_switch_to_buffer
  */
-void ppset_in (FILE *  _in_str , yyscan_t yyscanner)
+void yyset_in (FILE *  _in_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyin = _in_str ;
 }
 
-void ppset_out (FILE *  _out_str , yyscan_t yyscanner)
+
+
+void yyset_out (FILE *  _out_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyout = _out_str ;
 }
 
-int ppget_debug  (yyscan_t yyscanner)
+
+
+
+int yyget_debug  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yy_flex_debug;
 }
 
-void ppset_debug (int  _bdebug , yyscan_t yyscanner)
+
+
+void yyset_debug (int  _bdebug , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yy_flex_debug = _bdebug ;
 }
 
+
 /* Accessor methods for yylval and yylloc */
 
-YYSTYPE * ppget_lval  (yyscan_t yyscanner)
+
+YYSTYPE * yyget_lval  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yylval;
 }
 
-void ppset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+
+
+void yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yylval = yylval_param;
 }
 
-YYLTYPE *ppget_lloc  (yyscan_t yyscanner)
+
+
+    
+YYLTYPE *yyget_lloc  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yylloc;
 }
     
-void ppset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
+
+    
+void yyset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yylloc = yylloc_param;
 }
     
+
+
+
+
 /* User-visible API */
 
-/* pplex_init is special because it creates the scanner itself, so it is
+/* yylex_init is special because it creates the scanner itself, so it is
  * the ONLY reentrant function that doesn't take the scanner as the last argument.
  * That's why we explicitly handle the declaration, instead of using our macros.
  */
-
-int pplex_init(yyscan_t* ptr_yy_globals)
-
+int yylex_init(yyscan_t* ptr_yy_globals)
 {
     if (ptr_yy_globals == NULL){
         errno = EINVAL;
         return 1;
     }
 
-    *ptr_yy_globals = (yyscan_t) ppalloc ( sizeof( struct yyguts_t ), NULL );
+    *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
 
     if (*ptr_yy_globals == NULL){
         errno = ENOMEM;
@@ -2206,111 +2802,127 @@
     return yy_init_globals ( *ptr_yy_globals );
 }
 
-/* pplex_init_extra has the same functionality as pplex_init, but follows the
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
  * convention of taking the scanner as the last argument. Note however, that
  * this is a *pointer* to a scanner, as it will be allocated by this call (and
  * is the reason, too, why this function also must handle its own declaration).
- * The user defined value in the first argument will be available to ppalloc in
+ * The user defined value in the first argument will be available to yyalloc in
  * the yyextra field.
  */
-
-int pplex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
-
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
 {
     struct yyguts_t dummy_yyguts;
 
-    ppset_extra (yy_user_defined, &dummy_yyguts);
+    yyset_extra (yy_user_defined, &dummy_yyguts);
 
     if (ptr_yy_globals == NULL){
         errno = EINVAL;
         return 1;
     }
-	
-    *ptr_yy_globals = (yyscan_t) ppalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-	
+
+    *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
     if (*ptr_yy_globals == NULL){
         errno = ENOMEM;
         return 1;
     }
-    
+
     /* By setting to 0xAA, we expose bugs in
     yy_init_globals. Leave at 0x00 for releases. */
     memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-    
-    ppset_extra (yy_user_defined, *ptr_yy_globals);
-    
+
+    yyset_extra (yy_user_defined, *ptr_yy_globals);
+
     return yy_init_globals ( *ptr_yy_globals );
 }
 
+
 static int yy_init_globals (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     /* Initialization is the same as for the non-reentrant scanner.
-     * This function is called from pplex_destroy(), so don't allocate here.
+     * This function is called from yylex_destroy(), so don't allocate here.
      */
 
-    yyg->yy_buffer_stack = 0;
+
+    yyg->yy_buffer_stack = NULL;
     yyg->yy_buffer_stack_top = 0;
     yyg->yy_buffer_stack_max = 0;
-    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_c_buf_p = NULL;
     yyg->yy_init = 0;
     yyg->yy_start = 0;
 
+
     yyg->yy_start_stack_ptr = 0;
     yyg->yy_start_stack_depth = 0;
     yyg->yy_start_stack =  NULL;
 
+
+
+
+
+
 /* Defined in main.c */
 #ifdef YY_STDINIT
     yyin = stdin;
     yyout = stdout;
 #else
-    yyin = (FILE *) 0;
-    yyout = (FILE *) 0;
+    yyin = NULL;
+    yyout = NULL;
 #endif
 
     /* For future reference: Set errno on error, since we are called by
-     * pplex_init()
+     * yylex_init()
      */
     return 0;
 }
 
-/* pplex_destroy is for both reentrant and non-reentrant scanners. */
-int pplex_destroy  (yyscan_t yyscanner)
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
     /* Pop the buffer stack, destroying each element. */
 	while(YY_CURRENT_BUFFER){
-		pp_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
 		YY_CURRENT_BUFFER_LVALUE = NULL;
-		pppop_buffer_state(yyscanner);
+		yypop_buffer_state(yyscanner);
 	}
 
 	/* Destroy the stack itself. */
-	ppfree(yyg->yy_buffer_stack ,yyscanner);
+	yyfree(yyg->yy_buffer_stack , yyscanner);
 	yyg->yy_buffer_stack = NULL;
 
+
     /* Destroy the start condition stack. */
-        ppfree(yyg->yy_start_stack ,yyscanner );
+        yyfree( yyg->yy_start_stack , yyscanner );
         yyg->yy_start_stack = NULL;
 
+
+
+
     /* Reset the globals. This is important in a non-reentrant scanner so the next time
-     * pplex() is called, initialization will occur. */
+     * yylex() is called, initialization will occur. */
     yy_init_globals( yyscanner);
 
     /* Destroy the main struct (reentrant only). */
-    ppfree ( yyscanner , yyscanner );
+    yyfree ( yyscanner , yyscanner );
     yyscanner = NULL;
     return 0;
 }
 
+
+
 /*
  * Internal utility routines.
  */
 
+
+
 #ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
@@ -2321,8 +2933,10 @@
 }
 #endif
 
+
+
 #ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
 {
 	int n;
 	for ( n = 0; s[n]; ++n )
@@ -2332,14 +2946,18 @@
 }
 #endif
 
-void *ppalloc (yy_size_t  size , yyscan_t yyscanner)
+
+
+void *yyalloc (yy_size_t  size , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
-	return (void *) malloc( size );
+	return malloc(size);
 }
 
-void *pprealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+
+
+void *yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
@@ -2351,25 +2969,31 @@
 	 * any pointer type to void*, and deal with argument conversions
 	 * as though doing an assignment.
 	 */
-	return (void *) realloc( (char *) ptr, size );
+	return realloc(ptr, size);
 }
 
-void ppfree (void * ptr , yyscan_t yyscanner)
+
+
+void yyfree (void * ptr , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
-	free( (char *) ptr );	/* see pprealloc() for (char *) cast */
+	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
 }
 
+
 #define YYTABLES_NAME "yytables"
 
+
+
+
+
+
+
+
 namespace pp {
 
-// TODO(alokp): Maximum token length should ideally be specified by
-// the preprocessor client, i.e., the compiler.
-const size_t Tokenizer::kMaxTokenLength = 256;
-
-Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0)
+Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(1024)
 {
     mContext.diagnostics = diagnostics;
 }
@@ -2379,10 +3003,10 @@
     destroyScanner();
 }
 
-bool Tokenizer::init(int count, const char* const string[], const int length[])
+bool Tokenizer::init(size_t count, const char * const string[], const int length[])
 {
-    if (count < 0) return false;
-    if ((count > 0) && (string == 0)) return false;
+    if ((count > 0) && (string == 0))
+        return false;
 
     mContext.input = Input(count, string, length);
     return initScanner();
@@ -2392,22 +3016,38 @@
 {
     // We use column number as file number.
     // See macro yyfileno.
-    ppset_column(file,mHandle);
+    yyset_column(file, mHandle);
 }
 
 void Tokenizer::setLineNumber(int line)
 {
-    ppset_lineno(line,mHandle);
+    yyset_lineno(line, mHandle);
 }
 
-void Tokenizer::lex(Token* token)
+void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
 {
-    token->type = pplex(&token->text,&token->location,mHandle);
-    if (token->text.size() > kMaxTokenLength)
+    mMaxTokenSize = maxTokenSize;
+}
+
+void Tokenizer::lex(Token *token)
+{
+    int tokenType = yylex(&token->text, &token->location, mHandle);
+
+    if (tokenType == Token::GOT_ERROR)
     {
-        mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG,
+        mContext.diagnostics->report(Diagnostics::PP_TOKENIZER_ERROR, token->location, token->text);
+        token->type = Token::LAST;
+    }
+    else
+    {
+        token->type = tokenType;
+    }
+
+    if (token->text.size() > mMaxTokenSize)
+    {
+        mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG,
                                      token->location, token->text);
-        token->text.erase(kMaxTokenLength);
+        token->text.erase(mMaxTokenSize);
     }
 
     token->flags = 0;
@@ -2421,21 +3061,22 @@
 
 bool Tokenizer::initScanner()
 {
-    if ((mHandle == NULL) && pplex_init_extra(&mContext,&mHandle))
+    if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle))
         return false;
 
-    pprestart(0,mHandle);
+    yyrestart(0, mHandle);
     return true;
 }
 
 void Tokenizer::destroyScanner()
 {
-    if (mHandle == NULL)
+    if (mHandle == nullptr)
         return;
 
-    pplex_destroy(mHandle);
-    mHandle = NULL;
+    yylex_destroy(mHandle);
+    mHandle = nullptr;
 }
 
 }  // namespace pp
 
+
diff --git a/src/OpenGL/compiler/preprocessor/Tokenizer.h b/src/OpenGL/compiler/preprocessor/Tokenizer.h
index 3bad966..7227fe0 100644
--- a/src/OpenGL/compiler/preprocessor/Tokenizer.h
+++ b/src/OpenGL/compiler/preprocessor/Tokenizer.h
@@ -19,8 +19,6 @@
 #include "Lexer.h"
 #include "pp_utils.h"
 
-#include <algorithm>
-
 namespace pp
 {
 
@@ -31,7 +29,7 @@
 public:
 	struct Context
 	{
-		Diagnostics* diagnostics;
+		Diagnostics *diagnostics;
 
 		Input input;
 		// The location where yytext points to. Token location should track
@@ -42,25 +40,26 @@
 		bool leadingSpace;
 		bool lineStart;
 	};
-	static const size_t kMaxTokenLength;
 
-	Tokenizer(Diagnostics* diagnostics);
-	~Tokenizer();
+	Tokenizer(Diagnostics *diagnostics);
+	~Tokenizer() override;
 
-	bool init(int count, const char* const string[], const int length[]);
+	bool init(size_t count, const char *const string[], const int length[]);
 
 	void setFileNumber(int file);
 	void setLineNumber(int line);
+	void setMaxTokenSize(size_t maxTokenSize);
 
-	virtual void lex(Token* token);
+	void lex(Token *token) override;
 
 private:
 	PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer);
 	bool initScanner();
 	void destroyScanner();
 
-	void* mHandle;  // Scanner handle.
+	void *mHandle;  // Scanner handle.
 	Context mContext;  // Scanner extra.
+	size_t mMaxTokenSize;  // Maximum token size
 };
 
 }  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/Tokenizer.l b/src/OpenGL/compiler/preprocessor/Tokenizer.l
index 094627e..f99cfd4 100644
--- a/src/OpenGL/compiler/preprocessor/Tokenizer.l
+++ b/src/OpenGL/compiler/preprocessor/Tokenizer.l
@@ -39,14 +39,27 @@
 }
 
 %{
+#if defined(_MSC_VER)
+#pragma warning(disable: 4005)
+#endif
+
 #include "Tokenizer.h"
 
-#include "Diagnostics.h"
+#include "DiagnosticsBase.h"
 #include "Token.h"
 
 #if defined(__GNUC__)
 // Triggered by the auto-generated yy_fatal_error function.
 #pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4244)
+#endif
+
+// Workaround for flex using the register keyword, deprecated in C++11.
+#ifdef __cplusplus
+#if __cplusplus > 199711L
+#define register
+#endif
 #endif
 
 typedef std::string YYSTYPE;
@@ -80,7 +93,7 @@
     } while(0);
 
 #define YY_INPUT(buf, result, maxSize) \
-    result = yyextra->input.read(buf, maxSize);
+    result = yyextra->input.read(buf, maxSize, &yylineno);
 
 %}
 
@@ -109,11 +122,18 @@
 
     /* Block comment */
     /* Line breaks are just counted - not returned. */
-    /* The comment is replaced by a single space. */ 
+    /* The comment is replaced by a single space. */
 "/*" { BEGIN(COMMENT); }
 <COMMENT>[^*\r\n]+
 <COMMENT>"*"
-<COMMENT>{NEWLINE} { ++yylineno; }
+<COMMENT>{NEWLINE} {
+    if (yylineno == INT_MAX)
+    {
+        *yylval = "Integer overflow on line number";
+        return pp::Token::GOT_ERROR;
+    }
+    ++yylineno;
+}
 <COMMENT>"*/" {
     yyextra->leadingSpace = true;
     BEGIN(INITIAL);
@@ -240,13 +260,16 @@
 [ \t\v\f]+   { yyextra->leadingSpace = true; }
 
 {NEWLINE} {
+    if (yylineno == INT_MAX)
+    {
+        *yylval = "Integer overflow on line number";
+        return pp::Token::GOT_ERROR;
+    }
     ++yylineno;
     yylval->assign(1, '\n');
     return '\n';
 }
 
-\\{NEWLINE} { ++yylineno; }
-
 . {
     yylval->assign(1, yytext[0]);
     return pp::Token::PP_OTHER;
@@ -257,23 +280,30 @@
     // Set the location for EOF token manually.
     pp::Input* input = &yyextra->input;
     pp::Input::Location* scanLoc = &yyextra->scanLoc;
-    int sIndexMax = std::max(0, input->count() - 1);
+    yy_size_t sIndexMax = input->count() ? input->count() - 1 : 0;
     if (scanLoc->sIndex != sIndexMax)
     {
         // We can only reach here if there are empty strings at the
         // end of the input.
         scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
-        yyfileno = sIndexMax; yylineno = 1;
+        // FIXME: this is not 64-bit clean.
+        yyfileno = static_cast<int>(sIndexMax); yylineno = 1;
     }
     yylloc->file = yyfileno;
     yylloc->line = yylineno;
     yylval->clear();
 
-    if (YY_START == COMMENT)
+    // Line number overflows fake EOFs to exit early, check for this case.
+    if (yylineno == INT_MAX) {
+        yyextra->diagnostics->report(pp::Diagnostics::PP_TOKENIZER_ERROR,
+                pp::SourceLocation(yyfileno, yylineno),
+                "Integer overflow on line number");
+    }
+    else if (YY_START == COMMENT)
     {
-        yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT,
+        yyextra->diagnostics->report(pp::Diagnostics::PP_EOF_IN_COMMENT,
                                      pp::SourceLocation(yyfileno, yylineno),
-                                     "");
+                                     "EOF while in a comment");
     }
     yyterminate();
 }
@@ -282,11 +312,7 @@
 
 namespace pp {
 
-// TODO(alokp): Maximum token length should ideally be specified by
-// the preprocessor client, i.e., the compiler.
-const size_t Tokenizer::kMaxTokenLength = 256;
-
-Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0)
+Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(1024)
 {
     mContext.diagnostics = diagnostics;
 }
@@ -296,10 +322,10 @@
     destroyScanner();
 }
 
-bool Tokenizer::init(int count, const char* const string[], const int length[])
+bool Tokenizer::init(size_t count, const char * const string[], const int length[])
 {
-    if (count < 0) return false;
-    if ((count > 0) && (string == 0)) return false;
+    if ((count > 0) && (string == 0))
+        return false;
 
     mContext.input = Input(count, string, length);
     return initScanner();
@@ -317,14 +343,30 @@
     yyset_lineno(line, mHandle);
 }
 
-void Tokenizer::lex(Token* token)
+void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
 {
-    token->type = yylex(&token->text, &token->location, mHandle);
-    if (token->text.size() > kMaxTokenLength)
+    mMaxTokenSize = maxTokenSize;
+}
+
+void Tokenizer::lex(Token *token)
+{
+    int tokenType = yylex(&token->text, &token->location, mHandle);
+
+    if (tokenType == Token::GOT_ERROR)
     {
-        mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG,
+        mContext.diagnostics->report(Diagnostics::PP_TOKENIZER_ERROR, token->location, token->text);
+        token->type = Token::LAST;
+    }
+    else
+    {
+        token->type = tokenType;
+    }
+
+    if (token->text.size() > mMaxTokenSize)
+    {
+        mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG,
                                      token->location, token->text);
-        token->text.erase(kMaxTokenLength);
+        token->text.erase(mMaxTokenSize);
     }
 
     token->flags = 0;
@@ -338,7 +380,7 @@
 
 bool Tokenizer::initScanner()
 {
-    if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle))
+    if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle))
         return false;
 
     yyrestart(0, mHandle);
@@ -347,11 +389,11 @@
 
 void Tokenizer::destroyScanner()
 {
-    if (mHandle == NULL)
+    if (mHandle == nullptr)
         return;
 
     yylex_destroy(mHandle);
-    mHandle = NULL;
+    mHandle = nullptr;
 }
 
 }  // namespace pp
diff --git a/src/OpenGL/compiler/preprocessor/numeric_lex.h b/src/OpenGL/compiler/preprocessor/numeric_lex.h
index f57410c..ed22e03 100644
--- a/src/OpenGL/compiler/preprocessor/numeric_lex.h
+++ b/src/OpenGL/compiler/preprocessor/numeric_lex.h
@@ -18,6 +18,7 @@
 #define COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
 
 #include <sstream>
+#include <cmath>
 
 namespace pp {
 
@@ -62,7 +63,7 @@
 	stream.imbue(std::locale::classic());
 
 	stream >> (*value);
-	return !stream.fail();
+	return !stream.fail() && std::isfinite(*value);
 }
 
 } // namespace pp.
diff --git a/src/OpenGL/compiler/preprocessor/preprocessor.vcxproj b/src/OpenGL/compiler/preprocessor/preprocessor.vcxproj
index 701e965..0060904 100644
--- a/src/OpenGL/compiler/preprocessor/preprocessor.vcxproj
+++ b/src/OpenGL/compiler/preprocessor/preprocessor.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -21,33 +21,34 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{92940255-AB4B-42FB-A2C4-0FAB19C3C48A}</ProjectGuid>

     <RootNamespace>preprocessor</RootNamespace>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

@@ -89,6 +90,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>4005;</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <GenerateDebugInformation>true</GenerateDebugInformation>

@@ -102,6 +104,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>4005;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <GenerateDebugInformation>true</GenerateDebugInformation>

@@ -117,6 +120,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>4005;</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <GenerateDebugInformation>true</GenerateDebugInformation>

@@ -134,6 +138,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>4005;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <GenerateDebugInformation>true</GenerateDebugInformation>

@@ -142,8 +147,8 @@
     </Link>

   </ItemDefinitionGroup>

   <ItemGroup>

-    <ClInclude Include="Diagnostics.h" />

-    <ClInclude Include="DirectiveHandler.h" />

+    <ClInclude Include="DiagnosticsBase.h" />

+    <ClInclude Include="DirectiveHandlerBase.h" />

     <ClInclude Include="DirectiveParser.h" />

     <ClInclude Include="ExpressionParser.h" />

     <ClInclude Include="Input.h" />

@@ -159,8 +164,8 @@
     <ClInclude Include="Tokenizer.h" />

   </ItemGroup>

   <ItemGroup>

-    <ClCompile Include="Diagnostics.cpp" />

-    <ClCompile Include="DirectiveHandler.cpp" />

+    <ClCompile Include="DiagnosticsBase.cpp" />

+    <ClCompile Include="DirectiveHandlerBase.cpp" />

     <ClCompile Include="DirectiveParser.cpp" />

     <ClCompile Include="ExpressionParser.cpp" />

     <ClCompile Include="Input.cpp" />

diff --git a/src/OpenGL/compiler/preprocessor/preprocessor.vcxproj.filters b/src/OpenGL/compiler/preprocessor/preprocessor.vcxproj.filters
index d68cbe2..02c06a0 100644
--- a/src/OpenGL/compiler/preprocessor/preprocessor.vcxproj.filters
+++ b/src/OpenGL/compiler/preprocessor/preprocessor.vcxproj.filters
@@ -15,12 +15,6 @@
     </Filter>

   </ItemGroup>

   <ItemGroup>

-    <ClInclude Include="Diagnostics.h">

-      <Filter>Header Files</Filter>

-    </ClInclude>

-    <ClInclude Include="DirectiveHandler.h">

-      <Filter>Header Files</Filter>

-    </ClInclude>

     <ClInclude Include="DirectiveParser.h">

       <Filter>Header Files</Filter>

     </ClInclude>

@@ -60,14 +54,14 @@
     <ClInclude Include="Tokenizer.h">

       <Filter>Header Files</Filter>

     </ClInclude>

+    <ClInclude Include="DiagnosticsBase.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="DirectiveHandlerBase.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

   </ItemGroup>

   <ItemGroup>

-    <ClCompile Include="Diagnostics.cpp">

-      <Filter>Source Files</Filter>

-    </ClCompile>

-    <ClCompile Include="DirectiveHandler.cpp">

-      <Filter>Source Files</Filter>

-    </ClCompile>

     <ClCompile Include="DirectiveParser.cpp">

       <Filter>Source Files</Filter>

     </ClCompile>

@@ -95,9 +89,15 @@
     <ClCompile Include="Tokenizer.cpp">

       <Filter>Source Files</Filter>

     </ClCompile>

+    <ClCompile Include="DiagnosticsBase.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="DirectiveHandlerBase.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

   </ItemGroup>

   <ItemGroup>

     <None Include="Tokenizer.l" />

     <None Include="ExpressionParser.y" />

   </ItemGroup>

-</Project>

+</Project>
\ No newline at end of file
diff --git a/src/OpenGL/compiler/util.cpp b/src/OpenGL/compiler/util.cpp
index 2905c1d..bd9783c 100644
--- a/src/OpenGL/compiler/util.cpp
+++ b/src/OpenGL/compiler/util.cpp
@@ -32,3 +32,11 @@
 		*value = std::numeric_limits<int>::max();
 	return success;
 }
+
+bool atou_clamp(const char *str, unsigned int *value)
+{
+	bool success = pp::numeric_lex_int(str, value);
+	if(!success)
+		*value = std::numeric_limits<unsigned int>::max();
+	return success;
+}
diff --git a/src/OpenGL/compiler/util.h b/src/OpenGL/compiler/util.h
index a5c4842..563407e 100644
--- a/src/OpenGL/compiler/util.h
+++ b/src/OpenGL/compiler/util.h
@@ -21,14 +21,18 @@
 
 // atof_clamp is like atof 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.
+//   2. it sets the value to FLT_MAX if overflow happens.
 // Return false if overflow happens.
 bool atof_clamp(const char *str, float *value);
 
-// If overflow happens, clamp the value to INT_MIN or INT_MAX.
+// If overflow happens, value is set to INT_MAX.
 // Return false if overflow happens.
 bool atoi_clamp(const char *str, int *value);
 
+// If overflow happens, value is set to UINT_MAX.
+// Return false if overflow happens.
+bool atou_clamp(const char *str, unsigned int *value);
+
 #ifdef __cplusplus
 } // end extern "C"
 #endif
diff --git a/src/OpenGL/libEGL/Android.mk b/src/OpenGL/libEGL/Android.mk
index 6e78d63..64ccc55 100644
--- a/src/OpenGL/libEGL/Android.mk
+++ b/src/OpenGL/libEGL/Android.mk
@@ -63,7 +63,8 @@
 endif
 
 COMMON_LDFLAGS := \
-	-Wl,--version-script=$(LOCAL_PATH)/exports.map \
+	-Wl,--version-script=$(LOCAL_PATH)/libEGL.lds \
+	-Wl,--gc-sections \
 	-Wl,--hash-style=sysv
 
 include $(CLEAR_VARS)
@@ -71,14 +72,10 @@
 ifdef TARGET_2ND_ARCH
 ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
 LOCAL_MULTILIB := first
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
-else
-LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib/egl
-LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64/egl
 endif
-else
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
 endif
+LOCAL_MODULE_RELATIVE_PATH := egl
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_TAGS := optional
 LOCAL_CLANG := true
 LOCAL_SRC_FILES := $(COMMON_SRC_FILES)
@@ -95,14 +92,10 @@
 ifdef TARGET_2ND_ARCH
 ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
 LOCAL_MULTILIB := first
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
-else
-LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib/egl
-LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64/egl
 endif
-else
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
 endif
+LOCAL_MODULE_RELATIVE_PATH := egl
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_TAGS := optional
 LOCAL_CLANG := true
 LOCAL_SRC_FILES := $(COMMON_SRC_FILES)
diff --git a/src/OpenGL/libEGL/BUILD.gn b/src/OpenGL/libEGL/BUILD.gn
index 68a10bc..24727cf 100644
--- a/src/OpenGL/libEGL/BUILD.gn
+++ b/src/OpenGL/libEGL/BUILD.gn
@@ -74,7 +74,7 @@
   } else if (is_linux) {
     sources += [ "../../Main/libX11.cpp" ]
     ldflags =
-        [ "-Wl,--version-script=" + rebase_path("exports.map", root_build_dir) ]
+        [ "-Wl,--version-script=" + rebase_path("libEGL.lds", root_build_dir) ]
   }
 
   configs = [ ":swiftshader_libEGL_private_config" ]
diff --git a/src/OpenGL/libEGL/Config.cpp b/src/OpenGL/libEGL/Config.cpp
index a1c800b..2595ef1 100644
--- a/src/OpenGL/libEGL/Config.cpp
+++ b/src/OpenGL/libEGL/Config.cpp
@@ -34,16 +34,8 @@
 
 namespace egl
 {
-// OpenGL ES 3.0 support is not conformant yet, but can be used for testing purposes. Expose it as conformant configs
-// if strict conformance advertisement isn't required. If strict conformance advertisement is required, expose them
-// as non-conformant configs, but only when EGL_CONFIG_CAVEAT is EGL_NON_CONFORMANT_CONFIG or EGL_DONT_CARE.
-#if defined(__ANDROID__) || defined(STRICT_CONFORMANCE)
-const bool strictConformance = true;
-#else
-const bool strictConformance = false;
-#endif
 
-Config::Config(sw::Format displayFormat, EGLint minInterval, EGLint maxInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample, bool conformant)
+Config::Config(sw::Format displayFormat, EGLint minInterval, EGLint maxInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
 	: mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample)
 {
 	mBindToTextureRGB = EGL_FALSE;
@@ -127,9 +119,9 @@
 	mBufferSize = mRedSize + mGreenSize + mBlueSize + mLuminanceSize + mAlphaSize;
 	mAlphaMaskSize = 0;
 	mColorBufferType = EGL_RGB_BUFFER;
-	mConfigCaveat = (conformant || !strictConformance) ? EGL_NONE : EGL_NON_CONFORMANT_CONFIG;
+	mConfigCaveat = EGL_NONE;
 	mConfigID = 0;
-	mConformant = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | (strictConformance ? 0 : EGL_OPENGL_ES3_BIT);
+	mConformant = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT;
 
 	switch(depthStencilFormat)
 	{
@@ -186,7 +178,7 @@
 	mMinSwapInterval = minInterval;
 	mNativeRenderable = EGL_FALSE;
 	mNativeVisualType = 0;
-	mRenderableType = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | ((conformant && strictConformance) ? 0 : EGL_OPENGL_ES3_BIT);
+	mRenderableType = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT;
 	mSampleBuffers = (multiSample > 0) ? 1 : 0;
 	mSamples = multiSample;
 	mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
@@ -338,14 +330,8 @@
 
 void ConfigSet::add(sw::Format displayFormat, EGLint minSwapInterval, EGLint maxSwapInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
 {
-	Config conformantConfig(displayFormat, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample, true);
+	Config conformantConfig(displayFormat, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample);
 	mSet.insert(conformantConfig);
-
-	if(strictConformance)   // When strict conformance is required, add non-conformant configs explicitly as such.
-	{
-		Config nonConformantConfig(displayFormat, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample, false);
-		mSet.insert(nonConformantConfig);
-	}
 }
 
 size_t ConfigSet::size() const
diff --git a/src/OpenGL/libEGL/Config.h b/src/OpenGL/libEGL/Config.h
index a15fbd1..46719e1 100644
--- a/src/OpenGL/libEGL/Config.h
+++ b/src/OpenGL/libEGL/Config.h
@@ -32,7 +32,7 @@
 class Config
 {
 public:
-	Config(sw::Format displayFormat, EGLint minSwapInterval, EGLint maxSwapInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample, bool conformant);
+	Config(sw::Format displayFormat, EGLint minSwapInterval, EGLint maxSwapInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample);
 
 	EGLConfig getHandle() const;
 
diff --git a/src/OpenGL/libEGL/Display.cpp b/src/OpenGL/libEGL/Display.cpp
index 0ae67bd..0e58125 100644
--- a/src/OpenGL/libEGL/Display.cpp
+++ b/src/OpenGL/libEGL/Display.cpp
@@ -567,11 +567,14 @@
 			XWindowAttributes windowAttributes;
 			Status status = libX11->XGetWindowAttributes((::Display*)nativeDisplay, window, &windowAttributes);
 
-			return status == True;
+			return status != 0;
 		}
 		return false;
 	#elif defined(__APPLE__)
 		return sw::OSX::IsValidWindow(window);
+	#elif defined(__Fuchsia__)
+		// TODO(crbug.com/800951): Integrate with Mozart.
+		return true;
 	#else
 		#error "Display::isValidWindow unimplemented for this platform"
 		return false;
@@ -580,11 +583,11 @@
 
 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
 {
-	for(SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+	for(const auto &surface : mSurfaceSet)
 	{
-		if((*surface)->isWindowSurface())
+		if(surface->isWindowSurface())
 		{
-			if((*surface)->getWindowHandle() == window)
+			if(surface->getWindowHandle() == window)
 			{
 				return true;
 			}
@@ -744,6 +747,8 @@
 		}
 	#elif defined(__APPLE__)
 		return sw::FORMAT_A8B8G8R8;
+	#elif defined(__Fuchsia__)
+		return sw::FORMAT_A8B8G8R8;
 	#else
 		#error "Display::isValidWindow unimplemented for this platform"
 	#endif
diff --git a/src/OpenGL/libEGL/Surface.cpp b/src/OpenGL/libEGL/Surface.cpp
index 8cb3b39..d373990 100644
--- a/src/OpenGL/libEGL/Surface.cpp
+++ b/src/OpenGL/libEGL/Surface.cpp
@@ -76,14 +76,14 @@
 {
 	ASSERT(!backBuffer && !depthStencil);
 
-	if(libGLES_CM)
-	{
-		backBuffer = libGLES_CM->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples);
-	}
-	else if(libGLESv2)
+	if(libGLESv2)
 	{
 		backBuffer = libGLESv2->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples);
 	}
+	else if(libGLES_CM)
+	{
+		backBuffer = libGLES_CM->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples);
+	}
 
 	if(!backBuffer)
 	{
@@ -94,14 +94,14 @@
 
 	if(config->mDepthStencilFormat != sw::FORMAT_NULL)
 	{
-		if(libGLES_CM)
-		{
-			depthStencil = libGLES_CM->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples);
-		}
-		else if(libGLESv2)
+		if(libGLESv2)
 		{
 			depthStencil = libGLESv2->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples);
 		}
+		else if(libGLES_CM)
+		{
+			depthStencil = libGLES_CM->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples);
+		}
 
 		if(!depthStencil)
 		{
@@ -182,11 +182,6 @@
 	return config->mSurfaceType;
 }
 
-sw::Format Surface::getInternalFormat() const
-{
-	return config->mRenderTargetFormat;
-}
-
 EGLint Surface::getWidth() const
 {
 	return width;
@@ -259,9 +254,7 @@
 {
 	if(backBuffer && frameBuffer)
 	{
-		void *source = backBuffer->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
-		frameBuffer->flip(source, backBuffer->sw::Surface::getInternalFormat(), backBuffer->getInternalPitchB());
-		backBuffer->unlockInternal();
+		frameBuffer->flip(backBuffer);
 
 		checkForResize();
 	}
@@ -276,10 +269,11 @@
 {
 	#if defined(_WIN32)
 		RECT client;
-		if(!GetClientRect(window, &client))
+		BOOL status = GetClientRect(window, &client);
+
+		if(status == 0)
 		{
-			ASSERT(false);
-			return false;
+			return error(EGL_BAD_NATIVE_WINDOW, false);
 		}
 
 		int windowWidth = client.right - client.left;
@@ -289,7 +283,12 @@
 		int windowHeight; window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight);
 	#elif defined(__linux__)
 		XWindowAttributes windowAttributes;
-		libX11->XGetWindowAttributes((::Display*)display->getNativeDisplay(), window, &windowAttributes);
+		Status status = libX11->XGetWindowAttributes((::Display*)display->getNativeDisplay(), window, &windowAttributes);
+
+		if(status == 0)
+		{
+			return error(EGL_BAD_NATIVE_WINDOW, false);
+		}
 
 		int windowWidth = windowAttributes.width;
 		int windowHeight = windowAttributes.height;
@@ -297,6 +296,10 @@
 		int windowWidth;
 		int windowHeight;
 		sw::OSX::GetNativeWindowSize(window, windowWidth, windowHeight);
+	#elif defined(__Fuchsia__)
+		// TODO(crbug.com/800951): Integrate with Mozart.
+		int windowWidth = 100;
+		int windowHeight = 100;
 	#else
 		#error "WindowSurface::checkForResize unimplemented for this platform"
 	#endif
@@ -333,14 +336,14 @@
 
 	if(window)
 	{
-		if(libGLES_CM)
-		{
-			frameBuffer = libGLES_CM->createFrameBuffer(display->getNativeDisplay(), window, width, height);
-		}
-		else if(libGLESv2)
+		if(libGLESv2)
 		{
 			frameBuffer = libGLESv2->createFrameBuffer(display->getNativeDisplay(), window, width, height);
 		}
+		else if(libGLES_CM)
+		{
+			frameBuffer = libGLES_CM->createFrameBuffer(display->getNativeDisplay(), window, width, height);
+		}
 
 		if(!frameBuffer)
 		{
diff --git a/src/OpenGL/libEGL/Surface.hpp b/src/OpenGL/libEGL/Surface.hpp
index e140a8e..2e9e26b 100644
--- a/src/OpenGL/libEGL/Surface.hpp
+++ b/src/OpenGL/libEGL/Surface.hpp
@@ -45,7 +45,6 @@
 
 	virtual EGLint getConfigID() const;
 	virtual EGLenum getSurfaceType() const;
-	sw::Format getInternalFormat() const override;
 
 	EGLint getWidth() const override;
 	EGLint getHeight() const override;
diff --git a/src/OpenGL/libEGL/libEGL.cpp b/src/OpenGL/libEGL/libEGL.cpp
index 21ef933..5944efd 100644
--- a/src/OpenGL/libEGL/libEGL.cpp
+++ b/src/OpenGL/libEGL/libEGL.cpp
@@ -29,6 +29,7 @@
 #include "Main/libX11.hpp"
 #endif
 
+#include <algorithm>
 #include <string.h>
 
 using namespace egl;
@@ -174,6 +175,7 @@
 	if(dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
 	{
 		return success(
+			"EGL_KHR_client_get_all_proc_addresses "
 #if defined(__linux__) && !defined(__ANDROID__)
 			"EGL_KHR_platform_gbm "
 			"EGL_KHR_platform_x11 "
@@ -195,6 +197,7 @@
 		return success("OpenGL_ES");
 	case EGL_EXTENSIONS:
 		return success("EGL_KHR_create_context "
+		               "EGL_KHR_get_all_proc_addresses "
 		               "EGL_KHR_gl_texture_2D_image "
 		               "EGL_KHR_gl_texture_cubemap_image "
 		               "EGL_KHR_gl_renderbuffer_image "
@@ -477,9 +480,15 @@
 {
 	TRACE("()");
 
-	UNIMPLEMENTED();   // FIXME
+	// eglWaitClient is ignored if there is no current EGL rendering context for the current rendering API.
+	egl::Context *context = egl::getCurrentContext();
 
-	return success(EGL_FALSE);
+	if(context)
+	{
+		context->finish();
+	}
+
+	return success(EGL_TRUE);
 }
 
 EGLBoolean ReleaseThread(void)
@@ -910,18 +919,46 @@
 {
 	TRACE("()");
 
-	UNIMPLEMENTED();   // FIXME
+	// glWaitGL is ignored if there is no current EGL rendering context for OpenGL ES.
+	egl::Context *context = egl::getCurrentContext();
 
-	return success(EGL_FALSE);
+	if(context)
+	{
+		context->finish();
+	}
+
+	return success(EGL_TRUE);
 }
 
 EGLBoolean WaitNative(EGLint engine)
 {
 	TRACE("(EGLint engine = %d)", engine);
 
-	UNIMPLEMENTED();   // FIXME
+	if(engine != EGL_CORE_NATIVE_ENGINE)
+	{
+		return error(EGL_BAD_PARAMETER, EGL_FALSE);
+	}
 
-	return success(EGL_FALSE);
+	// eglWaitNative is ignored if there is no current EGL rendering context.
+	egl::Context *context = egl::getCurrentContext();
+
+	if(context)
+	{
+		#if defined(__linux__) && !defined(__ANDROID__)
+			egl::Display *display = context->getDisplay();
+
+			if(!display)
+			{
+				return error(EGL_BAD_DISPLAY, EGL_FALSE);
+			}
+
+			libX11->XSync((::Display*)display->getNativeDisplay(), False);
+		#else
+			UNIMPLEMENTED();
+		#endif
+	}
+
+	return success(EGL_TRUE);
 }
 
 EGLBoolean SwapBuffers(EGLDisplay dpy, EGLSurface surface)
@@ -1241,34 +1278,85 @@
 {
 	TRACE("(const char *procname = \"%s\")", procname);
 
-	struct Extension
+	struct Function
 	{
 		const char *name;
 		__eglMustCastToProperFunctionPointerType address;
 	};
 
-	static const Extension eglExtensions[] =
+	struct CompareFunctor
 	{
-		#define EXTENSION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
-
-		EXTENSION(eglCreateImageKHR),
-		EXTENSION(eglDestroyImageKHR),
-		EXTENSION(eglGetPlatformDisplayEXT),
-		EXTENSION(eglCreatePlatformWindowSurfaceEXT),
-		EXTENSION(eglCreatePlatformPixmapSurfaceEXT),
-		EXTENSION(eglCreateSyncKHR),
-		EXTENSION(eglDestroySyncKHR),
-		EXTENSION(eglClientWaitSyncKHR),
-		EXTENSION(eglGetSyncAttribKHR),
-
-		#undef EXTENSION
+		bool operator()(const Function &a, const Function &b) const
+		{
+			return strcmp(a.name, b.name) < 0;
+		}
 	};
 
-	for(unsigned int ext = 0; ext < sizeof(eglExtensions) / sizeof(Extension); ext++)
+	// This array must be kept sorted with respect to strcmp(), so that binary search works correctly.
+	// The Unix command "LC_COLLATE=C sort" will generate the correct order.
+	static const Function eglFunctions[] =
 	{
-		if(strcmp(procname, eglExtensions[ext].name) == 0)
+		#define FUNCTION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
+
+		FUNCTION(eglBindAPI),
+		FUNCTION(eglBindTexImage),
+		FUNCTION(eglChooseConfig),
+		FUNCTION(eglClientWaitSyncKHR),
+		FUNCTION(eglCopyBuffers),
+		FUNCTION(eglCreateContext),
+		FUNCTION(eglCreateImageKHR),
+		FUNCTION(eglCreatePbufferFromClientBuffer),
+		FUNCTION(eglCreatePbufferSurface),
+		FUNCTION(eglCreatePixmapSurface),
+		FUNCTION(eglCreatePlatformPixmapSurfaceEXT),
+		FUNCTION(eglCreatePlatformWindowSurfaceEXT),
+		FUNCTION(eglCreateSyncKHR),
+		FUNCTION(eglCreateWindowSurface),
+		FUNCTION(eglDestroyContext),
+		FUNCTION(eglDestroyImageKHR),
+		FUNCTION(eglDestroySurface),
+		FUNCTION(eglDestroySyncKHR),
+		FUNCTION(eglGetConfigAttrib),
+		FUNCTION(eglGetConfigs),
+		FUNCTION(eglGetCurrentContext),
+		FUNCTION(eglGetCurrentDisplay),
+		FUNCTION(eglGetCurrentSurface),
+		FUNCTION(eglGetDisplay),
+		FUNCTION(eglGetError),
+		FUNCTION(eglGetPlatformDisplayEXT),
+		FUNCTION(eglGetProcAddress),
+		FUNCTION(eglGetSyncAttribKHR),
+		FUNCTION(eglInitialize),
+		FUNCTION(eglMakeCurrent),
+		FUNCTION(eglQueryAPI),
+		FUNCTION(eglQueryContext),
+		FUNCTION(eglQueryString),
+		FUNCTION(eglQuerySurface),
+		FUNCTION(eglReleaseTexImage),
+		FUNCTION(eglReleaseThread),
+		FUNCTION(eglSurfaceAttrib),
+		FUNCTION(eglSwapBuffers),
+		FUNCTION(eglSwapInterval),
+		FUNCTION(eglTerminate),
+		FUNCTION(eglWaitClient),
+		FUNCTION(eglWaitGL),
+		FUNCTION(eglWaitNative),
+
+		#undef FUNCTION
+	};
+
+	static const size_t numFunctions = sizeof eglFunctions / sizeof(Function);
+	static const Function *const eglFunctionsEnd = eglFunctions + numFunctions;
+
+	Function needle;
+	needle.name = procname;
+
+	if(procname && strncmp("egl", procname, 3) == 0)
+	{
+		const Function *result = std::lower_bound(eglFunctions, eglFunctionsEnd, needle, CompareFunctor());
+		if (result != eglFunctionsEnd && strcmp(procname, result->name) == 0)
 		{
-			return success((__eglMustCastToProperFunctionPointerType)eglExtensions[ext].address);
+			return success((__eglMustCastToProperFunctionPointerType)result->address);
 		}
 	}
 
diff --git a/src/OpenGL/libEGL/libEGL.hpp b/src/OpenGL/libEGL/libEGL.hpp
index 683b0d1..77ddf70 100644
--- a/src/OpenGL/libEGL/libEGL.hpp
+++ b/src/OpenGL/libEGL/libEGL.hpp
@@ -118,6 +118,8 @@
 				#else
 					const char *libEGL_lib[] = {"libEGL_translator.dylib", "libEGL.so", "libEGL.dylib", "libswiftshader_libEGL.dylib"};
 				#endif
+			#elif defined(__Fuchsia__)
+				const char *libEGL_lib[] = {"libEGL.so"};
 			#else
 				#error "libEGL::loadExports unimplemented for this platform"
 			#endif
diff --git a/src/OpenGL/libEGL/exports.map b/src/OpenGL/libEGL/libEGL.lds
similarity index 99%
rename from src/OpenGL/libEGL/exports.map
rename to src/OpenGL/libEGL/libEGL.lds
index 8455dc9..7a2a479 100644
--- a/src/OpenGL/libEGL/exports.map
+++ b/src/OpenGL/libEGL/libEGL.lds
@@ -56,4 +56,4 @@
 
 local:
 	*;
-};
+};
\ No newline at end of file
diff --git a/src/OpenGL/libEGL/libEGL.vcxproj b/src/OpenGL/libEGL/libEGL.vcxproj
index 032077b..172d6b8 100644
--- a/src/OpenGL/libEGL/libEGL.vcxproj
+++ b/src/OpenGL/libEGL/libEGL.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -30,41 +30,42 @@
     <ProjectGuid>{E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}</ProjectGuid>

     <RootNamespace>libEGL</RootNamespace>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

@@ -131,6 +132,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

       <DisableSpecificWarnings>5030</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -162,6 +164,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

       <DisableSpecificWarnings>5030</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -194,6 +197,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

       <DisableSpecificWarnings>5030</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -226,6 +230,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

       <DisableSpecificWarnings>5030</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -260,6 +265,7 @@
       <OmitFramePointers>false</OmitFramePointers>

       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -292,6 +298,7 @@
       <OmitFramePointers>false</OmitFramePointers>

       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

diff --git a/src/OpenGL/libEGL/main.cpp b/src/OpenGL/libEGL/main.cpp
index 3a8d1ce..b953e4b 100644
--- a/src/OpenGL/libEGL/main.cpp
+++ b/src/OpenGL/libEGL/main.cpp
@@ -48,14 +48,7 @@
 		currentTLS = sw::Thread::allocateLocalStorageKey();
 	}
 
-	Current *current = (Current*)sw::Thread::getLocalStorage(currentTLS);
-
-	if(!current)
-	{
-		current = new Current;
-
-		sw::Thread::setLocalStorage(currentTLS, current);
-	}
+	Current *current = (Current*)sw::Thread::allocateLocalStorage(currentTLS, sizeof(Current));
 
 	current->error = EGL_SUCCESS;
 	current->API = EGL_OPENGL_ES_API;
@@ -72,8 +65,7 @@
 
 	eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
 
-	delete (Current*)sw::Thread::getLocalStorage(currentTLS);
-	sw::Thread::setLocalStorage(currentTLS, nullptr);
+	sw::Thread::freeLocalStorage(currentTLS);
 }
 
 CONSTRUCTOR void attachProcess()
diff --git a/src/OpenGL/libGL/Context.cpp b/src/OpenGL/libGL/Context.cpp
index 4922ecb..8f8d96a 100644
--- a/src/OpenGL/libGL/Context.cpp
+++ b/src/OpenGL/libGL/Context.cpp
@@ -2109,7 +2109,7 @@
 
 	if(baseTexture && textureUsed)
 	{
-		int levelCount = baseTexture->getLevelCount();
+		int topLevel = baseTexture->getTopLevel();
 
 		if(baseTexture->getTarget() == GL_TEXTURE_2D)
 		{
@@ -2123,9 +2123,9 @@
 				{
 					surfaceLevel = 0;
 				}
-				else if(surfaceLevel >= levelCount)
+				else if(surfaceLevel > topLevel)
 				{
-					surfaceLevel = levelCount - 1;
+					surfaceLevel = topLevel;
 				}
 
 				Image *surface = texture->getImage(surfaceLevel);
@@ -2146,9 +2146,9 @@
 					{
 						surfaceLevel = 0;
 					}
-					else if(surfaceLevel >= levelCount)
+					else if(surfaceLevel > topLevel)
 					{
-						surfaceLevel = levelCount - 1;
+						surfaceLevel = topLevel;
 					}
 
 					Image *surface = cubeTexture->getImage(face, surfaceLevel);
@@ -2477,7 +2477,7 @@
 {
 	if(!mState.currentProgram)
 	{
-		return error(GL_INVALID_OPERATION);
+		return;
 	}
 
 	if(!indices && !mState.elementArrayBuffer)
diff --git a/src/OpenGL/libGL/Context.h b/src/OpenGL/libGL/Context.h
index 877d768..10f4ae0 100644
--- a/src/OpenGL/libGL/Context.h
+++ b/src/OpenGL/libGL/Context.h
@@ -328,12 +328,10 @@
 
 const GLenum compressedTextureFormats[] =
 {
-#if (S3TC_SUPPORT)
 	GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
 	GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
 	GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
 	GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
-#endif
 };
 
 const GLint NUM_COMPRESSED_TEXTURE_FORMATS = sizeof(compressedTextureFormats) / sizeof(compressedTextureFormats[0]);
diff --git a/src/OpenGL/libGL/Device.cpp b/src/OpenGL/libGL/Device.cpp
index 736bb99..be7d10e 100644
--- a/src/OpenGL/libGL/Device.cpp
+++ b/src/OpenGL/libGL/Device.cpp
@@ -621,7 +621,8 @@
 		}
 		else
 		{
-			blit(source, sRect, dest, dRect, scaling && filter);
+			sw::SliceRectF sRectF((float)sRect.x0, (float)sRect.y0, (float)sRect.x1, (float)sRect.y1, sRect.slice);
+			blit(source, sRectF, dest, dRect, scaling && filter);
 		}
 
 		return true;
diff --git a/src/OpenGL/libGL/Image.cpp b/src/OpenGL/libGL/Image.cpp
index 8126de2..b86b689 100644
--- a/src/OpenGL/libGL/Image.cpp
+++ b/src/OpenGL/libGL/Image.cpp
@@ -33,20 +33,20 @@
 			return texture->getResource();
 		}
 
-		return 0;
+		return nullptr;
 	}
 
 	Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
-		: parentTexture(parentTexture), width(width), height(height), format(format), type(type)
+		: sw::Surface(getParentResource(parentTexture), width, height, 1, 0, 1, selectInternalFormat(format, type), true, true)
+		, parentTexture(parentTexture), width(width), height(height), format(format), type(type)
 		, internalFormat(selectInternalFormat(format, type)), multiSampleDepth(1)
-		, sw::Surface(getParentResource(parentTexture), width, height, 1, selectInternalFormat(format, type), true, true)
 	{
 		referenceCount = 1;
 	}
 
 	Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable, bool renderTarget)
-		: parentTexture(parentTexture), width(width), height(height), internalFormat(internalFormat), format(0 /*GL_NONE*/), type(0 /*GL_NONE*/), multiSampleDepth(multiSampleDepth)
-		, sw::Surface(getParentResource(parentTexture), width, height, multiSampleDepth, internalFormat, lockable, renderTarget)
+		: sw::Surface(getParentResource(parentTexture), width, height, 1, 0, multiSampleDepth, internalFormat, lockable, renderTarget)
+		, parentTexture(parentTexture), width(width), height(height), format(0 /*GL_NONE*/), type(0 /*GL_NONE*/), internalFormat(internalFormat), multiSampleDepth(multiSampleDepth)
 	{
 		referenceCount = 1;
 	}
@@ -141,7 +141,7 @@
 
 	void Image::unbind()
 	{
-		parentTexture = 0;
+		parentTexture = nullptr;
 
 		release();
 	}
@@ -152,10 +152,8 @@
 		{
 			return sw::FORMAT_NULL;
 		}
-		else
-		#if S3TC_SUPPORT
-		if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
-		   format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
+		else if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+		        format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
 		{
 			return sw::FORMAT_DXT1;
 		}
@@ -167,9 +165,7 @@
 		{
 			return sw::FORMAT_DXT5;
 		}
-		else
-		#endif
-		if(type == GL_FLOAT)
+		else if(type == GL_FLOAT)
 		{
 			return sw::FORMAT_A32B32G32R32F;
 		}
diff --git a/src/OpenGL/libGL/Program.cpp b/src/OpenGL/libGL/Program.cpp
index db3a860..1a55bce 100644
--- a/src/OpenGL/libGL/Program.cpp
+++ b/src/OpenGL/libGL/Program.cpp
@@ -73,7 +73,7 @@
 	{
 	}
 
-	Program::Program(ResourceManager *manager, GLuint handle) : resourceManager(manager), handle(handle), serial(issueSerial())
+	Program::Program(ResourceManager *manager, GLuint handle) : serial(issueSerial()), resourceManager(manager), handle(handle)
 	{
 		device = getDevice();
 
@@ -968,8 +968,8 @@
 
 					if(available)
 					{
-						varying->reg = r;
-						varying->col = 0;
+						varying->registerIndex = r;
+						varying->column = 0;
 
 						for(int y = 0; y < n; y++)
 						{
@@ -1002,8 +1002,8 @@
 
 						if(available)
 						{
-							varying->reg = r;
-							varying->col = 2;
+							varying->registerIndex = r;
+							varying->column = 2;
 
 							for(int y = 0; y < n; y++)
 							{
@@ -1046,7 +1046,7 @@
 					{
 						if(!packing[r][column])
 						{
-							varying->reg = r;
+							varying->registerIndex = r;
 
 							for(int y = r; y < r + n; y++)
 							{
@@ -1057,7 +1057,7 @@
 						}
 					}
 
-					varying->col = column;
+					varying->column = column;
 
 					success = true;
 				}
@@ -1125,8 +1125,8 @@
 			{
 				if(output->name == input->name)
 				{
-					int in = input->reg;
-					int out = output->reg;
+					int in = input->registerIndex;
+					int out = output->registerIndex;
 					int components = VariableColumnCount(output->type);
 					int registers = VariableRowCount(output->type) * output->size();
 
diff --git a/src/OpenGL/libGL/Surface.cpp b/src/OpenGL/libGL/Surface.cpp
index a6ec333..f5bfa0e 100644
--- a/src/OpenGL/libGL/Surface.cpp
+++ b/src/OpenGL/libGL/Surface.cpp
@@ -160,9 +160,7 @@
 {
 	if(backBuffer)
 	{
-		void *source = backBuffer->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
-		frameBuffer->flip(source, backBuffer->Surface::getInternalFormat(), backBuffer->getInternalPitchB());
-		backBuffer->unlockInternal();
+		frameBuffer->flip(backBuffer);
 
 		checkForResize();
 	}
diff --git a/src/OpenGL/libGL/Surface.h b/src/OpenGL/libGL/Surface.h
index 20ab599..70f910f 100644
--- a/src/OpenGL/libGL/Surface.h
+++ b/src/OpenGL/libGL/Surface.h
@@ -74,8 +74,8 @@
 
 	const NativeWindowType mWindow;   // Window that the surface is created for.
 	bool mWindowSubclassed;           // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking
-	GLint mHeight;                    // Height of surface
 	GLint mWidth;                     // Width of surface
+	GLint mHeight;                    // Height of surface
 	GLenum mTextureFormat;            // Format of texture: RGB, RGBA, or no texture
 	GLenum mTextureTarget;            // Type of texture: 2D or no texture
 	GLint mSwapInterval;
diff --git a/src/OpenGL/libGL/Texture.cpp b/src/OpenGL/libGL/Texture.cpp
index e0756d2..70ff9b2 100644
--- a/src/OpenGL/libGL/Texture.cpp
+++ b/src/OpenGL/libGL/Texture.cpp
@@ -181,7 +181,7 @@
 
 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
 {
-	if(pixels && image)
+	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), 1, imageSize, pixels);
 	}
@@ -232,7 +232,7 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(pixels)
+	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(xoffset, yoffset, 0, width, height, 1, imageSize, pixels);
 	}
@@ -353,7 +353,7 @@
 	return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
 }
 
-int Texture2D::getLevelCount() const
+int Texture2D::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
 	int levels = 0;
@@ -726,7 +726,7 @@
 	return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
 }
 
-int TextureCubeMap::getLevelCount() const
+int TextureCubeMap::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
 	int levels = 0;
diff --git a/src/OpenGL/libGL/Texture.h b/src/OpenGL/libGL/Texture.h
index ed124c8..483dc77 100644
--- a/src/OpenGL/libGL/Texture.h
+++ b/src/OpenGL/libGL/Texture.h
@@ -77,7 +77,7 @@
 	virtual GLenum getFormat(GLenum target, GLint level) const = 0;
 	virtual GLenum getType(GLenum target, GLint level) const = 0;
 	virtual sw::Format getInternalFormat(GLenum target, GLint level) const = 0;
-	virtual int getLevelCount() const = 0;
+	virtual int getTopLevel() const = 0;
 
 	virtual bool isSamplerComplete() const = 0;
 	virtual bool isCompressed(GLenum target, GLint level) const = 0;
@@ -126,7 +126,7 @@
 	virtual GLenum getFormat(GLenum target, GLint level) const;
 	virtual GLenum getType(GLenum target, GLint level) const;
 	virtual sw::Format getInternalFormat(GLenum target, GLint level) const;
-	virtual int getLevelCount() const;
+	virtual int getTopLevel() const;
 
 	void setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
 	void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
@@ -179,7 +179,7 @@
 	virtual GLenum getFormat(GLenum target, GLint level) const;
 	virtual GLenum getType(GLenum target, GLint level) const;
 	virtual sw::Format getInternalFormat(GLenum target, GLint level) const;
-	virtual int getLevelCount() const;
+	virtual int getTopLevel() const;
 
 	void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
 	void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
diff --git a/src/OpenGL/libGL/libGL.cpp b/src/OpenGL/libGL/libGL.cpp
index 171e520..87829be 100644
--- a/src/OpenGL/libGL/libGL.cpp
+++ b/src/OpenGL/libGL/libGL.cpp
@@ -802,10 +802,6 @@
 	case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
 	case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
 	case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-		if(!S3TC_SUPPORT)
-		{
-			return error(GL_INVALID_ENUM);
-		}
 		break;
 	case GL_DEPTH_COMPONENT:
 	case GL_DEPTH_COMPONENT16:
@@ -931,10 +927,6 @@
 	case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
 	case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
 	case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-		if(!S3TC_SUPPORT)
-		{
-			return error(GL_INVALID_ENUM);
-		}
 		break;
 	default:
 		return error(GL_INVALID_ENUM);
@@ -1101,14 +1093,7 @@
 		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
 		case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
 		case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-			if(S3TC_SUPPORT)
-			{
-				return error(GL_INVALID_OPERATION);
-			}
-			else
-			{
-				return error(GL_INVALID_ENUM);
-			}
+			return error(GL_INVALID_OPERATION);
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -3068,19 +3053,15 @@
 			"GL_EXT_texture_npot "
 			"GL_EXT_occlusion_query_boolean "
 			"GL_EXT_read_format_bgra "
-			#if (S3TC_SUPPORT)
 			"GL_EXT_texture_compression_dxt1 "
-			#endif
 			"GL_EXT_blend_func_separate "
 			"GL_EXT_secondary_color "
 			"GL_EXT_texture_filter_anisotropic "
 			"GL_EXT_texture_format_BGRA8888 "
 			"GL_EXT_framebuffer_blit "
 			"GL_EXT_framebuffer_multisample "
-			#if (S3TC_SUPPORT)
 			"GL_EXT_texture_compression_dxt3 "
 			"GL_EXT_texture_compression_dxt5 "
-			#endif
 			"GL_NV_fence";
 	default:
 		return error(GL_INVALID_ENUM, (GLubyte*)nullptr);
@@ -4384,14 +4365,7 @@
 	   format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
 	   format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
 	{
-		if(S3TC_SUPPORT)
-		{
-			return error(GL_INVALID_OPERATION);
-		}
-		else
-		{
-			return error(GL_INVALID_ENUM);
-		}
+		return error(GL_INVALID_OPERATION);
 	}
 
 	gl::Context *context = gl::getContext();
diff --git a/src/OpenGL/libGL/libGL.vcxproj b/src/OpenGL/libGL/libGL.vcxproj
index 415dcd8..ea8f5b5 100644
--- a/src/OpenGL/libGL/libGL.vcxproj
+++ b/src/OpenGL/libGL/libGL.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -30,41 +30,42 @@
     <ProjectGuid>{3EF851E7-4AAB-4C7C-9A79-3122CEA1EB67}</ProjectGuid>

     <RootNamespace>libGL</RootNamespace>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

@@ -153,6 +154,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

       <BrowseInformation>true</BrowseInformation>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -179,6 +181,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

       <BrowseInformation>true</BrowseInformation>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -212,6 +215,7 @@
       <WholeProgramOptimization>true</WholeProgramOptimization>

       <IntrinsicFunctions>false</IntrinsicFunctions>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -246,6 +250,7 @@
       <WholeProgramOptimization>true</WholeProgramOptimization>

       <IntrinsicFunctions>false</IntrinsicFunctions>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -280,6 +285,7 @@
       <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>

       <WholeProgramOptimization>true</WholeProgramOptimization>

       <IntrinsicFunctions>false</IntrinsicFunctions>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -312,6 +318,7 @@
       <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>

       <WholeProgramOptimization>true</WholeProgramOptimization>

       <IntrinsicFunctions>false</IntrinsicFunctions>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

diff --git a/src/OpenGL/libGL/main.cpp b/src/OpenGL/libGL/main.cpp
index 6a6e3da..5533321 100644
--- a/src/OpenGL/libGL/main.cpp
+++ b/src/OpenGL/libGL/main.cpp
@@ -36,12 +36,10 @@
 {
 	TRACE("()");
 
-	gl::Current *current = new gl::Current;
+	gl::Current *current = (gl::Current*)sw::Thread::allocateLocalStorage(currentTLS, sizeof(gl::Current));
 
 	if(current)
 	{
-		sw::Thread::setLocalStorage(currentTLS, current);
-
 		current->context = nullptr;
 		current->display = nullptr;
 		current->drawSurface = nullptr;
@@ -55,8 +53,7 @@
 
 	wglMakeCurrent(NULL, NULL);
 
-	delete (gl::Current*)sw::Thread::getLocalStorage(currentTLS);
-	sw::Thread::setLocalStorage(currentTLS, nullptr);
+	sw::Thread::freeLocalStorage(currentTLS);
 }
 
 CONSTRUCTOR static bool glAttachProcess()
diff --git a/src/OpenGL/libGLES_CM/Android.mk b/src/OpenGL/libGLES_CM/Android.mk
index 7fa9070..9e68a53 100644
--- a/src/OpenGL/libGLES_CM/Android.mk
+++ b/src/OpenGL/libGLES_CM/Android.mk
@@ -86,8 +86,8 @@
 endif
 
 COMMON_LDFLAGS := \
+	-Wl,--version-script=$(LOCAL_PATH)/libGLES_CM.lds \
 	-Wl,--gc-sections \
-	-Wl,--version-script=$(LOCAL_PATH)/exports.map \
 	-Wl,--hash-style=sysv
 
 include $(CLEAR_VARS)
@@ -95,14 +95,10 @@
 ifdef TARGET_2ND_ARCH
 ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
 LOCAL_MULTILIB := first
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
-else
-LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib/egl
-LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64/egl
 endif
-else
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
 endif
+LOCAL_MODULE_RELATIVE_PATH := egl
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_TAGS := optional
 LOCAL_CLANG := true
 LOCAL_SRC_FILES += $(COMMON_SRC_FILES)
@@ -119,14 +115,10 @@
 ifdef TARGET_2ND_ARCH
 ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
 LOCAL_MULTILIB := first
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
-else
-LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib/egl
-LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64/egl
 endif
-else
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
 endif
+LOCAL_MODULE_RELATIVE_PATH := egl
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_TAGS := optional
 LOCAL_CLANG := true
 LOCAL_SRC_FILES += $(COMMON_SRC_FILES)
diff --git a/src/OpenGL/libGLES_CM/Context.cpp b/src/OpenGL/libGLES_CM/Context.cpp
index b6f76c8..31351b3 100644
--- a/src/OpenGL/libGLES_CM/Context.cpp
+++ b/src/OpenGL/libGLES_CM/Context.cpp
@@ -149,9 +149,14 @@
 	mTextureExternalZero = new TextureExternal(0);
 
 	mState.activeSampler = 0;
+
+	for(int type = 0; type < TEXTURE_TYPE_COUNT; type++)
+	{
+		bindTexture((TextureType)type, 0);
+	}
+
 	bindArrayBuffer(0);
 	bindElementArrayBuffer(0);
-	bindTexture2D(0);
 	bindFramebuffer(0);
 	bindRenderbuffer(0);
 
@@ -1012,18 +1017,11 @@
 	mState.elementArrayBuffer = getBuffer(buffer);
 }
 
-void Context::bindTexture2D(GLuint texture)
+void Context::bindTexture(TextureType type, GLuint texture)
 {
-	mResourceManager->checkTextureAllocation(texture, TEXTURE_2D);
+	mResourceManager->checkTextureAllocation(texture, type);
 
-	mState.samplerTexture[TEXTURE_2D][mState.activeSampler] = getTexture(texture);
-}
-
-void Context::bindTextureExternal(GLuint texture)
-{
-	mResourceManager->checkTextureAllocation(texture, TEXTURE_EXTERNAL);
-
-	mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler] = getTexture(texture);
+	mState.samplerTexture[type][mState.activeSampler] = getTexture(texture);
 }
 
 void Context::bindFramebuffer(GLuint framebuffer)
@@ -1368,7 +1366,6 @@
 		}
 		break;
 	case GL_TEXTURE_BINDING_2D:                  *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].name();                   break;
-	case GL_TEXTURE_BINDING_CUBE_MAP_OES:        *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].name();                 break;
 	case GL_TEXTURE_BINDING_EXTERNAL_OES:        *params = mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler].name();             break;
 	case GL_MAX_LIGHTS:                          *params = MAX_LIGHTS;                                                                       break;
 	case GL_MAX_MODELVIEW_STACK_DEPTH:           *params = MAX_MODELVIEW_STACK_DEPTH;                                                        break;
@@ -2358,7 +2355,7 @@
 
 	if(baseTexture)
 	{
-		int levelCount = baseTexture->getLevelCount();
+		int topLevel = baseTexture->getTopLevel();
 
 		if(baseTexture->getTarget() == GL_TEXTURE_2D || baseTexture->getTarget() == GL_TEXTURE_EXTERNAL_OES)
 		{
@@ -2372,9 +2369,9 @@
 				{
 					surfaceLevel = 0;
 				}
-				else if(surfaceLevel >= levelCount)
+				else if(surfaceLevel > topLevel)
 				{
-					surfaceLevel = levelCount - 1;
+					surfaceLevel = topLevel;
 				}
 
 				egl::Image *surface = texture->getImage(surfaceLevel);
@@ -2413,7 +2410,7 @@
 		}
 	}
 
-	GLsizei outputPitch = egl::ComputePitch(width, format, type, mState.packAlignment);
+	GLsizei outputPitch = gl::ComputePitch(width, format, type, mState.packAlignment);
 
 	// Sized query sanity check
 	if(bufSize)
@@ -2435,7 +2432,7 @@
 	sw::Rect rect = {x, y, x + width, y + height};
 	rect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
 
-	unsigned char *source = (unsigned char*)renderTarget->lock(rect.x0, rect.y0, sw::LOCK_READONLY);
+	unsigned char *source = (unsigned char*)renderTarget->lock(rect.x0, rect.y0, 0, sw::LOCK_READONLY);
 	unsigned char *dest = (unsigned char*)pixels;
 	int inputPitch = (int)renderTarget->getPitch();
 
@@ -2444,12 +2441,12 @@
 		unsigned short *dest16 = (unsigned short*)dest;
 		unsigned int *dest32 = (unsigned int*)dest;
 
-		if(renderTarget->getInternalFormat() == sw::FORMAT_A8B8G8R8 &&
+		if(renderTarget->getExternalFormat() == sw::FORMAT_A8B8G8R8 &&
 		   format == GL_RGBA && type == GL_UNSIGNED_BYTE)
 		{
 			memcpy(dest, source, (rect.x1 - rect.x0) * 4);
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_A8R8G8B8 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_A8R8G8B8 &&
 				format == GL_RGBA && type == GL_UNSIGNED_BYTE)
 		{
 			for(int i = 0; i < rect.x1 - rect.x0; i++)
@@ -2459,7 +2456,7 @@
 				dest32[i] = (argb & 0xFF00FF00) | ((argb & 0x000000FF) << 16) | ((argb & 0x00FF0000) >> 16);
 			}
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_X8R8G8B8 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_X8R8G8B8 &&
 				format == GL_RGBA && type == GL_UNSIGNED_BYTE)
 		{
 			for(int i = 0; i < rect.x1 - rect.x0; i++)
@@ -2469,7 +2466,7 @@
 				dest32[i] = (xrgb & 0xFF00FF00) | ((xrgb & 0x000000FF) << 16) | ((xrgb & 0x00FF0000) >> 16) | 0xFF000000;
 			}
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_X8R8G8B8 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_X8R8G8B8 &&
 				format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE)
 		{
 			for(int i = 0; i < rect.x1 - rect.x0; i++)
@@ -2479,17 +2476,17 @@
 				dest32[i] = xrgb | 0xFF000000;
 			}
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_A8R8G8B8 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_A8R8G8B8 &&
 				format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE)
 		{
 			memcpy(dest, source, (rect.x1 - rect.x0) * 4);
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_A1R5G5B5 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_A1R5G5B5 &&
 				format == GL_BGRA_EXT && type == GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)
 		{
 			memcpy(dest, source, (rect.x1 - rect.x0) * 2);
 		}
-		else if(renderTarget->getInternalFormat() == sw::FORMAT_R5G6B5 &&
+		else if(renderTarget->getExternalFormat() == sw::FORMAT_R5G6B5 &&
 				format == 0x80E0 && type == GL_UNSIGNED_SHORT_5_6_5)   // GL_BGR_EXT
 		{
 			memcpy(dest, source, (rect.x1 - rect.x0) * 2);
@@ -2503,7 +2500,7 @@
 				float b;
 				float a;
 
-				switch(renderTarget->getInternalFormat())
+				switch(renderTarget->getExternalFormat())
 				{
 				case sw::FORMAT_R5G6B5:
 					{
@@ -2577,7 +2574,7 @@
 					break;
 				default:
 					UNIMPLEMENTED();   // FIXME
-					UNREACHABLE(renderTarget->getInternalFormat());
+					UNREACHABLE(renderTarget->getExternalFormat());
 				}
 
 				switch(format)
@@ -2852,7 +2849,8 @@
 
 void Context::blit(sw::Surface *source, const sw::SliceRect &sRect, sw::Surface *dest, const sw::SliceRect &dRect)
 {
-	device->blit(source, sRect, dest, dRect, false);
+	sw::SliceRectF sRectF((float)sRect.x0, (float)sRect.y0, (float)sRect.x1, (float)sRect.y1, sRect.slice);
+	device->blit(source, sRectF, dest, dRect, false);
 }
 
 void Context::finish()
@@ -3146,7 +3144,7 @@
 			return EGL_BAD_PARAMETER;
 		}
 
-		if(textureLevel == 0 && !(texture->isSamplerComplete() && texture->getLevelCount() == 1))
+		if(textureLevel == 0 && !(texture->isSamplerComplete() && texture->getTopLevel() == 0))
 		{
 			return EGL_BAD_PARAMETER;
 		}
diff --git a/src/OpenGL/libGLES_CM/Context.h b/src/OpenGL/libGLES_CM/Context.h
index ece2860..7bf7791 100644
--- a/src/OpenGL/libGLES_CM/Context.h
+++ b/src/OpenGL/libGLES_CM/Context.h
@@ -79,10 +79,8 @@
 const GLenum compressedTextureFormats[] =
 {
 	GL_ETC1_RGB8_OES,
-#if (S3TC_SUPPORT)
 	GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
 	GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
-#endif
 };
 
 const GLint NUM_COMPRESSED_TEXTURE_FORMATS = sizeof(compressedTextureFormats) / sizeof(compressedTextureFormats[0]);
@@ -456,7 +454,7 @@
 
 	void bindArrayBuffer(GLuint buffer);
 	void bindElementArrayBuffer(GLuint buffer);
-	void bindTexture2D(GLuint texture);
+	void bindTexture(TextureType type, GLuint texture);
 	void bindTextureExternal(GLuint texture);
 	void bindFramebuffer(GLuint framebuffer);
 	void bindRenderbuffer(GLuint renderbuffer);
diff --git a/src/OpenGL/libGLES_CM/Device.cpp b/src/OpenGL/libGLES_CM/Device.cpp
index 26f53bc..d1c3a04 100644
--- a/src/OpenGL/libGLES_CM/Device.cpp
+++ b/src/OpenGL/libGLES_CM/Device.cpp
@@ -217,69 +217,6 @@
 		stencilBuffer->clearStencil(stencil, mask, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
 	}
 
-	egl::Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
-	{
-		if(height > OUTLINE_RESOLUTION)
-		{
-			ERR("Invalid parameters: %dx%d", width, height);
-			return nullptr;
-		}
-
-		bool lockable = true;
-
-		switch(format)
-		{
-	//	case FORMAT_D15S1:
-		case FORMAT_D24S8:
-		case FORMAT_D24X8:
-	//	case FORMAT_D24X4S4:
-		case FORMAT_D24FS8:
-		case FORMAT_D32:
-		case FORMAT_D16:
-			lockable = false;
-			break;
-	//	case FORMAT_S8_LOCKABLE:
-	//	case FORMAT_D16_LOCKABLE:
-		case FORMAT_D32F_LOCKABLE:
-	//	case FORMAT_D32_LOCKABLE:
-		case FORMAT_DF24S8:
-		case FORMAT_DF16S8:
-			lockable = true;
-			break;
-		default:
-			UNREACHABLE(format);
-		}
-
-		egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
-
-		if(!surface)
-		{
-			ERR("Out of memory");
-			return nullptr;
-		}
-
-		return surface;
-	}
-
-	egl::Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
-	{
-		if(height > OUTLINE_RESOLUTION)
-		{
-			ERR("Invalid parameters: %dx%d", width, height);
-			return nullptr;
-		}
-
-		egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
-
-		if(!surface)
-		{
-			ERR("Out of memory");
-			return nullptr;
-		}
-
-		return surface;
-	}
-
 	void Device::drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount)
 	{
 		if(!bindResources() || !primitiveCount)
@@ -506,7 +443,8 @@
 		}
 		else
 		{
-			blit(source, sRect, dest, dRect, scaling && filter);
+			sw::SliceRectF sRectF((float)sRect.x0, (float)sRect.y0, (float)sRect.x1, (float)sRect.y1, sRect.slice);
+			blit(source, sRectF, dest, dRect, scaling && filter);
 		}
 
 		return true;
diff --git a/src/OpenGL/libGLES_CM/Device.hpp b/src/OpenGL/libGLES_CM/Device.hpp
index c40e30d..ffabc45 100644
--- a/src/OpenGL/libGLES_CM/Device.hpp
+++ b/src/OpenGL/libGLES_CM/Device.hpp
@@ -49,8 +49,6 @@
 		void clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask);
 		void clearDepth(float z);
 		void clearStencil(unsigned int stencil, unsigned int mask);
-		egl::Image *createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard);
-		egl::Image *createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable);
 		void drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount);
 		void drawPrimitive(sw::DrawType type, unsigned int primiveCount);
 		void setScissorEnable(bool enable);
diff --git a/src/OpenGL/libGLES_CM/Framebuffer.cpp b/src/OpenGL/libGLES_CM/Framebuffer.cpp
index 933aa2a..097c6a2 100644
--- a/src/OpenGL/libGLES_CM/Framebuffer.cpp
+++ b/src/OpenGL/libGLES_CM/Framebuffer.cpp
@@ -405,16 +405,16 @@
 
 	if(colorbuffer)
 	{
-		switch(colorbuffer->getInternalFormat())
+		switch(colorbuffer->getFormat())
 		{
-		case sw::FORMAT_A8R8G8B8: return GL_BGRA_EXT;
-		case sw::FORMAT_A8B8G8R8: return GL_RGBA;
-		case sw::FORMAT_X8R8G8B8: return GL_BGRA_EXT;
-		case sw::FORMAT_X8B8G8R8: return GL_RGBA;
-		case sw::FORMAT_A1R5G5B5: return GL_BGRA_EXT;
-		case sw::FORMAT_R5G6B5:   return GL_RGB;
+		case GL_BGRA8_EXT:   return GL_BGRA_EXT;
+		case GL_RGBA4_OES:   return GL_RGBA;
+		case GL_RGB5_A1_OES: return GL_RGBA;
+		case GL_RGBA8_OES:   return GL_RGBA;
+		case GL_RGB565_OES:  return GL_RGBA;
+		case GL_RGB8_OES:    return GL_RGB;
 		default:
-			UNREACHABLE(colorbuffer->getInternalFormat());
+			UNREACHABLE(colorbuffer->getFormat());
 		}
 	}
 
@@ -427,16 +427,16 @@
 
 	if(colorbuffer)
 	{
-		switch(colorbuffer->getInternalFormat())
+		switch(colorbuffer->getFormat())
 		{
-		case sw::FORMAT_A8R8G8B8: return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_A8B8G8R8: return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_X8R8G8B8: return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_X8B8G8R8: return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_A1R5G5B5: return GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT;
-		case sw::FORMAT_R5G6B5:   return GL_UNSIGNED_SHORT_5_6_5;
+		case GL_BGRA8_EXT:   return GL_UNSIGNED_BYTE;
+		case GL_RGBA4_OES:   return GL_UNSIGNED_SHORT_4_4_4_4;
+		case GL_RGB5_A1_OES: return GL_UNSIGNED_SHORT_5_5_5_1;
+		case GL_RGBA8_OES:   return GL_UNSIGNED_BYTE;
+		case GL_RGB565_OES:  return GL_UNSIGNED_SHORT_5_6_5;
+		case GL_RGB8_OES:    return GL_UNSIGNED_BYTE;
 		default:
-			UNREACHABLE(colorbuffer->getInternalFormat());
+			UNREACHABLE(colorbuffer->getFormat());
 		}
 	}
 
diff --git a/src/OpenGL/libGLES_CM/Renderbuffer.cpp b/src/OpenGL/libGLES_CM/Renderbuffer.cpp
index 96bf733..c832443 100644
--- a/src/OpenGL/libGLES_CM/Renderbuffer.cpp
+++ b/src/OpenGL/libGLES_CM/Renderbuffer.cpp
@@ -41,32 +41,32 @@
 
 GLuint RenderbufferInterface::getRedSize() const
 {
-	return sw2es::GetRedSize(getInternalFormat());
+	return GetRedSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getGreenSize() const
 {
-	return sw2es::GetGreenSize(getInternalFormat());
+	return GetGreenSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getBlueSize() const
 {
-	return sw2es::GetBlueSize(getInternalFormat());
+	return GetBlueSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getAlphaSize() const
 {
-	return sw2es::GetAlphaSize(getInternalFormat());
+	return GetAlphaSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getDepthSize() const
 {
-	return sw2es::GetDepthSize(getInternalFormat());
+	return GetDepthSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getStencilSize() const
 {
-	return sw2es::GetStencilSize(getInternalFormat());
+	return GetStencilSize(getFormat());
 }
 
 ///// RenderbufferTexture2D Implementation ////////
@@ -122,16 +122,11 @@
 	return mTexture2D->getHeight(GL_TEXTURE_2D, 0);
 }
 
-GLenum RenderbufferTexture2D::getFormat() const
+GLint RenderbufferTexture2D::getFormat() const
 {
 	return mTexture2D->getFormat(GL_TEXTURE_2D, 0);
 }
 
-sw::Format RenderbufferTexture2D::getInternalFormat() const
-{
-	return mTexture2D->getInternalFormat(GL_TEXTURE_2D, 0);
-}
-
 GLsizei RenderbufferTexture2D::getSamples() const
 {
 	return 0;
@@ -200,11 +195,6 @@
 	return mInstance->getFormat();
 }
 
-sw::Format Renderbuffer::getInternalFormat() const
-{
-	return mInstance->getInternalFormat();
-}
-
 GLuint Renderbuffer::getRedSize() const
 {
 	return mInstance->getRedSize();
@@ -252,8 +242,7 @@
 {
 	mWidth = 0;
 	mHeight = 0;
-	format = GL_RGBA4_OES;
-	internalFormat = sw::FORMAT_A8B8G8R8;
+	format = GL_NONE_OES;
 	mSamples = 0;
 }
 
@@ -271,16 +260,11 @@
 	return mHeight;
 }
 
-GLenum RenderbufferStorage::getFormat() const
+GLint RenderbufferStorage::getFormat() const
 {
 	return format;
 }
 
-sw::Format RenderbufferStorage::getInternalFormat() const
-{
-	return internalFormat;
-}
-
 GLsizei RenderbufferStorage::getSamples() const
 {
 	return mSamples;
@@ -294,22 +278,24 @@
 
 		mWidth = renderTarget->getWidth();
 		mHeight = renderTarget->getHeight();
-		internalFormat = renderTarget->getInternalFormat();
-		format = sw2es::ConvertBackBufferFormat(internalFormat);
+		format = renderTarget->getFormat();
 		mSamples = renderTarget->getDepth() & ~1;
 	}
 }
 
-Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(nullptr)
+Colorbuffer::Colorbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mRenderTarget(nullptr)
 {
-	Device *device = getDevice();
-
-	sw::Format requestedFormat = es2sw::ConvertRenderbufferFormat(format);
 	int supportedSamples = Context::getSupportedMultisampleCount(samples);
 
 	if(width > 0 && height > 0)
 	{
-		mRenderTarget = device->createRenderTarget(width, height, requestedFormat, supportedSamples, false);
+		if(height > sw::OUTLINE_RESOLUTION)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+
+		mRenderTarget = egl::Image::create(width, height, internalformat, supportedSamples, false);
 
 		if(!mRenderTarget)
 		{
@@ -320,8 +306,7 @@
 
 	mWidth = width;
 	mHeight = height;
-	this->format = format;
-	internalFormat = requestedFormat;
+	format = internalformat;
 	mSamples = supportedSamples;
 }
 
@@ -371,21 +356,24 @@
 
 		mWidth = depthStencil->getWidth();
 		mHeight = depthStencil->getHeight();
-		internalFormat = depthStencil->getInternalFormat();
-		format = sw2es::ConvertDepthStencilFormat(internalFormat);
+		format = depthStencil->getFormat();
 		mSamples = depthStencil->getDepth() & ~1;
 	}
 }
 
-DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLsizei samples) : mDepthStencil(nullptr)
+DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mDepthStencil(nullptr)
 {
-	Device *device = getDevice();
-
 	int supportedSamples = Context::getSupportedMultisampleCount(samples);
 
 	if(width > 0 && height > 0)
 	{
-		mDepthStencil = device->createDepthStencilSurface(width, height, sw::FORMAT_D24S8, supportedSamples, false);
+		if(height > sw::OUTLINE_RESOLUTION)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+
+		mDepthStencil = egl::Image::create(width, height, internalformat, supportedSamples, false);
 
 		if(!mDepthStencil)
 		{
@@ -396,8 +384,7 @@
 
 	mWidth = width;
 	mHeight = height;
-	format = GL_DEPTH24_STENCIL8_OES;
-	internalFormat = sw::FORMAT_D24S8;
+	format = internalformat;
 	mSamples = supportedSamples;
 }
 
@@ -441,22 +428,10 @@
 
 Depthbuffer::Depthbuffer(egl::Image *depthStencil) : DepthStencilbuffer(depthStencil)
 {
-	if(depthStencil)
-	{
-		format = GL_DEPTH_COMPONENT16_OES;   // If the renderbuffer parameters are queried, the calling function
-		                                     // will expect one of the valid renderbuffer formats for use in
-		                                     // glRenderbufferStorage
-	}
 }
 
-Depthbuffer::Depthbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples)
+Depthbuffer::Depthbuffer(int width, int height, GLenum internalformat, GLsizei samples) : DepthStencilbuffer(width, height, internalformat, samples)
 {
-	if(mDepthStencil)
-	{
-		format = GL_DEPTH_COMPONENT16_OES;   // If the renderbuffer parameters are queried, the calling function
-		                                     // will expect one of the valid renderbuffer formats for use in
-		                                     // glRenderbufferStorage
-	}
 }
 
 Depthbuffer::~Depthbuffer()
@@ -465,22 +440,10 @@
 
 Stencilbuffer::Stencilbuffer(egl::Image *depthStencil) : DepthStencilbuffer(depthStencil)
 {
-	if(depthStencil)
-	{
-		format = GL_STENCIL_INDEX8_OES;   // If the renderbuffer parameters are queried, the calling function
-		                                  // will expect one of the valid renderbuffer formats for use in
-		                                  // glRenderbufferStorage
-	}
 }
 
-Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples)
+Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, GL_STENCIL_INDEX8_OES, samples)
 {
-	if(mDepthStencil)
-	{
-		format = GL_STENCIL_INDEX8_OES;   // If the renderbuffer parameters are queried, the calling function
-		                                  // will expect one of the valid renderbuffer formats for use in
-		                                  // glRenderbufferStorage
-	}
 }
 
 Stencilbuffer::~Stencilbuffer()
diff --git a/src/OpenGL/libGLES_CM/Renderbuffer.h b/src/OpenGL/libGLES_CM/Renderbuffer.h
index 6bb462f..4405b93 100644
--- a/src/OpenGL/libGLES_CM/Renderbuffer.h
+++ b/src/OpenGL/libGLES_CM/Renderbuffer.h
@@ -48,8 +48,7 @@
 
 	virtual GLsizei getWidth() const = 0;
 	virtual GLsizei getHeight() const = 0;
-	virtual GLenum getFormat() const = 0;
-	virtual sw::Format getInternalFormat() const = 0;
+	virtual GLint getFormat() const = 0;
 	virtual GLsizei getSamples() const = 0;
 
 	GLuint getRedSize() const;
@@ -76,8 +75,7 @@
 
 	virtual GLsizei getWidth() const;
 	virtual GLsizei getHeight() const;
-	virtual GLenum getFormat() const;
-	virtual sw::Format getInternalFormat() const;
+	virtual GLint getFormat() const;
 	virtual GLsizei getSamples() const;
 
 private:
@@ -100,15 +98,13 @@
 
 	virtual GLsizei getWidth() const;
 	virtual GLsizei getHeight() const;
-	virtual GLenum getFormat() const;
-	virtual sw::Format getInternalFormat() const;
+	virtual GLint getFormat() const;
 	virtual GLsizei getSamples() const;
 
 protected:
 	GLsizei mWidth;
 	GLsizei mHeight;
 	GLenum format;
-	sw::Format internalFormat;
 	GLsizei mSamples;
 };
 
@@ -136,7 +132,6 @@
 	GLsizei getWidth() const;
 	GLsizei getHeight() const;
 	GLenum getFormat() const;
-	sw::Format getInternalFormat() const;
 	GLuint getRedSize() const;
 	GLuint getGreenSize() const;
 	GLuint getBlueSize() const;
@@ -155,7 +150,7 @@
 {
 public:
 	explicit Colorbuffer(egl::Image *renderTarget);
-	Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples);
+	Colorbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
 
 	virtual ~Colorbuffer();
 
@@ -171,7 +166,7 @@
 {
 public:
 	explicit DepthStencilbuffer(egl::Image *depthStencil);
-	DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
+	DepthStencilbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
 
 	~DepthStencilbuffer();
 
@@ -187,7 +182,7 @@
 {
 public:
 	explicit Depthbuffer(egl::Image *depthStencil);
-	Depthbuffer(GLsizei width, GLsizei height, GLsizei samples);
+	Depthbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
 
 	virtual ~Depthbuffer();
 };
diff --git a/src/OpenGL/libGLES_CM/ResourceManager.h b/src/OpenGL/libGLES_CM/ResourceManager.h
index 7520580..24953e8 100644
--- a/src/OpenGL/libGLES_CM/ResourceManager.h
+++ b/src/OpenGL/libGLES_CM/ResourceManager.h
@@ -33,7 +33,6 @@
 enum TextureType
 {
 	TEXTURE_2D,
-	TEXTURE_CUBE,
 	TEXTURE_EXTERNAL,
 
 	TEXTURE_TYPE_COUNT,
diff --git a/src/OpenGL/libGLES_CM/Texture.cpp b/src/OpenGL/libGLES_CM/Texture.cpp
index 80a3886..05f1ebd 100644
--- a/src/OpenGL/libGLES_CM/Texture.cpp
+++ b/src/OpenGL/libGLES_CM/Texture.cpp
@@ -227,51 +227,36 @@
 	return image;
 }
 
-void Texture::setImage(egl::Context *context, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
+void Texture::setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
 {
 	if(pixels && image)
 	{
-		egl::Image::UnpackInfo unpackInfo;
-		unpackInfo.alignment = unpackAlignment;
-		image->loadImageData(context, 0, 0, 0, image->getWidth(), image->getHeight(), 1, format, type, unpackInfo, pixels);
+		gl::PixelStorageModes unpackParameters;
+		unpackParameters.alignment = unpackAlignment;
+		image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), 1, format, type, unpackParameters, pixels);
 	}
 }
 
 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
 {
-	if(pixels && image)
+	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), 1, imageSize, pixels);
 	}
 }
 
-void Texture::subImage(egl::Context *context, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
+void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
 {
 	if(!image)
 	{
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
-	{
-		return error(GL_INVALID_VALUE);
-	}
-
-	if(IsCompressed(image->getFormat()))
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
-	if(format != image->getFormat())
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
 	if(pixels)
 	{
-		egl::Image::UnpackInfo unpackInfo;
-		unpackInfo.alignment = unpackAlignment;
-		image->loadImageData(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels);
+		gl::PixelStorageModes unpackParameters;
+		unpackParameters.alignment = unpackAlignment;
+		image->loadImageData(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels);
 	}
 }
 
@@ -282,17 +267,7 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
-	{
-		return error(GL_INVALID_VALUE);
-	}
-
-	if(format != image->getFormat())
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
-	if(pixels)
+	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(xoffset, yoffset, 0, width, height, 1, imageSize, pixels);
 	}
@@ -426,68 +401,44 @@
 	return image[level] ? image[level]->getHeight() : 0;
 }
 
-GLenum Texture2D::getFormat(GLenum target, GLint level) const
+GLint Texture2D::getFormat(GLenum target, GLint level) const
 {
 	ASSERT(target == GL_TEXTURE_2D);
 	return image[level] ? image[level]->getFormat() : GL_NONE;
 }
 
-GLenum Texture2D::getType(GLenum target, GLint level) const
-{
-	ASSERT(target == GL_TEXTURE_2D);
-	return image[level] ? image[level]->getType() : GL_NONE;
-}
-
-sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
-{
-	ASSERT(target == GL_TEXTURE_2D);
-	return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
-}
-
-int Texture2D::getLevelCount() const
+int Texture2D::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
-	int levels = 0;
+	int level = 0;
 
-	while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
+	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[level])
 	{
-		levels++;
+		level++;
 	}
 
-	return levels;
+	return level - 1;
 }
 
-void Texture2D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
 	if(image[level])
 	{
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, format, type);
+	image[level] = egl::Image::create(this, width, height, internalformat);
 
 	if(!image[level])
 	{
 		return error(GL_OUT_OF_MEMORY);
 	}
 
-	Texture::setImage(context, format, type, unpackAlignment, pixels, image[level]);
+	Texture::setImage(format, type, unpackAlignment, pixels, image[level]);
 }
 
 void Texture2D::bindTexImage(gl::Surface *surface)
 {
-	switch(surface->getInternalFormat())
-	{
-	case sw::FORMAT_A8R8G8B8:
-	case sw::FORMAT_A8B8G8R8:
-	case sw::FORMAT_X8B8G8R8:
-	case sw::FORMAT_X8R8G8B8:
-		break;
-	default:
-		UNIMPLEMENTED();
-		return;
-	}
-
 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
 	{
 		if(image[level])
@@ -522,7 +473,7 @@
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, format, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, format);
 
 	if(!image[level])
 	{
@@ -532,9 +483,9 @@
 	Texture::setCompressedImage(imageSize, pixels, image[level]);
 }
 
-void Texture2D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-	Texture::subImage(context, xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
+	Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
 }
 
 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
@@ -557,7 +508,7 @@
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, format, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, format);
 
 	if(!image[level])
 	{
@@ -662,11 +613,6 @@
 			return false;
 		}
 
-		if(image[level]->getType() != image[0]->getType())
-		{
-			return false;
-		}
-
 		if(image[level]->getWidth() != std::max(1, width >> level))
 		{
 			return false;
@@ -707,7 +653,7 @@
 			image[i]->release();
 		}
 
-		image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
+		image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat());
 
 		if(!image[i])
 		{
@@ -720,10 +666,10 @@
 
 void Texture2D::autoGenerateMipmaps()
 {
-	if(generateMipmap && image[0]->hasDirtyMipmaps())
+	if(generateMipmap && image[0]->hasDirtyContents())
 	{
 		generateMipmaps();
-		image[0]->cleanMipmaps();
+		image[0]->markContentsClean();
 	}
 }
 
@@ -805,7 +751,9 @@
 		return nullptr;
 	}
 
-	return egl::Image::create(width, height, format, multiSampleDepth, false);
+	GLenum internalformat = sw2es::ConvertBackBufferFormat(format);
+
+	return egl::Image::create(width, height, internalformat, multiSampleDepth, false);
 }
 
 egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth)
@@ -841,7 +789,9 @@
 		UNREACHABLE(format);
 	}
 
-	egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
+	GLenum internalformat = sw2es::ConvertDepthStencilFormat(format);
+
+	egl::Image *surface = egl::Image::create(width, height, internalformat, multiSampleDepth, lockable);
 
 	if(!surface)
 	{
diff --git a/src/OpenGL/libGLES_CM/Texture.h b/src/OpenGL/libGLES_CM/Texture.h
index c99c1dc..0439039 100644
--- a/src/OpenGL/libGLES_CM/Texture.h
+++ b/src/OpenGL/libGLES_CM/Texture.h
@@ -76,10 +76,8 @@
 
 	virtual GLsizei getWidth(GLenum target, GLint level) const = 0;
 	virtual GLsizei getHeight(GLenum target, GLint level) const = 0;
-	virtual GLenum getFormat(GLenum target, GLint level) const = 0;
-	virtual GLenum getType(GLenum target, GLint level) const = 0;
-	virtual sw::Format getInternalFormat(GLenum target, GLint level) const = 0;
-	virtual int getLevelCount() const = 0;
+	virtual GLint getFormat(GLenum target, GLint level) const = 0;
+	virtual int getTopLevel() const = 0;
 
 	virtual bool isSamplerComplete() const = 0;
 	virtual bool isCompressed(GLenum target, GLint level) const = 0;
@@ -98,8 +96,8 @@
 protected:
 	~Texture() override;
 
-	void setImage(egl::Context *context, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
-	void subImage(egl::Context *context, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
+	void setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
+	void subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
 	void setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image);
 	void subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image);
 
@@ -134,14 +132,12 @@
 
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
-	GLenum getFormat(GLenum target, GLint level) const override;
-	GLenum getType(GLenum target, GLint level) const override;
-	sw::Format getInternalFormat(GLenum target, GLint level) const override;
-	int getLevelCount() const override;
+	GLint getFormat(GLenum target, GLint level) const override;
+	int getTopLevel() const override;
 
-	void setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+	void setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
 	void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
-	void subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+	void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
 	void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
 	void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
 	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
diff --git a/src/OpenGL/libGLES_CM/libGLES_CM.cpp b/src/OpenGL/libGLES_CM/libGLES_CM.cpp
index 62acae1..e717d60 100644
--- a/src/OpenGL/libGLES_CM/libGLES_CM.cpp
+++ b/src/OpenGL/libGLES_CM/libGLES_CM.cpp
@@ -32,6 +32,7 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+#include <algorithm>
 #include <limits>
 
 namespace es1
@@ -47,41 +48,6 @@
 	return true;
 }
 
-static bool validateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, es1::Texture *texture)
-{
-	if(!texture)
-	{
-		return error(GL_INVALID_OPERATION, false);
-	}
-
-	if(compressed != texture->isCompressed(target, level))
-	{
-		return error(GL_INVALID_OPERATION, false);
-	}
-
-	if(format != GL_NONE_OES && format != texture->getFormat(target, level))
-	{
-		return error(GL_INVALID_OPERATION, false);
-	}
-
-	if(compressed)
-	{
-		if((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
-		   (height % 4 != 0 && height != texture->getHeight(target, 0)))
-		{
-			return error(GL_INVALID_OPERATION, false);
-		}
-	}
-
-	if(xoffset + width > texture->getWidth(target, level) ||
-	   yoffset + height > texture->getHeight(target, level))
-	{
-		return error(GL_INVALID_VALUE, false);
-	}
-
-	return true;
-}
-
 void ActiveTexture(GLenum texture)
 {
 	TRACE("(GLenum texture = 0x%X)", texture);
@@ -200,15 +166,9 @@
 
 	if(context)
 	{
-		if(renderbuffer != 0 && !context->getRenderbuffer(renderbuffer))
-		{
-			// [OpenGL ES 2.0.25] Section 4.4.3 page 112
-			// [OpenGL ES 3.0.2] Section 4.4.2 page 201
-			// 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
-			// type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
-			return error(GL_INVALID_OPERATION);
-		}
-
+		// [GL_EXT_framebuffer_object]
+		// If <renderbuffer> is not zero, then the resulting renderbuffer object
+		// is a new state vector, initialized with a zero-sized memory buffer
 		context->bindRenderbuffer(renderbuffer);
 	}
 }
@@ -231,11 +191,11 @@
 		switch(target)
 		{
 		case GL_TEXTURE_2D:
-			context->bindTexture2D(texture);
-			return;
+			context->bindTexture(TEXTURE_2D, texture);
+			break;
 		case GL_TEXTURE_EXTERNAL_OES:
-			context->bindTextureExternal(texture);
-			return;
+			context->bindTexture(TEXTURE_EXTERNAL, texture);
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -720,16 +680,10 @@
 	switch(internalformat)
 	{
 	case GL_ETC1_RGB8_OES:
-		break;
 	case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
 	case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-		if(!S3TC_SUPPORT)
-		{
-			return error(GL_INVALID_ENUM);
-		}
 		break;
 	case GL_DEPTH_COMPONENT16_OES:
-	case GL_DEPTH_COMPONENT32_OES:
 	case GL_DEPTH_STENCIL_OES:
 	case GL_DEPTH24_STENCIL8_OES:
 		return error(GL_INVALID_OPERATION);
@@ -759,7 +713,7 @@
 			return error(GL_INVALID_ENUM);
 		}
 
-		if(imageSize != egl::ComputeCompressedSize(width, height, internalformat))
+		if(imageSize != gl::ComputeCompressedSize(width, height, internalformat))
 		{
 			return error(GL_INVALID_VALUE);
 		}
@@ -805,13 +759,8 @@
 	switch(format)
 	{
 	case GL_ETC1_RGB8_OES:
-		break;
 	case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
 	case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-		if(!S3TC_SUPPORT)
-		{
-			return error(GL_INVALID_ENUM);
-		}
 		break;
 	default:
 		return error(GL_INVALID_ENUM);
@@ -826,7 +775,7 @@
 
 	if(context)
 	{
-		if(imageSize != egl::ComputeCompressedSize(width, height, format))
+		if(imageSize != gl::ComputeCompressedSize(width, height, format))
 		{
 			return error(GL_INVALID_VALUE);
 		}
@@ -841,10 +790,13 @@
 		{
 			es1::Texture2D *texture = context->getTexture2D();
 
-			if(validateSubImageParams(true, width, height, xoffset, yoffset, target, level, format, texture))
+			GLenum validationError = ValidateSubImageParams(true, false, target, level, xoffset, yoffset, width, height, format, GL_NONE_OES, texture);
+			if(validationError != GL_NO_ERROR)
 			{
-				texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
+				return error(validationError);
 			}
+
+			texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
 		}
 		else UNREACHABLE(target);
 	}
@@ -898,7 +850,7 @@
 		es1::Renderbuffer *source = framebuffer->getColorbuffer();
 		GLenum colorbufferFormat = source->getFormat();
 
-		// [OpenGL ES 2.0.24] table 3.9
+		// [OpenGL ES 1.1.12] table 3.9
 		switch(internalformat)
 		{
 		case GL_ALPHA:
@@ -929,27 +881,38 @@
 			if(colorbufferFormat != GL_RGBA &&
 			   colorbufferFormat != GL_RGBA4_OES &&
 			   colorbufferFormat != GL_RGB5_A1_OES &&
-			   colorbufferFormat != GL_RGBA8_OES)
+			   colorbufferFormat != GL_RGBA8_OES &&
+			   colorbufferFormat != GL_BGRA_EXT &&  // GL_EXT_texture_format_BGRA8888
+			   colorbufferFormat != GL_BGRA8_EXT)   // GL_EXT_texture_format_BGRA8888
 			{
 				return error(GL_INVALID_OPERATION);
 			}
 			break;
 		case GL_ETC1_RGB8_OES:
-			return error(GL_INVALID_OPERATION);
 		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
 		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-			if(S3TC_SUPPORT)
-			{
-				return error(GL_INVALID_OPERATION);
-			}
-			else
-			{
-				return error(GL_INVALID_ENUM);
-			}
+			return error(GL_INVALID_OPERATION);
+		case GL_BGRA_EXT:   // GL_EXT_texture_format_BGRA8888 doesn't mention the format to be accepted by glCopyTexImage2D.
 		default:
 			return error(GL_INVALID_ENUM);
 		}
 
+		// Determine the sized internal format.
+		if(gl::GetBaseInternalFormat(colorbufferFormat) == internalformat)
+		{
+			internalformat = colorbufferFormat;
+		}
+		else if(GetRedSize(colorbufferFormat) == 8)
+		{
+			internalformat = gl::GetSizedInternalFormat(internalformat, GL_UNSIGNED_BYTE);
+		}
+		else
+		{
+			UNIMPLEMENTED();
+
+			return error(GL_INVALID_OPERATION);
+		}
+
 		if(target == GL_TEXTURE_2D)
 		{
 			es1::Texture2D *texture = context->getTexture2D();
@@ -1023,9 +986,10 @@
 		}
 		else UNREACHABLE(target);
 
-		if(!validateSubImageParams(false, width, height, xoffset, yoffset, target, level, GL_NONE_OES, texture))
+		GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, width, height, GL_NONE_OES, GL_NONE_OES, texture);
+		if(validationError != GL_NO_ERROR)
 		{
-			return;
+			return error(validationError);
 		}
 
 		texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer);
@@ -1877,7 +1841,12 @@
 		{
 		case GL_RENDERBUFFER_WIDTH_OES:           *params = renderbuffer->getWidth();       break;
 		case GL_RENDERBUFFER_HEIGHT_OES:          *params = renderbuffer->getHeight();      break;
-		case GL_RENDERBUFFER_INTERNAL_FORMAT_OES: *params = renderbuffer->getFormat();      break;
+		case GL_RENDERBUFFER_INTERNAL_FORMAT_OES:
+			{
+				GLint internalformat = renderbuffer->getFormat();
+				*params = (internalformat == GL_NONE_OES) ? GL_RGBA4_OES : internalformat;
+			}
+			break;
 		case GL_RENDERBUFFER_RED_SIZE_OES:        *params = renderbuffer->getRedSize();     break;
 		case GL_RENDERBUFFER_GREEN_SIZE_OES:      *params = renderbuffer->getGreenSize();   break;
 		case GL_RENDERBUFFER_BLUE_SIZE_OES:       *params = renderbuffer->getBlueSize();    break;
@@ -2285,7 +2254,6 @@
 			"GL_OES_blend_func_separate "
 			"GL_OES_blend_subtract "
 			"GL_OES_compressed_ETC1_RGB8_texture "
-			"GL_OES_depth_texture "
 			"GL_OES_EGL_image "
 			"GL_OES_EGL_image_external "
 			"GL_OES_EGL_sync "
@@ -2300,11 +2268,9 @@
 			"GL_OES_texture_npot "
 			"GL_EXT_blend_minmax "
 			"GL_EXT_read_format_bgra "
-			#if (S3TC_SUPPORT)
 			"GL_EXT_texture_compression_dxt1 "
 			"GL_ANGLE_texture_compression_dxt3 "
 			"GL_ANGLE_texture_compression_dxt5 "
-			#endif
 			"GL_EXT_texture_filter_anisotropic "
 			"GL_EXT_texture_format_BGRA8888";
 	default:
@@ -3444,9 +3410,6 @@
 
 		switch(internalformat)
 		{
-		case GL_DEPTH_COMPONENT16_OES:
-			context->setRenderbufferStorage(new es1::Depthbuffer(width, height, 0));
-			break;
 		case GL_RGBA4_OES:
 		case GL_RGB5_A1_OES:
 		case GL_RGB565_OES:
@@ -3454,11 +3417,14 @@
 		case GL_RGBA8_OES:
 			context->setRenderbufferStorage(new es1::Colorbuffer(width, height, internalformat, 0));
 			break;
+		case GL_DEPTH_COMPONENT16_OES:
+			context->setRenderbufferStorage(new es1::Depthbuffer(width, height, internalformat,  0));
+			break;
 		case GL_STENCIL_INDEX8_OES:
 			context->setRenderbufferStorage(new es1::Stencilbuffer(width, height, 0));
 			break;
 		case GL_DEPTH24_STENCIL8_OES:
-			context->setRenderbufferStorage(new es1::DepthStencilbuffer(width, height, 0));
+			context->setRenderbufferStorage(new es1::DepthStencilbuffer(width, height, internalformat, 0));
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -4226,7 +4192,6 @@
 		switch(type)
 		{
 		case GL_UNSIGNED_BYTE:
-		case GL_FLOAT:
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -4237,7 +4202,6 @@
 		{
 		case GL_UNSIGNED_BYTE:
 		case GL_UNSIGNED_SHORT_5_6_5:
-		case GL_FLOAT:
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -4249,7 +4213,6 @@
 		case GL_UNSIGNED_BYTE:
 		case GL_UNSIGNED_SHORT_4_4_4_4:
 		case GL_UNSIGNED_SHORT_5_5_5_1:
-		case GL_FLOAT:
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -4265,17 +4228,9 @@
 		}
 		break;
 	case GL_ETC1_RGB8_OES:
-		return error(GL_INVALID_OPERATION);
 	case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
 	case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-		if(S3TC_SUPPORT)
-		{
-			return error(GL_INVALID_OPERATION);
-		}
-		else
-		{
-			return error(GL_INVALID_ENUM);
-		}
+		return error(GL_INVALID_OPERATION);
 	case GL_DEPTH_STENCIL_OES:
 		switch(type)
 		{
@@ -4294,6 +4249,8 @@
 		return error(GL_INVALID_VALUE);
 	}
 
+	GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
+
 	es1::Context *context = es1::getContext();
 
 	if(context)
@@ -4320,7 +4277,7 @@
 				return error(GL_INVALID_OPERATION);
 			}
 
-			texture->setImage(context, level, width, height, format, type, context->getUnpackAlignment(), pixels);
+			texture->setImage(level, width, height, sizedInternalFormat, format, type, context->getUnpackAlignment(), pixels);
 		}
 		else UNREACHABLE(target);
 	}
@@ -4537,11 +4494,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(!es1::CheckTextureFormatType(format, type))
-	{
-		return error(GL_INVALID_ENUM);
-	}
-
 	if(width == 0 || height == 0 || !pixels)
 	{
 		return;
@@ -4555,10 +4507,13 @@
 		{
 			es1::Texture2D *texture = context->getTexture2D();
 
-			if(validateSubImageParams(false, width, height, xoffset, yoffset, target, level, format, texture))
+			GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, width, height, format, type, texture);
+			if(validationError != GL_NO_ERROR)
 			{
-				texture->subImage(context, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
+				return error(validationError);
 			}
+
+			texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
 		}
 		else UNREACHABLE(target);
 	}
@@ -4727,46 +4682,215 @@
 
 extern "C" __eglMustCastToProperFunctionPointerType es1GetProcAddress(const char *procname)
 {
-	struct Extension
+	struct Function
 	{
 		const char *name;
 		__eglMustCastToProperFunctionPointerType address;
 	};
 
-	static const Extension glExtensions[] =
+	struct CompareFunctor
 	{
-		#define EXTENSION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
-
-		EXTENSION(glEGLImageTargetTexture2DOES),
-		EXTENSION(glEGLImageTargetRenderbufferStorageOES),
-		EXTENSION(glIsRenderbufferOES),
-		EXTENSION(glBindRenderbufferOES),
-		EXTENSION(glDeleteRenderbuffersOES),
-		EXTENSION(glGenRenderbuffersOES),
-		EXTENSION(glRenderbufferStorageOES),
-		EXTENSION(glGetRenderbufferParameterivOES),
-		EXTENSION(glIsFramebufferOES),
-		EXTENSION(glBindFramebufferOES),
-		EXTENSION(glDeleteFramebuffersOES),
-		EXTENSION(glGenFramebuffersOES),
-		EXTENSION(glCheckFramebufferStatusOES),
-		EXTENSION(glFramebufferRenderbufferOES),
-		EXTENSION(glFramebufferTexture2DOES),
-		EXTENSION(glGetFramebufferAttachmentParameterivOES),
-		EXTENSION(glGenerateMipmapOES),
-		EXTENSION(glBlendEquationOES),
-		EXTENSION(glBlendEquationSeparateOES),
-		EXTENSION(glBlendFuncSeparateOES),
-		EXTENSION(glPointSizePointerOES),
-
-		#undef EXTENSION
+		bool operator()(const Function &a, const Function &b) const
+		{
+			return strcmp(a.name, b.name) < 0;
+		}
 	};
 
-	for(unsigned int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++)
+	// This array must be kept sorted with respect to strcmp(), so that binary search works correctly.
+	// The Unix command "LC_COLLATE=C sort" will generate the correct order.
+	static const Function glFunctions[] =
 	{
-		if(strcmp(procname, glExtensions[ext].name) == 0)
+		#define FUNCTION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
+
+		FUNCTION(glActiveTexture),
+		FUNCTION(glAlphaFunc),
+		FUNCTION(glAlphaFuncx),
+		FUNCTION(glBindBuffer),
+		FUNCTION(glBindFramebufferOES),
+		FUNCTION(glBindRenderbufferOES),
+		FUNCTION(glBindTexture),
+		FUNCTION(glBlendEquationOES),
+		FUNCTION(glBlendEquationSeparateOES),
+		FUNCTION(glBlendFunc),
+		FUNCTION(glBlendFuncSeparateOES),
+		FUNCTION(glBufferData),
+		FUNCTION(glBufferSubData),
+		FUNCTION(glCheckFramebufferStatusOES),
+		FUNCTION(glClear),
+		FUNCTION(glClearColor),
+		FUNCTION(glClearColorx),
+		FUNCTION(glClearDepthf),
+		FUNCTION(glClearDepthx),
+		FUNCTION(glClearStencil),
+		FUNCTION(glClientActiveTexture),
+		FUNCTION(glClipPlanef),
+		FUNCTION(glClipPlanex),
+		FUNCTION(glColor4f),
+		FUNCTION(glColor4ub),
+		FUNCTION(glColor4x),
+		FUNCTION(glColorMask),
+		FUNCTION(glColorPointer),
+		FUNCTION(glCompressedTexImage2D),
+		FUNCTION(glCompressedTexSubImage2D),
+		FUNCTION(glCopyTexImage2D),
+		FUNCTION(glCopyTexSubImage2D),
+		FUNCTION(glCullFace),
+		FUNCTION(glDeleteBuffers),
+		FUNCTION(glDeleteFramebuffersOES),
+		FUNCTION(glDeleteRenderbuffersOES),
+		FUNCTION(glDeleteTextures),
+		FUNCTION(glDepthFunc),
+		FUNCTION(glDepthMask),
+		FUNCTION(glDepthRangef),
+		FUNCTION(glDepthRangex),
+		FUNCTION(glDisable),
+		FUNCTION(glDisableClientState),
+		FUNCTION(glDrawArrays),
+		FUNCTION(glDrawElements),
+		FUNCTION(glDrawTexfOES),
+		FUNCTION(glDrawTexfvOES),
+		FUNCTION(glDrawTexiOES),
+		FUNCTION(glDrawTexivOES),
+		FUNCTION(glDrawTexsOES),
+		FUNCTION(glDrawTexsvOES),
+		FUNCTION(glDrawTexxOES),
+		FUNCTION(glDrawTexxvOES),
+		FUNCTION(glEGLImageTargetRenderbufferStorageOES),
+		FUNCTION(glEGLImageTargetTexture2DOES),
+		FUNCTION(glEnable),
+		FUNCTION(glEnableClientState),
+		FUNCTION(glFinish),
+		FUNCTION(glFlush),
+		FUNCTION(glFogf),
+		FUNCTION(glFogfv),
+		FUNCTION(glFogx),
+		FUNCTION(glFogxv),
+		FUNCTION(glFramebufferRenderbufferOES),
+		FUNCTION(glFramebufferTexture2DOES),
+		FUNCTION(glFrontFace),
+		FUNCTION(glFrustumf),
+		FUNCTION(glFrustumx),
+		FUNCTION(glGenBuffers),
+		FUNCTION(glGenFramebuffersOES),
+		FUNCTION(glGenRenderbuffersOES),
+		FUNCTION(glGenTextures),
+		FUNCTION(glGenerateMipmapOES),
+		FUNCTION(glGetBooleanv),
+		FUNCTION(glGetBufferParameteriv),
+		FUNCTION(glGetClipPlanef),
+		FUNCTION(glGetClipPlanex),
+		FUNCTION(glGetError),
+		FUNCTION(glGetFixedv),
+		FUNCTION(glGetFloatv),
+		FUNCTION(glGetFramebufferAttachmentParameterivOES),
+		FUNCTION(glGetIntegerv),
+		FUNCTION(glGetLightfv),
+		FUNCTION(glGetLightxv),
+		FUNCTION(glGetMaterialfv),
+		FUNCTION(glGetMaterialxv),
+		FUNCTION(glGetPointerv),
+		FUNCTION(glGetRenderbufferParameterivOES),
+		FUNCTION(glGetString),
+		FUNCTION(glGetTexEnvfv),
+		FUNCTION(glGetTexEnviv),
+		FUNCTION(glGetTexEnvxv),
+		FUNCTION(glGetTexParameterfv),
+		FUNCTION(glGetTexParameteriv),
+		FUNCTION(glGetTexParameterxv),
+		FUNCTION(glHint),
+		FUNCTION(glIsBuffer),
+		FUNCTION(glIsEnabled),
+		FUNCTION(glIsFramebufferOES),
+		FUNCTION(glIsRenderbufferOES),
+		FUNCTION(glIsTexture),
+		FUNCTION(glLightModelf),
+		FUNCTION(glLightModelfv),
+		FUNCTION(glLightModelx),
+		FUNCTION(glLightModelxv),
+		FUNCTION(glLightf),
+		FUNCTION(glLightfv),
+		FUNCTION(glLightx),
+		FUNCTION(glLightxv),
+		FUNCTION(glLineWidth),
+		FUNCTION(glLineWidthx),
+		FUNCTION(glLoadIdentity),
+		FUNCTION(glLoadMatrixf),
+		FUNCTION(glLoadMatrixx),
+		FUNCTION(glLogicOp),
+		FUNCTION(glMaterialf),
+		FUNCTION(glMaterialfv),
+		FUNCTION(glMaterialx),
+		FUNCTION(glMaterialxv),
+		FUNCTION(glMatrixMode),
+		FUNCTION(glMultMatrixf),
+		FUNCTION(glMultMatrixx),
+		FUNCTION(glMultiTexCoord4f),
+		FUNCTION(glMultiTexCoord4x),
+		FUNCTION(glNormal3f),
+		FUNCTION(glNormal3x),
+		FUNCTION(glNormalPointer),
+		FUNCTION(glOrthof),
+		FUNCTION(glOrthox),
+		FUNCTION(glPixelStorei),
+		FUNCTION(glPointParameterf),
+		FUNCTION(glPointParameterfv),
+		FUNCTION(glPointParameterx),
+		FUNCTION(glPointParameterxv),
+		FUNCTION(glPointSize),
+		FUNCTION(glPointSizePointerOES),
+		FUNCTION(glPointSizex),
+		FUNCTION(glPolygonOffset),
+		FUNCTION(glPolygonOffsetx),
+		FUNCTION(glPopMatrix),
+		FUNCTION(glPushMatrix),
+		FUNCTION(glReadPixels),
+		FUNCTION(glRenderbufferStorageOES),
+		FUNCTION(glRotatef),
+		FUNCTION(glRotatex),
+		FUNCTION(glSampleCoverage),
+		FUNCTION(glSampleCoveragex),
+		FUNCTION(glScalef),
+		FUNCTION(glScalex),
+		FUNCTION(glScissor),
+		FUNCTION(glShadeModel),
+		FUNCTION(glStencilFunc),
+		FUNCTION(glStencilMask),
+		FUNCTION(glStencilOp),
+		FUNCTION(glTexCoordPointer),
+		FUNCTION(glTexEnvf),
+		FUNCTION(glTexEnvfv),
+		FUNCTION(glTexEnvi),
+		FUNCTION(glTexEnviv),
+		FUNCTION(glTexEnvx),
+		FUNCTION(glTexEnvxv),
+		FUNCTION(glTexImage2D),
+		FUNCTION(glTexParameterf),
+		FUNCTION(glTexParameterfv),
+		FUNCTION(glTexParameteri),
+		FUNCTION(glTexParameteriv),
+		FUNCTION(glTexParameterx),
+		FUNCTION(glTexParameterxv),
+		FUNCTION(glTexSubImage2D),
+		FUNCTION(glTranslatef),
+		FUNCTION(glTranslatex),
+		FUNCTION(glVertexPointer),
+		FUNCTION(glViewport),
+
+		#undef FUNCTION
+	};
+
+	static const size_t numFunctions = sizeof glFunctions / sizeof(Function);
+	static const Function *const glFunctionsEnd = glFunctions + numFunctions;
+
+	Function needle;
+	needle.name = procname;
+
+	if(procname && strncmp("gl", procname, 2) == 0)
+	{
+		const Function *result = std::lower_bound(glFunctions, glFunctionsEnd, needle, CompareFunctor());
+		if(result != glFunctionsEnd && strcmp(procname, result->name) == 0)
 		{
-			return (__eglMustCastToProperFunctionPointerType)glExtensions[ext].address;
+			return (__eglMustCastToProperFunctionPointerType)result->address;
 		}
 	}
 
diff --git a/src/OpenGL/libGLES_CM/libGLES_CM.hpp b/src/OpenGL/libGLES_CM/libGLES_CM.hpp
index 5a3a289..cd9447e 100644
--- a/src/OpenGL/libGLES_CM/libGLES_CM.hpp
+++ b/src/OpenGL/libGLES_CM/libGLES_CM.hpp
@@ -279,6 +279,8 @@
 				#else
 					const char *libGLES_CM_lib[] = {"libGLES_CM_translator.dylib", "libGLES_CM.dylib"};
 				#endif
+			#elif defined(__Fuchsia__)
+				const char *libGLES_CM_lib[] = {"libGLES_CM.so"};
 			#else
 				#error "libGLES_CM::loadExports unimplemented for this platform"
 			#endif
diff --git a/src/OpenGL/libGLES_CM/exports.map b/src/OpenGL/libGLES_CM/libGLES_CM.lds
similarity index 100%
rename from src/OpenGL/libGLES_CM/exports.map
rename to src/OpenGL/libGLES_CM/libGLES_CM.lds
diff --git a/src/OpenGL/libGLES_CM/libGLES_CM.vcxproj b/src/OpenGL/libGLES_CM/libGLES_CM.vcxproj
index 7d2a496..fec59e6 100644
--- a/src/OpenGL/libGLES_CM/libGLES_CM.vcxproj
+++ b/src/OpenGL/libGLES_CM/libGLES_CM.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -30,41 +30,42 @@
     <ProjectGuid>{235B1D85-E6B6-45E2-BA5D-5C60396428FF}</ProjectGuid>

     <RootNamespace>libGLES_CM</RootNamespace>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

@@ -124,7 +125,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

     <ClCompile>

       <Optimization>Disabled</Optimization>

-      <AdditionalIncludeDirectories>$(SolutionDir)\src;$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;EGLAPI=;GL_API=;GL_APICALL=;GL_GLEXT_PROTOTYPES;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <MinimalRebuild>true</MinimalRebuild>

       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

@@ -135,6 +136,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

       <BrowseInformation>true</BrowseInformation>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -153,7 +155,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

     <ClCompile>

       <Optimization>Disabled</Optimization>

-      <AdditionalIncludeDirectories>$(SolutionDir)\src;$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;EGLAPI=;GL_API=;GL_APICALL=;GL_GLEXT_PROTOTYPES;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

@@ -163,6 +165,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

       <BrowseInformation>true</BrowseInformation>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -198,6 +201,7 @@
       <WholeProgramOptimization>true</WholeProgramOptimization>

       <IntrinsicFunctions>false</IntrinsicFunctions>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -234,6 +238,7 @@
       <WholeProgramOptimization>true</WholeProgramOptimization>

       <IntrinsicFunctions>false</IntrinsicFunctions>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -270,6 +275,7 @@
       <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>

       <WholeProgramOptimization>true</WholeProgramOptimization>

       <IntrinsicFunctions>false</IntrinsicFunctions>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -304,6 +310,7 @@
       <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>

       <WholeProgramOptimization>true</WholeProgramOptimization>

       <IntrinsicFunctions>false</IntrinsicFunctions>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

diff --git a/src/OpenGL/libGLES_CM/utilities.cpp b/src/OpenGL/libGLES_CM/utilities.cpp
index b0b110a..0df34c7 100644
--- a/src/OpenGL/libGLES_CM/utilities.cpp
+++ b/src/OpenGL/libGLES_CM/utilities.cpp
@@ -32,6 +32,72 @@
                format == GL_ETC1_RGB8_OES;
 	}
 
+	bool IsSizedInternalFormat(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_ALPHA8_EXT:
+		case GL_LUMINANCE8_ALPHA8_EXT:
+		case GL_LUMINANCE8_EXT:
+		case GL_RGBA4_OES:
+		case GL_RGB5_A1_OES:
+		case GL_RGB565_OES:
+		case GL_RGB8_OES:
+		case GL_RGBA8_OES:
+		case GL_BGRA8_EXT:   // GL_APPLE_texture_format_BGRA8888
+		case GL_DEPTH_COMPONENT16_OES:
+		case GL_STENCIL_INDEX8_OES:
+		case GL_DEPTH24_STENCIL8_OES:
+			return true;
+		default:
+			return false;
+		}
+	}
+
+	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	                              GLsizei width, GLsizei height, GLenum format, GLenum type, Texture *texture)
+	{
+		if(!texture)
+		{
+			return GL_INVALID_OPERATION;
+		}
+
+		GLenum sizedInternalFormat = texture->getFormat(target, level);
+
+		if(compressed)
+		{
+			if(format != sizedInternalFormat)
+			{
+				return GL_INVALID_OPERATION;
+			}
+		}
+		else if(!copy)   // CopyTexSubImage doesn't have format/type parameters.
+		{
+			GLenum validationError = ValidateTextureFormatType(format, type, sizedInternalFormat, target);
+			if(validationError != GL_NO_ERROR)
+			{
+				return validationError;
+			}
+		}
+
+		if(compressed)
+		{
+			if((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
+			   (height % 4 != 0 && height != texture->getHeight(target, 0)))
+			{
+				return GL_INVALID_OPERATION;
+			}
+		}
+
+		if(xoffset + width > texture->getWidth(target, level) ||
+		   yoffset + height > texture->getHeight(target, level))
+		{
+			return GL_INVALID_VALUE;
+		}
+
+		return GL_NO_ERROR;
+	}
+
 	bool IsDepthTexture(GLenum format)
 	{
 		return format == GL_DEPTH_STENCIL_OES;
@@ -68,120 +134,366 @@
 	}
 
 	// Verify that format/type are one of the combinations from table 3.4.
-	bool CheckTextureFormatType(GLenum format, GLenum type)
+	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLenum target)
 	{
 		switch(type)
 		{
 		case GL_UNSIGNED_BYTE:
+		case GL_UNSIGNED_SHORT_4_4_4_4:
+		case GL_UNSIGNED_SHORT_5_5_5_1:
+		case GL_UNSIGNED_SHORT_5_6_5:
+		case GL_UNSIGNED_INT_24_8_OES:   // GL_OES_packed_depth_stencil
+			break;
+		default:
+			return GL_INVALID_ENUM;
+		}
+
+		switch(format)
+		{
+		case GL_ALPHA:
+		case GL_RGB:
+		case GL_RGBA:
+		case GL_LUMINANCE:
+		case GL_LUMINANCE_ALPHA:
+		case GL_BGRA_EXT:            // GL_EXT_texture_format_BGRA8888
+			break;
+		case GL_DEPTH_STENCIL_OES:   // GL_OES_packed_depth_stencil (GL_DEPTH_STENCIL_OES)
+			switch(target)
+			{
+			case GL_TEXTURE_2D:
+				break;
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
+		default:
+			return GL_INVALID_ENUM;
+		}
+
+		if((GLenum)internalformat != format)
+		{
+			if(gl::IsUnsizedInternalFormat(internalformat))
+			{
+				return GL_INVALID_OPERATION;
+			}
+
+			if(!IsSizedInternalFormat(internalformat))
+			{
+				return GL_INVALID_VALUE;
+			}
+		}
+
+		if((GLenum)internalformat == format)
+		{
+			// Validate format, type, and unsized internalformat combinations [OpenGL ES 1.1 Table 3.3]
 			switch(format)
 			{
 			case GL_RGBA:
-			case GL_BGRA_EXT:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+				case GL_UNSIGNED_SHORT_4_4_4_4:
+				case GL_UNSIGNED_SHORT_5_5_5_1:
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
 			case GL_RGB:
-			case GL_ALPHA:
-			case GL_LUMINANCE:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+				case GL_UNSIGNED_SHORT_5_6_5:
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
 			case GL_LUMINANCE_ALPHA:
-				return true;
+			case GL_LUMINANCE:
+			case GL_ALPHA:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_DEPTH_STENCIL_OES:
+				switch(type)
+				{
+				case GL_UNSIGNED_INT_24_8_OES:   // GL_OES_packed_depth_stencil
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_BGRA_EXT:
+				if(type != GL_UNSIGNED_BYTE)   // GL_APPLE_texture_format_BGRA8888 / GL_EXT_texture_format_BGRA8888
+				{
+					return GL_INVALID_OPERATION;
+				}
+				break;
 			default:
-				return false;
+				UNREACHABLE(format);
+				return GL_INVALID_ENUM;
 			}
-		case GL_FLOAT:
-		case GL_UNSIGNED_SHORT_4_4_4_4:
-		case GL_UNSIGNED_SHORT_5_5_5_1:
-			return (format == GL_RGBA);
-		case GL_UNSIGNED_SHORT_5_6_5:
-			return (format == GL_RGB);
-		case GL_UNSIGNED_INT_24_8_OES:
-			return (format == GL_DEPTH_STENCIL_OES);
-		default:
-			return false;
-		}
-	}
 
-	bool IsColorRenderable(GLenum internalformat)
-	{
-		switch(internalformat)
+			return GL_NO_ERROR;
+		}
+
+		// Validate format, type, and sized internalformat combinations [OpenGL ES 3.0 Table 3.2]
+		bool validSizedInternalformat = false;
+		#define VALIDATE_INTERNALFORMAT(...) { GLint validInternalformats[] = {__VA_ARGS__}; for(GLint v : validInternalformats) {if(internalformat == v) validSizedInternalformat = true;} } break;
+
+		switch(format)
 		{
-		case GL_RGB:
 		case GL_RGBA:
-		case GL_RGBA4_OES:
-		case GL_RGB5_A1_OES:
-		case GL_RGB565_OES:
-		case GL_RGB8_OES:
-		case GL_RGBA8_OES:
-			return true;
-		case GL_DEPTH_COMPONENT16_OES:
-		case GL_STENCIL_INDEX8_OES:
-		case GL_DEPTH24_STENCIL8_OES:
-			return false;
-		default:
-			UNIMPLEMENTED();
-		}
-
-		return false;
-	}
-
-	bool IsDepthRenderable(GLenum internalformat)
-	{
-		switch(internalformat)
-		{
-		case GL_DEPTH_COMPONENT16_OES:
-		case GL_DEPTH24_STENCIL8_OES:
-			return true;
-		case GL_STENCIL_INDEX8_OES:
-		case GL_RGBA4_OES:
-		case GL_RGB5_A1_OES:
-		case GL_RGB565_OES:
-		case GL_RGB8_OES:
-		case GL_RGBA8_OES:
-			return false;
-		default:
-			UNIMPLEMENTED();
-		}
-
-		return false;
-	}
-
-	bool IsStencilRenderable(GLenum internalformat)
-	{
-		switch(internalformat)
-		{
-		case GL_STENCIL_INDEX8_OES:
-		case GL_DEPTH24_STENCIL8_OES:
-			return true;
-		case GL_RGBA4_OES:
-		case GL_RGB5_A1_OES:
-		case GL_RGB565_OES:
-		case GL_RGB8_OES:
-		case GL_RGBA8_OES:
-		case GL_DEPTH_COMPONENT16_OES:
-			return false;
-		default:
-			UNIMPLEMENTED();
-		}
-
-		return false;
-	}
-
-	bool IsAlpha(GLenum texFormat)
-	{
-		switch(texFormat)
-		{
-		case GL_ALPHA:
-			return true;
-		default:
-			return false;
-		}
-	}
-
-	bool IsRGB(GLenum texFormat)
-	{
-		switch(texFormat)
-		{
-		case GL_LUMINANCE:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:               VALIDATE_INTERNALFORMAT(GL_RGBA8_OES, GL_RGB5_A1_OES, GL_RGBA4_OES)
+			case GL_UNSIGNED_SHORT_4_4_4_4:      VALIDATE_INTERNALFORMAT(GL_RGBA4_OES)
+			case GL_UNSIGNED_SHORT_5_5_5_1:      VALIDATE_INTERNALFORMAT(GL_RGB5_A1_OES)
+			default:                             return GL_INVALID_OPERATION;
+			}
+			break;
 		case GL_RGB:
-		case GL_RGB565_OES:   // GL_OES_framebuffer_object
-		case GL_RGB8_OES:     // GL_OES_rgb8_rgba8
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:                VALIDATE_INTERNALFORMAT(GL_RGB8_OES, GL_RGB565_OES)
+			case GL_UNSIGNED_SHORT_5_6_5:         VALIDATE_INTERNALFORMAT(GL_RGB565_OES)
+			default:                              return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_DEPTH_STENCIL_OES:
+			switch(type)
+			{
+			case GL_UNSIGNED_INT_24_8_OES: VALIDATE_INTERNALFORMAT(GL_DEPTH24_STENCIL8_OES)
+			default:                       return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_LUMINANCE_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_LUMINANCE8_ALPHA8_EXT)
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_LUMINANCE:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_LUMINANCE8_EXT)
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_ALPHA8_EXT)
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
+		case GL_BGRA_EXT:   // GL_APPLE_texture_format_BGRA8888
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_BGRA8_EXT)
+			default:               return GL_INVALID_OPERATION;
+			}
+			break;
+		default:
+			UNREACHABLE(format);
+			return GL_INVALID_ENUM;
+		}
+
+		#undef VALIDATE_INTERNALFORMAT
+
+		if(!validSizedInternalformat)
+		{
+			return GL_INVALID_OPERATION;
+		}
+
+		return GL_NO_ERROR;
+	}
+
+	bool IsColorRenderable(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_RGBA4_OES:
+		case GL_RGB5_A1_OES:
+		case GL_RGB565_OES:
+		case GL_RGB8_OES:
+		case GL_RGBA8_OES:
+			return true;
+		case GL_DEPTH_COMPONENT16_OES:
+		case GL_STENCIL_INDEX8_OES:
+		case GL_DEPTH24_STENCIL8_OES:
+			return false;
+		default:
+			UNIMPLEMENTED();
+		}
+
+		return false;
+	}
+
+	bool IsDepthRenderable(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_DEPTH_COMPONENT16_OES:
+		case GL_DEPTH24_STENCIL8_OES:
+			return true;
+		case GL_STENCIL_INDEX8_OES:
+		case GL_RGBA4_OES:
+		case GL_RGB5_A1_OES:
+		case GL_RGB565_OES:
+		case GL_RGB8_OES:
+		case GL_RGBA8_OES:
+			return false;
+		default:
+			UNIMPLEMENTED();
+		}
+
+		return false;
+	}
+
+	bool IsStencilRenderable(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_STENCIL_INDEX8_OES:
+		case GL_DEPTH24_STENCIL8_OES:
+			return true;
+		case GL_RGBA4_OES:
+		case GL_RGB5_A1_OES:
+		case GL_RGB565_OES:
+		case GL_RGB8_OES:
+		case GL_RGBA8_OES:
+		case GL_DEPTH_COMPONENT16_OES:
+			return false;
+		default:
+			UNIMPLEMENTED();
+		}
+
+		return false;
+	}
+
+	GLuint GetAlphaSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE_OES:    return 0;
+		case GL_RGBA4_OES:   return 4;
+		case GL_RGB5_A1_OES: return 1;
+		case GL_RGB565_OES:  return 0;
+		case GL_RGB8_OES:    return 0;
+		case GL_RGBA8_OES:   return 8;
+		case GL_BGRA8_EXT:   return 8;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetRedSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE_OES:    return 0;
+		case GL_RGBA4_OES:   return 4;
+		case GL_RGB5_A1_OES: return 5;
+		case GL_RGB565_OES:  return 5;
+		case GL_RGB8_OES:    return 8;
+		case GL_RGBA8_OES:   return 8;
+		case GL_BGRA8_EXT:   return 8;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetGreenSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE_OES:    return 0;
+		case GL_RGBA4_OES:   return 4;
+		case GL_RGB5_A1_OES: return 5;
+		case GL_RGB565_OES:  return 6;
+		case GL_RGB8_OES:    return 8;
+		case GL_RGBA8_OES:   return 8;
+		case GL_BGRA8_EXT:   return 8;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetBlueSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE_OES:    return 0;
+		case GL_RGBA4_OES:   return 4;
+		case GL_RGB5_A1_OES: return 5;
+		case GL_RGB565_OES:  return 5;
+		case GL_RGB8_OES:    return 8;
+		case GL_RGBA8_OES:   return 8;
+		case GL_BGRA8_EXT:   return 8;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetDepthSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_STENCIL_INDEX8_OES:    return 0;
+		case GL_DEPTH_COMPONENT16_OES: return 16;
+		case GL_DEPTH24_STENCIL8_OES:  return 24;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetStencilSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_STENCIL_INDEX8_OES:    return 8;
+		case GL_DEPTH_COMPONENT16_OES: return 0;
+		case GL_DEPTH24_STENCIL8_OES:  return 8;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	bool IsAlpha(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_ALPHA8_EXT:
+			return true;
+		default:
+			return false;
+		}
+	}
+
+	bool IsRGB(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_LUMINANCE8_EXT:
+		case GL_RGB565_OES:
+		case GL_RGB8_OES:
 		case SW_YV12_BT601:
 		case SW_YV12_BT709:
 		case SW_YV12_JFIF:
@@ -191,16 +503,16 @@
 		}
 	}
 
-	bool IsRGBA(GLenum texFormat)
+	bool IsRGBA(GLint internalformat)
 	{
-		switch(texFormat)
+		switch(internalformat)
 		{
-		case GL_LUMINANCE_ALPHA:
+		case GL_LUMINANCE8_ALPHA8_EXT:
 		case GL_RGBA:
-		case GL_BGRA_EXT:      // GL_EXT_texture_format_BGRA8888
-		case GL_RGBA4_OES:     // GL_OES_framebuffer_object
-		case GL_RGB5_A1_OES:   // GL_OES_framebuffer_object
-		case GL_RGBA8_OES:     // GL_OES_rgb8_rgba8
+		case GL_BGRA8_EXT:     // GL_EXT_texture_format_BGRA8888
+		case GL_RGBA4_OES:
+		case GL_RGB5_A1_OES:
+		case GL_RGBA8_OES:
 			return true;
 		default:
 			return false;
@@ -478,7 +790,7 @@
 		sw::DrawType elementSize;
 		switch(elementType)
 		{
-		case GL_NONE:           elementSize = sw::DRAW_NONINDEXED; break;
+		case GL_NONE_OES:       elementSize = sw::DRAW_NONINDEXED; break;
 		case GL_UNSIGNED_BYTE:  elementSize = sw::DRAW_INDEXED8;   break;
 		case GL_UNSIGNED_SHORT: elementSize = sw::DRAW_INDEXED16;  break;
 		case GL_UNSIGNED_INT:   elementSize = sw::DRAW_INDEXED32;  break;
@@ -490,22 +802,6 @@
 		return true;
 	}
 
-	sw::Format ConvertRenderbufferFormat(GLenum format)
-	{
-		switch(format)
-		{
-		case GL_RGBA4_OES:
-		case GL_RGB5_A1_OES:
-		case GL_RGBA8_OES:            return sw::FORMAT_A8B8G8R8;
-		case GL_RGB565_OES:           return sw::FORMAT_R5G6B5;
-		case GL_RGB8_OES:             return sw::FORMAT_X8B8G8R8;
-		case GL_DEPTH_COMPONENT16_OES:
-		case GL_STENCIL_INDEX8_OES:
-		case GL_DEPTH24_STENCIL8_OES: return sw::FORMAT_D24S8;
-		default: UNREACHABLE(format); return sw::FORMAT_A8B8G8R8;
-		}
-	}
-
 	sw::TextureStage::StageOperation ConvertCombineOperation(GLenum operation)
 	{
 		switch(operation)
@@ -549,145 +845,6 @@
 
 namespace sw2es
 {
-	unsigned int GetStencilSize(sw::Format stencilFormat)
-	{
-		switch(stencilFormat)
-		{
-		case sw::FORMAT_D24FS8:
-		case sw::FORMAT_D24S8:
-		case sw::FORMAT_D32FS8_TEXTURE:
-			return 8;
-	//	case sw::FORMAT_D24X4S4:
-	//		return 4;
-	//	case sw::FORMAT_D15S1:
-	//		return 1;
-	//	case sw::FORMAT_D16_LOCKABLE:
-		case sw::FORMAT_D32:
-		case sw::FORMAT_D24X8:
-		case sw::FORMAT_D32F_LOCKABLE:
-		case sw::FORMAT_D16:
-			return 0;
-	//	case sw::FORMAT_D32_LOCKABLE:  return 0;
-	//	case sw::FORMAT_S8_LOCKABLE:   return 8;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetAlphaSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_A16B16G16R16F:
-			return 16;
-		case sw::FORMAT_A32B32G32R32F:
-			return 32;
-		case sw::FORMAT_A2R10G10B10:
-			return 2;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-			return 1;
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-		case sw::FORMAT_R5G6B5:
-			return 0;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetRedSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_A16B16G16R16F:
-			return 16;
-		case sw::FORMAT_A32B32G32R32F:
-			return 32;
-		case sw::FORMAT_A2R10G10B10:
-			return 10;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-		case sw::FORMAT_R5G6B5:
-			return 5;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetGreenSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_A16B16G16R16F:
-			return 16;
-		case sw::FORMAT_A32B32G32R32F:
-			return 32;
-		case sw::FORMAT_A2R10G10B10:
-			return 10;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-			return 5;
-		case sw::FORMAT_R5G6B5:
-			return 6;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetBlueSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_A16B16G16R16F:
-			return 16;
-		case sw::FORMAT_A32B32G32R32F:
-			return 32;
-		case sw::FORMAT_A2R10G10B10:
-			return 10;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-		case sw::FORMAT_R5G6B5:
-			return 5;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetDepthSize(sw::Format depthFormat)
-	{
-		switch(depthFormat)
-		{
-	//	case sw::FORMAT_D16_LOCKABLE:   return 16;
-		case sw::FORMAT_D32:            return 32;
-	//	case sw::FORMAT_D15S1:          return 15;
-		case sw::FORMAT_D24S8:          return 24;
-		case sw::FORMAT_D24X8:          return 24;
-	//	case sw::FORMAT_D24X4S4:        return 24;
-		case sw::FORMAT_D16:            return 16;
-		case sw::FORMAT_D32F_LOCKABLE:  return 32;
-		case sw::FORMAT_D24FS8:         return 24;
-	//	case sw::FORMAT_D32_LOCKABLE:   return 32;
-	//	case sw::FORMAT_S8_LOCKABLE:    return 0;
-		case sw::FORMAT_D32FS8_TEXTURE: return 32;
-		default:                        return 0;
-		}
-	}
-
 	GLenum ConvertBackBufferFormat(sw::Format format)
 	{
 		switch(format)
diff --git a/src/OpenGL/libGLES_CM/utilities.h b/src/OpenGL/libGLES_CM/utilities.h
index ec2a257..402a341 100644
--- a/src/OpenGL/libGLES_CM/utilities.h
+++ b/src/OpenGL/libGLES_CM/utilities.h
@@ -31,20 +31,29 @@
 	struct Color;
 
 	bool IsCompressed(GLenum format);
+	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	                              GLsizei width, GLsizei height, GLenum format, GLenum type, Texture *texture);
 	bool IsDepthTexture(GLenum format);
 	bool IsStencilTexture(GLenum format);
 	bool IsCubemapTextureTarget(GLenum target);
 	int CubeFaceIndex(GLenum cubeTarget);
 	bool IsTextureTarget(GLenum target);
-	bool CheckTextureFormatType(GLenum format, GLenum type);
+	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLenum target);
 
-	bool IsColorRenderable(GLenum internalformat);
-	bool IsDepthRenderable(GLenum internalformat);
-	bool IsStencilRenderable(GLenum internalformat);
+	bool IsColorRenderable(GLint internalformat);
+	bool IsDepthRenderable(GLint internalformat);
+	bool IsStencilRenderable(GLint internalformat);
 
-	bool IsAlpha(GLenum texFormat);
-	bool IsRGB(GLenum texFormat);
-	bool IsRGBA(GLenum texFormat);
+	GLuint GetAlphaSize(GLint internalformat);
+	GLuint GetRedSize(GLint internalformat);
+	GLuint GetGreenSize(GLint internalformat);
+	GLuint GetBlueSize(GLint internalformat);
+	GLuint GetDepthSize(GLint internalformat);
+	GLuint GetStencilSize(GLint internalformat);
+
+	bool IsAlpha(GLint texFormat);
+	bool IsRGB(GLint texFormat);
+	bool IsRGBA(GLint texFormat);
 }
 
 namespace es2sw
@@ -63,7 +72,6 @@
 	sw::MipmapType ConvertMipMapFilter(GLenum minFilter);
 	sw::FilterType ConvertTextureFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy);
 	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,  GLenum elementType, sw::DrawType &swPrimitiveType, int &primitiveCount);
-	sw::Format ConvertRenderbufferFormat(GLenum format);
 	sw::TextureStage::StageOperation ConvertCombineOperation(GLenum operation);
 	sw::TextureStage::SourceArgument ConvertSourceArgument(GLenum argument);
 	sw::TextureStage::ArgumentModifier ConvertSourceOperand(GLenum operand);
@@ -71,13 +79,6 @@
 
 namespace sw2es
 {
-	GLuint GetAlphaSize(sw::Format colorFormat);
-	GLuint GetRedSize(sw::Format colorFormat);
-	GLuint GetGreenSize(sw::Format colorFormat);
-	GLuint GetBlueSize(sw::Format colorFormat);
-	GLuint GetDepthSize(sw::Format depthFormat);
-	GLuint GetStencilSize(sw::Format stencilFormat);
-
 	GLenum ConvertBackBufferFormat(sw::Format format);
 	GLenum ConvertDepthStencilFormat(sw::Format format);
 }
diff --git a/src/OpenGL/libGLESv2/Android.mk b/src/OpenGL/libGLESv2/Android.mk
index 5b020cb..94e8089 100644
--- a/src/OpenGL/libGLESv2/Android.mk
+++ b/src/OpenGL/libGLESv2/Android.mk
@@ -41,6 +41,7 @@
 	libGLESv2.cpp \
 	libGLESv3.cpp \
 	main.cpp \
+	entry_points.cpp \
 	Program.cpp \
 	Query.cpp \
 	Renderbuffer.cpp \
@@ -94,8 +95,8 @@
 endif
 
 COMMON_LDFLAGS := \
+	-Wl,--version-script=$(LOCAL_PATH)/libGLESv2.lds \
 	-Wl,--gc-sections \
-	-Wl,--version-script=$(LOCAL_PATH)/exports.map \
 	-Wl,--hash-style=sysv
 
 include $(CLEAR_VARS)
@@ -103,14 +104,10 @@
 ifdef TARGET_2ND_ARCH
 ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
 LOCAL_MULTILIB := first
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
-else
-LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib/egl
-LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64/egl
 endif
-else
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
 endif
+LOCAL_MODULE_RELATIVE_PATH := egl
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_TAGS := optional
 LOCAL_CLANG := true
 LOCAL_SRC_FILES += $(COMMON_SRC_FILES)
@@ -127,14 +124,10 @@
 ifdef TARGET_2ND_ARCH
 ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
 LOCAL_MULTILIB := first
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
-else
-LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib/egl
-LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64/egl
 endif
-else
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/egl
 endif
+LOCAL_MODULE_RELATIVE_PATH := egl
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_TAGS := optional
 LOCAL_CLANG := true
 LOCAL_SRC_FILES += $(COMMON_SRC_FILES)
diff --git a/src/OpenGL/libGLESv2/BUILD.gn b/src/OpenGL/libGLESv2/BUILD.gn
index a917cfd..b4383c9 100644
--- a/src/OpenGL/libGLESv2/BUILD.gn
+++ b/src/OpenGL/libGLESv2/BUILD.gn
@@ -50,17 +50,11 @@
   }
 }
 
-swiftshader_shared_library("swiftshader_libGLESv2") {
-  if (!is_mac) {
-    output_name = "libGLESv2"
-    output_dir = "$root_out_dir/swiftshader"
-  }
-
+swiftshader_static_library("swiftshader_libGLESv2_static") {
   deps = [
     "../../OpenGL/compiler:swiftshader_opengl_compiler",
     "../../Reactor:swiftshader_reactor",
     "../../Renderer:swiftshader_renderer",
-    "//build/config:exe_and_shlib_deps",
   ]
 
   sources = [
@@ -80,21 +74,45 @@
     "VertexArray.cpp",
     "VertexDataManager.cpp",
     "libGLESv2.cpp",
-    "libGLESv2.def",
-    "libGLESv2.rc",
     "libGLESv3.cpp",
     "main.cpp",
     "resource.h",
     "utilities.cpp",
   ]
 
+  configs = [ ":swiftshader_libGLESv2_private_config" ]
+
+  include_dirs = [
+    "../../../include",
+    "../..",
+    "..",
+  ]
+}
+
+swiftshader_shared_library("swiftshader_libGLESv2") {
+  if (!is_mac) {
+    output_name = "libGLESv2"
+    output_dir = "$root_out_dir/swiftshader"
+  }
+
+  deps = [
+    ":swiftshader_libGLESv2_static",
+    "//build/config:exe_and_shlib_deps",
+  ]
+
+  sources = [
+    "entry_points.cpp",
+    "libGLESv2.def",
+    "libGLESv2.rc",
+  ]
+
   if (is_win) {
     ldflags = [ "/DEF:" + rebase_path("libGLESv2.def", root_build_dir) ]
   } else if (is_mac) {
     ldflags = [ "-Wl,-install_name,@rpath/libswiftshader_libGLESv2.dylib" ]
   } else if (is_linux) {
     ldflags =
-        [ "-Wl,--version-script=" + rebase_path("exports.map", root_build_dir) ]
+        [ "-Wl,--version-script=" + rebase_path("libGLESv2.lds", root_build_dir) ]
   }
 
   configs = [ ":swiftshader_libGLESv2_private_config" ]
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 6ca3c81..f495e8a 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
Binary files differ
diff --git a/src/OpenGL/libGLESv2/Context.h b/src/OpenGL/libGLESv2/Context.h
index d00f545..a9c5259 100644
--- a/src/OpenGL/libGLESv2/Context.h
+++ b/src/OpenGL/libGLESv2/Context.h
@@ -53,6 +53,7 @@
 class Texture3D;
 class Texture2DArray;
 class TextureCubeMap;
+class Texture2DRect;
 class TextureExternal;
 class Framebuffer;
 class Renderbuffer;
@@ -102,19 +103,17 @@
 	MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = MAX_VERTEX_UNIFORM_BLOCKS_COMPONENTS + MAX_VERTEX_UNIFORM_COMPONENTS,
 	MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 4,
 	MAX_UNIFORM_BUFFER_BINDINGS = sw::MAX_UNIFORM_BUFFER_BINDINGS,
-	UNIFORM_BUFFER_OFFSET_ALIGNMENT = 1,
+	UNIFORM_BUFFER_OFFSET_ALIGNMENT = 4,
 	NUM_PROGRAM_BINARY_FORMATS = 0,
 };
 
 const GLenum compressedTextureFormats[] =
 {
 	GL_ETC1_RGB8_OES,
-#if (S3TC_SUPPORT)
 	GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
 	GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
 	GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE,
 	GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE,
-#endif
 #if (GL_ES_VERSION_3_0)
 	GL_COMPRESSED_R11_EAC,
 	GL_COMPRESSED_SIGNED_R11_EAC,
@@ -126,6 +125,7 @@
 	GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
 	GL_COMPRESSED_RGBA8_ETC2_EAC,
 	GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
+#if (ASTC_SUPPORT)
 	GL_COMPRESSED_RGBA_ASTC_4x4_KHR,
 	GL_COMPRESSED_RGBA_ASTC_5x4_KHR,
 	GL_COMPRESSED_RGBA_ASTC_5x5_KHR,
@@ -154,7 +154,8 @@
 	GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
 	GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR,
 	GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
-#endif
+#endif // ASTC_SUPPORT
+#endif // GL_ES_VERSION_3_0
 };
 
 const GLenum GL_TEXTURE_FILTERING_HINT_CHROMIUM = 0x8AF0;
@@ -192,7 +193,7 @@
 class VertexAttribute
 {
 public:
-	VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mDivisor(0), mPointer(nullptr), mArrayEnabled(false)
+	VertexAttribute() : mType(GL_FLOAT), mSize(4), mNormalized(false), mPureInteger(false), mStride(0), mDivisor(0), mPointer(nullptr), mArrayEnabled(false)
 	{
 		mCurrentValue[0].f = 0.0f;
 		mCurrentValue[1].f = 0.0f;
@@ -299,6 +300,7 @@
 	GLenum mType;
 	GLint mSize;
 	bool mNormalized;
+	bool mPureInteger;
 	GLsizei mStride;   // 0 means natural stride
 	GLuint mDivisor;   // From glVertexAttribDivisor
 
@@ -420,13 +422,8 @@
 	gl::BindingPointer<Texture> samplerTexture[TEXTURE_TYPE_COUNT][MAX_COMBINED_TEXTURE_IMAGE_UNITS];
 	gl::BindingPointer<Query> activeQuery[QUERY_TYPE_COUNT];
 
-	egl::Image::UnpackInfo unpackInfo;
-	GLint packAlignment;
-	GLint packRowLength;
-	GLint packImageHeight;
-	GLint packSkipPixels;
-	GLint packSkipRows;
-	GLint packSkipImages;
+	gl::PixelStorageModes unpackParameters;
+	gl::PixelStorageModes packParameters;
 };
 
 class [[clang::lto_visibility_public]] Context : public egl::Context
@@ -513,7 +510,6 @@
 
 	void setFramebufferReadBuffer(GLenum buf);
 	void setFramebufferDrawBuffers(GLsizei n, const GLenum *bufs);
-	GLuint getReadFramebufferColorIndex() const;
 
 	GLuint getActiveQuery(GLenum target) const;
 
@@ -524,7 +520,7 @@
 	void setVertexAttribDivisor(unsigned int attribNum, GLuint divisor);
 	const VertexAttribute &getVertexAttribState(unsigned int attribNum) const;
 	void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
-	                          bool normalized, GLsizei stride, const void *pointer);
+	                          bool normalized, bool pureInteger, GLsizei stride, const void *pointer);
 	const void *getVertexAttribPointer(unsigned int attribNum) const;
 
 	const VertexAttributeArray &getVertexArrayAttributes();
@@ -537,14 +533,12 @@
 	void setUnpackSkipPixels(GLint skipPixels);
 	void setUnpackSkipRows(GLint skipRows);
 	void setUnpackSkipImages(GLint skipImages);
-	const egl::Image::UnpackInfo& getUnpackInfo() const;
+	const gl::PixelStorageModes &getUnpackParameters() const;
 
 	void setPackAlignment(GLint alignment);
 	void setPackRowLength(GLint rowLength);
-	void setPackImageHeight(GLint imageHeight);
 	void setPackSkipPixels(GLint skipPixels);
 	void setPackSkipRows(GLint skipRows);
-	void setPackSkipImages(GLint skipImages);
 
 	// These create and destroy methods are merely pass-throughs to
 	// ResourceManager, which owns these object types
@@ -591,11 +585,7 @@
 	void bindPixelPackBuffer(GLuint buffer);
 	void bindPixelUnpackBuffer(GLuint buffer);
 	void bindTransformFeedbackBuffer(GLuint buffer);
-	void bindTexture2D(GLuint texture);
-	void bindTextureCubeMap(GLuint texture);
-	void bindTextureExternal(GLuint texture);
-	void bindTexture3D(GLuint texture);
-	void bindTexture2DArray(GLuint texture);
+	void bindTexture(TextureType type, GLuint texture);
 	void bindReadFramebuffer(GLuint framebuffer);
 	void bindDrawFramebuffer(GLuint framebuffer);
 	void bindRenderbuffer(GLuint renderbuffer);
@@ -632,6 +622,7 @@
 	VertexArray *getCurrentVertexArray() const;
 	bool isVertexArray(GLuint array) const;
 	TransformFeedback *getTransformFeedback(GLuint transformFeedback) const;
+	bool isTransformFeedback(GLuint transformFeedback) const;
 	TransformFeedback *getTransformFeedback() const;
 	Sampler *getSampler(GLuint sampler) const;
 	bool isSampler(GLuint sampler) const;
@@ -643,13 +634,16 @@
 	Buffer *getPixelPackBuffer() const;
 	Buffer *getPixelUnpackBuffer() const;
 	Buffer *getGenericUniformBuffer() const;
-	const GLvoid* getPixels(const GLvoid* data) const;
+	GLsizei getRequiredBufferSize(GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type) const;
+	GLenum getPixels(const GLvoid **data, GLenum type, GLsizei imageSize) const;
 	bool getBuffer(GLenum target, es2::Buffer **buffer) const;
 	Program *getCurrentProgram() const;
 	Texture2D *getTexture2D() const;
+	Texture2D *getTexture2D(GLenum target) const;
 	Texture3D *getTexture3D() const;
 	Texture2DArray *getTexture2DArray() const;
 	TextureCubeMap *getTextureCubeMap() const;
+	Texture2DRect *getTexture2DRect() const;
 	TextureExternal *getTextureExternal() const;
 	Texture *getSamplerTexture(unsigned int sampler, TextureType type) const;
 	Framebuffer *getReadFramebuffer() const;
@@ -739,6 +733,7 @@
 	gl::BindingPointer<Texture3D> mTexture3DZero;
 	gl::BindingPointer<Texture2DArray> mTexture2DArrayZero;
 	gl::BindingPointer<TextureCubeMap> mTextureCubeMapZero;
+	gl::BindingPointer<Texture2DRect> mTexture2DRectZero;
 	gl::BindingPointer<TextureExternal> mTextureExternalZero;
 
 	gl::NameSpace<Framebuffer> mFramebufferNameSpace;
diff --git a/src/OpenGL/libGLESv2/Device.cpp b/src/OpenGL/libGLESv2/Device.cpp
index a4ba15a..6fcfba8 100644
--- a/src/OpenGL/libGLESv2/Device.cpp
+++ b/src/OpenGL/libGLESv2/Device.cpp
@@ -249,73 +249,6 @@
 		stencilBuffer->clearStencil(stencil, mask, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
 	}
 
-	egl::Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
-	{
-		if(height > OUTLINE_RESOLUTION)
-		{
-			ERR("Invalid parameters: %dx%d", width, height);
-			return nullptr;
-		}
-
-		bool lockable = true;
-
-		switch(format)
-		{
-	//	case FORMAT_D15S1:
-		case FORMAT_D24S8:
-		case FORMAT_D24X8:
-	//	case FORMAT_D24X4S4:
-		case FORMAT_D24FS8:
-		case FORMAT_D32:
-		case FORMAT_D16:
-		case FORMAT_D32F:
-		case FORMAT_D32F_COMPLEMENTARY:
-			lockable = false;
-			break;
-	//	case FORMAT_S8_LOCKABLE:
-	//	case FORMAT_D16_LOCKABLE:
-		case FORMAT_D32F_LOCKABLE:
-	//	case FORMAT_D32_LOCKABLE:
-		case FORMAT_DF24S8:
-		case FORMAT_DF16S8:
-		case FORMAT_D32FS8_TEXTURE:
-		case FORMAT_D32FS8_SHADOW:
-			lockable = true;
-			break;
-		default:
-			UNREACHABLE(format);
-		}
-
-		egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
-
-		if(!surface)
-		{
-			ERR("Out of memory");
-			return nullptr;
-		}
-
-		return surface;
-	}
-
-	egl::Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
-	{
-		if(height > OUTLINE_RESOLUTION)
-		{
-			ERR("Invalid parameters: %dx%d", width, height);
-			return nullptr;
-		}
-
-		egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
-
-		if(!surface)
-		{
-			ERR("Out of memory");
-			return nullptr;
-		}
-
-		return surface;
-	}
-
 	void Device::drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount)
 	{
 		if(!bindResources() || !primitiveCount)
@@ -363,7 +296,7 @@
 		scissorEnable = enable;
 	}
 
-	void Device::setRenderTarget(int index, egl::Image *renderTarget)
+	void Device::setRenderTarget(int index, egl::Image *renderTarget, unsigned int layer)
 	{
 		if(renderTarget)
 		{
@@ -377,10 +310,10 @@
 
 		this->renderTarget[index] = renderTarget;
 
-		Renderer::setRenderTarget(index, renderTarget);
+		Renderer::setRenderTarget(index, renderTarget, layer);
 	}
 
-	void Device::setDepthBuffer(egl::Image *depthBuffer)
+	void Device::setDepthBuffer(egl::Image *depthBuffer, unsigned int layer)
 	{
 		if(this->depthBuffer == depthBuffer)
 		{
@@ -399,10 +332,10 @@
 
 		this->depthBuffer = depthBuffer;
 
-		Renderer::setDepthBuffer(depthBuffer);
+		Renderer::setDepthBuffer(depthBuffer, layer);
 	}
 
-	void Device::setStencilBuffer(egl::Image *stencilBuffer)
+	void Device::setStencilBuffer(egl::Image *stencilBuffer, unsigned int layer)
 	{
 		if(this->stencilBuffer == stencilBuffer)
 		{
@@ -421,7 +354,7 @@
 
 		this->stencilBuffer = stencilBuffer;
 
-		Renderer::setStencilBuffer(stencilBuffer);
+		Renderer::setStencilBuffer(stencilBuffer, layer);
 	}
 
 	void Device::setScissorRect(const sw::Rect &rect)
@@ -454,7 +387,7 @@
 		this->viewport = viewport;
 	}
 
-	void Device::copyBuffer(sw::byte *sourceBuffer, sw::byte *destBuffer, unsigned int width, unsigned int height, unsigned int sourcePitch, unsigned int destPitch, unsigned int bytes, bool flipX, bool flipY)
+	void Device::copyBuffer(byte *sourceBuffer, byte *destBuffer, unsigned int width, unsigned int height, unsigned int sourcePitch, unsigned int destPitch, unsigned int bytes, bool flipX, bool flipY)
 	{
 		if(flipX)
 		{
@@ -463,8 +396,8 @@
 				sourceBuffer += (height - 1) * sourcePitch;
 				for(unsigned int y = 0; y < height; ++y, sourceBuffer -= sourcePitch, destBuffer += destPitch)
 				{
-					sw::byte *srcX = sourceBuffer + (width - 1) * bytes;
-					sw::byte *dstX = destBuffer;
+					byte *srcX = sourceBuffer + (width - 1) * bytes;
+					byte *dstX = destBuffer;
 					for(unsigned int x = 0; x < width; ++x, dstX += bytes, srcX -= bytes)
 					{
 						memcpy(dstX, srcX, bytes);
@@ -475,8 +408,8 @@
 			{
 				for(unsigned int y = 0; y < height; ++y, sourceBuffer += sourcePitch, destBuffer += destPitch)
 				{
-					sw::byte *srcX = sourceBuffer + (width - 1) * bytes;
-					sw::byte *dstX = destBuffer;
+					byte *srcX = sourceBuffer + (width - 1) * bytes;
+					byte *dstX = destBuffer;
 					for(unsigned int x = 0; x < width; ++x, dstX += bytes, srcX -= bytes)
 					{
 						memcpy(dstX, srcX, bytes);
@@ -506,7 +439,7 @@
 		}
 	}
 
-	bool Device::stretchRect(sw::Surface *source, const sw::SliceRect *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, unsigned char flags)
+	bool Device::stretchRect(sw::Surface *source, const sw::SliceRectF *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, unsigned char flags)
 	{
 		if(!source || !dest)
 		{
@@ -537,12 +470,16 @@
 			flipY = (destRect->y0 > destRect->y1);
 		}
 
-		SliceRect sRect;
+		SliceRectF sRect;
 		SliceRect dRect;
 
 		if(sourceRect)
 		{
-			sRect = *sourceRect;
+			sRect.x0 = sourceRect->x0;
+			sRect.x1 = sourceRect->x1;
+			sRect.y0 = sourceRect->y0;
+			sRect.y1 = sourceRect->y1;
+			sRect.slice = sourceRect->slice;
 
 			if(sRect.x0 > sRect.x1)
 			{
@@ -556,10 +493,10 @@
 		}
 		else
 		{
-			sRect.y0 = 0;
-			sRect.x0 = 0;
-			sRect.y1 = sHeight;
-			sRect.x1 = sWidth;
+			sRect.y0 = 0.0f;
+			sRect.x0 = 0.0f;
+			sRect.y1 = (float)sHeight;
+			sRect.x1 = (float)sWidth;
 		}
 
 		if(destRect)
@@ -584,21 +521,47 @@
 			dRect.x1 = dWidth;
 		}
 
+		sw::Rect srcClipRect(0, 0, sWidth, sHeight);
+		ClipSrcRect(sRect, dRect, srcClipRect, flipX, flipY);
+
+		sw::Rect dstClipRect(0, 0, dWidth, dHeight);
+		ClipDstRect(sRect, dRect, dstClipRect, flipX, flipY);
+
+		if((sRect.width() == 0) || (sRect.height() == 0) ||
+		   (dRect.width() == 0) || (dRect.height() == 0))
+		{
+			return true; // no work to do
+		}
+
 		if(!validRectangle(&sRect, source) || !validRectangle(&dRect, dest))
 		{
 			ERR("Invalid parameters");
 			return false;
 		}
 
-		bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);
+		bool isDepth = (flags & Device::DEPTH_BUFFER) && Surface::isDepth(source->getInternalFormat());
+		bool isStencil = (flags & Device::STENCIL_BUFFER) && Surface::isStencil(source->getInternalFormat());
+		bool isColor = (flags & Device::COLOR_BUFFER) == Device::COLOR_BUFFER;
+
+		if(!isColor && !isDepth && !isStencil)
+		{
+			return true;
+		}
+
+		int sourceSliceB = isStencil ? source->getStencilSliceB() : source->getInternalSliceB();
+		int destSliceB = isStencil ? dest->getStencilSliceB() : dest->getInternalSliceB();
+		int sourcePitchB = isStencil ? source->getStencilPitchB() : source->getInternalPitchB();
+		int destPitchB = isStencil ? dest->getStencilPitchB() : dest->getInternalPitchB();
+
+		bool isOutOfBounds = (sRect.x0 < 0.0f) || (sRect.y0 < 0.0f) || (sRect.x1 > (float)sWidth) || (sRect.y1 > (float)sHeight);
+		bool scaling = (sRect.width() != (float)dRect.width()) || (sRect.height() != (float)dRect.height());
 		bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
 		bool hasQuadLayout = Surface::hasQuadLayout(source->getInternalFormat()) || Surface::hasQuadLayout(dest->getInternalFormat());
-		bool fullCopy = (sRect.x0 == 0) && (sRect.y0 == 0) && (dRect.x0 == 0) && (dRect.y0 == 0) &&
-		                (sRect.x1 == sWidth) && (sRect.y1 == sHeight) && (dRect.x1 == dWidth) && (dRect.y0 == dHeight);
-		bool isDepth = (flags & Device::DEPTH_BUFFER) && egl::Image::isDepth(source->getInternalFormat());
-		bool isStencil = (flags & Device::STENCIL_BUFFER) && (egl::Image::isDepth(source->getInternalFormat()) || egl::Image::isStencil(source->getInternalFormat()));
-		bool isColor = (flags & Device::COLOR_BUFFER) == Device::COLOR_BUFFER;
+		bool fullCopy = (sRect.x0 == 0.0f) && (sRect.y0 == 0.0f) && (dRect.x0 == 0) && (dRect.y0 == 0) &&
+		                (sRect.x1 == (float)sWidth) && (sRect.y1 == (float)sHeight) && (dRect.x1 == dWidth) && (dRect.y1 == dHeight);
 		bool alpha0xFF = false;
+		bool equalSlice = sourceSliceB == destSliceB;
+		bool smallMargin = sourcePitchB <= source->getWidth() * Surface::bytes(source->getInternalFormat()) + 16;
 
 		if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) ||
 		   (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8))
@@ -607,50 +570,46 @@
 			alpha0xFF = true;
 		}
 
-		if((isDepth || isStencil) && !scaling && equalFormats && (!hasQuadLayout || fullCopy))
+		if(fullCopy && !scaling && !isOutOfBounds && equalFormats && !alpha0xFF && equalSlice && smallMargin && !flipX && !flipY)
 		{
-			if(source->hasDepth() && isDepth)
-			{
-				sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(sRect.x0, sRect.y0, 0, LOCK_READONLY, PUBLIC);
-				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(dRect.x0, dRect.y0, 0, LOCK_DISCARD, PUBLIC);
+			byte *sourceBuffer = isStencil ? (byte*)source->lockStencil(0, 0, 0, PUBLIC) : (byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC);
+			byte *destBuffer = isStencil ? (byte*)dest->lockStencil(0, 0, 0, PUBLIC) : (byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC);
 
-				copyBuffer(sourceBuffer, destBuffer, dRect.width(), dRect.height(), source->getInternalPitchB(), dest->getInternalPitchB(), egl::Image::bytes(source->getInternalFormat()), flipX, flipY);
+			memcpy(destBuffer, sourceBuffer, sourceSliceB);
 
-				source->unlockInternal();
-				dest->unlockInternal();
-			}
-
-			if(source->hasStencil() && isStencil)
-			{
-				sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(sRect.x0, sRect.y0, 0, PUBLIC);
-				sw::byte *destBuffer = (sw::byte*)dest->lockStencil(dRect.x0, dRect.y0, 0, PUBLIC);
-
-				copyBuffer(sourceBuffer, destBuffer, source->getWidth(), source->getHeight(), source->getStencilPitchB(), dest->getStencilPitchB(), egl::Image::bytes(source->getStencilFormat()), flipX, flipY);
-
-				source->unlockStencil();
-				dest->unlockStencil();
-			}
+			isStencil ? source->unlockStencil() : source->unlockInternal();
+			isStencil ? dest->unlockStencil() : dest->unlockInternal();
 		}
-		else if((flags & Device::COLOR_BUFFER) && !scaling && equalFormats && (!hasQuadLayout || fullCopy))
+		else if(isDepth && !scaling && !isOutOfBounds && equalFormats && !hasQuadLayout)
 		{
-			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, sourceRect->slice, LOCK_READONLY, PUBLIC);
-			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, destRect->slice, LOCK_READWRITE, PUBLIC);
-			unsigned int sourcePitch = source->getInternalPitchB();
-			unsigned int destPitch = dest->getInternalPitchB();
+			byte *sourceBuffer = (byte*)source->lockInternal((int)sRect.x0, (int)sRect.y0, 0, LOCK_READONLY, PUBLIC);
+			byte *destBuffer = (byte*)dest->lockInternal(dRect.x0, dRect.y0, 0, fullCopy ? LOCK_DISCARD : LOCK_WRITEONLY, PUBLIC);
+
+			copyBuffer(sourceBuffer, destBuffer, dRect.width(), dRect.height(), sourcePitchB, destPitchB, Surface::bytes(source->getInternalFormat()), flipX, flipY);
+
+			source->unlockInternal();
+			dest->unlockInternal();
+		}
+		else if((flags & Device::COLOR_BUFFER) && !scaling && !isOutOfBounds && equalFormats && !hasQuadLayout)
+		{
+			byte *sourceBytes = (byte*)source->lockInternal((int)sRect.x0, (int)sRect.y0, sourceRect->slice, LOCK_READONLY, PUBLIC);
+			byte *destBytes = (byte*)dest->lockInternal(dRect.x0, dRect.y0, destRect->slice, fullCopy ? LOCK_DISCARD : LOCK_WRITEONLY, PUBLIC);
 
 			unsigned int width = dRect.x1 - dRect.x0;
 			unsigned int height = dRect.y1 - dRect.y0;
 
-			copyBuffer(sourceBytes, destBytes, width, height, sourcePitch, destPitch, egl::Image::bytes(source->getInternalFormat()), flipX, flipY);
+			copyBuffer(sourceBytes, destBytes, width, height, sourcePitchB, destPitchB, Surface::bytes(source->getInternalFormat()), flipX, flipY);
 
 			if(alpha0xFF)
 			{
-				for(unsigned int y = 0; y < height; ++y, destBytes += destPitch)
+				for(unsigned int y = 0; y < height; y++)
 				{
-					for(unsigned int x = 0; x < width; ++x)
+					for(unsigned int x = 0; x < width; x++)
 					{
 						destBytes[4 * x + 3] = 0xFF;
 					}
+
+					destBytes += destPitchB;
 				}
 			}
 
@@ -667,19 +626,17 @@
 			{
 				swap(dRect.y0, dRect.y1);
 			}
+
 			blit(source, sRect, dest, dRect, scaling && (flags & Device::USE_FILTER), isStencil);
 		}
-		else
-		{
-			UNREACHABLE(false);
-		}
+		else UNREACHABLE(false);
 
 		return true;
 	}
 
 	bool Device::stretchCube(sw::Surface *source, sw::Surface *dest)
 	{
-		if(!source || !dest || egl::Image::isDepth(source->getInternalFormat()) || egl::Image::isStencil(source->getInternalFormat()))
+		if(!source || !dest || Surface::isDepth(source->getInternalFormat()) || Surface::isStencil(source->getInternalFormat()))
 		{
 			ERR("Invalid parameters");
 			return false;
@@ -707,19 +664,20 @@
 		{
 			unsigned int sourcePitch = source->getInternalPitchB();
 			unsigned int destPitch = dest->getInternalPitchB();
-			unsigned int bytes = dWidth * egl::Image::bytes(source->getInternalFormat());
+			unsigned int bytes = dWidth * Surface::bytes(source->getInternalFormat());
 
-			for(int z = 0; z < dDepth; ++z)
+			for(int z = 0; z < dDepth; z++)
 			{
 				unsigned char *sourceBytes = (unsigned char*)source->lockInternal(0, 0, z, LOCK_READONLY, PUBLIC);
 				unsigned char *destBytes = (unsigned char*)dest->lockInternal(0, 0, z, LOCK_READWRITE, PUBLIC);
-				for(int y = 0; y < dHeight; ++y)
+
+				for(int y = 0; y < dHeight; y++)
 				{
 					memcpy(destBytes, sourceBytes, bytes);
 
 					if(alpha0xFF)
 					{
-						for(int x = 0; x < dWidth; ++x)
+						for(int x = 0; x < dWidth; x++)
 						{
 							destBytes[4 * x + 3] = 0xFF;
 						}
@@ -728,10 +686,10 @@
 					sourceBytes += sourcePitch;
 					destBytes += destPitch;
 				}
-			}
 
-			source->unlockInternal();
-			dest->unlockInternal();
+				source->unlockInternal();
+				dest->unlockInternal();
+			}
 		}
 		else
 		{
@@ -886,7 +844,7 @@
 			return false;
 		}
 
-		if(rect->x1 > (int)surface->getWidth() || rect->y1 > (int)surface->getHeight())
+		if(rect->x1 >(int)surface->getWidth() || rect->y1 >(int)surface->getHeight())
 		{
 			return false;
 		}
@@ -894,6 +852,141 @@
 		return true;
 	}
 
+	bool Device::validRectangle(const sw::RectF *rect, sw::Surface *surface)
+	{
+		if(!rect)
+		{
+			return true;
+		}
+
+		if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0)
+		{
+			return false;
+		}
+
+		return true;
+	}
+
+	void Device::ClipDstRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX, bool flipY)
+	{
+		if(dstRect.x0 < clipRect.x0)
+		{
+			float offset = (static_cast<float>(clipRect.x0 - dstRect.x0) / static_cast<float>(dstRect.width())) * srcRect.width();
+			if(flipX)
+			{
+				srcRect.x1 -= offset;
+			}
+			else
+			{
+				srcRect.x0 += offset;
+			}
+			dstRect.x0 = clipRect.x0;
+		}
+		if(dstRect.x1 > clipRect.x1)
+		{
+			float offset = (static_cast<float>(dstRect.x1 - clipRect.x1) / static_cast<float>(dstRect.width())) * srcRect.width();
+			if(flipX)
+			{
+				srcRect.x0 += offset;
+			}
+			else
+			{
+				srcRect.x1 -= offset;
+			}
+			dstRect.x1 = clipRect.x1;
+		}
+		if(dstRect.y0 < clipRect.y0)
+		{
+			float offset = (static_cast<float>(clipRect.y0 - dstRect.y0) / static_cast<float>(dstRect.height())) * srcRect.height();
+			if(flipY)
+			{
+				srcRect.y1 -= offset;
+			}
+			else
+			{
+				srcRect.y0 += offset;
+			}
+			dstRect.y0 = clipRect.y0;
+		}
+		if(dstRect.y1 > clipRect.y1)
+		{
+			float offset = (static_cast<float>(dstRect.y1 - clipRect.y1) / static_cast<float>(dstRect.height())) * srcRect.height();
+			if(flipY)
+			{
+				srcRect.y0 += offset;
+			}
+			else
+			{
+				srcRect.y1 -= offset;
+			}
+			dstRect.y1 = clipRect.y1;
+		}
+	}
+
+	void Device::ClipSrcRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX, bool flipY)
+	{
+		if(srcRect.x0 < static_cast<float>(clipRect.x0))
+		{
+			float ratio = static_cast<float>(dstRect.width()) / srcRect.width();
+			float offsetf = roundf((static_cast<float>(clipRect.x0) - srcRect.x0) * ratio);
+			int offset = static_cast<int>(offsetf);
+			if(flipX)
+			{
+				dstRect.x1 -= offset;
+			}
+			else
+			{
+				dstRect.x0 += offset;
+			}
+			srcRect.x0 += offsetf / ratio;
+		}
+		if(srcRect.x1 > static_cast<float>(clipRect.x1))
+		{
+			float ratio = static_cast<float>(dstRect.width()) / srcRect.width();
+			float offsetf = roundf((srcRect.x1 - static_cast<float>(clipRect.x1)) * ratio);
+			int offset = static_cast<int>(offsetf);
+			if(flipX)
+			{
+				dstRect.x0 += offset;
+			}
+			else
+			{
+				dstRect.x1 -= offset;
+			}
+			srcRect.x1 -= offsetf / ratio;
+		}
+		if(srcRect.y0 < static_cast<float>(clipRect.y0))
+		{
+			float ratio = static_cast<float>(dstRect.height()) / srcRect.height();
+			float offsetf = roundf((static_cast<float>(clipRect.y0) - srcRect.y0) * ratio);
+			int offset = static_cast<int>(offsetf);
+			if(flipY)
+			{
+				dstRect.y1 -= offset;
+			}
+			else
+			{
+				dstRect.y0 += offset;
+			}
+			srcRect.y0 += offsetf / ratio;
+		}
+		if(srcRect.y1 > static_cast<float>(clipRect.y1))
+		{
+			float ratio = static_cast<float>(dstRect.height()) / srcRect.height();
+			float offsetf = roundf((srcRect.y1 - static_cast<float>(clipRect.y1)) * ratio);
+			int offset = static_cast<int>(offsetf);
+			if(flipY)
+			{
+				dstRect.y0 += offset;
+			}
+			else
+			{
+				dstRect.y1 -= offset;
+			}
+			srcRect.y1 -= offsetf / ratio;
+		}
+	}
+
 	void Device::finish()
 	{
 		synchronize();
diff --git a/src/OpenGL/libGLESv2/Device.hpp b/src/OpenGL/libGLESv2/Device.hpp
index 17c7925..1b0636b 100644
--- a/src/OpenGL/libGLESv2/Device.hpp
+++ b/src/OpenGL/libGLESv2/Device.hpp
@@ -58,25 +58,26 @@
 		void clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask);
 		void clearDepth(float z);
 		void clearStencil(unsigned int stencil, unsigned int mask);
-		egl::Image *createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard);
-		egl::Image *createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable);
 		void drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount);
 		void drawPrimitive(sw::DrawType type, unsigned int primiveCount);
 		void setPixelShader(const sw::PixelShader *shader);
 		void setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);
 		void setScissorEnable(bool enable);
-		void setRenderTarget(int index, egl::Image *renderTarget);
-		void setDepthBuffer(egl::Image *depthBuffer);
-		void setStencilBuffer(egl::Image *stencilBuffer);
+		void setRenderTarget(int index, egl::Image *renderTarget, unsigned int layer);
+		void setDepthBuffer(egl::Image *depthBuffer, unsigned int layer);
+		void setStencilBuffer(egl::Image *stencilBuffer, unsigned int layer);
 		void setScissorRect(const sw::Rect &rect);
 		void setVertexShader(const sw::VertexShader *shader);
 		void setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);
 		void setViewport(const Viewport &viewport);
 
-		bool stretchRect(sw::Surface *sourceSurface, const sw::SliceRect *sourceRect, sw::Surface *destSurface, const sw::SliceRect *destRect, unsigned char flags);
+		bool stretchRect(sw::Surface *sourceSurface, const sw::SliceRectF *sourceRect, sw::Surface *destSurface, const sw::SliceRect *destRect, unsigned char flags);
 		bool stretchCube(sw::Surface *sourceSurface, sw::Surface *destSurface);
 		void finish();
 
+		static void ClipDstRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX = false, bool flipY = false);
+		static void ClipSrcRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX = false, bool flipY = false);
+
 	private:
 		sw::Context *const context;
 
@@ -85,6 +86,7 @@
 		bool bindViewport();   // Also adjusts for scissoring
 
 		bool validRectangle(const sw::Rect *rect, sw::Surface *surface);
+		bool validRectangle(const sw::RectF *rect, sw::Surface *surface);
 
 		void copyBuffer(sw::byte *sourceBuffer, sw::byte *destBuffer, unsigned int width, unsigned int height, unsigned int sourcePitch, unsigned int destPitch, unsigned int bytes, bool flipX, bool flipY);
 
diff --git a/src/OpenGL/libGLESv2/Framebuffer.cpp b/src/OpenGL/libGLESv2/Framebuffer.cpp
index fa01ff3..eaa7615 100644
--- a/src/OpenGL/libGLESv2/Framebuffer.cpp
+++ b/src/OpenGL/libGLESv2/Framebuffer.cpp
@@ -22,6 +22,8 @@
 #include "Texture.h"
 #include "utilities.h"
 
+#include <algorithm>
+
 namespace es2
 {
 
@@ -32,19 +34,23 @@
 
 Framebuffer::Framebuffer()
 {
-	for(int i = 0; i < MAX_COLOR_ATTACHMENTS; i++)
-	{
-		mColorbufferType[i] = GL_NONE;
-	}
-	mDepthbufferType = GL_NONE;
-	mStencilbufferType = GL_NONE;
-
-	readBuffer = GL_BACK;
-	drawBuffer[0] = GL_BACK;
-	for(int i = 1; i < MAX_COLOR_ATTACHMENTS; ++i)
+	readBuffer = GL_COLOR_ATTACHMENT0;
+	drawBuffer[0] = GL_COLOR_ATTACHMENT0;
+	for(int i = 1; i < MAX_COLOR_ATTACHMENTS; i++)
 	{
 		drawBuffer[i] = GL_NONE;
 	}
+
+	for(int i = 0; i < MAX_COLOR_ATTACHMENTS; i++)
+	{
+		mColorbufferType[i] = GL_NONE;
+		mColorbufferLayer[i] = 0;
+	}
+
+	mDepthbufferType = GL_NONE;
+	mDepthbufferLayer = 0;
+	mStencilbufferType = GL_NONE;
+	mStencilbufferLayer = 0;
 }
 
 Framebuffer::~Framebuffer()
@@ -57,7 +63,7 @@
 	mStencilbufferPointer = nullptr;
 }
 
-Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle, GLint level, GLint layer) const
+Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle, GLint level) const
 {
 	Context *context = getContext();
 	Renderbuffer *buffer = nullptr;
@@ -72,7 +78,7 @@
 	}
 	else if(IsTextureTarget(type))
 	{
-		buffer = context->getTexture(handle)->getRenderbuffer(type, level, layer);
+		buffer = context->getTexture(handle)->getRenderbuffer(type, level);
 	}
 	else UNREACHABLE(type);
 
@@ -82,19 +88,22 @@
 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer, GLuint index, GLint level, GLint layer)
 {
 	mColorbufferType[index] = (colorbuffer != 0) ? type : GL_NONE;
-	mColorbufferPointer[index] = lookupRenderbuffer(type, colorbuffer, level, layer);
+	mColorbufferPointer[index] = lookupRenderbuffer(type, colorbuffer, level);
+	mColorbufferLayer[index] = layer;
 }
 
 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer)
 {
 	mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE;
-	mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer, level, layer);
+	mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer, level);
+	mDepthbufferLayer = layer;
 }
 
 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer)
 {
 	mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE;
-	mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer, level, layer);
+	mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer, level);
+	mStencilbufferLayer = layer;
 }
 
 void Framebuffer::setReadBuffer(GLenum buf)
@@ -169,11 +178,14 @@
 // caller must Release() the returned surface
 egl::Image *Framebuffer::getRenderTarget(GLuint index)
 {
-	Renderbuffer *colorbuffer = mColorbufferPointer[index];
-
-	if(colorbuffer)
+	if(index < MAX_COLOR_ATTACHMENTS)
 	{
-		return colorbuffer->getRenderTarget();
+		Renderbuffer *colorbuffer = mColorbufferPointer[index];
+
+		if(colorbuffer)
+		{
+			return colorbuffer->getRenderTarget();
+		}
 	}
 
 	return nullptr;
@@ -181,8 +193,7 @@
 
 egl::Image *Framebuffer::getReadRenderTarget()
 {
-	Context *context = getContext();
-	return getRenderTarget(context->getReadFramebufferColorIndex());
+	return getRenderTarget(getReadBufferIndex());
 }
 
 // Increments refcount on surface.
@@ -220,8 +231,7 @@
 
 Renderbuffer *Framebuffer::getReadColorbuffer() const
 {
-	Context *context = getContext();
-	return getColorbuffer(context->getReadFramebufferColorIndex());
+	return getColorbuffer(getReadBufferIndex());
 }
 
 Renderbuffer *Framebuffer::getDepthbuffer() const
@@ -234,6 +244,16 @@
 	return mStencilbufferPointer;
 }
 
+GLenum Framebuffer::getReadBufferType()
+{
+	if(readBuffer == GL_NONE)
+	{
+		return GL_NONE;
+	}
+
+	return mColorbufferType[getReadBufferIndex()];
+}
+
 GLenum Framebuffer::getColorbufferType(GLuint index)
 {
 	return mColorbufferType[index];
@@ -266,18 +286,17 @@
 
 GLint Framebuffer::getColorbufferLayer(GLuint index)
 {
-	Renderbuffer *colorbuffer = mColorbufferPointer[index];
-	return colorbuffer ? colorbuffer->getLayer() : 0;
+	return mColorbufferLayer[index];
 }
 
 GLint Framebuffer::getDepthbufferLayer()
 {
-	return mDepthbufferPointer ? mDepthbufferPointer->getLayer() : 0;
+	return mDepthbufferLayer;
 }
 
 GLint Framebuffer::getStencilbufferLayer()
 {
-	return mStencilbufferPointer ? mStencilbufferPointer->getLayer() : 0;
+	return mStencilbufferLayer;
 }
 
 bool Framebuffer::hasStencil()
@@ -310,6 +329,8 @@
 	height = -1;
 	samples = -1;
 
+	GLint version = egl::getClientVersion();
+
 	for(int i = 0; i < MAX_COLOR_ATTACHMENTS; i++)
 	{
 		if(mColorbufferType[i] != GL_NONE)
@@ -321,14 +342,14 @@
 				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 			}
 
-			if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0 || (colorbuffer->getDepth() <= colorbuffer->getLayer()))
+			if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0 || (colorbuffer->getDepth() <= mColorbufferLayer[i]))
 			{
 				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 			}
 
 			if(IsRenderbuffer(mColorbufferType[i]))
 			{
-				if(!IsColorRenderable(colorbuffer->getFormat(), egl::getClientVersion(), false))
+				if(!IsColorRenderable(colorbuffer->getFormat(), version))
 				{
 					return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 				}
@@ -337,7 +358,7 @@
 			{
 				GLenum format = colorbuffer->getFormat();
 
-				if(!IsColorRenderable(format, egl::getClientVersion(), true))
+				if(!IsColorRenderable(format, version))
 				{
 					return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 				}
@@ -353,16 +374,26 @@
 				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 			}
 
-			width = colorbuffer->getWidth();
-			height = colorbuffer->getHeight();
-
-			if(samples == -1)
+			if(width == -1 || height == -1)
 			{
+				width = colorbuffer->getWidth();
+				height = colorbuffer->getHeight();
 				samples = colorbuffer->getSamples();
 			}
-			else if(samples != colorbuffer->getSamples())
+			else
 			{
-				return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+				if(version < 3 && (width != colorbuffer->getWidth() || height != colorbuffer->getHeight()))
+				{
+					return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+				}
+
+				if(samples != colorbuffer->getSamples())
+				{
+					return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
+				}
+
+				width = std::min(width, colorbuffer->getWidth());
+				height = std::min(height, colorbuffer->getHeight());
 			}
 		}
 	}
@@ -379,14 +410,14 @@
 			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 		}
 
-		if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
+		if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0 || (depthbuffer->getDepth() <= mDepthbufferLayer))
 		{
 			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 		}
 
 		if(IsRenderbuffer(mDepthbufferType))
 		{
-			if(!es2::IsDepthRenderable(depthbuffer->getFormat(), egl::getClientVersion()))
+			if(!es2::IsDepthRenderable(depthbuffer->getFormat(), version))
 			{
 				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 			}
@@ -410,13 +441,20 @@
 			height = depthbuffer->getHeight();
 			samples = depthbuffer->getSamples();
 		}
-		else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
+		else
 		{
-			return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
-		}
-		else if(samples != depthbuffer->getSamples())
-		{
-			return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+			if(version < 3 && (width != depthbuffer->getWidth() || height != depthbuffer->getHeight()))
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+			}
+
+			if(samples != depthbuffer->getSamples())
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
+			}
+
+			width = std::min(width, depthbuffer->getWidth());
+			height = std::min(height, depthbuffer->getHeight());
 		}
 	}
 
@@ -429,14 +467,14 @@
 			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 		}
 
-		if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
+		if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0 || (stencilbuffer->getDepth() <= mStencilbufferLayer))
 		{
 			return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 		}
 
 		if(IsRenderbuffer(mStencilbufferType))
 		{
-			if(!es2::IsStencilRenderable(stencilbuffer->getFormat(), egl::getClientVersion()))
+			if(!es2::IsStencilRenderable(stencilbuffer->getFormat(), version))
 			{
 				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 			}
@@ -462,17 +500,24 @@
 			height = stencilbuffer->getHeight();
 			samples = stencilbuffer->getSamples();
 		}
-		else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
+		else
 		{
-			return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
-		}
-		else if(samples != stencilbuffer->getSamples())
-		{
-			return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+			if(version < 3 && (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()))
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+			}
+
+			if(samples != stencilbuffer->getSamples())
+			{
+				return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
+			}
+
+			width = std::min(width, stencilbuffer->getWidth());
+			height = std::min(height, stencilbuffer->getHeight());
 		}
 	}
 
-	if((egl::getClientVersion() >= 3) && depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer))
+	if((version >= 3) && depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer))
 	{
 		// In the GLES 3.0 spec, section 4.4.4, Framebuffer Completeness:
 		// "The framebuffer object target is said to be framebuffer complete if all the following conditions are true:
@@ -497,57 +542,55 @@
 
 	if(colorbuffer)
 	{
-		switch(colorbuffer->getInternalFormat())
+		switch(colorbuffer->getFormat())
 		{
-		case sw::FORMAT_A8B8G8R8I:       return GL_RGBA_INTEGER;
-		case sw::FORMAT_A8B8G8R8UI:      return GL_RGBA_INTEGER;
-		case sw::FORMAT_A16B16G16R16I:   return GL_RGBA_INTEGER;
-		case sw::FORMAT_A16B16G16R16UI:  return GL_RGBA_INTEGER;
-		case sw::FORMAT_A32B32G32R32I:   return GL_RGBA_INTEGER;
-		case sw::FORMAT_A32B32G32R32UI:  return GL_RGBA_INTEGER;
-		case sw::FORMAT_A2B10G10R10:     return GL_RGB10_A2;
-		case sw::FORMAT_A8B8G8R8I_SNORM: return GL_RGBA;
-		case sw::FORMAT_A8B8G8R8:        return GL_RGBA;
-		case sw::FORMAT_SRGB8_A8:        return GL_RGBA;
-		case sw::FORMAT_A8R8G8B8:        return GL_BGRA_EXT;
-		case sw::FORMAT_A1R5G5B5:        return GL_BGRA_EXT;
-		case sw::FORMAT_X8B8G8R8I:       return GL_RGBA_INTEGER;
-		case sw::FORMAT_X8B8G8R8UI:      return GL_RGBA_INTEGER;
-		case sw::FORMAT_X16B16G16R16I:   return GL_RGBA_INTEGER;
-		case sw::FORMAT_X16B16G16R16UI:  return GL_RGBA_INTEGER;
-		case sw::FORMAT_X32B32G32R32I:   return GL_RGBA_INTEGER;
-		case sw::FORMAT_X32B32G32R32UI:  return GL_RGBA_INTEGER;
-		case sw::FORMAT_X8B8G8R8I_SNORM: return GL_RGBA;
-		case sw::FORMAT_SRGB8_X8:        return GL_RGBA;
-		case sw::FORMAT_X8B8G8R8:        return GL_RGBA;
-		case sw::FORMAT_X8R8G8B8:        return GL_BGRA_EXT;
-		case sw::FORMAT_R5G6B5:          return GL_RGB;
-		case sw::FORMAT_G8R8I:           return GL_RG_INTEGER;
-		case sw::FORMAT_G8R8UI:          return GL_RG_INTEGER;
-		case sw::FORMAT_G16R16I:         return GL_RG_INTEGER;
-		case sw::FORMAT_G16R16UI:        return GL_RG_INTEGER;
-		case sw::FORMAT_G32R32I:         return GL_RG_INTEGER;
-		case sw::FORMAT_G32R32UI:        return GL_RG_INTEGER;
-		case sw::FORMAT_R8I:             return GL_RED_INTEGER;
-		case sw::FORMAT_R8UI:            return GL_RED_INTEGER;
-		case sw::FORMAT_R16I:            return GL_RED_INTEGER;
-		case sw::FORMAT_R16UI:           return GL_RED_INTEGER;
-		case sw::FORMAT_R32I:            return GL_RED_INTEGER;
-		case sw::FORMAT_R32UI:           return GL_RED_INTEGER;
-		case sw::FORMAT_R8:              return GL_RED;
-		case sw::FORMAT_R8I_SNORM:       return GL_RED;
-		case sw::FORMAT_R16F:            return GL_RED;
-		case sw::FORMAT_R32F:            return GL_RED;
-		case sw::FORMAT_G8R8:            return GL_RG;
-		case sw::FORMAT_G8R8I_SNORM:     return GL_RG;
-		case sw::FORMAT_G16R16F:         return GL_RG;
-		case sw::FORMAT_G32R32F:         return GL_RG;
-		case sw::FORMAT_B16G16R16F:      return GL_RGB;
-		case sw::FORMAT_X32B32G32R32F:   return GL_RGBA;
-		case sw::FORMAT_A16B16G16R16F:   return GL_RGBA;
-		case sw::FORMAT_A32B32G32R32F:   return GL_RGBA;
+		case GL_BGRA8_EXT:      return GL_BGRA_EXT;
+		case GL_RGBA4:          return GL_RGBA;
+		case GL_RGB5_A1:        return GL_RGBA;
+		case GL_RGBA8:          return GL_RGBA;
+		case GL_RGB565:         return GL_RGBA;
+		case GL_RGB8:           return GL_RGB;
+		case GL_R8:             return GL_RED;
+		case GL_RG8:            return GL_RG;
+		case GL_R8I:            return GL_RED_INTEGER;
+		case GL_RG8I:           return GL_RG_INTEGER;
+		case GL_RGB8I:          return GL_RGB_INTEGER;
+		case GL_RGBA8I:         return GL_RGBA_INTEGER;
+		case GL_R8UI:           return GL_RED_INTEGER;
+		case GL_RG8UI:          return GL_RG_INTEGER;
+		case GL_RGB8UI:         return GL_RGB_INTEGER;
+		case GL_RGBA8UI:        return GL_RGBA_INTEGER;
+		case GL_R16I:           return GL_RED_INTEGER;
+		case GL_RG16I:          return GL_RG_INTEGER;
+		case GL_RGB16I:         return GL_RGB_INTEGER;
+		case GL_RGBA16I:        return GL_RGBA_INTEGER;
+		case GL_R16UI:          return GL_RED_INTEGER;
+		case GL_RG16UI:         return GL_RG_INTEGER;
+		case GL_RGB16UI:        return GL_RGB_INTEGER;
+		case GL_RGB10_A2UI:     return GL_RGBA_INTEGER;
+		case GL_RGBA16UI:       return GL_RGBA_INTEGER;
+		case GL_R32I:           return GL_RED_INTEGER;
+		case GL_RG32I:          return GL_RG_INTEGER;
+		case GL_RGB32I:         return GL_RGB_INTEGER;
+		case GL_RGBA32I:        return GL_RGBA_INTEGER;
+		case GL_R32UI:          return GL_RED_INTEGER;
+		case GL_RG32UI:         return GL_RG_INTEGER;
+		case GL_RGB32UI:        return GL_RGB_INTEGER;
+		case GL_RGBA32UI:       return GL_RGBA_INTEGER;
+		case GL_R16F:           return GL_RED;
+		case GL_RG16F:          return GL_RG;
+		case GL_R11F_G11F_B10F: return GL_RGB;
+		case GL_RGB16F:         return GL_RGB;
+		case GL_RGBA16F:        return GL_RGBA;
+		case GL_R32F:           return GL_RED;
+		case GL_RG32F:          return GL_RG;
+		case GL_RGB32F:         return GL_RGB;
+		case GL_RGBA32F:        return GL_RGBA;
+		case GL_RGB10_A2:       return GL_RGBA;
+		case GL_SRGB8:          return GL_RGB;
+		case GL_SRGB8_ALPHA8:   return GL_RGBA;
 		default:
-			UNREACHABLE(colorbuffer->getInternalFormat());
+			UNREACHABLE(colorbuffer->getFormat());
 		}
 	}
 
@@ -560,58 +603,55 @@
 
 	if(colorbuffer)
 	{
-		switch(colorbuffer->getInternalFormat())
+		switch(colorbuffer->getFormat())
 		{
-		case sw::FORMAT_R16F:            return GL_FLOAT;
-		case sw::FORMAT_G16R16F:         return GL_FLOAT;
-		case sw::FORMAT_B16G16R16F:      return GL_FLOAT;
-		case sw::FORMAT_A16B16G16R16F:   return GL_FLOAT;
-		case sw::FORMAT_R32F:            return GL_FLOAT;
-		case sw::FORMAT_G32R32F:         return GL_FLOAT;
-		case sw::FORMAT_B32G32R32F:      return GL_FLOAT;
-		case sw::FORMAT_X32B32G32R32F:   return GL_FLOAT;
-		case sw::FORMAT_A32B32G32R32F:   return GL_FLOAT;
-		case sw::FORMAT_R8I_SNORM:       return GL_BYTE;
-		case sw::FORMAT_G8R8I_SNORM:     return GL_BYTE;
-		case sw::FORMAT_X8B8G8R8I_SNORM: return GL_BYTE;
-		case sw::FORMAT_A8B8G8R8I_SNORM: return GL_BYTE;
-		case sw::FORMAT_R8:              return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_G8R8:            return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_SRGB8_X8:        return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_SRGB8_A8:        return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_A8R8G8B8:        return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_A8B8G8R8:        return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_X8R8G8B8:        return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_X8B8G8R8:        return GL_UNSIGNED_BYTE;
-		case sw::FORMAT_R8I:             return GL_INT;
-		case sw::FORMAT_G8R8I:           return GL_INT;
-		case sw::FORMAT_X8B8G8R8I:       return GL_INT;
-		case sw::FORMAT_A8B8G8R8I:       return GL_INT;
-		case sw::FORMAT_R16I:            return GL_INT;
-		case sw::FORMAT_G16R16I:         return GL_INT;
-		case sw::FORMAT_X16B16G16R16I:   return GL_INT;
-		case sw::FORMAT_A16B16G16R16I:   return GL_INT;
-		case sw::FORMAT_R32I:            return GL_INT;
-		case sw::FORMAT_G32R32I:         return GL_INT;
-		case sw::FORMAT_X32B32G32R32I:   return GL_INT;
-		case sw::FORMAT_A32B32G32R32I:   return GL_INT;
-		case sw::FORMAT_R8UI:            return GL_UNSIGNED_INT;
-		case sw::FORMAT_G8R8UI:          return GL_UNSIGNED_INT;
-		case sw::FORMAT_X8B8G8R8UI:      return GL_UNSIGNED_INT;
-		case sw::FORMAT_A8B8G8R8UI:      return GL_UNSIGNED_INT;
-		case sw::FORMAT_R16UI:           return GL_UNSIGNED_INT;
-		case sw::FORMAT_G16R16UI:        return GL_UNSIGNED_INT;
-		case sw::FORMAT_X16B16G16R16UI:  return GL_UNSIGNED_INT;
-		case sw::FORMAT_A16B16G16R16UI:  return GL_UNSIGNED_INT;
-		case sw::FORMAT_R32UI:           return GL_UNSIGNED_INT;
-		case sw::FORMAT_G32R32UI:        return GL_UNSIGNED_INT;
-		case sw::FORMAT_X32B32G32R32UI:  return GL_UNSIGNED_INT;
-		case sw::FORMAT_A32B32G32R32UI:  return GL_UNSIGNED_INT;
-		case sw::FORMAT_A2B10G10R10:     return GL_UNSIGNED_INT_10_10_10_2_OES;
-		case sw::FORMAT_A1R5G5B5:        return GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT;
-		case sw::FORMAT_R5G6B5:          return GL_UNSIGNED_SHORT_5_6_5;
+		case GL_BGRA8_EXT:      return GL_UNSIGNED_BYTE;
+		case GL_RGBA4:          return GL_UNSIGNED_SHORT_4_4_4_4;
+		case GL_RGB5_A1:        return GL_UNSIGNED_SHORT_5_5_5_1;
+		case GL_RGBA8:          return GL_UNSIGNED_BYTE;
+		case GL_RGB565:         return GL_UNSIGNED_SHORT_5_6_5;
+		case GL_RGB8:           return GL_UNSIGNED_BYTE;
+		case GL_R8:             return GL_UNSIGNED_BYTE;
+		case GL_RG8:            return GL_UNSIGNED_BYTE;
+		case GL_R8I:            return GL_INT;
+		case GL_RG8I:           return GL_INT;
+		case GL_RGB8I:          return GL_INT;
+		case GL_RGBA8I:         return GL_INT;
+		case GL_R8UI:           return GL_UNSIGNED_BYTE;
+		case GL_RG8UI:          return GL_UNSIGNED_BYTE;
+		case GL_RGB8UI:         return GL_UNSIGNED_BYTE;
+		case GL_RGBA8UI:        return GL_UNSIGNED_BYTE;
+		case GL_R16I:           return GL_INT;
+		case GL_RG16I:          return GL_INT;
+		case GL_RGB16I:         return GL_INT;
+		case GL_RGBA16I:        return GL_INT;
+		case GL_R16UI:          return GL_UNSIGNED_INT;
+		case GL_RG16UI:         return GL_UNSIGNED_INT;
+		case GL_RGB16UI:        return GL_UNSIGNED_INT;
+		case GL_RGB10_A2UI:     return GL_UNSIGNED_INT_2_10_10_10_REV;
+		case GL_RGBA16UI:       return GL_UNSIGNED_INT;
+		case GL_R32I:           return GL_INT;
+		case GL_RG32I:          return GL_INT;
+		case GL_RGB32I:         return GL_INT;
+		case GL_RGBA32I:        return GL_INT;
+		case GL_R32UI:          return GL_UNSIGNED_INT;
+		case GL_RG32UI:         return GL_UNSIGNED_INT;
+		case GL_RGB32UI:        return GL_UNSIGNED_INT;
+		case GL_RGBA32UI:       return GL_UNSIGNED_INT;
+		case GL_R16F:           return GL_FLOAT;
+		case GL_RG16F:          return GL_FLOAT;
+		case GL_R11F_G11F_B10F: return GL_FLOAT;
+		case GL_RGB16F:         return GL_FLOAT;
+		case GL_RGBA16F:        return GL_FLOAT;
+		case GL_R32F:           return GL_FLOAT;
+		case GL_RG32F:          return GL_FLOAT;
+		case GL_RGB32F:         return GL_FLOAT;
+		case GL_RGBA32F:        return GL_FLOAT;
+		case GL_RGB10_A2:       return GL_UNSIGNED_INT_2_10_10_10_REV;
+		case GL_SRGB8:          return GL_UNSIGNED_BYTE;
+		case GL_SRGB8_ALPHA8:   return GL_UNSIGNED_BYTE;
 		default:
-			UNREACHABLE(colorbuffer->getInternalFormat());
+			UNREACHABLE(colorbuffer->getFormat());
 		}
 	}
 
@@ -638,18 +678,16 @@
 
 	if(depthbuffer)
 	{
-		switch(depthbuffer->getInternalFormat())
+		switch(depthbuffer->getFormat())
 		{
-		case sw::FORMAT_D16:                return GL_UNSIGNED_SHORT;
-		case sw::FORMAT_D24S8:              return GL_UNSIGNED_INT_24_8_OES;
-		case sw::FORMAT_D32:                return GL_UNSIGNED_INT;
-		case sw::FORMAT_D32F:
-		case sw::FORMAT_D32F_COMPLEMENTARY:
-		case sw::FORMAT_D32F_LOCKABLE:
-		case sw::FORMAT_D32FS8_TEXTURE:
-		case sw::FORMAT_D32FS8_SHADOW:      return GL_FLOAT;
+		case GL_DEPTH_COMPONENT16:     return GL_UNSIGNED_SHORT;
+		case GL_DEPTH_COMPONENT24:     return GL_UNSIGNED_INT;
+		case GL_DEPTH_COMPONENT32_OES: return GL_UNSIGNED_INT;
+		case GL_DEPTH_COMPONENT32F:    return GL_FLOAT;
+		case GL_DEPTH24_STENCIL8:      return GL_UNSIGNED_INT_24_8_OES;
+		case GL_DEPTH32F_STENCIL8:     return GL_FLOAT;
 		default:
-			UNREACHABLE(depthbuffer->getInternalFormat());
+			UNREACHABLE(depthbuffer->getFormat());
 		}
 	}
 
@@ -657,12 +695,33 @@
 	return GL_NONE;
 }
 
+GLuint Framebuffer::getReadBufferIndex() const
+{
+	switch(readBuffer)
+	{
+	case GL_BACK:
+		return 0;
+	case GL_NONE:
+		return GL_INVALID_INDEX;
+	default:
+		return readBuffer - GL_COLOR_ATTACHMENT0;
+	}
+}
+
+DefaultFramebuffer::DefaultFramebuffer()
+{
+	readBuffer = GL_BACK;
+	drawBuffer[0] = GL_BACK;
+}
+
 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
 {
 	GLenum defaultRenderbufferType = egl::getClientVersion() < 3 ? GL_RENDERBUFFER : GL_FRAMEBUFFER_DEFAULT;
 	mColorbufferPointer[0] = new Renderbuffer(0, colorbuffer);
 	mColorbufferType[0] = defaultRenderbufferType;
 
+	readBuffer = GL_BACK;
+	drawBuffer[0] = GL_BACK;
 	for(int i = 1; i < MAX_COLOR_ATTACHMENTS; i++)
 	{
 		mColorbufferPointer[i] = nullptr;
diff --git a/src/OpenGL/libGLESv2/Framebuffer.h b/src/OpenGL/libGLESv2/Framebuffer.h
index 1405031..e1a3611 100644
--- a/src/OpenGL/libGLESv2/Framebuffer.h
+++ b/src/OpenGL/libGLESv2/Framebuffer.h
@@ -61,6 +61,7 @@
 	Renderbuffer *getDepthbuffer() const;
 	Renderbuffer *getStencilbuffer() const;
 
+	GLenum getReadBufferType();
 	GLenum getColorbufferType(GLuint index);
 	GLenum getDepthbufferType();
 	GLenum getStencilbufferType();
@@ -88,24 +89,31 @@
 	static bool IsRenderbuffer(GLenum type);
 
 protected:
-	GLenum mColorbufferType[MAX_COLOR_ATTACHMENTS];
-	gl::BindingPointer<Renderbuffer> mColorbufferPointer[MAX_COLOR_ATTACHMENTS];
+	GLuint getReadBufferIndex() const;
+
 	GLenum readBuffer;
 	GLenum drawBuffer[MAX_COLOR_ATTACHMENTS];
 
+	GLenum mColorbufferType[MAX_COLOR_ATTACHMENTS];
+	gl::BindingPointer<Renderbuffer> mColorbufferPointer[MAX_COLOR_ATTACHMENTS];
+	GLint mColorbufferLayer[MAX_COLOR_ATTACHMENTS];
+
 	GLenum mDepthbufferType;
 	gl::BindingPointer<Renderbuffer> mDepthbufferPointer;
+	GLint mDepthbufferLayer;
 
 	GLenum mStencilbufferType;
 	gl::BindingPointer<Renderbuffer> mStencilbufferPointer;
+	GLint mStencilbufferLayer;
 
 private:
-	Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle, GLint level, GLint layer) const;
+	Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle, GLint level) const;
 };
 
 class DefaultFramebuffer : public Framebuffer
 {
 public:
+	DefaultFramebuffer();
 	DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil);
 
 	bool isDefaultFramebuffer() const override { return true; }
diff --git a/src/OpenGL/libGLESv2/IndexDataManager.cpp b/src/OpenGL/libGLESv2/IndexDataManager.cpp
index 81d1c6a..55c15b2 100644
--- a/src/OpenGL/libGLESv2/IndexDataManager.cpp
+++ b/src/OpenGL/libGLESv2/IndexDataManager.cpp
@@ -63,37 +63,214 @@
 	else UNREACHABLE(type);
 }
 
-template<class IndexType>
-void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+inline GLsizei getNumIndices(const std::vector<GLsizei>& restartIndices, size_t i, GLsizei count)
 {
-	*minIndex = indices[0];
-	*maxIndex = indices[0];
+	return restartIndices.empty() ? count :
+	       ((i == 0) ? restartIndices[0] : ((i == restartIndices.size()) ? (count - restartIndices[i - 1] - 1) : (restartIndices[i] - restartIndices[i - 1] - 1)));
+}
+
+void copyIndices(GLenum mode, GLenum type, const std::vector<GLsizei>& restartIndices, const void *input, GLsizei count, void* output)
+{
+	size_t bytesPerIndex = 0;
+	const unsigned char* inPtr = static_cast<const unsigned char*>(input);
+	unsigned char* outPtr = static_cast<unsigned char*>(output);
+	switch(type)
+	{
+	case GL_UNSIGNED_BYTE:
+		bytesPerIndex = sizeof(GLubyte);
+		break;
+	case GL_UNSIGNED_INT:
+		bytesPerIndex = sizeof(GLuint);
+		break;
+	case GL_UNSIGNED_SHORT:
+		bytesPerIndex = sizeof(GLushort);
+		break;
+	default:
+		UNREACHABLE(type);
+	}
+
+	size_t numRestarts = restartIndices.size();
+	switch(mode)
+	{
+	case GL_TRIANGLES:
+	case GL_LINES:
+	case GL_POINTS:
+	{
+		GLsizei verticesPerPrimitive = (mode == GL_TRIANGLES) ? 3 : ((mode == GL_LINES) ? 2 : 1);
+		for(size_t i = 0; i <= numRestarts; ++i)
+		{
+			GLsizei numIndices = getNumIndices(restartIndices, i, count);
+			size_t numBytes = (numIndices / verticesPerPrimitive) * verticesPerPrimitive * bytesPerIndex;
+			if(numBytes > 0)
+			{
+				memcpy(outPtr, inPtr, numBytes);
+				outPtr += numBytes;
+			}
+			inPtr += (numIndices + 1) * bytesPerIndex;
+		}
+	}
+		break;
+	case GL_TRIANGLE_FAN:
+		for(size_t i = 0; i <= numRestarts; ++i)
+		{
+			GLsizei numIndices = getNumIndices(restartIndices, i, count);
+			GLsizei numTriangles = (numIndices - 2);
+			for(GLsizei tri = 0; tri < numTriangles; ++tri)
+			{
+				memcpy(outPtr, inPtr, bytesPerIndex);
+				outPtr += bytesPerIndex;
+				memcpy(outPtr, inPtr + ((tri + 1) * bytesPerIndex), bytesPerIndex + bytesPerIndex);
+				outPtr += bytesPerIndex + bytesPerIndex;
+			}
+			inPtr += (numIndices + 1) * bytesPerIndex;
+		}
+		break;
+	case GL_TRIANGLE_STRIP:
+		for(size_t i = 0; i <= numRestarts; ++i)
+		{
+			GLsizei numIndices = getNumIndices(restartIndices, i, count);
+			GLsizei numTriangles = (numIndices - 2);
+			for(GLsizei tri = 0; tri < numTriangles; ++tri)
+			{
+				if(tri & 1) // Reverse odd triangles
+				{
+					memcpy(outPtr, inPtr + ((tri + 1) * bytesPerIndex), bytesPerIndex);
+					outPtr += bytesPerIndex;
+					memcpy(outPtr, inPtr + ((tri + 0) * bytesPerIndex), bytesPerIndex);
+					outPtr += bytesPerIndex;
+					memcpy(outPtr, inPtr + ((tri + 2) * bytesPerIndex), bytesPerIndex);
+					outPtr += bytesPerIndex;
+				}
+				else
+				{
+					size_t numBytes = 3 * bytesPerIndex;
+					memcpy(outPtr, inPtr + (tri * bytesPerIndex), numBytes);
+					outPtr += numBytes;
+				}
+			}
+			inPtr += (numIndices + 1) * bytesPerIndex;
+		}
+		break;
+	case GL_LINE_LOOP:
+		for(size_t i = 0; i <= numRestarts; ++i)
+		{
+			GLsizei numIndices = getNumIndices(restartIndices, i, count);
+			if(numIndices >= 2)
+			{
+				GLsizei numLines = numIndices;
+				memcpy(outPtr, inPtr + (numIndices - 1) * bytesPerIndex, bytesPerIndex); // Last vertex
+				outPtr += bytesPerIndex;
+				memcpy(outPtr, inPtr, bytesPerIndex); // First vertex
+				outPtr += bytesPerIndex;
+				size_t bytesPerLine = 2 * bytesPerIndex;
+				for(GLsizei tri = 0; tri < (numLines - 1); ++tri)
+				{
+					memcpy(outPtr, inPtr + tri * bytesPerIndex, bytesPerLine);
+					outPtr += bytesPerLine;
+				}
+			}
+			inPtr += (numIndices + 1) * bytesPerIndex;
+		}
+		break;
+	case GL_LINE_STRIP:
+		for(size_t i = 0; i <= numRestarts; ++i)
+		{
+			GLsizei numIndices = getNumIndices(restartIndices, i, count);
+			GLsizei numLines = numIndices - 1;
+			size_t bytesPerLine = 2 * bytesPerIndex;
+			for(GLsizei tri = 0; tri < numLines; ++tri)
+			{
+				memcpy(outPtr, inPtr + tri * bytesPerIndex, bytesPerLine);
+				outPtr += bytesPerLine;
+			}
+			inPtr += (numIndices + 1) * bytesPerIndex;
+		}
+		break;
+	default:
+		UNREACHABLE(mode);
+		break;
+	}
+}
+
+template<class IndexType>
+void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex, std::vector<GLsizei>* restartIndices)
+{
+	*maxIndex = 0;
+	*minIndex = MAX_ELEMENTS_INDICES;
 
 	for(GLsizei i = 0; i < count; i++)
 	{
+		if(restartIndices && indices[i] == IndexType(-1))
+		{
+			restartIndices->push_back(i);
+			continue;
+		}
 		if(*minIndex > indices[i]) *minIndex = indices[i];
 		if(*maxIndex < indices[i]) *maxIndex = indices[i];
 	}
 }
 
-void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex, std::vector<GLsizei>* restartIndices)
 {
 	if(type == GL_UNSIGNED_BYTE)
 	{
-		computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
+		computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex, restartIndices);
 	}
 	else if(type == GL_UNSIGNED_INT)
 	{
-		computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
+		computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex, restartIndices);
 	}
 	else if(type == GL_UNSIGNED_SHORT)
 	{
-		computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
+		computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex, restartIndices);
 	}
 	else UNREACHABLE(type);
 }
 
-GLenum IndexDataManager::prepareIndexData(GLenum type, GLuint start, GLuint end, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated)
+int recomputePrimitiveCount(GLenum mode, GLsizei count, const std::vector<GLsizei>& restartIndices, unsigned int* primitiveCount)
+{
+	size_t numRestarts = restartIndices.size();
+	*primitiveCount = 0;
+
+	unsigned int countOffset = 0;
+	unsigned int vertexPerPrimitive = 0;
+
+	switch(mode)
+	{
+	case GL_TRIANGLES: // 3 vertex per primitive
+		++vertexPerPrimitive;
+	case GL_LINES: //  2 vertex per primitive
+		vertexPerPrimitive += 2;
+		for(size_t i = 0; i <= numRestarts; ++i)
+		{
+			unsigned int nbIndices = getNumIndices(restartIndices, i, count);
+			*primitiveCount += nbIndices / vertexPerPrimitive;
+		}
+		return vertexPerPrimitive;
+	case GL_TRIANGLE_FAN:
+	case GL_TRIANGLE_STRIP: // (N - 2) polygons, 3 vertex per primitive
+		++vertexPerPrimitive;
+		--countOffset;
+	case GL_LINE_STRIP: // (N - 1) polygons, 2 vertex per primitive
+		--countOffset;
+	case GL_LINE_LOOP: // N polygons, 2 vertex per primitive
+		vertexPerPrimitive += 2;
+		for(size_t i = 0; i <= numRestarts; ++i)
+		{
+			unsigned int nbIndices = getNumIndices(restartIndices, i, count);
+			*primitiveCount += (nbIndices >= vertexPerPrimitive) ? (nbIndices + countOffset) : 0;
+		}
+		return vertexPerPrimitive;
+	case GL_POINTS:
+		*primitiveCount = static_cast<unsigned int>(count - restartIndices.size());
+		return 1;
+	default:
+		UNREACHABLE(mode);
+		return -1;
+	}
+}
+
+GLenum IndexDataManager::prepareIndexData(GLenum mode, GLenum type, GLuint start, GLuint end, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated, bool primitiveRestart)
 {
 	if(!mStreamingBuffer)
 	{
@@ -112,14 +289,44 @@
 		indices = static_cast<const GLubyte*>(buffer->data()) + offset;
 	}
 
+	std::vector<GLsizei>* restartIndices = primitiveRestart ? new std::vector<GLsizei>() : nullptr;
+	computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex, restartIndices);
+
 	StreamingIndexBuffer *streamingBuffer = mStreamingBuffer;
 
 	sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;
 
-	if(staticBuffer)
+	if(restartIndices)
 	{
-		computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+		int vertexPerPrimitive = recomputePrimitiveCount(mode, count, *restartIndices, &translated->primitiveCount);
+		if(vertexPerPrimitive == -1)
+		{
+			delete restartIndices;
+			return GL_INVALID_ENUM;
+		}
 
+		size_t streamOffset = 0;
+		int convertCount = translated->primitiveCount * vertexPerPrimitive;
+
+		streamingBuffer->reserveSpace(convertCount * typeSize(type), type);
+		void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);
+
+		if(output == NULL)
+		{
+			delete restartIndices;
+			ERR("Failed to map index buffer.");
+			return GL_OUT_OF_MEMORY;
+		}
+
+		copyIndices(mode, type, *restartIndices, staticBuffer ? buffer->data() : indices, count, output);
+		streamingBuffer->unmap();
+
+		translated->indexBuffer = streamingBuffer->getResource();
+		translated->indexOffset = static_cast<unsigned int>(streamOffset);
+		delete restartIndices;
+	}
+	else if(staticBuffer)
+	{
 		translated->indexBuffer = staticBuffer;
 		translated->indexOffset = static_cast<unsigned int>(offset);
 	}
@@ -137,11 +344,9 @@
 			return GL_OUT_OF_MEMORY;
 		}
 
-		copyIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
+		copyIndices(type, indices, convertCount, output);
 		streamingBuffer->unmap();
 
-		computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
-
 		translated->indexBuffer = streamingBuffer->getResource();
 		translated->indexOffset = static_cast<unsigned int>(streamOffset);
 	}
diff --git a/src/OpenGL/libGLESv2/IndexDataManager.h b/src/OpenGL/libGLESv2/IndexDataManager.h
index 0a5e398..1834fbc 100644
--- a/src/OpenGL/libGLESv2/IndexDataManager.h
+++ b/src/OpenGL/libGLESv2/IndexDataManager.h
@@ -27,9 +27,12 @@
 
 struct TranslatedIndexData
 {
+	TranslatedIndexData(unsigned int primitiveCount) : primitiveCount(primitiveCount) {}
+
 	unsigned int minIndex;
 	unsigned int maxIndex;
 	unsigned int indexOffset;
+	unsigned int primitiveCount;
 
 	sw::Resource *indexBuffer;
 };
@@ -58,7 +61,7 @@
 	IndexDataManager();
 	virtual ~IndexDataManager();
 
-	GLenum prepareIndexData(GLenum type, GLuint start, GLuint end, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated);
+	GLenum prepareIndexData(GLenum mode, GLenum type, GLuint start, GLuint end, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated, bool primitiveRestart);
 
 	static std::size_t typeSize(GLenum type);
 
diff --git a/src/OpenGL/libGLESv2/Program.cpp b/src/OpenGL/libGLESv2/Program.cpp
index 7eda6f5..d2cff33 100644
--- a/src/OpenGL/libGLESv2/Program.cpp
+++ b/src/OpenGL/libGLESv2/Program.cpp
@@ -61,11 +61,11 @@
 		}
 	}
 
-	Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,
-	                 const BlockInfo &blockInfo)
-	 : type(type), precision(precision), name(name), arraySize(arraySize), blockInfo(blockInfo)
+	Uniform::Uniform(const glsl::Uniform &uniform, const BlockInfo &blockInfo)
+	 : type(uniform.type), precision(uniform.precision), name(uniform.name),
+	   arraySize(uniform.arraySize), blockInfo(blockInfo), fields(uniform.fields)
 	{
-		if(blockInfo.index == -1)
+		if((blockInfo.index == -1) && uniform.fields.empty())
 		{
 			size_t bytes = UniformTypeSize(type) * size();
 			data = new unsigned char[bytes];
@@ -261,13 +261,24 @@
 			std::string baseName(name);
 			unsigned int subscript = GL_INVALID_INDEX;
 			baseName = ParseUniformName(baseName, &subscript);
-			for(glsl::VaryingList::iterator input = fragmentShader->varyings.begin(); input != fragmentShader->varyings.end(); ++input)
+			for(auto const &varying : fragmentShader->varyings)
 			{
-				if(input->name == baseName)
+				if(varying.qualifier == EvqFragmentOut)
 				{
-					int rowCount = VariableRowCount(input->type);
-					int colCount = VariableColumnCount(input->type);
-					return (subscript == GL_INVALID_INDEX) ? input->reg : input->reg + (rowCount > 1 ? colCount * subscript : subscript);
+					if(varying.name == baseName)
+					{
+						ASSERT(varying.registerIndex >= 0);
+
+						if(subscript == GL_INVALID_INDEX)   // No subscript
+						{
+							return varying.registerIndex;
+						}
+
+						int rowCount = VariableRowCount(varying.type);
+						int colCount = VariableColumnCount(varying.type);
+
+						return varying.registerIndex + (rowCount > 1 ? colCount * subscript : subscript);
+					}
 				}
 			}
 		}
@@ -277,26 +288,19 @@
 
 	void Program::bindAttributeLocation(GLuint index, const char *name)
 	{
-		if(index < MAX_VERTEX_ATTRIBS)
-		{
-			for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
-			{
-				attributeBinding[i].erase(name);
-			}
-
-			attributeBinding[index].insert(name);
-		}
+		attributeBinding[name] = index;
 	}
 
 	GLint Program::getAttributeLocation(const char *name)
 	{
 		if(name)
 		{
-			for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+			std::string strName(name);
+			for(auto const &it : linkedAttribute)
 			{
-				if(linkedAttribute[index].name == std::string(name))
+				if(it.name == strName)
 				{
-					return index;
+					return getAttributeBinding(it);
 				}
 			}
 		}
@@ -364,6 +368,26 @@
 		return TEXTURE_2D;
 	}
 
+	bool Program::isUniformDefined(const std::string &name) const
+	{
+		unsigned int subscript = GL_INVALID_INDEX;
+		std::string baseName = es2::ParseUniformName(name, &subscript);
+
+		size_t numUniforms = uniformIndex.size();
+		for(size_t location = 0; location < numUniforms; location++)
+		{
+			const unsigned int index = uniformIndex[location].index;
+			if((uniformIndex[location].name == baseName) && ((index == GL_INVALID_INDEX) ||
+			   ((uniforms[index]->isArray() && uniformIndex[location].element == subscript) ||
+			    (subscript == GL_INVALID_INDEX))))
+			{
+				return true;
+			}
+		}
+
+		return false;
+	}
+
 	GLint Program::getUniformLocation(const std::string &name) const
 	{
 		unsigned int subscript = GL_INVALID_INDEX;
@@ -372,11 +396,9 @@
 		size_t numUniforms = uniformIndex.size();
 		for(size_t location = 0; location < numUniforms; location++)
 		{
-			const int index = uniformIndex[location].index;
-			const bool isArray = uniforms[index]->isArray();
-
-			if(uniformIndex[location].name == baseName &&
-			   ((isArray && uniformIndex[location].element == subscript) ||
+			const unsigned int index = uniformIndex[location].index;
+			if((index != GL_INVALID_INDEX) && (uniformIndex[location].name == baseName) &&
+			   ((uniforms[index]->isArray() && uniformIndex[location].element == subscript) ||
 			    (subscript == GL_INVALID_INDEX)))
 			{
 				return (GLint)location;
@@ -471,11 +493,20 @@
 
 	void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
 	{
+		if(uniformBlockIndex >= getActiveUniformBlockCount())
+		{
+			return error(GL_INVALID_VALUE);
+		}
+
 		uniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
 	}
 
 	GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
 	{
+		if(uniformBlockIndex >= getActiveUniformBlockCount())
+		{
+			return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
+		}
 		return uniformBlockBindings[uniformBlockIndex];
 	}
 
@@ -494,7 +525,7 @@
 		static GLenum floatType[] = { GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4 };
 		static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
 
-		if(location < 0 || location >= (int)uniformIndex.size())
+		if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
 		{
 			return false;
 		}
@@ -584,7 +615,7 @@
 			return false;
 		}
 
-		if(location < 0 || location >= (int)uniformIndex.size())
+		if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
 		{
 			return false;
 		}
@@ -681,7 +712,7 @@
 
 	bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
 	{
-		if(location < 0 || location >= (int)uniformIndex.size())
+		if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
 		{
 			return false;
 		}
@@ -698,7 +729,7 @@
 
 		count = std::min(size - (int)uniformIndex[location].element, count);
 
-		if(targetUniform->type == GL_INT || targetUniform->type == GL_UNSIGNED_INT || IsSamplerUniform(targetUniform->type))
+		if(targetUniform->type == GL_INT || IsSamplerUniform(targetUniform->type))
 		{
 			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint),
 				   v, sizeof(GLint) * count);
@@ -735,10 +766,9 @@
 	bool Program::setUniformiv(GLint location, GLsizei count, const GLint *v, int numElements)
 	{
 		static GLenum intType[] = { GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4 };
-		static GLenum uintType[] = { GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT_VEC4 };
 		static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
 
-		if(location < 0 || location >= (int)uniformIndex.size())
+		if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
 		{
 			return false;
 		}
@@ -756,7 +786,7 @@
 		count = std::min(size - (int)uniformIndex[location].element, count);
 
 		int index = numElements - 1;
-		if(targetUniform->type == intType[index] || targetUniform->type == uintType[index])
+		if(targetUniform->type == intType[index])
 		{
 			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint)* numElements,
 				   v, numElements * sizeof(GLint)* count);
@@ -800,7 +830,7 @@
 
 	bool Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
 	{
-		if(location < 0 || location >= (int)uniformIndex.size())
+		if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
 		{
 			return false;
 		}
@@ -817,7 +847,7 @@
 
 		count = std::min(size - (int)uniformIndex[location].element, count);
 
-		if(targetUniform->type == GL_INT || targetUniform->type == GL_UNSIGNED_INT || IsSamplerUniform(targetUniform->type))
+		if(targetUniform->type == GL_UNSIGNED_INT)
 		{
 			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint),
 				   v, sizeof(GLuint)* count);
@@ -853,11 +883,10 @@
 
 	bool Program::setUniformuiv(GLint location, GLsizei count, const GLuint *v, int numElements)
 	{
-		static GLenum intType[] = { GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4 };
 		static GLenum uintType[] = { GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT_VEC4 };
 		static GLenum boolType[] = { GL_BOOL, GL_BOOL_VEC2, GL_BOOL_VEC3, GL_BOOL_VEC4 };
 
-		if(location < 0 || location >= (int)uniformIndex.size())
+		if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
 		{
 			return false;
 		}
@@ -875,7 +904,7 @@
 		count = std::min(size - (int)uniformIndex[location].element, count);
 
 		int index = numElements - 1;
-		if(targetUniform->type == uintType[index] || targetUniform->type == intType[index])
+		if(targetUniform->type == uintType[index])
 		{
 			memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLuint)* numElements,
 				   v, numElements * sizeof(GLuint)* count);
@@ -919,7 +948,7 @@
 
 	bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
 	{
-		if(location < 0 || location >= (int)uniformIndex.size())
+		if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
 		{
 			return false;
 		}
@@ -977,7 +1006,7 @@
 
 	bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
 	{
-		if(location < 0 || location >= (int)uniformIndex.size())
+		if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
 		{
 			return false;
 		}
@@ -1026,7 +1055,7 @@
 
 	bool Program::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
 	{
-		if(location < 0 || location >= (int)uniformIndex.size())
+		if(location < 0 || location >= (int)uniformIndex.size() || (uniformIndex[location].index == GL_INVALID_INDEX))
 		{
 			return false;
 		}
@@ -1088,7 +1117,7 @@
 		GLint numUniforms = static_cast<GLint>(uniformIndex.size());
 		for(GLint location = 0; location < numUniforms; location++)
 		{
-			if(uniformIndex[location].element != 0)
+			if((uniformIndex[location].element != 0) || (uniformIndex[location].index == GL_INVALID_INDEX))
 			{
 				continue;
 			}
@@ -1124,6 +1153,7 @@
 				case GL_FLOAT_MAT4:   applyUniformMatrix4fv(device, location, size, f);   break;
 				case GL_SAMPLER_2D:
 				case GL_SAMPLER_CUBE:
+				case GL_SAMPLER_2D_RECT_ARB:
 				case GL_SAMPLER_EXTERNAL_OES:
 				case GL_SAMPLER_3D_OES:
 				case GL_SAMPLER_2D_ARRAY:
@@ -1294,21 +1324,36 @@
 
 	bool Program::linkVaryings()
 	{
-		for(glsl::VaryingList::iterator input = fragmentShader->varyings.begin(); input != fragmentShader->varyings.end(); ++input)
+		glsl::VaryingList &psVaryings = fragmentShader->varyings;
+		glsl::VaryingList &vsVaryings = vertexShader->varyings;
+
+		for(auto const &input : psVaryings)
 		{
 			bool matched = false;
 
-			for(glsl::VaryingList::iterator output = vertexShader->varyings.begin(); output != vertexShader->varyings.end(); ++output)
+			for(auto const &output : vsVaryings)
 			{
-				if(output->name == input->name)
+				if(output.name == input.name)
 				{
-					if(output->type != input->type || output->size() != input->size())
+					if(output.type != input.type || output.size() != input.size())
 					{
-						appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
+						appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output.name.c_str());
 
 						return false;
 					}
 
+					if((output.qualifier == EvqFlatOut) ^ (input.qualifier == EvqFlatIn))
+					{
+						appendToInfoLog("Interpolation qualifiers for %s differ between vertex and fragment shaders", output.name.c_str());
+
+						return false;
+					}
+
+					if(!areMatchingFields(input.fields, output.fields, input.name))
+					{
+						return false;
+					}
+
 					matched = true;
 					break;
 				}
@@ -1316,31 +1361,35 @@
 
 			if(!matched)
 			{
-				appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
+				// If a fragment varying is declared but not statically used, it's not an error to not have a matching vertex varying.
+				if(input.registerIndex >= 0)
+				{
+					appendToInfoLog("Fragment varying %s does not match any vertex varying", input.name.c_str());
 
-				return false;
+					return false;
+				}
 			}
 		}
 
-		glsl::VaryingList &psVaryings = fragmentShader->varyings;
-		glsl::VaryingList &vsVaryings = vertexShader->varyings;
-
-		for(glsl::VaryingList::iterator output = vsVaryings.begin(); output != vsVaryings.end(); ++output)
+		for(auto const &output : vsVaryings)
 		{
 			bool matched = false;
 
-			for(glsl::VaryingList::iterator input = psVaryings.begin(); input != psVaryings.end(); ++input)
+			for(auto const &input : psVaryings)
 			{
-				if(output->name == input->name)
+				if(output.name == input.name)
 				{
-					int in = input->reg;
-					int out = output->reg;
-					int components = VariableRegisterSize(output->type);
-					int registers = VariableRegisterCount(output->type) * output->size();
+					int in = input.registerIndex;
+					int out = output.registerIndex;
+					int components = VariableRegisterSize(output.type);
+					int registers = VariableRegisterCount(output.type) * output.size();
 
-					ASSERT(in >= 0);
+					if(in < 0)  // Fragment varying declared but not used
+					{
+						continue;
+					}
 
-					if(in + registers > MAX_VARYING_VECTORS)
+					if(in + registers >= MAX_VARYING_VECTORS)
 					{
 						appendToInfoLog("Too many varyings");
 						return false;
@@ -1348,7 +1397,7 @@
 
 					if(out >= 0)
 					{
-						if(out + registers > MAX_VARYING_VECTORS)
+						if(out + registers >= MAX_VARYING_VECTORS)
 						{
 							appendToInfoLog("Too many varyings");
 							return false;
@@ -1379,15 +1428,15 @@
 				{
 					std::string tfVaryingName = es2::ParseUniformName(indexedTfVaryingName, nullptr);
 
-					if(tfVaryingName == output->name)
+					if(tfVaryingName == output.name)
 					{
-						int out = output->reg;
-						int components = VariableRegisterSize(output->type);
-						int registers = VariableRegisterCount(output->type) * output->size();
+						int out = output.registerIndex;
+						int components = VariableRegisterSize(output.type);
+						int registers = VariableRegisterCount(output.type) * output.size();
 
 						if(out >= 0)
 						{
-							if(out + registers > MAX_VARYING_VECTORS)
+							if(out + registers >= MAX_VARYING_VECTORS)
 							{
 								appendToInfoLog("Too many varyings");
 								return false;
@@ -1459,12 +1508,12 @@
 
 					totalComponents += componentCount;
 
-					int reg = varying.reg;
+					int reg = varying.registerIndex;
 					if(hasSubscript)
 					{
 						reg += rowCount > 1 ? colCount * subscript : subscript;
 					}
-					int col = varying.col;
+					int col = varying.column;
 					if(tfVaryingName == "gl_PointSize")
 					{
 						// Point size is stored in the y element of the vector, not the x element
@@ -1559,73 +1608,81 @@
 		unsigned int usedLocations = 0;
 
 		// Link attributes that have a binding location
-		for(glsl::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); ++attribute)
+		for(auto const &attribute : vertexShader->activeAttributes)
 		{
-			int location = getAttributeBinding(*attribute);
+			int location = (attributeBinding.find(attribute.name) != attributeBinding.end()) ? attributeBinding[attribute.name] : -1;
 
 			if(location != -1)   // Set by glBindAttribLocation
 			{
-				int rows = VariableRegisterCount(attribute->type);
+				int rows = VariableRegisterCount(attribute.type);
 
 				if(rows + location > MAX_VERTEX_ATTRIBS)
 				{
-					appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
+					appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
 					return false;
 				}
 
 				// In GLSL 3.00, attribute aliasing produces a link error
 				// In GLSL 1.00, attribute aliasing is allowed
-				if(egl::getClientVersion() >= 3)
+				if(vertexShader->getShaderVersion() >= 300)
 				{
-					for(int i = 0; i < rows; i++)
+					for(auto const &it : linkedAttribute)
 					{
-						if(!linkedAttribute[location + i].name.empty())
+						int itLocStart = getAttributeBinding(it);
+						ASSERT(itLocStart >= 0);
+						int itLocEnd = itLocStart + VariableRegisterCount(it.type);
+						for(int i = 0; i < rows; i++)
 						{
-							appendToInfoLog("Attribute '%s' aliases attribute '%s' at location %d", attribute->name.c_str(), linkedAttribute[location].name.c_str(), location);
-							return false;
+							int loc = location + i;
+							if((loc >= itLocStart) && (loc < itLocEnd))
+							{
+								appendToInfoLog("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), it.name.c_str(), location);
+								return false;
+							}
 						}
 					}
 				}
 
+				linkedAttributeLocation[attribute.name] = location;
+				linkedAttribute.push_back(attribute);
 				for(int i = 0; i < rows; i++)
 				{
-					linkedAttribute[location + i] = *attribute;
 					usedLocations |= 1 << (location + i);
 				}
 			}
 		}
 
 		// Link attributes that don't have a binding location
-		for(glsl::ActiveAttributes::iterator attribute = vertexShader->activeAttributes.begin(); attribute != vertexShader->activeAttributes.end(); ++attribute)
+		for(auto const &attribute : vertexShader->activeAttributes)
 		{
-			int location = getAttributeBinding(*attribute);
+			int location = (attributeBinding.find(attribute.name) != attributeBinding.end()) ? attributeBinding[attribute.name] : -1;
 
 			if(location == -1)   // Not set by glBindAttribLocation
 			{
-				int rows = VariableRegisterCount(attribute->type);
+				int rows = VariableRegisterCount(attribute.type);
 				int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
 
 				if(availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
 				{
-					appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
+					appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
 					return false;   // Fail to link
 				}
 
-				for(int i = 0; i < rows; i++)
-				{
-					linkedAttribute[availableIndex + i] = *attribute;
-				}
+				linkedAttributeLocation[attribute.name] = availableIndex;
+				linkedAttribute.push_back(attribute);
 			}
 		}
 
-		for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
+		for(auto const &it : linkedAttribute)
 		{
-			int index = vertexShader->getSemanticIndex(linkedAttribute[attributeIndex].name);
-			int rows = std::max(VariableRegisterCount(linkedAttribute[attributeIndex].type), 1);
+			int location = getAttributeBinding(it);
+			ASSERT(location >= 0);
+			int index = vertexShader->getSemanticIndex(it.name);
+			int rows = std::max(VariableRegisterCount(it.type), 1);
 
 			for(int r = 0; r < rows; r++)
 			{
-				attributeStream[attributeIndex++] = index++;
+				attributeStream[r + location] = index++;
 			}
 		}
 
@@ -1639,12 +1696,10 @@
 			return attribute.location;
 		}
 
-		for(int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
+		std::map<std::string, GLuint>::const_iterator it = linkedAttributeLocation.find(attribute.name);
+		if(it != linkedAttributeLocation.end())
 		{
-			if(attributeBinding[location].find(attribute.name.c_str()) != attributeBinding[location].end())
-			{
-				return location;
-			}
+			return it->second;
 		}
 
 		return -1;
@@ -1652,12 +1707,8 @@
 
 	bool Program::linkUniforms(const Shader *shader)
 	{
-		const glsl::ActiveUniforms &activeUniforms = shader->activeUniforms;
-
-		for(unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)
+		for(const auto &uniform : shader->activeUniforms)
 		{
-			const glsl::Uniform &uniform = activeUniforms[uniformIndex];
-
 			unsigned int blockIndex = GL_INVALID_INDEX;
 			if(uniform.blockId >= 0)
 			{
@@ -1666,7 +1717,15 @@
 				blockIndex = getUniformBlockIndex(activeUniformBlocks[uniform.blockId].name);
 				ASSERT(blockIndex != GL_INVALID_INDEX);
 			}
-			if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex, Uniform::BlockInfo(uniform, blockIndex)))
+			if(!defineUniform(shader->getType(), uniform, Uniform::BlockInfo(uniform, blockIndex)))
+			{
+				return false;
+			}
+		}
+
+		for(const auto &uniformStruct : shader->activeUniformStructs)
+		{
+			if(!validateUniformStruct(shader->getType(), uniformStruct))
 			{
 				return false;
 			}
@@ -1675,11 +1734,11 @@
 		return true;
 	}
 
-	bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex, const Uniform::BlockInfo& blockInfo)
+	bool Program::defineUniform(GLenum shader, const glsl::Uniform &glslUniform, const Uniform::BlockInfo& blockInfo)
 	{
-		if(IsSamplerUniform(type))
+		if(IsSamplerUniform(glslUniform.type))
 	    {
-			int index = registerIndex;
+			int index = glslUniform.registerIndex;
 
 			do
 			{
@@ -1689,9 +1748,9 @@
 					{
 						samplersVS[index].active = true;
 
-						switch(type)
+						switch(glslUniform.type)
 						{
-						default:                      UNREACHABLE(type);
+						default:                      UNREACHABLE(glslUniform.type);
 						case GL_INT_SAMPLER_2D:
 						case GL_UNSIGNED_INT_SAMPLER_2D:
 						case GL_SAMPLER_2D_SHADOW:
@@ -1703,6 +1762,7 @@
 						case GL_INT_SAMPLER_3D:
 						case GL_UNSIGNED_INT_SAMPLER_3D:
 						case GL_SAMPLER_3D_OES:       samplersVS[index].textureType = TEXTURE_3D;       break;
+						case GL_SAMPLER_2D_RECT_ARB:  samplersVS[index].textureType = TEXTURE_2D_RECT;  break;
 						case GL_SAMPLER_EXTERNAL_OES: samplersVS[index].textureType = TEXTURE_EXTERNAL; break;
 						case GL_INT_SAMPLER_2D_ARRAY:
 						case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
@@ -1724,9 +1784,9 @@
 					{
 						samplersPS[index].active = true;
 
-						switch(type)
+						switch(glslUniform.type)
 						{
-						default:                      UNREACHABLE(type);
+						default:                      UNREACHABLE(glslUniform.type);
 						case GL_INT_SAMPLER_2D:
 						case GL_UNSIGNED_INT_SAMPLER_2D:
 						case GL_SAMPLER_2D_SHADOW:
@@ -1738,6 +1798,7 @@
 						case GL_INT_SAMPLER_3D:
 						case GL_UNSIGNED_INT_SAMPLER_3D:
 						case GL_SAMPLER_3D_OES:       samplersPS[index].textureType = TEXTURE_3D;       break;
+						case GL_SAMPLER_2D_RECT_ARB:  samplersPS[index].textureType = TEXTURE_2D_RECT;  break;
 						case GL_SAMPLER_EXTERNAL_OES: samplersPS[index].textureType = TEXTURE_EXTERNAL; break;
 						case GL_INT_SAMPLER_2D_ARRAY:
 						case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
@@ -1757,31 +1818,36 @@
 
 				index++;
 			}
-			while(index < registerIndex + static_cast<int>(arraySize));
+			while(index < glslUniform.registerIndex + static_cast<int>(glslUniform.arraySize));
 	    }
 
 		Uniform *uniform = 0;
-		GLint location = getUniformLocation(name);
+		GLint location = getUniformLocation(glslUniform.name);
 
 		if(location >= 0)   // Previously defined, types must match
 		{
 			uniform = uniforms[uniformIndex[location].index];
 
-			if(uniform->type != type)
+			if(uniform->type != glslUniform.type)
 			{
 				appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
 				return false;
 			}
 
-			if(uniform->precision != precision)
+			if(uniform->precision != glslUniform.precision)
 			{
 				appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
 				return false;
 			}
+
+			if(!areMatchingFields(uniform->fields, glslUniform.fields, uniform->name))
+			{
+				return false;
+			}
 		}
 		else
 		{
-			uniform = new Uniform(type, precision, name, arraySize, blockInfo);
+			uniform = new Uniform(glslUniform, blockInfo);
 		}
 
 		if(!uniform)
@@ -1791,28 +1857,28 @@
 
 		if(shader == GL_VERTEX_SHADER)
 		{
-			uniform->vsRegisterIndex = registerIndex;
+			uniform->vsRegisterIndex = glslUniform.registerIndex;
 		}
 		else if(shader == GL_FRAGMENT_SHADER)
 		{
-			uniform->psRegisterIndex = registerIndex;
+			uniform->psRegisterIndex = glslUniform.registerIndex;
 		}
 		else UNREACHABLE(shader);
 
-		if(location == -1)   // Not previously defined
+		if(!isUniformDefined(glslUniform.name))
 		{
 			uniforms.push_back(uniform);
-			unsigned int index = static_cast<unsigned int>(uniforms.size() - 1);
+			unsigned int index = (blockInfo.index == -1) ? static_cast<unsigned int>(uniforms.size() - 1) : GL_INVALID_INDEX;
 
 			for(int i = 0; i < uniform->size(); i++)
 			{
-				uniformIndex.push_back(UniformLocation(name, i, index));
+				uniformIndex.push_back(UniformLocation(glslUniform.name, i, index));
 			}
 		}
 
 		if(shader == GL_VERTEX_SHADER)
 		{
-			if(registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)
+			if(glslUniform.registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)
 			{
 				appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS);
 				return false;
@@ -1820,7 +1886,7 @@
 		}
 		else if(shader == GL_FRAGMENT_SHADER)
 		{
-			if(registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)
+			if(glslUniform.registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)
 			{
 				appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS);
 				return false;
@@ -1831,19 +1897,37 @@
 		return true;
 	}
 
+	bool Program::validateUniformStruct(GLenum shader, const glsl::Uniform &newUniformStruct)
+	{
+		for(const auto &uniformStruct : uniformStructs)
+		{
+			if(uniformStruct.name == newUniformStruct.name)
+			{
+				return areMatchingFields(uniformStruct.fields, newUniformStruct.fields, newUniformStruct.name);
+			}
+		}
+
+		uniformStructs.push_back(Uniform(newUniformStruct, Uniform::BlockInfo(newUniformStruct, -1)));
+
+		return true;
+	}
+
 	bool Program::areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2)
 	{
 		// validate blocks for the same member types
 		if(block1.fields.size() != block2.fields.size())
 		{
+			appendToInfoLog("Types for interface block '%s' differ between vertex and fragment shaders", block1.name.c_str());
 			return false;
 		}
 		if(block1.arraySize != block2.arraySize)
 		{
+			appendToInfoLog("Array sizes differ for interface block '%s' between vertex and fragment shaders", block1.name.c_str());
 			return false;
 		}
 		if(block1.layout != block2.layout || block1.isRowMajorLayout != block2.isRowMajorLayout)
 		{
+			appendToInfoLog("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", block1.name.c_str());
 			return false;
 		}
 		const size_t numBlockMembers = block1.fields.size();
@@ -1851,14 +1935,68 @@
 		{
 			const glsl::Uniform& member1 = shader1->activeUniforms[block1.fields[blockMemberIndex]];
 			const glsl::Uniform& member2 = shader2->activeUniforms[block2.fields[blockMemberIndex]];
-			if(member1.name != member2.name ||
-			   member1.arraySize != member2.arraySize ||
-			   member1.precision != member2.precision ||
-			   member1.type != member2.type)
+			if(member1.name != member2.name)
+			{
+				appendToInfoLog("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
+				                blockMemberIndex, block1.name.c_str(), member1.name.c_str(), member2.name.c_str());
+				return false;
+			}
+			if(member1.arraySize != member2.arraySize)
+			{
+				appendToInfoLog("Array sizes for %s differ between vertex and fragment shaders", member1.name.c_str());
+				return false;
+			}
+			if(member1.precision != member2.precision)
+			{
+				appendToInfoLog("Precisions for %s differ between vertex and fragment shaders", member1.name.c_str());
+				return false;
+			}
+			if(member1.type != member2.type)
+			{
+				appendToInfoLog("Types for %s differ between vertex and fragment shaders", member1.name.c_str());
+				return false;
+			}
+			if(member1.blockInfo.isRowMajorMatrix != member2.blockInfo.isRowMajorMatrix)
+			{
+				appendToInfoLog("Matrix packings for %s differ between vertex and fragment shaders", member1.name.c_str());
+				return false;
+			}
+		}
+		return true;
+	}
+
+	bool Program::areMatchingFields(const std::vector<glsl::ShaderVariable>& fields1, const std::vector<glsl::ShaderVariable>& fields2, const std::string& name)
+	{
+		if(fields1.size() != fields2.size())
+		{
+			appendToInfoLog("Structure lengths for %s differ between vertex and fragment shaders", name.c_str());
+			return false;
+		}
+
+		for(size_t i = 0; i < fields1.size(); ++i)
+		{
+			if(fields1[i].name != fields2[i].name)
+			{
+				appendToInfoLog("Name mismatch for field '%d' of %s: ('%s', '%s')",
+				                i, name.c_str(), fields1[i].name.c_str(), fields2[i].name.c_str());
+				return false;
+			}
+			if(fields1[i].type != fields2[i].type)
+			{
+				appendToInfoLog("Type for %s.%s differ between vertex and fragment shaders", name.c_str(), fields1[i].name.c_str());
+				return false;
+			}
+			if(fields1[i].arraySize != fields2[i].arraySize)
+			{
+				appendToInfoLog("Array size for %s.%s differ between vertex and fragment shaders", name.c_str(), fields1[i].name.c_str());
+				return false;
+			}
+			if(!areMatchingFields(fields1[i].fields, fields2[i].fields, fields1[i].name))
 			{
 				return false;
 			}
 		}
+
 		return true;
 	}
 
@@ -2478,9 +2616,11 @@
 		delete pixelBinary;
 		pixelBinary = 0;
 
+		linkedAttribute.clear();
+		linkedAttributeLocation.clear();
+
 		for(int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
 		{
-			linkedAttribute[index].name.clear();
 			attributeStream[index] = -1;
 		}
 
@@ -2616,27 +2756,13 @@
 
 	void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
 	{
-		// Skip over inactive attributes
-		unsigned int activeAttribute = 0;
-		unsigned int attribute;
-		for(attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
-		{
-			if(linkedAttribute[attribute].name.empty())
-			{
-				continue;
-			}
+		ASSERT(index < linkedAttribute.size());
 
-			if(activeAttribute == index)
-			{
-				break;
-			}
-
-			activeAttribute++;
-		}
+		std::vector<glsl::Attribute>::const_iterator it = linkedAttribute.begin() + index;
 
 		if(bufsize > 0)
 		{
-			const char *string = linkedAttribute[attribute].name.c_str();
+			const char *string = it->name.c_str();
 
 			strncpy(name, string, bufsize);
 			name[bufsize - 1] = '\0';
@@ -2649,34 +2775,23 @@
 
 		*size = 1;   // Always a single 'type' instance
 
-		*type = linkedAttribute[attribute].type;
+		*type = it->type;
 	}
 
 	size_t Program::getActiveAttributeCount() const
 	{
-		int count = 0;
-
-		for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
-		{
-			if(!linkedAttribute[attributeIndex].name.empty())
-			{
-				count++;
-			}
-		}
-
-		return count;
+		return linkedAttribute.size();
 	}
 
 	GLint Program::getActiveAttributeMaxLength() const
 	{
 		int maxLength = 0;
 
-		for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+		std::vector<glsl::Attribute>::const_iterator it = linkedAttribute.begin();
+		std::vector<glsl::Attribute>::const_iterator itEnd = linkedAttribute.end();
+		for(; it != itEnd; ++it)
 		{
-			if(!linkedAttribute[attributeIndex].name.empty())
-			{
-				maxLength = std::max((int)(linkedAttribute[attributeIndex].name.length() + 1), maxLength);
-			}
+			maxLength = std::max((int)(it->name.length() + 1), maxLength);
 		}
 
 		return maxLength;
@@ -2755,7 +2870,10 @@
 
 	void Program::getActiveUniformBlockName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const
 	{
-		ASSERT(index < getActiveUniformBlockCount());
+		if(index >= getActiveUniformBlockCount())
+		{
+			return error(GL_INVALID_VALUE);
+		}
 
 		const UniformBlock &uniformBlock = *uniformBlocks[index];
 
diff --git a/src/OpenGL/libGLESv2/Program.h b/src/OpenGL/libGLESv2/Program.h
index 9d4621e..4d89d7a 100644
--- a/src/OpenGL/libGLESv2/Program.h
+++ b/src/OpenGL/libGLESv2/Program.h
@@ -26,6 +26,7 @@
 #include <string>
 #include <vector>
 #include <set>
+#include <map>
 
 namespace es2
 {
@@ -48,8 +49,7 @@
 			bool isRowMajorMatrix;
 		};
 
-		Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,
-		        const BlockInfo &blockInfo);
+		Uniform(const glsl::Uniform &uniform, const BlockInfo &blockInfo);
 
 		~Uniform();
 
@@ -62,6 +62,7 @@
 		const std::string name;
 		const unsigned int arraySize;
 		const BlockInfo blockInfo;
+		std::vector<glsl::ShaderVariable> fields;
 
 		unsigned char *data;
 		bool dirty;
@@ -144,6 +145,7 @@
 		GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const;
 		void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const;
 
+		bool isUniformDefined(const std::string &name) const;
 		GLint getUniformLocation(const std::string &name) const;
 		bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
 		bool setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
@@ -232,7 +234,9 @@
 		bool linkUniforms(const Shader *shader);
 		bool linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader);
 		bool areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2);
-		bool defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &_name, unsigned int arraySize, int registerIndex, const Uniform::BlockInfo& blockInfo);
+		bool areMatchingFields(const std::vector<glsl::ShaderVariable>& fields1, const std::vector<glsl::ShaderVariable>& fields2, const std::string& name);
+		bool validateUniformStruct(GLenum shader, const glsl::Uniform &newUniformStruct);
+		bool defineUniform(GLenum shader, const glsl::Uniform &uniform, const Uniform::BlockInfo& blockInfo);
 		bool defineUniformBlock(const Shader *shader, const glsl::UniformBlock &block);
 		bool applyUniform(Device *device, GLint location, float* data);
 		bool applyUniform1bv(Device *device, GLint location, GLsizei count, const GLboolean *v);
@@ -278,8 +282,9 @@
 		sw::PixelShader *pixelBinary;
 		sw::VertexShader *vertexBinary;
 
-		std::set<std::string> attributeBinding[MAX_VERTEX_ATTRIBS];
-		glsl::Attribute linkedAttribute[MAX_VERTEX_ATTRIBS];
+		std::map<std::string, GLuint> attributeBinding;
+		std::map<std::string, GLuint> linkedAttributeLocation;
+		std::vector<glsl::Attribute> linkedAttribute;
 		int attributeStream[MAX_VERTEX_ATTRIBS];
 
 		GLuint uniformBlockBindings[MAX_UNIFORM_BUFFER_BINDINGS];
@@ -300,6 +305,8 @@
 
 		typedef std::vector<Uniform*> UniformArray;
 		UniformArray uniforms;
+		typedef std::vector<Uniform> UniformStructArray;
+		UniformStructArray uniformStructs;
 		typedef std::vector<UniformLocation> UniformIndex;
 		UniformIndex uniformIndex;
 		typedef std::vector<UniformBlock*> UniformBlockArray;
diff --git a/src/OpenGL/libGLESv2/Renderbuffer.cpp b/src/OpenGL/libGLESv2/Renderbuffer.cpp
index 9b92698..48a61e9 100644
--- a/src/OpenGL/libGLESv2/Renderbuffer.cpp
+++ b/src/OpenGL/libGLESv2/Renderbuffer.cpp
@@ -22,6 +22,8 @@
 #include "Texture.h"
 #include "utilities.h"
 
+#include "compiler/Compiler.h"
+
 namespace es2
 {
 RenderbufferInterface::RenderbufferInterface()
@@ -41,32 +43,32 @@
 
 GLuint RenderbufferInterface::getRedSize() const
 {
-	return sw2es::GetRedSize(getInternalFormat());
+	return GetRedSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getGreenSize() const
 {
-	return sw2es::GetGreenSize(getInternalFormat());
+	return GetGreenSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getBlueSize() const
 {
-	return sw2es::GetBlueSize(getInternalFormat());
+	return GetBlueSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getAlphaSize() const
 {
-	return sw2es::GetAlphaSize(getInternalFormat());
+	return GetAlphaSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getDepthSize() const
 {
-	return sw2es::GetDepthSize(getInternalFormat());
+	return GetDepthSize(getFormat());
 }
 
 GLuint RenderbufferInterface::getStencilSize() const
 {
-	return sw2es::GetStencilSize(getInternalFormat());
+	return GetStencilSize(getFormat());
 }
 
 ///// RenderbufferTexture2D Implementation ////////
@@ -122,30 +124,84 @@
 	return mTexture2D->getHeight(GL_TEXTURE_2D, mLevel);
 }
 
-GLenum RenderbufferTexture2D::getFormat() const
+GLint RenderbufferTexture2D::getFormat() const
 {
 	return mTexture2D->getFormat(GL_TEXTURE_2D, mLevel);
 }
 
-sw::Format RenderbufferTexture2D::getInternalFormat() const
-{
-	return mTexture2D->getInternalFormat(GL_TEXTURE_2D, mLevel);
-}
-
 GLsizei RenderbufferTexture2D::getSamples() const
 {
-	return 0;
+	return 0;   // Core OpenGL ES 3.0 does not support multisample textures.
+}
+
+///// RenderbufferTexture2DRect Implementation ////////
+
+RenderbufferTexture2DRect::RenderbufferTexture2DRect(Texture2DRect *texture)
+{
+	mTexture2DRect = texture;
+}
+
+RenderbufferTexture2DRect::~RenderbufferTexture2DRect()
+{
+	mTexture2DRect = NULL;
+}
+
+// Textures need to maintain their own reference count for references via
+// Renderbuffers acting as proxies. Here, we notify the texture of a reference.
+void RenderbufferTexture2DRect::addProxyRef(const Renderbuffer *proxy)
+{
+	mTexture2DRect->addProxyRef(proxy);
+}
+
+void RenderbufferTexture2DRect::releaseProxy(const Renderbuffer *proxy)
+{
+	mTexture2DRect->releaseProxy(proxy);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+egl::Image *RenderbufferTexture2DRect::getRenderTarget()
+{
+	return mTexture2DRect->getRenderTarget(GL_TEXTURE_RECTANGLE_ARB, 0);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+egl::Image *RenderbufferTexture2DRect::createSharedImage()
+{
+	return mTexture2DRect->createSharedImage(GL_TEXTURE_RECTANGLE_ARB, 0);
+}
+
+bool RenderbufferTexture2DRect::isShared() const
+{
+	return mTexture2DRect->isShared(GL_TEXTURE_RECTANGLE_ARB, 0);
+}
+
+GLsizei RenderbufferTexture2DRect::getWidth() const
+{
+	return mTexture2DRect->getWidth(GL_TEXTURE_RECTANGLE_ARB, 0);
+}
+
+GLsizei RenderbufferTexture2DRect::getHeight() const
+{
+	return mTexture2DRect->getHeight(GL_TEXTURE_RECTANGLE_ARB, 0);
+}
+
+GLint RenderbufferTexture2DRect::getFormat() const
+{
+	return mTexture2DRect->getFormat(GL_TEXTURE_RECTANGLE_ARB, 0);
+}
+
+GLsizei RenderbufferTexture2DRect::getSamples() const
+{
+	return 0;   // Core OpenGL ES 3.0 does not support multisample textures.
 }
 
 ///// RenderbufferTexture3D Implementation ////////
 
-RenderbufferTexture3D::RenderbufferTexture3D(Texture3D *texture, GLint level, GLint layer) : mLevel(level), mLayer(layer)
+RenderbufferTexture3D::RenderbufferTexture3D(Texture3D *texture, GLint level) : mLevel(level)
 {
 	mTexture3D = texture;
-	if(mLayer != 0)
-	{
-		UNIMPLEMENTED();
-	}
 }
 
 RenderbufferTexture3D::~RenderbufferTexture3D()
@@ -199,19 +255,14 @@
 	return mTexture3D->getDepth(mTexture3D->getTarget(), mLevel);
 }
 
-GLenum RenderbufferTexture3D::getFormat() const
+GLint RenderbufferTexture3D::getFormat() const
 {
 	return mTexture3D->getFormat(mTexture3D->getTarget(), mLevel);
 }
 
-sw::Format RenderbufferTexture3D::getInternalFormat() const
-{
-	return mTexture3D->getInternalFormat(mTexture3D->getTarget(), mLevel);
-}
-
 GLsizei RenderbufferTexture3D::getSamples() const
 {
-	return 0;
+	return 0;   // Core OpenGL ES 3.0 does not support multisample textures.
 }
 
 ///// RenderbufferTextureCubeMap Implementation ////////
@@ -267,19 +318,14 @@
 	return mTextureCubeMap->getHeight(mTarget, mLevel);
 }
 
-GLenum RenderbufferTextureCubeMap::getFormat() const
+GLint RenderbufferTextureCubeMap::getFormat() const
 {
 	return mTextureCubeMap->getFormat(mTarget, mLevel);
 }
 
-sw::Format RenderbufferTextureCubeMap::getInternalFormat() const
-{
-	return mTextureCubeMap->getInternalFormat(mTarget, mLevel);
-}
-
 GLsizei RenderbufferTextureCubeMap::getSamples() const
 {
-	return 0;
+	return 0;   // Core OpenGL ES 3.0 does not support multisample textures.
 }
 
 ////// Renderbuffer Implementation //////
@@ -345,26 +391,16 @@
 	return mInstance->getDepth();
 }
 
-GLint Renderbuffer::getLayer() const
-{
-	return mInstance->getLayer();
-}
-
 GLint Renderbuffer::getLevel() const
 {
 	return mInstance->getLevel();
 }
 
-GLenum Renderbuffer::getFormat() const
+GLint Renderbuffer::getFormat() const
 {
 	return mInstance->getFormat();
 }
 
-sw::Format Renderbuffer::getInternalFormat() const
-{
-	return mInstance->getInternalFormat();
-}
-
 GLuint Renderbuffer::getRedSize() const
 {
 	return mInstance->getRedSize();
@@ -400,11 +436,6 @@
 	return mInstance->getSamples();
 }
 
-void Renderbuffer::setLayer(GLint layer)
-{
-	return mInstance->setLayer(layer);
-}
-
 void Renderbuffer::setLevel(GLint level)
 {
 	return mInstance->setLevel(level);
@@ -422,8 +453,7 @@
 {
 	mWidth = 0;
 	mHeight = 0;
-	format = GL_RGBA4;
-	internalFormat = sw::FORMAT_A8B8G8R8;
+	format = GL_NONE;
 	mSamples = 0;
 }
 
@@ -441,16 +471,11 @@
 	return mHeight;
 }
 
-GLenum RenderbufferStorage::getFormat() const
+GLint RenderbufferStorage::getFormat() const
 {
 	return format;
 }
 
-sw::Format RenderbufferStorage::getInternalFormat() const
-{
-	return internalFormat;
-}
-
 GLsizei RenderbufferStorage::getSamples() const
 {
 	return mSamples;
@@ -464,22 +489,24 @@
 
 		mWidth = renderTarget->getWidth();
 		mHeight = renderTarget->getHeight();
-		internalFormat = renderTarget->getInternalFormat();
-		format = sw2es::ConvertBackBufferFormat(internalFormat);
+		format = renderTarget->getFormat();
 		mSamples = renderTarget->getDepth() & ~1;
 	}
 }
 
-Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(nullptr)
+Colorbuffer::Colorbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mRenderTarget(nullptr)
 {
-	Device *device = getDevice();
-
-	sw::Format requestedFormat = es2sw::ConvertRenderbufferFormat(format);
 	int supportedSamples = Context::getSupportedMultisampleCount(samples);
 
 	if(width > 0 && height > 0)
 	{
-		mRenderTarget = device->createRenderTarget(width, height, requestedFormat, supportedSamples, false);
+		if(height > sw::OUTLINE_RESOLUTION)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+
+		mRenderTarget = egl::Image::create(width, height, internalformat, supportedSamples, false);
 
 		if(!mRenderTarget)
 		{
@@ -490,8 +517,7 @@
 
 	mWidth = width;
 	mHeight = height;
-	this->format = format;
-	internalFormat = requestedFormat;
+	format = internalformat;
 	mSamples = supportedSamples;
 }
 
@@ -541,47 +567,24 @@
 
 		mWidth = depthStencil->getWidth();
 		mHeight = depthStencil->getHeight();
-		internalFormat = depthStencil->getInternalFormat();
-		format = sw2es::ConvertDepthStencilFormat(internalFormat);
+		format = depthStencil->getFormat();
 		mSamples = depthStencil->getDepth() & ~1;
 	}
 }
 
-DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLenum requestedFormat, GLsizei samples) : mDepthStencil(nullptr)
+DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mDepthStencil(nullptr)
 {
-	format = requestedFormat;
-	switch(requestedFormat)
-	{
-	case GL_STENCIL_INDEX8:
-	case GL_DEPTH_COMPONENT24:
-	case GL_DEPTH24_STENCIL8_OES:
-		internalFormat = sw::FORMAT_D24S8;
-		break;
-	case GL_DEPTH32F_STENCIL8:
-		internalFormat = sw::FORMAT_D32FS8_TEXTURE;
-		break;
-	case GL_DEPTH_COMPONENT16:
-		internalFormat = sw::FORMAT_D16;
-		break;
-	case GL_DEPTH_COMPONENT32_OES:
-		internalFormat = sw::FORMAT_D32;
-		break;
-	case GL_DEPTH_COMPONENT32F:
-		internalFormat = sw::FORMAT_D32F;
-		break;
-	default:
-		UNREACHABLE(requestedFormat);
-		format = GL_DEPTH24_STENCIL8_OES;
-		internalFormat = sw::FORMAT_D24S8;
-	}
-
-	Device *device = getDevice();
-
 	int supportedSamples = Context::getSupportedMultisampleCount(samples);
 
 	if(width > 0 && height > 0)
 	{
-		mDepthStencil = device->createDepthStencilSurface(width, height, internalFormat, supportedSamples, false);
+		if(height > sw::OUTLINE_RESOLUTION)
+		{
+			error(GL_OUT_OF_MEMORY);
+			return;
+		}
+
+		mDepthStencil = egl::Image::create(width, height, internalformat, supportedSamples, false);
 
 		if(!mDepthStencil)
 		{
@@ -592,6 +595,7 @@
 
 	mWidth = width;
 	mHeight = height;
+	format = internalformat;
 	mSamples = supportedSamples;
 }
 
@@ -637,7 +641,7 @@
 {
 }
 
-Depthbuffer::Depthbuffer(int width, int height, GLenum format, GLsizei samples) : DepthStencilbuffer(width, height, format, samples)
+Depthbuffer::Depthbuffer(int width, int height, GLenum internalformat, GLsizei samples) : DepthStencilbuffer(width, height, internalformat, samples)
 {
 }
 
diff --git a/src/OpenGL/libGLESv2/Renderbuffer.h b/src/OpenGL/libGLESv2/Renderbuffer.h
index 5e3f124..fa7123b 100644
--- a/src/OpenGL/libGLESv2/Renderbuffer.h
+++ b/src/OpenGL/libGLESv2/Renderbuffer.h
@@ -27,9 +27,11 @@
 
 namespace es2
 {
+
 class Texture2D;
 class Texture3D;
 class TextureCubeMap;
+class Texture2DRect;
 class Renderbuffer;
 class Colorbuffer;
 class DepthStencilbuffer;
@@ -51,13 +53,10 @@
 	virtual GLsizei getWidth() const = 0;
 	virtual GLsizei getHeight() const = 0;
 	virtual GLsizei getDepth() const { return 1; }
-	virtual GLint getLayer() const { return 0; }
 	virtual GLint getLevel() const { return 0; }
-	virtual GLenum getFormat() const = 0;
-	virtual sw::Format getInternalFormat() const = 0;
+	virtual GLint getFormat() const = 0;
 	virtual GLsizei getSamples() const = 0;
 
-	virtual void setLayer(GLint) {}
 	virtual void setLevel(GLint) {}
 
 	GLuint getRedSize() const;
@@ -73,59 +72,77 @@
 public:
 	RenderbufferTexture2D(Texture2D *texture, GLint level);
 
-	virtual ~RenderbufferTexture2D();
+	~RenderbufferTexture2D() override;
 
-	virtual void addProxyRef(const Renderbuffer *proxy);
-    virtual void releaseProxy(const Renderbuffer *proxy);
+	void addProxyRef(const Renderbuffer *proxy) override;
+    void releaseProxy(const Renderbuffer *proxy) override;
 
-	virtual egl::Image *getRenderTarget();
-    virtual egl::Image *createSharedImage();
-    virtual bool isShared() const;
+	egl::Image *getRenderTarget() override;
+    egl::Image *createSharedImage() override;
+    bool isShared() const override;
 
-	virtual GLsizei getWidth() const;
-	virtual GLsizei getHeight() const;
-	virtual GLint getLevel() const { return mLevel; }
-	virtual GLenum getFormat() const;
-	virtual sw::Format getInternalFormat() const;
-	virtual GLsizei getSamples() const;
+	GLsizei getWidth() const override;
+	GLsizei getHeight() const override;
+	GLint getLevel() const override { return mLevel; }
+	GLint getFormat() const override;
+	GLsizei getSamples() const override;
 
-	virtual void setLevel(GLint level) { mLevel = level; }
+	void setLevel(GLint level) override { mLevel = level; }
 
 private:
 	gl::BindingPointer<Texture2D> mTexture2D;
 	GLint mLevel;
 };
 
+class RenderbufferTexture2DRect : public RenderbufferInterface
+{
+public:
+	RenderbufferTexture2DRect(Texture2DRect *texture);
+
+	~RenderbufferTexture2DRect() override;
+
+	void addProxyRef(const Renderbuffer *proxy) override;
+	void releaseProxy(const Renderbuffer *proxy) override;
+
+	egl::Image *getRenderTarget() override;
+	egl::Image *createSharedImage() override;
+	bool isShared() const override;
+
+	GLsizei getWidth() const override;
+	GLsizei getHeight() const override;
+	GLint getFormat() const override;
+	GLsizei getSamples() const override;
+
+private:
+	gl::BindingPointer<Texture2DRect> mTexture2DRect;
+};
+
 class RenderbufferTexture3D : public RenderbufferInterface
 {
 public:
-	RenderbufferTexture3D(Texture3D *texture, GLint level, GLint layer);
+	RenderbufferTexture3D(Texture3D *texture, GLint level);
 
-	virtual ~RenderbufferTexture3D();
+	~RenderbufferTexture3D() override;
 
-	virtual void addProxyRef(const Renderbuffer *proxy);
-	virtual void releaseProxy(const Renderbuffer *proxy);
+	void addProxyRef(const Renderbuffer *proxy) override;
+	void releaseProxy(const Renderbuffer *proxy) override;
 
-	virtual egl::Image *getRenderTarget();
-	virtual egl::Image *createSharedImage();
-	virtual bool isShared() const;
+	egl::Image *getRenderTarget() override;
+	egl::Image *createSharedImage() override;
+	bool isShared() const override;
 
-	virtual GLsizei getWidth() const;
-	virtual GLsizei getHeight() const;
-	virtual GLsizei getDepth() const;
-	virtual GLint getLayer() const { return mLayer; }
-	virtual GLint getLevel() const { return mLevel; }
-	virtual GLenum getFormat() const;
-	virtual sw::Format getInternalFormat() const;
-	virtual GLsizei getSamples() const;
+	GLsizei getWidth() const override;
+	GLsizei getHeight() const override;
+	GLsizei getDepth() const override;
+	GLint getLevel() const override { return mLevel; }
+	GLint getFormat() const override;
+	GLsizei getSamples() const override;
 
-	virtual void setLayer(GLint layer) { mLayer = layer; }
-	virtual void setLevel(GLint level) { mLevel = level; }
+	void setLevel(GLint level) override { mLevel = level; }
 
 private:
 	gl::BindingPointer<Texture3D> mTexture3D;
 	GLint mLevel;
-	GLint mLayer;
 };
 
 class RenderbufferTextureCubeMap : public RenderbufferInterface
@@ -133,23 +150,22 @@
 public:
 	RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target, GLint level);
 
-	virtual ~RenderbufferTextureCubeMap();
+	~RenderbufferTextureCubeMap() override;
 
-	virtual void addProxyRef(const Renderbuffer *proxy);
-    virtual void releaseProxy(const Renderbuffer *proxy);
+	void addProxyRef(const Renderbuffer *proxy) override;
+    void releaseProxy(const Renderbuffer *proxy) override;
 
-	virtual egl::Image *getRenderTarget();
-    virtual egl::Image *createSharedImage();
-    virtual bool isShared() const;
+	egl::Image *getRenderTarget() override;
+    egl::Image *createSharedImage() override;
+    bool isShared() const override;
 
-	virtual GLsizei getWidth() const;
-	virtual GLsizei getHeight() const;
-	virtual GLint getLevel() const { return mLevel; }
-	virtual GLenum getFormat() const;
-	virtual sw::Format getInternalFormat() const;
-	virtual GLsizei getSamples() const;
+	GLsizei getWidth() const override;
+	GLsizei getHeight() const override;
+	GLint getLevel() const override { return mLevel; }
+	GLint getFormat() const override;
+	GLsizei getSamples() const override;
 
-	virtual void setLevel(GLint level) { mLevel = level; }
+	void setLevel(GLint level) override { mLevel = level; }
 
 private:
 	gl::BindingPointer<TextureCubeMap> mTextureCubeMap;
@@ -165,23 +181,21 @@
 public:
 	RenderbufferStorage();
 
-	virtual ~RenderbufferStorage() = 0;
+	~RenderbufferStorage() override = 0;
 
-	virtual egl::Image *getRenderTarget() = 0;
-    virtual egl::Image *createSharedImage() = 0;
-    virtual bool isShared() const = 0;
+	egl::Image *getRenderTarget() override = 0;
+    egl::Image *createSharedImage() override = 0;
+    bool isShared() const override = 0;
 
-	virtual GLsizei getWidth() const;
-	virtual GLsizei getHeight() const;
-	virtual GLenum getFormat() const;
-	virtual sw::Format getInternalFormat() const;
-	virtual GLsizei getSamples() const;
+	GLsizei getWidth() const override;
+	GLsizei getHeight() const override;
+	GLint getFormat() const override;
+	GLsizei getSamples() const override;
 
 protected:
 	GLsizei mWidth;
 	GLsizei mHeight;
 	GLenum format;
-	sw::Format internalFormat;
 	GLsizei mSamples;
 };
 
@@ -193,14 +207,14 @@
 public:
 	Renderbuffer(GLuint name, RenderbufferInterface *storage);
 
-	virtual ~Renderbuffer();
+	~Renderbuffer() override;
 
 	// These functions from Object are overloaded here because
     // Textures need to maintain their own count of references to them via
     // Renderbuffers/RenderbufferTextures. These functions invoke those
     // reference counting functions on the RenderbufferInterface.
-    virtual void addRef();
-    virtual void release();
+    void addRef() override;
+    void release() override;
 
 	egl::Image *getRenderTarget();
     virtual egl::Image *createSharedImage();
@@ -209,10 +223,8 @@
 	GLsizei getWidth() const;
 	GLsizei getHeight() const;
 	GLsizei getDepth() const;
-	GLint getLayer() const;
 	GLint getLevel() const;
-	GLenum getFormat() const;
-	sw::Format getInternalFormat() const;
+	GLint getFormat() const;
 	GLuint getRedSize() const;
 	GLuint getGreenSize() const;
 	GLuint getBlueSize() const;
@@ -221,7 +233,6 @@
 	GLuint getStencilSize() const;
 	GLsizei getSamples() const;
 
-	void setLayer(GLint layer);
 	void setLevel(GLint level);
 	void setStorage(RenderbufferStorage *newStorage);
 
@@ -233,13 +244,13 @@
 {
 public:
 	explicit Colorbuffer(egl::Image *renderTarget);
-	Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples);
+	Colorbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
 
-	virtual ~Colorbuffer();
+	~Colorbuffer() override;
 
-	virtual egl::Image *getRenderTarget();
-    virtual egl::Image *createSharedImage();
-    virtual bool isShared() const;
+	egl::Image *getRenderTarget() override;
+    egl::Image *createSharedImage() override;
+    bool isShared() const override;
 
 private:
 	egl::Image *mRenderTarget;
@@ -249,13 +260,13 @@
 {
 public:
 	explicit DepthStencilbuffer(egl::Image *depthStencil);
-	DepthStencilbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples);
+	DepthStencilbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
 
 	~DepthStencilbuffer();
 
-	virtual egl::Image *getRenderTarget();
-    virtual egl::Image *createSharedImage();
-    virtual bool isShared() const;
+	egl::Image *getRenderTarget() override;
+    egl::Image *createSharedImage() override;
+    bool isShared() const override;
 
 protected:
 	egl::Image *mDepthStencil;
@@ -265,9 +276,9 @@
 {
 public:
 	explicit Depthbuffer(egl::Image *depthStencil);
-	Depthbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples);
+	Depthbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
 
-	virtual ~Depthbuffer();
+	~Depthbuffer() override;
 };
 
 class Stencilbuffer : public DepthStencilbuffer
@@ -276,7 +287,7 @@
 	explicit Stencilbuffer(egl::Image *depthStencil);
 	Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
 
-	virtual ~Stencilbuffer();
+	~Stencilbuffer() override;
 };
 }
 
diff --git a/src/OpenGL/libGLESv2/ResourceManager.cpp b/src/OpenGL/libGLESv2/ResourceManager.cpp
index e5c5492..51a7bc1 100644
--- a/src/OpenGL/libGLESv2/ResourceManager.cpp
+++ b/src/OpenGL/libGLESv2/ResourceManager.cpp
@@ -308,6 +308,10 @@
 		{
 			textureObject = new Texture2DArray(texture);
 		}
+		else if(type == TEXTURE_2D_RECT)
+		{
+			textureObject = new Texture2DRect(texture);
+		}
 		else
 		{
 			UNREACHABLE(type);
@@ -324,7 +328,7 @@
 {
 	if(handle != 0 && !getRenderbuffer(handle))
 	{
-		Renderbuffer *renderbufferObject = new Renderbuffer(handle, new Colorbuffer(0, 0, GL_RGBA4_OES, 0));
+		Renderbuffer *renderbufferObject = new Renderbuffer(handle, new Colorbuffer(0, 0, GL_NONE, 0));
 		renderbufferObject->addRef();
 
 		mRenderbufferNameSpace.insert(handle, renderbufferObject);
diff --git a/src/OpenGL/libGLESv2/ResourceManager.h b/src/OpenGL/libGLESv2/ResourceManager.h
index efd0e20..c076653 100644
--- a/src/OpenGL/libGLESv2/ResourceManager.h
+++ b/src/OpenGL/libGLESv2/ResourceManager.h
@@ -40,6 +40,7 @@
 	TEXTURE_3D,
 	TEXTURE_2D_ARRAY,
 	TEXTURE_CUBE,
+	TEXTURE_2D_RECT,
 	TEXTURE_EXTERNAL,
 
 	TEXTURE_TYPE_COUNT,
diff --git a/src/OpenGL/libGLESv2/Sampler.h b/src/OpenGL/libGLESv2/Sampler.h
index 12ed6da..0dbf8c9 100644
--- a/src/OpenGL/libGLESv2/Sampler.h
+++ b/src/OpenGL/libGLESv2/Sampler.h
@@ -50,8 +50,8 @@
 	void setWrapR(GLenum wrapR) { mWrapModeR = wrapR; }
 	void setMinLod(GLfloat minLod) { mMinLod = minLod; }
 	void setMaxLod(GLfloat maxLod) { mMaxLod = maxLod; }
-	void setComparisonMode(GLenum comparisonMode) { mCompareMode = comparisonMode; }
-	void setComparisonFunc(GLenum comparisonFunc) { mCompareFunc = comparisonFunc; }
+	void setCompareMode(GLenum compareMode) { mCompareMode = compareMode; }
+	void setCompareFunc(GLenum compareFunc) { mCompareFunc = compareFunc; }
 
 	GLenum getMinFilter() const { return mMinFilter; }
 	GLenum getMagFilter() const { return mMagFilter; }
@@ -60,8 +60,8 @@
 	GLenum getWrapR() const { return mWrapModeR; }
 	GLfloat getMinLod() const { return mMinLod; }
 	GLfloat getMaxLod() const { return mMaxLod; }
-	GLenum getComparisonMode() const { return mCompareMode; }
-	GLenum getComparisonFunc() const { return mCompareFunc; }
+	GLenum getCompareMode() const { return mCompareMode; }
+	GLenum getCompareFunc() const { return mCompareFunc; }
 
 private:
 	GLenum mMinFilter;
diff --git a/src/OpenGL/libGLESv2/Shader.cpp b/src/OpenGL/libGLESv2/Shader.cpp
index df25d29..9cb6bd5 100644
--- a/src/OpenGL/libGLESv2/Shader.cpp
+++ b/src/OpenGL/libGLESv2/Shader.cpp
@@ -181,7 +181,8 @@
 	resources.OES_fragment_precision_high = 1;
 	resources.OES_EGL_image_external = 1;
 	resources.EXT_draw_buffers = 1;
-	resources.MaxCallStackDepth = 16;
+	resources.ARB_texture_rectangle = 1;
+	resources.MaxCallStackDepth = 64;
 	assembler->Init(resources);
 
 	return assembler;
@@ -215,16 +216,22 @@
 	if(false)
 	{
 		static int serial = 1;
-		char buffer[256];
-		sprintf(buffer, "shader-input-%d-%d.txt", getName(), serial);
-		FILE *file = fopen(buffer, "wt");
-		fprintf(file, "%s", mSource);
-		fclose(file);
+
+		if(false)
+		{
+			char buffer[256];
+			sprintf(buffer, "shader-input-%d-%d.txt", getName(), serial);
+			FILE *file = fopen(buffer, "wt");
+			fprintf(file, "%s", mSource);
+			fclose(file);
+		}
+
 		getShader()->print("shader-output-%d-%d.txt", getName(), serial);
+
 		serial++;
 	}
 
-	int shaderVersion = compiler->getShaderVersion();
+	shaderVersion = compiler->getShaderVersion();
 	int clientVersion = es2::getContext()->getClientVersion();
 
 	if(shaderVersion >= 300 && clientVersion < 3)
@@ -383,15 +390,15 @@
 	return GL_VERTEX_SHADER;
 }
 
-int VertexShader::getSemanticIndex(const std::string &attributeName)
+int VertexShader::getSemanticIndex(const std::string &attributeName) const
 {
 	if(!attributeName.empty())
 	{
-		for(glsl::ActiveAttributes::iterator attribute = activeAttributes.begin(); attribute != activeAttributes.end(); attribute++)
+		for(const auto &attribute : activeAttributes)
 		{
-			if(attribute->name == attributeName)
+			if(attribute.name == attributeName)
 			{
-				return attribute->registerIndex;
+				return attribute.registerIndex;
 			}
 		}
 	}
diff --git a/src/OpenGL/libGLESv2/Shader.h b/src/OpenGL/libGLESv2/Shader.h
index 0c29e4b..63d50ae 100644
--- a/src/OpenGL/libGLESv2/Shader.h
+++ b/src/OpenGL/libGLESv2/Shader.h
@@ -99,7 +99,7 @@
 	~VertexShader();
 
 	virtual GLenum getType() const;
-	int getSemanticIndex(const std::string &attributeName);
+	int getSemanticIndex(const std::string &attributeName) const;
 
 	virtual sw::Shader *getShader() const;
 	virtual sw::VertexShader *getVertexShader() const;
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp
index b0a46a5..dc0e807 100644
--- a/src/OpenGL/libGLESv2/Texture.cpp
+++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -22,6 +22,7 @@
 #include "mathutil.h"
 #include "Framebuffer.h"
 #include "Device.hpp"
+#include "Shader.h"
 #include "libEGL/Display.h"
 #include "common/Surface.hpp"
 #include "common/debug.h"
@@ -74,7 +75,7 @@
 	case GL_LINEAR_MIPMAP_NEAREST:
 	case GL_NEAREST_MIPMAP_LINEAR:
 	case GL_LINEAR_MIPMAP_LINEAR:
-		if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
+		if((getTarget() == GL_TEXTURE_EXTERNAL_OES) || (getTarget() == GL_TEXTURE_RECTANGLE_ARB))
 		{
 			return false;
 		}
@@ -109,7 +110,7 @@
 	{
 	case GL_REPEAT:
 	case GL_MIRRORED_REPEAT:
-		if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
+		if((getTarget() == GL_TEXTURE_EXTERNAL_OES) || (getTarget() == GL_TEXTURE_RECTANGLE_ARB))
 		{
 			return false;
 		}
@@ -129,7 +130,7 @@
 	{
 	case GL_REPEAT:
 	case GL_MIRRORED_REPEAT:
-		if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
+		if((getTarget() == GL_TEXTURE_EXTERNAL_OES) || (getTarget() == GL_TEXTURE_RECTANGLE_ARB))
 		{
 			return false;
 		}
@@ -149,7 +150,7 @@
 	{
 	case GL_REPEAT:
 	case GL_MIRRORED_REPEAT:
-		if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
+		if((getTarget() == GL_TEXTURE_EXTERNAL_OES) || (getTarget() == GL_TEXTURE_RECTANGLE_ARB))
 		{
 			return false;
 		}
@@ -182,6 +183,11 @@
 
 bool Texture::setBaseLevel(GLint baseLevel)
 {
+	if(baseLevel < 0)
+	{
+		return false;
+	}
+
 	mBaseLevel = baseLevel;
 	return true;
 }
@@ -310,85 +316,6 @@
 	}
 }
 
-GLenum Texture::getMinFilter() const
-{
-	return mMinFilter;
-}
-
-GLenum Texture::getMagFilter() const
-{
-	return mMagFilter;
-}
-
-GLenum Texture::getWrapS() const
-{
-	return mWrapS;
-}
-
-GLenum Texture::getWrapT() const
-{
-	return mWrapT;
-}
-
-GLenum Texture::getWrapR() const
-{
-	return mWrapR;
-}
-
-GLfloat Texture::getMaxAnisotropy() const
-{
-	return mMaxAnisotropy;
-}
-
-GLint Texture::getBaseLevel() const
-{
-	return mBaseLevel;
-}
-GLenum Texture::getCompareFunc() const
-{
-	return mCompareFunc;
-}
-GLenum Texture::getCompareMode() const
-{
-	return mCompareMode;
-}
-GLboolean Texture::getImmutableFormat() const
-{
-	return mImmutableFormat;
-}
-GLsizei Texture::getImmutableLevels() const
-{
-	return mImmutableLevels;
-}
-GLint Texture::getMaxLevel() const
-{
-	return mMaxLevel;
-}
-GLfloat Texture::getMaxLOD() const
-{
-	return mMaxLOD;
-}
-GLfloat Texture::getMinLOD() const
-{
-	return mMinLOD;
-}
-GLenum Texture::getSwizzleR() const
-{
-	return mSwizzleR;
-}
-GLenum Texture::getSwizzleG() const
-{
-	return mSwizzleG;
-}
-GLenum Texture::getSwizzleB() const
-{
-	return mSwizzleB;
-}
-GLenum Texture::getSwizzleA() const
-{
-	return mSwizzleA;
-}
-
 GLsizei Texture::getDepth(GLenum target, GLint level) const
 {
 	return 1;
@@ -406,49 +333,34 @@
 	return image;
 }
 
-void Texture::setImage(egl::Context *context, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image)
+void Texture::setImage(GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image)
 {
 	if(pixels && image)
 	{
 		GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
-		image->loadImageData(context, 0, 0, 0, image->getWidth(), image->getHeight(), depth, format, type, unpackInfo, pixels);
+		image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), depth, format, type, unpackParameters, pixels);
 	}
 }
 
 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image)
 {
-	if(pixels && image)
+	if(pixels && image && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES || getTarget() == GL_TEXTURE_2D_ARRAY) ? image->getDepth() : 1;
 		image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), depth, imageSize, pixels);
 	}
 }
 
-void Texture::subImage(egl::Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image)
+void Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image)
 {
 	if(!image)
 	{
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
+	if(pixels && width > 0 && height > 0 && depth > 0)
 	{
-		return error(GL_INVALID_VALUE);
-	}
-
-	if(IsCompressed(image->getFormat(), egl::getClientVersion()))
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
-	if(format != image->getFormat())
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
-	if(pixels)
-	{
-		image->loadImageData(context, xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels);
+		image->loadImageData(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackParameters, pixels);
 	}
 }
 
@@ -459,28 +371,23 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
-	{
-		return error(GL_INVALID_VALUE);
-	}
-
-	if(format != image->getFormat())
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
-	if(pixels)
+	if(pixels && (imageSize > 0)) // imageSize's correlation to width and height is already validated with gl::ComputeCompressedSize() at the API level
 	{
 		image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, imageSize, pixels);
 	}
 }
 
-bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest)
+bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest)
 {
 	Device *device = getDevice();
 
 	sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), zoffset);
-	bool success = device->stretchRect(source, &sourceRect, dest, &destRect, Device::ALL_BUFFERS);
+	sw::SliceRectF sourceRectF(static_cast<float>(sourceRect.x0),
+	                           static_cast<float>(sourceRect.y0),
+	                           static_cast<float>(sourceRect.x1),
+	                           static_cast<float>(sourceRect.y1),
+	                           sourceRect.slice);
+	bool success = device->stretchRect(source, &sourceRectF, dest, &destRect, Device::ALL_BUFFERS);
 
 	if(!success)
 	{
@@ -592,78 +499,54 @@
 
 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	return image[level] ? image[level]->getWidth() : 0;
 }
 
 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	return image[level] ? image[level]->getHeight() : 0;
 }
 
-GLenum Texture2D::getFormat(GLenum target, GLint level) const
+GLint Texture2D::getFormat(GLenum target, GLint level) const
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	return image[level] ? image[level]->getFormat() : GL_NONE;
 }
 
-GLenum Texture2D::getType(GLenum target, GLint level) const
-{
-	ASSERT(target == GL_TEXTURE_2D);
-	return image[level] ? image[level]->getType() : GL_NONE;
-}
-
-sw::Format Texture2D::getInternalFormat(GLenum target, GLint level) const
-{
-	ASSERT(target == GL_TEXTURE_2D);
-	return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
-}
-
-int Texture2D::getLevelCount() const
+int Texture2D::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
-	int levels = 0;
+	int level = mBaseLevel;
 
-	while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
+	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[level])
 	{
-		levels++;
+		level++;
 	}
 
-	return levels;
+	return level - 1;
 }
 
-void Texture2D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
+void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
 	if(image[level])
 	{
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, format, type);
+	image[level] = egl::Image::create(this, width, height, internalformat);
 
 	if(!image[level])
 	{
 		return error(GL_OUT_OF_MEMORY);
 	}
 
-	Texture::setImage(context, format, type, unpackInfo, pixels, image[level]);
+	Texture::setImage(format, type, unpackParameters, pixels, image[level]);
 }
 
 void Texture2D::bindTexImage(gl::Surface *surface)
 {
-	switch(surface->getInternalFormat())
-	{
-	case sw::FORMAT_A8R8G8B8:
-	case sw::FORMAT_A8B8G8R8:
-	case sw::FORMAT_X8B8G8R8:
-	case sw::FORMAT_X8R8G8B8:
-		break;
-	default:
-		UNIMPLEMENTED();
-		return;
-	}
-
 	for(int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
 	{
 		if(image[level])
@@ -689,6 +572,12 @@
 			image[level] = nullptr;
 		}
 	}
+
+	if(mSurface)
+	{
+		mSurface->setBoundTexture(nullptr);
+		mSurface = nullptr;
+	}
 }
 
 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
@@ -698,8 +587,7 @@
 		image[level]->release();
 	}
 
-	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, format);
 
 	if(!image[level])
 	{
@@ -709,9 +597,9 @@
 	Texture::setCompressedImage(imageSize, pixels, image[level]);
 }
 
-void Texture2D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
-	Texture::subImage(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[level]);
+	Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels, image[level]);
 }
 
 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
@@ -719,9 +607,9 @@
 	Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
 }
 
-void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+void Texture2D::copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
 {
-	egl::Image *renderTarget = source->getRenderTarget(0);
+	egl::Image *renderTarget = source->getRenderTarget();
 
 	if(!renderTarget)
 	{
@@ -734,8 +622,7 @@
 		image[level]->release();
 	}
 
-	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, internalformat);
 
 	if(!image[level])
 	{
@@ -744,24 +631,16 @@
 
 	if(width != 0 && height != 0)
 	{
-		Renderbuffer* renderbuffer = source->getReadColorbuffer();
-
-		if(!renderbuffer)
-		{
-			ERR("Failed to retrieve the source colorbuffer.");
-			return;
-		}
-
 		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
-		sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
+		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
 
-		copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[level]);
+		copy(renderTarget, sourceRect, 0, 0, 0, image[level]);
 	}
 
 	renderTarget->release();
 }
 
-void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
 {
 	if(!image[level])
 	{
@@ -773,28 +652,23 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	egl::Image *renderTarget = source->getRenderTarget(0);
-
-	if(!renderTarget)
+	if(width > 0 && height > 0)
 	{
-		ERR("Failed to retrieve the render target.");
-		return error(GL_OUT_OF_MEMORY);
+		egl::Image *renderTarget = source->getRenderTarget();
+
+		if(!renderTarget)
+		{
+			ERR("Failed to retrieve the render target.");
+			return error(GL_OUT_OF_MEMORY);
+		}
+
+		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
+		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
+
+		copy(renderTarget, sourceRect, xoffset, yoffset, zoffset, image[level]);
+
+		renderTarget->release();
 	}
-
-	Renderbuffer* renderbuffer = source->getReadColorbuffer();
-
-	if(!renderbuffer)
-	{
-		ERR("Failed to retrieve the source colorbuffer.");
-		return;
-	}
-
-	sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
-	sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
-
-	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
-
-	renderTarget->release();
 }
 
 void Texture2D::setSharedImage(egl::Image *sharedImage)
@@ -814,16 +688,16 @@
 	image[0] = sharedImage;
 }
 
-// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
+// Tests for 2D texture sampling completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
 bool Texture2D::isSamplerComplete() const
 {
-	if(!image[0])
+	if(!image[mBaseLevel])
 	{
 		return false;
 	}
 
-	GLsizei width = image[0]->getWidth();
-	GLsizei height = image[0]->getHeight();
+	GLsizei width = image[mBaseLevel]->getWidth();
+	GLsizei height = image[mBaseLevel]->getHeight();
 
 	if(width <= 0 || height <= 0)
 	{
@@ -841,13 +715,19 @@
 	return true;
 }
 
-// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+// Tests for 2D texture (mipmap) completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
 bool Texture2D::isMipmapComplete() const
 {
+	if(mBaseLevel > mMaxLevel)
+	{
+		return false;
+	}
+
 	GLsizei width = image[mBaseLevel]->getWidth();
 	GLsizei height = image[mBaseLevel]->getHeight();
-
-	int q = std::min(log2(std::max(width, height)), mMaxLevel);
+	int maxsize = std::max(width, height);
+	int p = log2(maxsize) + mBaseLevel;
+	int q = std::min(p, mMaxLevel);
 
 	for(int level = mBaseLevel + 1; level <= q; level++)
 	{
@@ -856,22 +736,19 @@
 			return false;
 		}
 
-		if(image[level]->getFormat() != image[0]->getFormat())
+		if(image[level]->getFormat() != image[mBaseLevel]->getFormat())
 		{
 			return false;
 		}
 
-		if(image[level]->getType() != image[0]->getType())
+		int i = level - mBaseLevel;
+
+		if(image[level]->getWidth() != std::max(1, width >> i))
 		{
 			return false;
 		}
 
-		if(image[level]->getWidth() != std::max(1, width >> level))
-		{
-			return false;
-		}
-
-		if(image[level]->getHeight() != std::max(1, height >> level))
+		if(image[level]->getHeight() != std::max(1, height >> i))
 		{
 			return false;
 		}
@@ -892,21 +769,20 @@
 
 void Texture2D::generateMipmaps()
 {
-	if(!image[0])
-	{
-		return;   // FIXME: error?
-	}
+	ASSERT(image[mBaseLevel]);
 
-	unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
+	int maxsize = std::max(image[mBaseLevel]->getWidth(), image[mBaseLevel]->getHeight());
+	int p = log2(maxsize) + mBaseLevel;
+	int q = std::min(p, mMaxLevel);
 
-	for(unsigned int i = 1; i <= q; i++)
+	for(int i = mBaseLevel + 1; i <= q; i++)
 	{
 		if(image[i])
 		{
 			image[i]->release();
 		}
 
-		image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), image[0]->getFormat(), image[0]->getType());
+		image[i] = egl::Image::create(this, std::max(image[mBaseLevel]->getWidth() >> i, 1), std::max(image[mBaseLevel]->getHeight() >> i, 1), image[mBaseLevel]->getFormat());
 
 		if(!image[i])
 		{
@@ -922,9 +798,9 @@
 	return image[level];
 }
 
-Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level, GLint layer)
+Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level)
 {
-	if(target != GL_TEXTURE_2D)
+	if(target != getTarget())
 	{
 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
 	}
@@ -943,7 +819,7 @@
 
 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
 
 	if(image[level])
@@ -956,7 +832,7 @@
 
 bool Texture2D::isShared(GLenum target, unsigned int level) const
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
 
 	if(mSurface)   // Bound to an EGLSurface
@@ -972,6 +848,35 @@
 	return image[level]->isShared();
 }
 
+Texture2DRect::Texture2DRect(GLuint name) : Texture2D(name)
+{
+	mMinFilter = GL_LINEAR;
+	mMagFilter = GL_LINEAR;
+	mWrapS = GL_CLAMP_TO_EDGE;
+	mWrapT = GL_CLAMP_TO_EDGE;
+	mWrapR = GL_CLAMP_TO_EDGE;
+}
+
+GLenum Texture2DRect::getTarget() const
+{
+	return GL_TEXTURE_RECTANGLE_ARB;
+}
+
+Renderbuffer *Texture2DRect::getRenderbuffer(GLenum target, GLint level)
+{
+	if((target != getTarget()) || (level != 0))
+	{
+		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
+	}
+
+	if(!mColorbufferProxy)
+	{
+		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2DRect(this));
+	}
+
+	return mColorbufferProxy;
+}
+
 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name)
 {
 	for(int f = 0; f < 6; f++)
@@ -1087,35 +992,23 @@
 	return image[face][level] ? image[face][level]->getHeight() : 0;
 }
 
-GLenum TextureCubeMap::getFormat(GLenum target, GLint level) const
+GLint TextureCubeMap::getFormat(GLenum target, GLint level) const
 {
 	int face = CubeFaceIndex(target);
 	return image[face][level] ? image[face][level]->getFormat() : 0;
 }
 
-GLenum TextureCubeMap::getType(GLenum target, GLint level) const
-{
-	int face = CubeFaceIndex(target);
-	return image[face][level] ? image[face][level]->getType() : 0;
-}
-
-sw::Format TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
-{
-	int face = CubeFaceIndex(target);
-	return image[face][level] ? image[face][level]->getInternalFormat() : sw::FORMAT_NULL;
-}
-
-int TextureCubeMap::getLevelCount() const
+int TextureCubeMap::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
-	int levels = 0;
+	int level = mBaseLevel;
 
-	while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][levels])
+	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][level])
 	{
-		levels++;
+		level++;
 	}
 
-	return levels;
+	return level - 1;
 }
 
 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
@@ -1127,8 +1020,8 @@
 		image[face][level]->release();
 	}
 
-	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[face][level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	int border = (egl::getClientVersion() >= 3) ? 1 : 0;
+	image[face][level] = egl::Image::create(this, width, height, 1, border, format);
 
 	if(!image[face][level])
 	{
@@ -1138,9 +1031,9 @@
 	Texture::setCompressedImage(imageSize, pixels, image[face][level]);
 }
 
-void TextureCubeMap::subImage(egl::Context *context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
+void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
-	Texture::subImage(context, xoffset, yoffset, 0, width, height, 1, format, type, unpackInfo, pixels, image[CubeFaceIndex(target)][level]);
+	Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackParameters, pixels, image[CubeFaceIndex(target)][level]);
 }
 
 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
@@ -1148,18 +1041,18 @@
 	Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
 }
 
-// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
+// Tests for cube map sampling completeness. [OpenGL ES 3.0.5] section 3.8.13 page 161.
 bool TextureCubeMap::isSamplerComplete() const
 {
 	for(int face = 0; face < 6; face++)
 	{
-		if(!image[face][0])
+		if(!image[face][mBaseLevel])
 		{
 			return false;
 		}
 	}
 
-	int size = image[0][0]->getWidth();
+	int size = image[0][mBaseLevel]->getWidth();
 
 	if(size <= 0)
 	{
@@ -1184,7 +1077,7 @@
 	return true;
 }
 
-// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+// Tests for cube texture completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
 bool TextureCubeMap::isCubeComplete() const
 {
 	if(image[0][mBaseLevel]->getWidth() <= 0 || image[0][mBaseLevel]->getHeight() != image[0][mBaseLevel]->getWidth())
@@ -1196,8 +1089,7 @@
 	{
 		if(image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getWidth() ||
 		   image[face][mBaseLevel]->getWidth()  != image[0][mBaseLevel]->getHeight() ||
-		   image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat() ||
-		   image[face][mBaseLevel]->getType()   != image[0][mBaseLevel]->getType())
+		   image[face][mBaseLevel]->getFormat() != image[0][mBaseLevel]->getFormat())
 		{
 			return false;
 		}
@@ -1208,13 +1100,19 @@
 
 bool TextureCubeMap::isMipmapCubeComplete() const
 {
+	if(mBaseLevel > mMaxLevel)
+	{
+		return false;
+	}
+
 	if(!isCubeComplete())
 	{
 		return false;
 	}
 
 	GLsizei size = image[0][mBaseLevel]->getWidth();
-	int q = std::min(log2(size), mMaxLevel);
+	int p = log2(size) + mBaseLevel;
+	int q = std::min(p, mMaxLevel);
 
 	for(int face = 0; face < 6; face++)
 	{
@@ -1230,12 +1128,9 @@
 				return false;
 			}
 
-			if(image[face][level]->getType() != image[0][mBaseLevel]->getType())
-			{
-				return false;
-			}
+			int i = level - mBaseLevel;
 
-			if(image[face][level]->getWidth() != std::max(1, size >> level))
+			if(image[face][level]->getWidth() != std::max(1, size >> i))
 			{
 				return false;
 			}
@@ -1245,6 +1140,69 @@
 	return true;
 }
 
+void TextureCubeMap::updateBorders(int level)
+{
+	egl::Image *posX = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_POSITIVE_X)][level];
+	egl::Image *negX = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_NEGATIVE_X)][level];
+	egl::Image *posY = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_POSITIVE_Y)][level];
+	egl::Image *negY = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y)][level];
+	egl::Image *posZ = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_POSITIVE_Z)][level];
+	egl::Image *negZ = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)][level];
+
+	if(!posX || !negX || !posY || !negY || !posZ || !negZ)
+	{
+		return;
+	}
+
+	if(posX->getBorder() == 0)   // Non-seamless cube map.
+	{
+		return;
+	}
+
+	if(!posX->hasDirtyContents() || !posY->hasDirtyContents() || !posZ->hasDirtyContents() || !negX->hasDirtyContents() || !negY->hasDirtyContents() || !negZ->hasDirtyContents())
+	{
+		return;
+	}
+
+	// Copy top / bottom first.
+	posX->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::RIGHT);
+	posY->copyCubeEdge(sw::Surface::BOTTOM, posZ, sw::Surface::TOP);
+	posZ->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::TOP);
+	negX->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::LEFT);
+	negY->copyCubeEdge(sw::Surface::BOTTOM, negZ, sw::Surface::BOTTOM);
+	negZ->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::BOTTOM);
+
+	posX->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::RIGHT);
+	posY->copyCubeEdge(sw::Surface::TOP, negZ, sw::Surface::TOP);
+	posZ->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::BOTTOM);
+	negX->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::LEFT);
+	negY->copyCubeEdge(sw::Surface::TOP, posZ, sw::Surface::BOTTOM);
+	negZ->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::TOP);
+
+	// Copy left / right after top and bottom are done.
+	// The corner colors will be computed assuming top / bottom are already set.
+	posX->copyCubeEdge(sw::Surface::RIGHT, negZ, sw::Surface::LEFT);
+	posY->copyCubeEdge(sw::Surface::RIGHT, posX, sw::Surface::TOP);
+	posZ->copyCubeEdge(sw::Surface::RIGHT, posX, sw::Surface::LEFT);
+	negX->copyCubeEdge(sw::Surface::RIGHT, posZ, sw::Surface::LEFT);
+	negY->copyCubeEdge(sw::Surface::RIGHT, posX, sw::Surface::BOTTOM);
+	negZ->copyCubeEdge(sw::Surface::RIGHT, negX, sw::Surface::LEFT);
+
+	posX->copyCubeEdge(sw::Surface::LEFT, posZ, sw::Surface::RIGHT);
+	posY->copyCubeEdge(sw::Surface::LEFT, negX, sw::Surface::TOP);
+	posZ->copyCubeEdge(sw::Surface::LEFT, negX, sw::Surface::RIGHT);
+	negX->copyCubeEdge(sw::Surface::LEFT, negZ, sw::Surface::RIGHT);
+	negY->copyCubeEdge(sw::Surface::LEFT, negX, sw::Surface::BOTTOM);
+	negZ->copyCubeEdge(sw::Surface::LEFT, posX, sw::Surface::RIGHT);
+
+	posX->markContentsClean();
+	posY->markContentsClean();
+	posZ->markContentsClean();
+	negX->markContentsClean();
+	negY->markContentsClean();
+	negZ->markContentsClean();
+}
+
 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
 {
 	return IsCompressed(getFormat(target, level), egl::getClientVersion());
@@ -1260,7 +1218,7 @@
 	UNREACHABLE(0);   // Cube maps cannot have an EGL surface bound as an image
 }
 
-void TextureCubeMap::setImage(egl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
+void TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
 	int face = CubeFaceIndex(target);
 
@@ -1269,19 +1227,20 @@
 		image[face][level]->release();
 	}
 
-	image[face][level] = egl::Image::create(this, width, height, format, type);
+	int border = (egl::getClientVersion() >= 3) ? 1 : 0;
+	image[face][level] = egl::Image::create(this, width, height, 1, border, internalformat);
 
 	if(!image[face][level])
 	{
 		return error(GL_OUT_OF_MEMORY);
 	}
 
-	Texture::setImage(context, format, type, unpackInfo, pixels, image[face][level]);
+	Texture::setImage(format, type, unpackParameters, pixels, image[face][level]);
 }
 
-void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
 {
-	egl::Image *renderTarget = source->getRenderTarget(0);
+	egl::Image *renderTarget = source->getRenderTarget();
 
 	if(!renderTarget)
 	{
@@ -1296,8 +1255,8 @@
 		image[face][level]->release();
 	}
 
-	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[face][level] = egl::Image::create(this, width, height, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	int border = (egl::getClientVersion() >= 3) ? 1 : 0;
+	image[face][level] = egl::Image::create(this, width, height, 1, border, internalformat);
 
 	if(!image[face][level])
 	{
@@ -1306,18 +1265,10 @@
 
 	if(width != 0 && height != 0)
 	{
-		Renderbuffer* renderbuffer = source->getReadColorbuffer();
-
-		if(!renderbuffer)
-		{
-			ERR("Failed to retrieve the source colorbuffer.");
-			return;
-		}
-
 		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
-		sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
+		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
 
-		copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, 0, image[face][level]);
+		copy(renderTarget, sourceRect, 0, 0, 0, image[face][level]);
 	}
 
 	renderTarget->release();
@@ -1333,7 +1284,7 @@
 	return image[CubeFaceIndex(face)][level];
 }
 
-void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
 {
 	int face = CubeFaceIndex(target);
 
@@ -1349,49 +1300,45 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	egl::Image *renderTarget = source->getRenderTarget(0);
-
-	if(!renderTarget)
+	if(width > 0 && height > 0)
 	{
-		ERR("Failed to retrieve the render target.");
-		return error(GL_OUT_OF_MEMORY);
+		egl::Image *renderTarget = source->getRenderTarget();
+
+		if(!renderTarget)
+		{
+			ERR("Failed to retrieve the render target.");
+			return error(GL_OUT_OF_MEMORY);
+		}
+
+		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
+		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
+
+		copy(renderTarget, sourceRect, xoffset, yoffset, zoffset, image[face][level]);
+
+		renderTarget->release();
 	}
-
-	Renderbuffer* renderbuffer = source->getReadColorbuffer();
-
-	if(!renderbuffer)
-	{
-		ERR("Failed to retrieve the source colorbuffer.");
-		return;
-	}
-
-	sw::SliceRect sourceRect(x, y, x + width, y + height, 0);
-	sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
-
-	copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, zoffset, image[face][level]);
-
-	renderTarget->release();
 }
 
 void TextureCubeMap::generateMipmaps()
 {
-	if(!isCubeComplete())
-	{
-		return error(GL_INVALID_OPERATION);
-	}
+	ASSERT(isCubeComplete());
 
-	unsigned int q = log2(image[0][0]->getWidth());
+	int p = log2(image[0][mBaseLevel]->getWidth()) + mBaseLevel;
+	int q = std::min(p, mMaxLevel);
 
-	for(unsigned int f = 0; f < 6; f++)
+	for(int f = 0; f < 6; f++)
 	{
-		for(unsigned int i = 1; i <= q; i++)
+		ASSERT(image[f][mBaseLevel]);
+
+		for(int i = mBaseLevel + 1; i <= q; i++)
 		{
 			if(image[f][i])
 			{
 				image[f][i]->release();
 			}
 
-			image[f][i] = egl::Image::create(this, std::max(image[0][0]->getWidth() >> i, 1), std::max(image[0][0]->getHeight() >> i, 1), image[0][0]->getFormat(), image[0][0]->getType());
+			int border = (egl::getClientVersion() >= 3) ? 1 : 0;
+			image[f][i] = egl::Image::create(this, std::max(image[f][mBaseLevel]->getWidth() >> i, 1), std::max(image[f][mBaseLevel]->getHeight() >> i, 1), 1, border, image[f][mBaseLevel]->getFormat());
 
 			if(!image[f][i])
 			{
@@ -1403,7 +1350,7 @@
 	}
 }
 
-Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level, GLint layer)
+Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
 {
 	if(!IsCubemapTextureTarget(target))
 	{
@@ -1554,52 +1501,40 @@
 	return image[level] ? image[level]->getDepth() : 0;
 }
 
-GLenum Texture3D::getFormat(GLenum target, GLint level) const
+GLint Texture3D::getFormat(GLenum target, GLint level) const
 {
 	ASSERT(target == getTarget());
 	return image[level] ? image[level]->getFormat() : GL_NONE;
 }
 
-GLenum Texture3D::getType(GLenum target, GLint level) const
-{
-	ASSERT(target == getTarget());
-	return image[level] ? image[level]->getType() : GL_NONE;
-}
-
-sw::Format Texture3D::getInternalFormat(GLenum target, GLint level) const
-{
-	ASSERT(target == getTarget());
-	return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
-}
-
-int Texture3D::getLevelCount() const
+int Texture3D::getTopLevel() const
 {
 	ASSERT(isSamplerComplete());
-	int levels = 0;
+	int level = mBaseLevel;
 
-	while(levels < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[levels])
+	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[level])
 	{
-		levels++;
+		level++;
 	}
 
-	return levels;
+	return level - 1;
 }
 
-void Texture3D::setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
+void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
 	if(image[level])
 	{
 		image[level]->release();
 	}
 
-	image[level] = egl::Image::create(this, width, height, depth, format, type);
+	image[level] = egl::Image::create(this, width, height, depth, 0, internalformat);
 
 	if(!image[level])
 	{
 		return error(GL_OUT_OF_MEMORY);
 	}
 
-	Texture::setImage(context, format, type, unpackInfo, pixels, image[level]);
+	Texture::setImage(format, type, unpackParameters, pixels, image[level]);
 }
 
 void Texture3D::releaseTexImage()
@@ -1614,8 +1549,7 @@
 		image[level]->release();
 	}
 
-	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[level] = egl::Image::create(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, depth, 0, format);
 
 	if(!image[level])
 	{
@@ -1625,9 +1559,9 @@
 	Texture::setCompressedImage(imageSize, pixels, image[level]);
 }
 
-void Texture3D::subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels)
+void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels)
 {
-	Texture::subImage(context, xoffset, yoffset, zoffset, width, height, depth, format, type, unpackInfo, pixels, image[level]);
+	Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackParameters, pixels, image[level]);
 }
 
 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
@@ -1635,9 +1569,9 @@
 	Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
 }
 
-void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source)
+void Texture3D::copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Renderbuffer *source)
 {
-	egl::Image *renderTarget = source->getRenderTarget(0);
+	egl::Image *renderTarget = source->getRenderTarget();
 
 	if(!renderTarget)
 	{
@@ -1650,8 +1584,7 @@
 		image[level]->release();
 	}
 
-	GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
-	image[level] = egl::Image::create(this, width, height, depth, sizedInternalFormat, GL_UNSIGNED_BYTE);
+	image[level] = egl::Image::create(this, width, height, depth, 0, internalformat);
 
 	if(!image[level])
 	{
@@ -1660,26 +1593,19 @@
 
 	if(width != 0 && height != 0 && depth != 0)
 	{
-		Renderbuffer* renderbuffer = source->getReadColorbuffer();
-
-		if(!renderbuffer)
-		{
-			ERR("Failed to retrieve the source colorbuffer.");
-			return;
-		}
-
 		sw::SliceRect sourceRect(x, y, x + width, y + height, z);
-		sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
-		for(GLint sliceZ = 0; sliceZ < depth; ++sliceZ, ++sourceRect.slice)
+		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
+
+		for(GLint sliceZ = 0; sliceZ < depth; sliceZ++, sourceRect.slice++)
 		{
-			copy(renderTarget, sourceRect, sizedInternalFormat, 0, 0, sliceZ, image[level]);
+			copy(renderTarget, sourceRect, 0, 0, sliceZ, image[level]);
 		}
 	}
 
 	renderTarget->release();
 }
 
-void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
 {
 	if(!image[level])
 	{
@@ -1691,28 +1617,23 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	egl::Image *renderTarget = source->getRenderTarget(0);
-
-	if(!renderTarget)
+	if(width > 0 && height > 0)
 	{
-		ERR("Failed to retrieve the render target.");
-		return error(GL_OUT_OF_MEMORY);
+		egl::Image *renderTarget = source->getRenderTarget();
+
+		if(!renderTarget)
+		{
+			ERR("Failed to retrieve the render target.");
+			return error(GL_OUT_OF_MEMORY);
+		}
+
+		sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};
+		sourceRect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
+
+		copy(renderTarget, sourceRect, xoffset, yoffset, zoffset, image[level]);
+
+		renderTarget->release();
 	}
-
-	Renderbuffer* renderbuffer = source->getReadColorbuffer();
-
-	if(!renderbuffer)
-	{
-		ERR("Failed to retrieve the source colorbuffer.");
-		return;
-	}
-
-	sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};
-	sourceRect.clip(0, 0, renderbuffer->getWidth(), renderbuffer->getHeight());
-
-	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);
-
-	renderTarget->release();
 }
 
 void Texture3D::setSharedImage(egl::Image *sharedImage)
@@ -1727,17 +1648,17 @@
 	image[0] = sharedImage;
 }
 
-// Tests for 3D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
+// Tests for 3D texture sampling completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
 bool Texture3D::isSamplerComplete() const
 {
-	if(!image[0])
+	if(!image[mBaseLevel])
 	{
 		return false;
 	}
 
-	GLsizei width = image[0]->getWidth();
-	GLsizei height = image[0]->getHeight();
-	GLsizei depth = image[0]->getDepth();
+	GLsizei width = image[mBaseLevel]->getWidth();
+	GLsizei height = image[mBaseLevel]->getHeight();
+	GLsizei depth = image[mBaseLevel]->getDepth();
 
 	if(width <= 0 || height <= 0 || depth <= 0)
 	{
@@ -1755,16 +1676,22 @@
 	return true;
 }
 
-// Tests for 3D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+// Tests for 3D texture (mipmap) completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
 bool Texture3D::isMipmapComplete() const
 {
+	if(mBaseLevel > mMaxLevel)
+	{
+		return false;
+	}
+
 	GLsizei width = image[mBaseLevel]->getWidth();
 	GLsizei height = image[mBaseLevel]->getHeight();
 	GLsizei depth = image[mBaseLevel]->getDepth();
 	bool isTexture2DArray = getTarget() == GL_TEXTURE_2D_ARRAY;
 
-	int q = isTexture2DArray ? std::min(log2(std::max(width, height)), mMaxLevel) :
-	        std::min(log2(std::max(std::max(width, height), depth)), mMaxLevel);
+	int maxsize = isTexture2DArray ? std::max(width, height) : std::max(std::max(width, height), depth);
+	int p = log2(maxsize) + mBaseLevel;
+	int q = std::min(p, mMaxLevel);
 
 	for(int level = mBaseLevel + 1; level <= q; level++)
 	{
@@ -1773,27 +1700,24 @@
 			return false;
 		}
 
-		if(image[level]->getFormat() != image[0]->getFormat())
+		if(image[level]->getFormat() != image[mBaseLevel]->getFormat())
 		{
 			return false;
 		}
 
-		if(image[level]->getType() != image[0]->getType())
+		int i = level - mBaseLevel;
+
+		if(image[level]->getWidth() != std::max(1, width >> i))
 		{
 			return false;
 		}
 
-		if(image[level]->getWidth() != std::max(1, width >> level))
+		if(image[level]->getHeight() != std::max(1, height >> i))
 		{
 			return false;
 		}
 
-		if(image[level]->getHeight() != std::max(1, height >> level))
-		{
-			return false;
-		}
-
-		int levelDepth = isTexture2DArray ? depth : std::max(1, depth >> level);
+		int levelDepth = isTexture2DArray ? depth : std::max(1, depth >> i);
 		if(image[level]->getDepth() != levelDepth)
 		{
 			return false;
@@ -1815,21 +1739,20 @@
 
 void Texture3D::generateMipmaps()
 {
-	if(!image[0])
-	{
-		return;   // FIXME: error?
-	}
+	ASSERT(image[mBaseLevel]);
 
-	unsigned int q = log2(std::max(std::max(image[0]->getWidth(), image[0]->getHeight()), image[0]->getDepth()));
+	int maxsize = std::max(std::max(image[mBaseLevel]->getWidth(), image[mBaseLevel]->getHeight()), image[mBaseLevel]->getDepth());
+	int p = log2(maxsize) + mBaseLevel;
+	int q = std::min(p, mMaxLevel);
 
-	for(unsigned int i = 1; i <= q; i++)
+	for(int i = mBaseLevel + 1; i <= q; i++)
 	{
 		if(image[i])
 		{
 			image[i]->release();
 		}
 
-		image[i] = egl::Image::create(this, std::max(image[0]->getWidth() >> i, 1), std::max(image[0]->getHeight() >> i, 1), std::max(image[0]->getDepth() >> i, 1), image[0]->getFormat(), image[0]->getType());
+		image[i] = egl::Image::create(this, std::max(image[mBaseLevel]->getWidth() >> i, 1), std::max(image[mBaseLevel]->getHeight() >> i, 1), std::max(image[mBaseLevel]->getDepth() >> i, 1), 0, image[mBaseLevel]->getFormat());
 
 		if(!image[i])
 		{
@@ -1845,7 +1768,7 @@
 	return image[level];
 }
 
-Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level, GLint layer)
+Renderbuffer *Texture3D::getRenderbuffer(GLenum target, GLint level)
 {
 	if(target != getTarget())
 	{
@@ -1854,12 +1777,11 @@
 
 	if(!mColorbufferProxy)
 	{
-		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level, layer));
+		mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture3D(this, level));
 	}
 	else
 	{
 		mColorbufferProxy->setLevel(level);
-		mColorbufferProxy->setLayer(layer);
 	}
 
 	return mColorbufferProxy;
@@ -1911,24 +1833,23 @@
 
 void Texture2DArray::generateMipmaps()
 {
-	int depth = image[0] ? image[0]->getDepth() : 0;
-	if(!depth)
-	{
-		return;   // FIXME: error?
-	}
+	ASSERT(image[mBaseLevel]);
 
-	unsigned int q = log2(std::max(image[0]->getWidth(), image[0]->getHeight()));
+	int depth = image[mBaseLevel]->getDepth();
+	int maxsize = std::max(image[mBaseLevel]->getWidth(), image[mBaseLevel]->getHeight());
+	int p = log2(maxsize) + mBaseLevel;
+	int q = std::min(p, mMaxLevel);
 
-	for(unsigned int i = 1; i <= q; i++)
+	for(int i = mBaseLevel + 1; i <= q; i++)
 	{
 		if(image[i])
 		{
 			image[i]->release();
 		}
 
-		GLsizei w = std::max(image[0]->getWidth() >> i, 1);
-		GLsizei h = std::max(image[0]->getHeight() >> i, 1);
-		image[i] = egl::Image::create(this, w, h, depth, image[0]->getFormat(), image[0]->getType());
+		GLsizei w = std::max(image[mBaseLevel]->getWidth() >> i, 1);
+		GLsizei h = std::max(image[mBaseLevel]->getHeight() >> i, 1);
+		image[i] = egl::Image::create(this, w, h, depth, 0, image[mBaseLevel]->getFormat());
 
 		if(!image[i])
 		{
@@ -1939,7 +1860,7 @@
 		GLsizei srch = image[i - 1]->getHeight();
 		for(int z = 0; z < depth; ++z)
 		{
-			sw::SliceRect srcRect(0, 0, srcw, srch, z);
+			sw::SliceRectF srcRect(0.0f, 0.0f, static_cast<float>(srcw), static_cast<float>(srch), z);
 			sw::SliceRect dstRect(0, 0, w, h, z);
 			getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, Device::ALL_BUFFERS | Device::USE_FILTER);
 		}
@@ -1974,7 +1895,9 @@
 		return nullptr;
 	}
 
-	return egl::Image::create(width, height, format, multiSampleDepth, false);
+	GLenum internalformat = sw2es::ConvertBackBufferFormat(format);
+
+	return egl::Image::create(width, height, internalformat, multiSampleDepth, false);
 }
 
 NO_SANITIZE_FUNCTION egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth)
@@ -2010,7 +1933,9 @@
 		UNREACHABLE(format);
 	}
 
-	egl::Image *surface = egl::Image::create(width, height, format, multiSampleDepth, lockable);
+	GLenum internalformat = sw2es::ConvertDepthStencilFormat(format);
+
+	egl::Image *surface = egl::Image::create(width, height, internalformat, multiSampleDepth, lockable);
 
 	if(!surface)
 	{
diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h
index 143c51e..54ca5f9 100644
--- a/src/OpenGL/libGLESv2/Texture.h
+++ b/src/OpenGL/libGLESv2/Texture.h
@@ -33,8 +33,6 @@
 
 namespace es2
 {
-class Framebuffer;
-
 enum
 {
 	IMPLEMENTATION_MAX_TEXTURE_LEVELS = sw::MIPMAP_LEVELS,
@@ -73,54 +71,52 @@
 	bool setSwizzleB(GLenum swizzleB);
 	bool setSwizzleA(GLenum swizzleA);
 
-	GLenum getMinFilter() const;
-	GLenum getMagFilter() const;
-	GLenum getWrapS() const;
-	GLenum getWrapT() const;
-	GLenum getWrapR() const;
-	GLfloat getMaxAnisotropy() const;
-	GLint getBaseLevel() const;
-	GLenum getCompareFunc() const;
-	GLenum getCompareMode() const;
-	GLboolean getImmutableFormat() const;
-	GLsizei getImmutableLevels() const;
-	GLint getMaxLevel() const;
-	GLfloat getMaxLOD() const;
-	GLfloat getMinLOD() const;
-	GLenum getSwizzleR() const;
-	GLenum getSwizzleG() const;
-	GLenum getSwizzleB() const;
-	GLenum getSwizzleA() const;
+	GLenum getMinFilter() const { return mMinFilter; }
+	GLenum getMagFilter() const { return mMagFilter; }
+	GLenum getWrapS() const { return mWrapS; }
+	GLenum getWrapT() const { return mWrapT; }
+	GLenum getWrapR() const { return mWrapR; }
+	GLfloat getMaxAnisotropy() const { return mMaxAnisotropy; }
+	GLint getBaseLevel() const { return mBaseLevel; }
+	GLenum getCompareFunc() const { return mCompareFunc; }
+	GLenum getCompareMode() const { return mCompareMode; }
+	GLboolean getImmutableFormat() const { return mImmutableFormat; }
+	GLsizei getImmutableLevels() const { return mImmutableLevels; }
+	GLint getMaxLevel() const { return mMaxLevel; }
+	GLfloat getMaxLOD() const { return mMaxLOD; }
+	GLfloat getMinLOD() const { return mMinLOD; }
+	GLenum getSwizzleR() const { return mSwizzleR; }
+	GLenum getSwizzleG() const { return mSwizzleG; }
+	GLenum getSwizzleB() const { return mSwizzleB; }
+	GLenum getSwizzleA() const { return mSwizzleA; }
 
 	virtual GLsizei getWidth(GLenum target, GLint level) const = 0;
 	virtual GLsizei getHeight(GLenum target, GLint level) const = 0;
 	virtual GLsizei getDepth(GLenum target, GLint level) const;
-	virtual GLenum getFormat(GLenum target, GLint level) const = 0;
-	virtual GLenum getType(GLenum target, GLint level) const = 0;
-	virtual sw::Format getInternalFormat(GLenum target, GLint level) const = 0;
-	virtual int getLevelCount() const = 0;
+	virtual GLint getFormat(GLenum target, GLint level) const = 0;
+	virtual int getTopLevel() const = 0;
 
 	virtual bool isSamplerComplete() const = 0;
 	virtual bool isCompressed(GLenum target, GLint level) const = 0;
 	virtual bool isDepth(GLenum target, GLint level) const = 0;
 
-	virtual Renderbuffer *getRenderbuffer(GLenum target, GLint level, GLint layer) = 0;
+	virtual Renderbuffer *getRenderbuffer(GLenum target, GLint level) = 0;
 	virtual egl::Image *getRenderTarget(GLenum target, unsigned int level) = 0;
 	egl::Image *createSharedImage(GLenum target, unsigned int level);
 	virtual bool isShared(GLenum target, unsigned int level) const = 0;
 
 	virtual void generateMipmaps() = 0;
-	virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0;
+	virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source) = 0;
 
 protected:
 	~Texture() override;
 
-	void setImage(egl::Context *context, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image);
-	void subImage(egl::Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels, egl::Image *image);
+	void setImage(GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image);
+	void subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels, egl::Image *image);
 	void setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image);
 	void subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image);
 
-	bool copy(egl::Image *source, const sw::SliceRect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest);
+	bool copy(egl::Image *source, const sw::SliceRect &sourceRect, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest);
 
 	bool isMipmapFiltered() const;
 
@@ -159,17 +155,15 @@
 
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
-	GLenum getFormat(GLenum target, GLint level) const override;
-	GLenum getType(GLenum target, GLint level) const override;
-	sw::Format getInternalFormat(GLenum target, GLint level) const override;
-	int getLevelCount() const override;
+	GLint getFormat(GLenum target, GLint level) const override;
+	int getTopLevel() const override;
 
-	void setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels);
+	void setImage(GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
-	void subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels);
+	void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
-	void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
-	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) override;
+	void copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
+	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source) override;
 
 	void setSharedImage(egl::Image *image);
 
@@ -181,7 +175,7 @@
 
 	void generateMipmaps() override;
 
-	Renderbuffer *getRenderbuffer(GLenum target, GLint level, GLint layer) override;
+	Renderbuffer *getRenderbuffer(GLenum target, GLint level) override;
 	egl::Image *getRenderTarget(GLenum target, unsigned int level) override;
 	bool isShared(GLenum target, unsigned int level) const override;
 
@@ -205,6 +199,16 @@
 	unsigned int mProxyRefs;
 };
 
+class Texture2DRect : public Texture2D
+{
+public:
+	explicit Texture2DRect(GLuint name);
+
+	GLenum getTarget() const override;
+
+	Renderbuffer *getRenderbuffer(GLenum target, GLint level) override;
+};
+
 class TextureCubeMap : public Texture
 {
 public:
@@ -218,18 +222,16 @@
 
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
-	GLenum getFormat(GLenum target, GLint level) const override;
-	GLenum getType(GLenum target, GLint level) const override;
-	sw::Format getInternalFormat(GLenum target, GLint level) const override;
-	int getLevelCount() const override;
+	GLint getFormat(GLenum target, GLint level) const override;
+	int getTopLevel() const override;
 
-	void setImage(egl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels);
+	void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
 
-	void subImage(egl::Context *context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels);
+	void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
-	void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
-	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) override;
+	void copyImage(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
+	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source) override;
 
 	bool isSamplerComplete() const override;
 	bool isCompressed(GLenum target, GLint level) const override;
@@ -237,18 +239,20 @@
 	void releaseTexImage() override;
 
 	void generateMipmaps() override;
+	void updateBorders(int level);
 
-	Renderbuffer *getRenderbuffer(GLenum target, GLint level, GLint layer) override;
+	Renderbuffer *getRenderbuffer(GLenum target, GLint level) override;
 	egl::Image *getRenderTarget(GLenum target, unsigned int level) override;
 	bool isShared(GLenum target, unsigned int level) const override;
 
 	egl::Image *getImage(int face, unsigned int level);
 
+	bool isCubeComplete() const;
+
 protected:
 	~TextureCubeMap() override;
 
 private:
-	bool isCubeComplete() const;
 	bool isMipmapCubeComplete() const;
 
 	// face is one of the GL_TEXTURE_CUBE_MAP_* enumerants. Returns nullptr on failure.
@@ -279,17 +283,15 @@
 	GLsizei getWidth(GLenum target, GLint level) const override;
 	GLsizei getHeight(GLenum target, GLint level) const override;
 	GLsizei getDepth(GLenum target, GLint level) const override;
-	GLenum getFormat(GLenum target, GLint level) const override;
-	GLenum getType(GLenum target, GLint level) const override;
-	sw::Format getInternalFormat(GLenum target, GLint level) const override;
-	int getLevelCount() const override;
+	GLint getFormat(GLenum target, GLint level) const override;
+	int getTopLevel() const override;
 
-	void setImage(egl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels);
+	void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalformat, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
-	void subImage(egl::Context *context, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const egl::Image::UnpackInfo& unpackInfo, const void *pixels);
+	void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels);
 	void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels);
-	void copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source);
-	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+	void copyImage(GLint level, GLenum internalformat, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Renderbuffer *source);
+	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
 
 	void setSharedImage(egl::Image *image);
 
@@ -300,7 +302,7 @@
 
 	void generateMipmaps() override;
 
-	Renderbuffer *getRenderbuffer(GLenum target, GLint level, GLint layer) override;
+	Renderbuffer *getRenderbuffer(GLenum target, GLint level) override;
 	egl::Image *getRenderTarget(GLenum target, unsigned int level) override;
 	bool isShared(GLenum target, unsigned int level) const override;
 
diff --git a/src/OpenGL/libGLESv2/VertexArray.cpp b/src/OpenGL/libGLESv2/VertexArray.cpp
index d52e7ca..64ae221 100644
--- a/src/OpenGL/libGLESv2/VertexArray.cpp
+++ b/src/OpenGL/libGLESv2/VertexArray.cpp
@@ -65,13 +65,14 @@
 }
 
 void VertexArray::setAttributeState(unsigned int attributeIndex, Buffer *boundBuffer, GLint size, GLenum type,
-                                    bool normalized, GLsizei stride, const void *pointer)
+                                    bool normalized, bool pureInteger, GLsizei stride, const void *pointer)
 {
 	ASSERT(attributeIndex < MAX_VERTEX_ATTRIBS);
 	mVertexAttributes[attributeIndex].mBoundBuffer = boundBuffer;
 	mVertexAttributes[attributeIndex].mSize = size;
 	mVertexAttributes[attributeIndex].mType = type;
 	mVertexAttributes[attributeIndex].mNormalized = normalized;
+	mVertexAttributes[attributeIndex].mPureInteger = pureInteger;
 	mVertexAttributes[attributeIndex].mStride = stride;
 	mVertexAttributes[attributeIndex].mPointer = pointer;
 }
diff --git a/src/OpenGL/libGLESv2/VertexArray.h b/src/OpenGL/libGLESv2/VertexArray.h
index 363cf53..bb0f480 100644
--- a/src/OpenGL/libGLESv2/VertexArray.h
+++ b/src/OpenGL/libGLESv2/VertexArray.h
@@ -38,7 +38,7 @@
 	void setVertexAttribDivisor(GLuint index, GLuint divisor);
 	void enableAttribute(unsigned int attributeIndex, bool enabledState);
 	void setAttributeState(unsigned int attributeIndex, Buffer *boundBuffer, GLint size, GLenum type,
-	                       bool normalized, GLsizei stride, const void *pointer);
+	                       bool normalized, bool pureInteger, GLsizei stride, const void *pointer);
 
 	Buffer *getElementArrayBuffer() const { return mElementArrayBuffer; }
 	void setElementArrayBuffer(Buffer *buffer);
diff --git a/src/OpenGL/libGLESv2/entry_points.cpp b/src/OpenGL/libGLESv2/entry_points.cpp
new file mode 100644
index 0000000..e4b35aa
--- /dev/null
+++ b/src/OpenGL/libGLESv2/entry_points.cpp
@@ -0,0 +1,1428 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// entry_points.cpp: GL entry points exports and definition
+
+#include "main.h"
+
+#include "libEGL/main.h"
+
+namespace es2
+{
+void ActiveTexture(GLenum texture);
+void AttachShader(GLuint program, GLuint shader);
+void BeginQueryEXT(GLenum target, GLuint name);
+void BindAttribLocation(GLuint program, GLuint index, const GLchar* name);
+void BindBuffer(GLenum target, GLuint buffer);
+void BindFramebuffer(GLenum target, GLuint framebuffer);
+void BindRenderbuffer(GLenum target, GLuint renderbuffer);
+void BindTexture(GLenum target, GLuint texture);
+void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+void BlendEquation(GLenum mode);
+void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
+void BlendFunc(GLenum sfactor, GLenum dfactor);
+void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+void BufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+GLenum CheckFramebufferStatus(GLenum target);
+void Clear(GLbitfield mask);
+void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+void ClearDepthf(GLclampf depth);
+void ClearStencil(GLint s);
+void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+void CompileShader(GLuint shader);
+void CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
+                          GLint border, GLsizei imageSize, const GLvoid* data);
+void CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                             GLenum format, GLsizei imageSize, const GLvoid* data);
+void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLuint CreateProgram(void);
+GLuint CreateShader(GLenum type);
+void CullFace(GLenum mode);
+void DeleteBuffers(GLsizei n, const GLuint* buffers);
+void DeleteFencesNV(GLsizei n, const GLuint* fences);
+void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
+void DeleteProgram(GLuint program);
+void DeleteQueriesEXT(GLsizei n, const GLuint *ids);
+void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
+void DeleteShader(GLuint shader);
+void DeleteTextures(GLsizei n, const GLuint* textures);
+void DepthFunc(GLenum func);
+void DepthMask(GLboolean flag);
+void DepthRangef(GLclampf zNear, GLclampf zFar);
+void DetachShader(GLuint program, GLuint shader);
+void Disable(GLenum cap);
+void DisableVertexAttribArray(GLuint index);
+void DrawArrays(GLenum mode, GLint first, GLsizei count);
+void DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
+void DrawArraysInstancedEXT(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
+void DrawElementsInstancedEXT(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount);
+void VertexAttribDivisorEXT(GLuint index, GLuint divisor);
+void DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
+void DrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount);
+void VertexAttribDivisorANGLE(GLuint index, GLuint divisor);
+void Enable(GLenum cap);
+void EnableVertexAttribArray(GLuint index);
+void EndQueryEXT(GLenum target);
+void FinishFenceNV(GLuint fence);
+void Finish(void);
+void Flush(void);
+void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+void FrontFace(GLenum mode);
+void GenBuffers(GLsizei n, GLuint* buffers);
+void GenerateMipmap(GLenum target);
+void GenFencesNV(GLsizei n, GLuint* fences);
+void GenFramebuffers(GLsizei n, GLuint* framebuffers);
+void GenQueriesEXT(GLsizei n, GLuint* ids);
+void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
+void GenTextures(GLsizei n, GLuint* textures);
+void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+void GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+void GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+int GetAttribLocation(GLuint program, const GLchar* name);
+void GetBooleanv(GLenum pname, GLboolean* params);
+void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
+GLenum GetError(void);
+void GetFenceivNV(GLuint fence, GLenum pname, GLint *params);
+void GetFloatv(GLenum pname, GLfloat* params);
+void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GLenum GetGraphicsResetStatusEXT(void);
+void GetIntegerv(GLenum pname, GLint* params);
+void GetProgramiv(GLuint program, GLenum pname, GLint* params);
+void GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+void GetQueryivEXT(GLenum target, GLenum pname, GLint *params);
+void GetQueryObjectuivEXT(GLuint name, GLenum pname, GLuint *params);
+void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
+void GetShaderiv(GLuint shader, GLenum pname, GLint* params);
+void GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+void GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+void GetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+const GLubyte* GetString(GLenum name);
+void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params);
+void GetTexParameteriv(GLenum target, GLenum pname, GLint* params);
+void GetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params);
+void GetUniformfv(GLuint program, GLint location, GLfloat* params);
+void GetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params);
+void GetUniformiv(GLuint program, GLint location, GLint* params);
+int GetUniformLocation(GLuint program, const GLchar* name);
+void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params);
+void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params);
+void GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer);
+void Hint(GLenum target, GLenum mode);
+GLboolean IsBuffer(GLuint buffer);
+GLboolean IsEnabled(GLenum cap);
+GLboolean IsFenceNV(GLuint fence);
+GLboolean IsFramebuffer(GLuint framebuffer);
+GLboolean IsProgram(GLuint program);
+GLboolean IsQueryEXT(GLuint name);
+GLboolean IsRenderbuffer(GLuint renderbuffer);
+GLboolean IsShader(GLuint shader);
+GLboolean IsTexture(GLuint texture);
+void LineWidth(GLfloat width);
+void LinkProgram(GLuint program);
+void PixelStorei(GLenum pname, GLint param);
+void PolygonOffset(GLfloat factor, GLfloat units);
+void ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
+                    GLenum format, GLenum type, GLsizei bufSize, GLvoid *data);
+void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+void ReleaseShaderCompiler(void);
+void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+void RenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+void SampleCoverage(GLclampf value, GLboolean invert);
+void SetFenceNV(GLuint fence, GLenum condition);
+void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
+void ShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+void ShaderSource(GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length);
+void StencilFunc(GLenum func, GLint ref, GLuint mask);
+void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
+void StencilMask(GLuint mask);
+void StencilMaskSeparate(GLenum face, GLuint mask);
+void StencilOp(GLenum fail, GLenum zfail, GLenum zpass);
+void StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GLboolean TestFenceNV(GLuint fence);
+void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+                GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+void TexParameterf(GLenum target, GLenum pname, GLfloat param);
+void TexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
+void TexParameteri(GLenum target, GLenum pname, GLint param);
+void TexParameteriv(GLenum target, GLenum pname, const GLint* params);
+void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                   GLenum format, GLenum type, const GLvoid* pixels);
+void Uniform1f(GLint location, GLfloat x);
+void Uniform1fv(GLint location, GLsizei count, const GLfloat* v);
+void Uniform1i(GLint location, GLint x);
+void Uniform1iv(GLint location, GLsizei count, const GLint* v);
+void Uniform2f(GLint location, GLfloat x, GLfloat y);
+void Uniform2fv(GLint location, GLsizei count, const GLfloat* v);
+void Uniform2i(GLint location, GLint x, GLint y);
+void Uniform2iv(GLint location, GLsizei count, const GLint* v);
+void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z);
+void Uniform3fv(GLint location, GLsizei count, const GLfloat* v);
+void Uniform3i(GLint location, GLint x, GLint y, GLint z);
+void Uniform3iv(GLint location, GLsizei count, const GLint* v);
+void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void Uniform4fv(GLint location, GLsizei count, const GLfloat* v);
+void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w);
+void Uniform4iv(GLint location, GLsizei count, const GLint* v);
+void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+void UseProgram(GLuint program);
+void ValidateProgram(GLuint program);
+void VertexAttrib1f(GLuint index, GLfloat x);
+void VertexAttrib1fv(GLuint index, const GLfloat* values);
+void VertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
+void VertexAttrib2fv(GLuint index, const GLfloat* values);
+void VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
+void VertexAttrib3fv(GLuint index, const GLfloat* values);
+void VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void VertexAttrib4fv(GLuint index, const GLfloat* values);
+GL_APICALL void VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+GL_APICALL void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void BlitFramebufferNV(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GL_APICALL void BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+                                     GLbitfield mask, GLenum filter);
+GL_APICALL void TexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
+                              GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void TexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+GL_APICALL void CopyTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void CompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+GL_APICALL void CompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+GL_APICALL void FramebufferTexture3DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GL_APICALL void EGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+GL_APICALL void EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
+GL_APICALL GLboolean IsRenderbufferOES(GLuint renderbuffer);
+GL_APICALL void BindRenderbufferOES(GLenum target, GLuint renderbuffer);
+GL_APICALL void DeleteRenderbuffersOES(GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GenRenderbuffersOES(GLsizei n, GLuint* renderbuffers);
+GL_APICALL void RenderbufferStorageOES(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GetRenderbufferParameterivOES(GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLboolean IsFramebufferOES(GLuint framebuffer);
+GL_APICALL void BindFramebufferOES(GLenum target, GLuint framebuffer);
+GL_APICALL void DeleteFramebuffersOES(GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GenFramebuffersOES(GLsizei n, GLuint* framebuffers);
+GL_APICALL GLenum CheckFramebufferStatusOES(GLenum target);
+GL_APICALL void FramebufferRenderbufferOES(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void FramebufferTexture2DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GetFramebufferAttachmentParameterivOES(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GenerateMipmapOES(GLenum target);
+GL_APICALL void DrawBuffersEXT(GLsizei n, const GLenum *bufs);
+}
+
+extern "C"
+{
+GL_APICALL void GL_APIENTRY glActiveTexture(GLenum texture)
+{
+	return es2::ActiveTexture(texture);
+}
+
+GL_APICALL void GL_APIENTRY glAttachShader(GLuint program, GLuint shader)
+{
+	return es2::AttachShader(program, shader);
+}
+
+GL_APICALL void GL_APIENTRY glBeginQueryEXT(GLenum target, GLuint name)
+{
+	return es2::BeginQueryEXT(target, name);
+}
+
+GL_APICALL void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
+{
+	return es2::BindAttribLocation(program, index, name);
+}
+
+GL_APICALL void GL_APIENTRY glBindBuffer(GLenum target, GLuint buffer)
+{
+	return es2::BindBuffer(target, buffer);
+}
+
+GL_APICALL void GL_APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer)
+{
+	return es2::BindFramebuffer(target, framebuffer);
+}
+
+GL_APICALL void GL_APIENTRY glBindFramebufferOES(GLenum target, GLuint framebuffer)
+{
+	return es2::BindFramebuffer(target, framebuffer);
+}
+
+GL_APICALL void GL_APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+	return es2::BindRenderbuffer(target, renderbuffer);
+}
+
+GL_APICALL void GL_APIENTRY glBindRenderbufferOES(GLenum target, GLuint renderbuffer)
+{
+	return es2::BindRenderbuffer(target, renderbuffer);
+}
+
+GL_APICALL void GL_APIENTRY glBindTexture(GLenum target, GLuint texture)
+{
+	return es2::BindTexture(target, texture);
+}
+
+GL_APICALL void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+	return es2::BlendColor(red, green, blue, alpha);
+}
+
+GL_APICALL void GL_APIENTRY glBlendEquation(GLenum mode)
+{
+	return es2::BlendEquation(mode);
+}
+
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+{
+	return es2::BlendEquationSeparate(modeRGB, modeAlpha);
+}
+
+GL_APICALL void GL_APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+	return es2::BlendFunc(sfactor, dfactor);
+}
+
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+	return es2::BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+GL_APICALL void GL_APIENTRY glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+	return es2::BufferData(target, size, data, usage);
+}
+
+GL_APICALL void GL_APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+	return es2::BufferSubData(target, offset, size, data);
+}
+
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus(GLenum target)
+{
+	return es2::CheckFramebufferStatus(target);
+}
+
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatusOES(GLenum target)
+{
+	return es2::CheckFramebufferStatus(target);
+}
+
+GL_APICALL void GL_APIENTRY glClear(GLbitfield mask)
+{
+	return es2::Clear(mask);
+}
+
+GL_APICALL void GL_APIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+	return es2::ClearColor(red, green, blue, alpha);
+}
+
+GL_APICALL void GL_APIENTRY glClearDepthf(GLclampf depth)
+{
+	return es2::ClearDepthf(depth);
+}
+
+GL_APICALL void GL_APIENTRY glClearStencil(GLint s)
+{
+	return es2::ClearStencil(s);
+}
+
+GL_APICALL void GL_APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+	return es2::ColorMask(red, green, blue, alpha);
+}
+
+GL_APICALL void GL_APIENTRY glCompileShader(GLuint shader)
+{
+	return es2::CompileShader(shader);
+}
+
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
+                                                   GLint border, GLsizei imageSize, const GLvoid* data)
+{
+	return es2::CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
+}
+
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                                                      GLenum format, GLsizei imageSize, const GLvoid* data)
+{
+	return es2::CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+
+GL_APICALL void GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+	return es2::CopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+}
+
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	return es2::CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+}
+
+GL_APICALL GLuint GL_APIENTRY glCreateProgram(void)
+{
+	return es2::CreateProgram();
+}
+
+GL_APICALL GLuint GL_APIENTRY glCreateShader(GLenum type)
+{
+	return es2::CreateShader(type);
+}
+
+GL_APICALL void GL_APIENTRY glCullFace(GLenum mode)
+{
+	return es2::CullFace(mode);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+	return es2::DeleteBuffers(n, buffers);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteFencesNV(GLsizei n, const GLuint* fences)
+{
+	return es2::DeleteFencesNV(n, fences);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+{
+	return es2::DeleteFramebuffers(n, framebuffers);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteFramebuffersOES(GLsizei n, const GLuint* framebuffers)
+{
+	return es2::DeleteFramebuffers(n, framebuffers);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteProgram(GLuint program)
+{
+	return es2::DeleteProgram(program);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteQueriesEXT(GLsizei n, const GLuint *ids)
+{
+	return es2::DeleteQueriesEXT(n, ids);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+{
+	return es2::DeleteRenderbuffers(n, renderbuffers);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffersOES(GLsizei n, const GLuint* renderbuffers)
+{
+	return es2::DeleteRenderbuffers(n, renderbuffers);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteShader(GLuint shader)
+{
+	return es2::DeleteShader(shader);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures)
+{
+	return es2::DeleteTextures(n, textures);
+}
+
+GL_APICALL void GL_APIENTRY glDepthFunc(GLenum func)
+{
+	return es2::DepthFunc(func);
+}
+
+GL_APICALL void GL_APIENTRY glDepthMask(GLboolean flag)
+{
+	return es2::DepthMask(flag);
+}
+
+GL_APICALL void GL_APIENTRY glDepthRangef(GLclampf zNear, GLclampf zFar)
+{
+	return es2::DepthRangef(zNear, zFar);
+}
+
+GL_APICALL void GL_APIENTRY glDetachShader(GLuint program, GLuint shader)
+{
+	return es2::DetachShader(program, shader);
+}
+
+GL_APICALL void GL_APIENTRY glDisable(GLenum cap)
+{
+	return es2::Disable(cap);
+}
+
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray(GLuint index)
+{
+	return es2::DisableVertexAttribArray(index);
+}
+
+GL_APICALL void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+	return es2::DrawArrays(mode, first, count);
+}
+
+GL_APICALL void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+{
+	return es2::DrawElements(mode, count, type, indices);
+}
+
+GL_APICALL void GL_APIENTRY glDrawArraysInstancedEXT(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
+{
+	return es2::DrawArraysInstancedEXT(mode, first, count, instanceCount);
+}
+
+GL_APICALL void GL_APIENTRY glDrawElementsInstancedEXT(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
+{
+	return es2::DrawElementsInstancedEXT(mode, count, type, indices, instanceCount);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttribDivisorEXT(GLuint index, GLuint divisor)
+{
+	return es2::VertexAttribDivisorEXT(index, divisor);
+}
+
+GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
+{
+	return es2::DrawArraysInstancedANGLE(mode, first, count, instanceCount);
+}
+
+GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
+{
+	return es2::DrawElementsInstancedANGLE(mode, count, type, indices, instanceCount);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE(GLuint index, GLuint divisor)
+{
+	return es2::VertexAttribDivisorANGLE(index, divisor);
+}
+
+GL_APICALL void GL_APIENTRY glEnable(GLenum cap)
+{
+	return es2::Enable(cap);
+}
+
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray(GLuint index)
+{
+	return es2::EnableVertexAttribArray(index);
+}
+
+GL_APICALL void GL_APIENTRY glEndQueryEXT(GLenum target)
+{
+	return es2::EndQueryEXT(target);
+}
+
+GL_APICALL void GL_APIENTRY glFinishFenceNV(GLuint fence)
+{
+	return es2::FinishFenceNV(fence);
+}
+
+GL_APICALL void GL_APIENTRY glFinish(void)
+{
+	return es2::Finish();
+}
+
+GL_APICALL void GL_APIENTRY glFlush(void)
+{
+	return es2::Flush();
+}
+
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+	return es2::FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+}
+
+GL_APICALL void GL_APIENTRY glFramebufferRenderbufferOES(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+	return es2::FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+}
+
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+	return es2::FramebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+	return es2::FramebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+GL_APICALL void GL_APIENTRY glFrontFace(GLenum mode)
+{
+	return es2::FrontFace(mode);
+}
+
+GL_APICALL void GL_APIENTRY glGenBuffers(GLsizei n, GLuint* buffers)
+{
+	return es2::GenBuffers(n, buffers);
+}
+
+GL_APICALL void GL_APIENTRY glGenerateMipmap(GLenum target)
+{
+	return es2::GenerateMipmap(target);
+}
+
+GL_APICALL void GL_APIENTRY glGenerateMipmapOES(GLenum target)
+{
+	return es2::GenerateMipmap(target);
+}
+
+GL_APICALL void GL_APIENTRY glGenFencesNV(GLsizei n, GLuint* fences)
+{
+	return es2::GenFencesNV(n, fences);
+}
+
+GL_APICALL void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers)
+{
+	return es2::GenFramebuffers(n, framebuffers);
+}
+
+GL_APICALL void GL_APIENTRY glGenFramebuffersOES(GLsizei n, GLuint* framebuffers)
+{
+	return es2::GenFramebuffers(n, framebuffers);
+}
+
+GL_APICALL void GL_APIENTRY glGenQueriesEXT(GLsizei n, GLuint* ids)
+{
+	return es2::GenQueriesEXT(n, ids);
+}
+
+GL_APICALL void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+{
+	return es2::GenRenderbuffers(n, renderbuffers);
+}
+
+GL_APICALL void GL_APIENTRY glGenRenderbuffersOES(GLsizei n, GLuint* renderbuffers)
+{
+	return es2::GenRenderbuffers(n, renderbuffers);
+}
+
+GL_APICALL void GL_APIENTRY glGenTextures(GLsizei n, GLuint* textures)
+{
+	return es2::GenTextures(n, textures);
+}
+
+GL_APICALL void GL_APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+	return es2::GetActiveAttrib(program, index, bufsize, length, size, type, name);
+}
+
+GL_APICALL void GL_APIENTRY glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+	return es2::GetActiveUniform(program, index, bufsize, length, size, type, name);
+}
+
+GL_APICALL void GL_APIENTRY glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+	return es2::GetAttachedShaders(program, maxcount, count, shaders);
+}
+
+GL_APICALL int GL_APIENTRY glGetAttribLocation(GLuint program, const GLchar* name)
+{
+	return es2::GetAttribLocation(program, name);
+}
+
+GL_APICALL void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean* params)
+{
+	return es2::GetBooleanv(pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+	return es2::GetBufferParameteriv(target, pname, params);
+}
+
+GL_APICALL GLenum GL_APIENTRY glGetError(void)
+{
+	return es2::GetError();
+}
+
+GL_APICALL void GL_APIENTRY glGetFenceivNV(GLuint fence, GLenum pname, GLint *params)
+{
+	return es2::GetFenceivNV(fence, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetFloatv(GLenum pname, GLfloat* params)
+{
+	return es2::GetFloatv(pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+	return es2::GetFramebufferAttachmentParameteriv(target, attachment, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameterivOES(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+	return es2::GetFramebufferAttachmentParameteriv(target, attachment, pname, params);
+}
+
+GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT(void)
+{
+	return es2::GetGraphicsResetStatusEXT();
+}
+
+GL_APICALL void GL_APIENTRY glGetIntegerv(GLenum pname, GLint* params)
+{
+	return es2::GetIntegerv(pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params)
+{
+	return es2::GetProgramiv(program, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+	return es2::GetProgramInfoLog(program, bufsize, length, infolog);
+}
+
+GL_APICALL void GL_APIENTRY glGetQueryivEXT(GLenum target, GLenum pname, GLint *params)
+{
+	return es2::GetQueryivEXT(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT(GLuint name, GLenum pname, GLuint *params)
+{
+	return es2::GetQueryObjectuivEXT(name, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+	return es2::GetRenderbufferParameteriv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameterivOES(GLenum target, GLenum pname, GLint* params)
+{
+	return es2::GetRenderbufferParameteriv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+{
+	return es2::GetShaderiv(shader, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+	return es2::GetShaderInfoLog(shader, bufsize, length, infolog);
+}
+
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+	return es2::GetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
+}
+
+GL_APICALL void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+{
+	return es2::GetShaderSource(shader, bufsize, length, source);
+}
+
+GL_APICALL const GLubyte* GL_APIENTRY glGetString(GLenum name)
+{
+	return es2::GetString(name);
+}
+
+GL_APICALL void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
+{
+	return es2::GetTexParameterfv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+	return es2::GetTexParameteriv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
+{
+	return es2::GetnUniformfvEXT(program, location, bufSize, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+	return es2::GetUniformfv(program, location, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params)
+{
+	return es2::GetnUniformivEXT(program, location, bufSize, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params)
+{
+	return es2::GetUniformiv(program, location, params);
+}
+
+GL_APICALL int GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar* name)
+{
+	return es2::GetUniformLocation(program, name);
+}
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+{
+	return es2::GetVertexAttribfv(index, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+{
+	return es2::GetVertexAttribiv(index, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
+{
+	return es2::GetVertexAttribPointerv(index, pname, pointer);
+}
+
+GL_APICALL void GL_APIENTRY glHint(GLenum target, GLenum mode)
+{
+	return es2::Hint(target, mode);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer(GLuint buffer)
+{
+	return es2::IsBuffer(buffer);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled(GLenum cap)
+{
+	return es2::IsEnabled(cap);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV(GLuint fence)
+{
+	return es2::IsFenceNV(fence);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer(GLuint framebuffer)
+{
+	return es2::IsFramebuffer(framebuffer);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsFramebufferOES(GLuint framebuffer)
+{
+	return es2::IsFramebuffer(framebuffer);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsProgram(GLuint program)
+{
+	return es2::IsProgram(program);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT(GLuint name)
+{
+	return es2::IsQueryEXT(name);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer(GLuint renderbuffer)
+{
+	return es2::IsRenderbuffer(renderbuffer);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbufferOES(GLuint renderbuffer)
+{
+	return es2::IsRenderbuffer(renderbuffer);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsShader(GLuint shader)
+{
+	return es2::IsShader(shader);
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsTexture(GLuint texture)
+{
+	return es2::IsTexture(texture);
+}
+
+GL_APICALL void GL_APIENTRY glLineWidth(GLfloat width)
+{
+	return es2::LineWidth(width);
+}
+
+GL_APICALL void GL_APIENTRY glLinkProgram(GLuint program)
+{
+	return es2::LinkProgram(program);
+}
+
+GL_APICALL void GL_APIENTRY glPixelStorei(GLenum pname, GLint param)
+{
+	return es2::PixelStorei(pname, param);
+}
+
+GL_APICALL void GL_APIENTRY glPolygonOffset(GLfloat factor, GLfloat units)
+{
+	return es2::PolygonOffset(factor, units);
+}
+
+GL_APICALL void GL_APIENTRY glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
+                                             GLenum format, GLenum type, GLsizei bufSize, GLvoid *data)
+{
+	return es2::ReadnPixelsEXT(x, y, width, height, format, type, bufSize, data);
+}
+
+GL_APICALL void GL_APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+{
+	return es2::ReadPixels(x, y, width, height, format, type, pixels);
+}
+
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler(void)
+{
+	return es2::ReleaseShaderCompiler();
+}
+
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+	return es2::RenderbufferStorageMultisample(target, samples, internalformat, width, height);
+}
+
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+	return es2::RenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height);
+}
+
+GL_APICALL void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+	return es2::RenderbufferStorage(target, internalformat, width, height);
+}
+
+GL_APICALL void GL_APIENTRY glRenderbufferStorageOES(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+	return es2::RenderbufferStorage(target, internalformat, width, height);
+}
+
+GL_APICALL void GL_APIENTRY glSampleCoverage(GLclampf value, GLboolean invert)
+{
+	return es2::SampleCoverage(value, invert);
+}
+
+GL_APICALL void GL_APIENTRY glSetFenceNV(GLuint fence, GLenum condition)
+{
+	return es2::SetFenceNV(fence, condition);
+}
+
+GL_APICALL void GL_APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	return es2::Scissor(x, y, width, height);
+}
+
+GL_APICALL void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
+{
+	return es2::ShaderBinary(n, shaders, binaryformat, binary, length);
+}
+
+GL_APICALL void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length)
+{
+	return es2::ShaderSource(shader, count, string, length);
+}
+
+GL_APICALL void GL_APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+	return es2::StencilFunc(func, ref, mask);
+}
+
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+	return es2::StencilFuncSeparate(face, func, ref, mask);
+}
+
+GL_APICALL void GL_APIENTRY glStencilMask(GLuint mask)
+{
+	return es2::StencilMask(mask);
+}
+
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask)
+{
+	return es2::StencilMaskSeparate(face, mask);
+}
+
+GL_APICALL void GL_APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+{
+	return es2::StencilOp(fail, zfail, zpass);
+}
+
+GL_APICALL void GL_APIENTRY glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+	return es2::StencilOpSeparate(face, fail, zfail, zpass);
+}
+
+GLboolean GL_APIENTRY glTestFenceNV(GLuint fence)
+{
+	return es2::TestFenceNV(fence);
+}
+
+GL_APICALL void GL_APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+                                         GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+	return es2::TexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+}
+
+GL_APICALL void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param)
+{
+	return es2::TexParameterf(target, pname, param);
+}
+
+GL_APICALL void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
+{
+	return es2::TexParameterfv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param)
+{
+	return es2::TexParameteri(target, pname, param);
+}
+
+GL_APICALL void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
+{
+	return es2::TexParameteriv(target, pname, params);
+}
+
+GL_APICALL void GL_APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                                            GLenum format, GLenum type, const GLvoid* pixels)
+{
+	return es2::TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+
+GL_APICALL void GL_APIENTRY glUniform1f(GLint location, GLfloat x)
+{
+	return es2::Uniform1f(location, x);
+}
+
+GL_APICALL void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+	return es2::Uniform1fv(location, count, v);
+}
+
+GL_APICALL void GL_APIENTRY glUniform1i(GLint location, GLint x)
+{
+	return es2::Uniform1i(location, x);
+}
+
+GL_APICALL void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v)
+{
+	return es2::Uniform1iv(location, count, v);
+}
+
+GL_APICALL void GL_APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y)
+{
+	return es2::Uniform2f(location, x, y);
+}
+
+GL_APICALL void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+{
+	return es2::Uniform2fv(location, count, v);
+}
+
+GL_APICALL void GL_APIENTRY glUniform2i(GLint location, GLint x, GLint y)
+{
+	return es2::Uniform2i(location, x, y);
+}
+
+GL_APICALL void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v)
+{
+	return es2::Uniform2iv(location, count, v);
+}
+
+GL_APICALL void GL_APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+	return es2::Uniform3f(location, x, y, z);
+}
+
+GL_APICALL void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+{
+	return es2::Uniform3fv(location, count, v);
+}
+
+GL_APICALL void GL_APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z)
+{
+	return es2::Uniform3i(location, x, y, z);
+}
+
+GL_APICALL void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v)
+{
+	return es2::Uniform3iv(location, count, v);
+}
+
+GL_APICALL void GL_APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	return es2::Uniform4f(location, x, y, z, w);
+}
+
+GL_APICALL void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+{
+	return es2::Uniform4fv(location, count, v);
+}
+
+GL_APICALL void GL_APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+	return es2::Uniform4i(location, x, y, z, w);
+}
+
+GL_APICALL void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v)
+{
+	return es2::Uniform4iv(location, count, v);
+}
+
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+	return es2::UniformMatrix2fv(location, count, transpose, value);
+}
+
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+	return es2::UniformMatrix3fv(location, count, transpose, value);
+}
+
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+	return es2::UniformMatrix4fv(location, count, transpose, value);
+}
+
+GL_APICALL void GL_APIENTRY glUseProgram(GLuint program)
+{
+	return es2::UseProgram(program);
+}
+
+GL_APICALL void GL_APIENTRY glValidateProgram(GLuint program)
+{
+	return es2::ValidateProgram(program);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib1f(GLuint index, GLfloat x)
+{
+	return es2::VertexAttrib1f(index, x);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv(GLuint index, const GLfloat* values)
+{
+	return es2::VertexAttrib1fv(index, values);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y)
+{
+	return es2::VertexAttrib2f(index, x, y);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv(GLuint index, const GLfloat* values)
+{
+	return es2::VertexAttrib2fv(index, values);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)
+{
+	return es2::VertexAttrib3f(index, x, y, z);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv(GLuint index, const GLfloat* values)
+{
+	return es2::VertexAttrib3fv(index, values);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	return es2::VertexAttrib4f(index, x, y, z, w);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv(GLuint index, const GLfloat* values)
+{
+	return es2::VertexAttrib4fv(index, values);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+{
+	return es2::VertexAttribPointer(index, size, type, normalized, stride, ptr);
+}
+
+GL_APICALL void GL_APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	return es2::Viewport(x, y, width, height);
+}
+
+GL_APICALL void GL_APIENTRY glBlitFramebufferNV(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+	return es2::BlitFramebufferNV(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
+GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+                                                   GLbitfield mask, GLenum filter)
+{
+	return es2::BlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
+GL_APICALL void GL_APIENTRY glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
+                                            GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+	return es2::TexImage3DOES(target, level, internalformat, width, height, depth, border, format, type, pixels);
+}
+
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels)
+{
+	return es2::TexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
+}
+
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	return es2::CopyTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, x, y, width, height);
+}
+
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data)
+{
+	return es2::CompressedTexImage3DOES(target, level,internalformat, width, height, depth, border, imageSize, data);
+}
+
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)
+{
+	return es2::CompressedTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
+}
+
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
+{
+	return es2::FramebufferTexture3DOES(target, attachment, textarget, texture, level, zoffset);
+}
+
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+	return es2::EGLImageTargetTexture2DOES(target, image);
+}
+
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+	return es2::EGLImageTargetRenderbufferStorageOES(target, image);
+}
+
+GL_APICALL void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs)
+{
+	return es2::DrawBuffersEXT(n, bufs);
+}
+
+void GL_APIENTRY Register(const char *licenseKey)
+{
+	// Nothing to do, SwiftShader is open-source
+}
+}
+
+egl::Context *es2CreateContext(egl::Display *display, const egl::Context *shareContext, int clientVersion, const egl::Config *config);
+extern "C" __eglMustCastToProperFunctionPointerType es2GetProcAddress(const char *procname);
+egl::Image *createBackBuffer(int width, int height, sw::Format format, int multiSampleDepth);
+egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth);
+sw::FrameBuffer *createFrameBuffer(void *nativeDisplay, EGLNativeWindowType window, int width, int height);
+
+LibGLESv2exports::LibGLESv2exports()
+{
+	this->glActiveTexture = es2::ActiveTexture;
+	this->glAttachShader = es2::AttachShader;
+	this->glBeginQueryEXT = es2::BeginQueryEXT;
+	this->glBindAttribLocation = es2::BindAttribLocation;
+	this->glBindBuffer = es2::BindBuffer;
+	this->glBindFramebuffer = es2::BindFramebuffer;
+	this->glBindRenderbuffer = es2::BindRenderbuffer;
+	this->glBindTexture = es2::BindTexture;
+	this->glBlendColor = es2::BlendColor;
+	this->glBlendEquation = es2::BlendEquation;
+	this->glBlendEquationSeparate = es2::BlendEquationSeparate;
+	this->glBlendFunc = es2::BlendFunc;
+	this->glBlendFuncSeparate = es2::BlendFuncSeparate;
+	this->glBufferData = es2::BufferData;
+	this->glBufferSubData = es2::BufferSubData;
+	this->glCheckFramebufferStatus = es2::CheckFramebufferStatus;
+	this->glClear = es2::Clear;
+	this->glClearColor = es2::ClearColor;
+	this->glClearDepthf = es2::ClearDepthf;
+	this->glClearStencil = es2::ClearStencil;
+	this->glColorMask = es2::ColorMask;
+	this->glCompileShader = es2::CompileShader;
+	this->glCompressedTexImage2D = es2::CompressedTexImage2D;
+	this->glCompressedTexSubImage2D = es2::CompressedTexSubImage2D;
+	this->glCopyTexImage2D = es2::CopyTexImage2D;
+	this->glCopyTexSubImage2D = es2::CopyTexSubImage2D;
+	this->glCreateProgram = es2::CreateProgram;
+	this->glCreateShader = es2::CreateShader;
+	this->glCullFace = es2::CullFace;
+	this->glDeleteBuffers = es2::DeleteBuffers;
+	this->glDeleteFencesNV = es2::DeleteFencesNV;
+	this->glDeleteFramebuffers = es2::DeleteFramebuffers;
+	this->glDeleteProgram = es2::DeleteProgram;
+	this->glDeleteQueriesEXT = es2::DeleteQueriesEXT;
+	this->glDeleteRenderbuffers = es2::DeleteRenderbuffers;
+	this->glDeleteShader = es2::DeleteShader;
+	this->glDeleteTextures = es2::DeleteTextures;
+	this->glDepthFunc = es2::DepthFunc;
+	this->glDepthMask = es2::DepthMask;
+	this->glDepthRangef = es2::DepthRangef;
+	this->glDetachShader = es2::DetachShader;
+	this->glDisable = es2::Disable;
+	this->glDisableVertexAttribArray = es2::DisableVertexAttribArray;
+	this->glDrawArrays = es2::DrawArrays;
+	this->glDrawElements = es2::DrawElements;
+	this->glDrawArraysInstancedEXT = es2::DrawArraysInstancedEXT;
+	this->glDrawElementsInstancedEXT = es2::DrawElementsInstancedEXT;
+	this->glVertexAttribDivisorEXT = es2::VertexAttribDivisorEXT;
+	this->glDrawArraysInstancedANGLE = es2::DrawArraysInstancedANGLE;
+	this->glDrawElementsInstancedANGLE = es2::DrawElementsInstancedANGLE;
+	this->glVertexAttribDivisorANGLE = es2::VertexAttribDivisorANGLE;
+	this->glEnable = es2::Enable;
+	this->glEnableVertexAttribArray = es2::EnableVertexAttribArray;
+	this->glEndQueryEXT = es2::EndQueryEXT;
+	this->glFinishFenceNV = es2::FinishFenceNV;
+	this->glFinish = es2::Finish;
+	this->glFlush = es2::Flush;
+	this->glFramebufferRenderbuffer = es2::FramebufferRenderbuffer;
+	this->glFramebufferTexture2D = es2::FramebufferTexture2D;
+	this->glFrontFace = es2::FrontFace;
+	this->glGenBuffers = es2::GenBuffers;
+	this->glGenerateMipmap = es2::GenerateMipmap;
+	this->glGenFencesNV = es2::GenFencesNV;
+	this->glGenFramebuffers = es2::GenFramebuffers;
+	this->glGenQueriesEXT = es2::GenQueriesEXT;
+	this->glGenRenderbuffers = es2::GenRenderbuffers;
+	this->glGenTextures = es2::GenTextures;
+	this->glGetActiveAttrib = es2::GetActiveAttrib;
+	this->glGetActiveUniform = es2::GetActiveUniform;
+	this->glGetAttachedShaders = es2::GetAttachedShaders;
+	this->glGetAttribLocation = es2::GetAttribLocation;
+	this->glGetBooleanv = es2::GetBooleanv;
+	this->glGetBufferParameteriv = es2::GetBufferParameteriv;
+	this->glGetError = es2::GetError;
+	this->glGetFenceivNV = es2::GetFenceivNV;
+	this->glGetFloatv = es2::GetFloatv;
+	this->glGetFramebufferAttachmentParameteriv = es2::GetFramebufferAttachmentParameteriv;
+	this->glGetGraphicsResetStatusEXT = es2::GetGraphicsResetStatusEXT;
+	this->glGetIntegerv = es2::GetIntegerv;
+	this->glGetProgramiv = es2::GetProgramiv;
+	this->glGetProgramInfoLog = es2::GetProgramInfoLog;
+	this->glGetQueryivEXT = es2::GetQueryivEXT;
+	this->glGetQueryObjectuivEXT = es2::GetQueryObjectuivEXT;
+	this->glGetRenderbufferParameteriv = es2::GetRenderbufferParameteriv;
+	this->glGetShaderiv = es2::GetShaderiv;
+	this->glGetShaderInfoLog = es2::GetShaderInfoLog;
+	this->glGetShaderPrecisionFormat = es2::GetShaderPrecisionFormat;
+	this->glGetShaderSource = es2::GetShaderSource;
+	this->glGetString = es2::GetString;
+	this->glGetTexParameterfv = es2::GetTexParameterfv;
+	this->glGetTexParameteriv = es2::GetTexParameteriv;
+	this->glGetnUniformfvEXT = es2::GetnUniformfvEXT;
+	this->glGetUniformfv = es2::GetUniformfv;
+	this->glGetnUniformivEXT = es2::GetnUniformivEXT;
+	this->glGetUniformiv = es2::GetUniformiv;
+	this->glGetUniformLocation = es2::GetUniformLocation;
+	this->glGetVertexAttribfv = es2::GetVertexAttribfv;
+	this->glGetVertexAttribiv = es2::GetVertexAttribiv;
+	this->glGetVertexAttribPointerv = es2::GetVertexAttribPointerv;
+	this->glHint = es2::Hint;
+	this->glIsBuffer = es2::IsBuffer;
+	this->glIsEnabled = es2::IsEnabled;
+	this->glIsFenceNV = es2::IsFenceNV;
+	this->glIsFramebuffer = es2::IsFramebuffer;
+	this->glIsProgram = es2::IsProgram;
+	this->glIsQueryEXT = es2::IsQueryEXT;
+	this->glIsRenderbuffer = es2::IsRenderbuffer;
+	this->glIsShader = es2::IsShader;
+	this->glIsTexture = es2::IsTexture;
+	this->glLineWidth = es2::LineWidth;
+	this->glLinkProgram = es2::LinkProgram;
+	this->glPixelStorei = es2::PixelStorei;
+	this->glPolygonOffset = es2::PolygonOffset;
+	this->glReadnPixelsEXT = es2::ReadnPixelsEXT;
+	this->glReadPixels = es2::ReadPixels;
+	this->glReleaseShaderCompiler = es2::ReleaseShaderCompiler;
+	this->glRenderbufferStorageMultisample = es2::RenderbufferStorageMultisample;
+	this->glRenderbufferStorageMultisampleANGLE = es2::RenderbufferStorageMultisampleANGLE;
+	this->glRenderbufferStorage = es2::RenderbufferStorage;
+	this->glSampleCoverage = es2::SampleCoverage;
+	this->glSetFenceNV = es2::SetFenceNV;
+	this->glScissor = es2::Scissor;
+	this->glShaderBinary = es2::ShaderBinary;
+	this->glShaderSource = es2::ShaderSource;
+	this->glStencilFunc = es2::StencilFunc;
+	this->glStencilFuncSeparate = es2::StencilFuncSeparate;
+	this->glStencilMask = es2::StencilMask;
+	this->glStencilMaskSeparate = es2::StencilMaskSeparate;
+	this->glStencilOp = es2::StencilOp;
+	this->glStencilOpSeparate = es2::StencilOpSeparate;
+	this->glTestFenceNV = es2::TestFenceNV;
+	this->glTexImage2D = es2::TexImage2D;
+	this->glTexParameterf = es2::TexParameterf;
+	this->glTexParameterfv = es2::TexParameterfv;
+	this->glTexParameteri = es2::TexParameteri;
+	this->glTexParameteriv = es2::TexParameteriv;
+	this->glTexSubImage2D = es2::TexSubImage2D;
+	this->glUniform1f = es2::Uniform1f;
+	this->glUniform1fv = es2::Uniform1fv;
+	this->glUniform1i = es2::Uniform1i;
+	this->glUniform1iv = es2::Uniform1iv;
+	this->glUniform2f = es2::Uniform2f;
+	this->glUniform2fv = es2::Uniform2fv;
+	this->glUniform2i = es2::Uniform2i;
+	this->glUniform2iv = es2::Uniform2iv;
+	this->glUniform3f = es2::Uniform3f;
+	this->glUniform3fv = es2::Uniform3fv;
+	this->glUniform3i = es2::Uniform3i;
+	this->glUniform3iv = es2::Uniform3iv;
+	this->glUniform4f = es2::Uniform4f;
+	this->glUniform4fv = es2::Uniform4fv;
+	this->glUniform4i = es2::Uniform4i;
+	this->glUniform4iv = es2::Uniform4iv;
+	this->glUniformMatrix2fv = es2::UniformMatrix2fv;
+	this->glUniformMatrix3fv = es2::UniformMatrix3fv;
+	this->glUniformMatrix4fv = es2::UniformMatrix4fv;
+	this->glUseProgram = es2::UseProgram;
+	this->glValidateProgram = es2::ValidateProgram;
+	this->glVertexAttrib1f = es2::VertexAttrib1f;
+	this->glVertexAttrib1fv = es2::VertexAttrib1fv;
+	this->glVertexAttrib2f = es2::VertexAttrib2f;
+	this->glVertexAttrib2fv = es2::VertexAttrib2fv;
+	this->glVertexAttrib3f = es2::VertexAttrib3f;
+	this->glVertexAttrib3fv = es2::VertexAttrib3fv;
+	this->glVertexAttrib4f = es2::VertexAttrib4f;
+	this->glVertexAttrib4fv = es2::VertexAttrib4fv;
+	this->glVertexAttribPointer = es2::VertexAttribPointer;
+	this->glViewport = es2::Viewport;
+	this->glBlitFramebufferNV = es2::BlitFramebufferNV;
+	this->glBlitFramebufferANGLE = es2::BlitFramebufferANGLE;
+	this->glTexImage3DOES = es2::TexImage3DOES;
+	this->glTexSubImage3DOES = es2::TexSubImage3DOES;
+	this->glCopyTexSubImage3DOES = es2::CopyTexSubImage3DOES;
+	this->glCompressedTexImage3DOES = es2::CompressedTexImage3DOES;
+	this->glCompressedTexSubImage3DOES = es2::CompressedTexSubImage3DOES;
+	this->glFramebufferTexture3DOES = es2::FramebufferTexture3DOES;
+	this->glEGLImageTargetTexture2DOES = es2::EGLImageTargetTexture2DOES;
+	this->glEGLImageTargetRenderbufferStorageOES = es2::EGLImageTargetRenderbufferStorageOES;
+	this->glIsRenderbufferOES = es2::IsRenderbufferOES;
+	this->glBindRenderbufferOES = es2::BindRenderbufferOES;
+	this->glDeleteRenderbuffersOES = es2::DeleteRenderbuffersOES;
+	this->glGenRenderbuffersOES = es2::GenRenderbuffersOES;
+	this->glRenderbufferStorageOES = es2::RenderbufferStorageOES;
+	this->glGetRenderbufferParameterivOES = es2::GetRenderbufferParameterivOES;
+	this->glIsFramebufferOES = es2::IsFramebufferOES;
+	this->glBindFramebufferOES = es2::BindFramebufferOES;
+	this->glDeleteFramebuffersOES = es2::DeleteFramebuffersOES;
+	this->glGenFramebuffersOES = es2::GenFramebuffersOES;
+	this->glCheckFramebufferStatusOES = es2::CheckFramebufferStatusOES;
+	this->glFramebufferRenderbufferOES = es2::FramebufferRenderbufferOES;
+	this->glFramebufferTexture2DOES = es2::FramebufferTexture2DOES;
+	this->glGetFramebufferAttachmentParameterivOES = es2::GetFramebufferAttachmentParameterivOES;
+	this->glGenerateMipmapOES = es2::GenerateMipmapOES;
+	this->glDrawBuffersEXT = es2::DrawBuffersEXT;
+
+	this->es2CreateContext = ::es2CreateContext;
+	this->es2GetProcAddress = ::es2GetProcAddress;
+	this->createBackBuffer = ::createBackBuffer;
+	this->createDepthStencil = ::createDepthStencil;
+	this->createFrameBuffer = ::createFrameBuffer;
+}
+
+extern "C" GL_APICALL LibGLESv2exports *libGLESv2_swiftshader()
+{
+	static LibGLESv2exports libGLESv2;
+	return &libGLESv2;
+}
+
+LibEGL libEGL;
+LibGLES_CM libGLES_CM;
diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index f486982..4be0273 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -26,6 +26,7 @@
 #include "Texture.h"
 #include "Query.h"
 #include "TransformFeedback.h"
+#include "VertexArray.h"
 #include "common/debug.h"
 #include "Common/Version.h"
 
@@ -33,6 +34,7 @@
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
 
+#include <algorithm>
 #include <limits>
 
 #ifdef __ANDROID__
@@ -52,70 +54,6 @@
 	return true;
 }
 
-static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFormat)
-{
-	GLenum validationError = ValidateCompressedFormat(textureFormat, egl::getClientVersion(), false);
-	if(validationError != GL_NONE)
-	{
-		return error(validationError, false);
-	}
-
-	// [OpenGL ES 2.0.24] table 3.9
-	switch(textureFormat)
-	{
-	case GL_ALPHA:
-		if(colorbufferFormat != GL_ALPHA &&
-		   colorbufferFormat != GL_RGBA &&
-		   colorbufferFormat != GL_RGBA4 &&
-		   colorbufferFormat != GL_RGB5_A1 &&
-		   colorbufferFormat != GL_RGBA8_OES &&
-		   colorbufferFormat != GL_BGRA8_EXT &&
-		   colorbufferFormat != GL_RGBA16F_EXT &&
-		   colorbufferFormat != GL_RGBA32F_EXT)
-		{
-			return error(GL_INVALID_OPERATION, false);
-		}
-		break;
-	case GL_LUMINANCE:
-	case GL_RGB:
-		if(colorbufferFormat != GL_RGB &&
-		   colorbufferFormat != GL_RGB565 &&
-		   colorbufferFormat != GL_RGB8_OES &&
-		   colorbufferFormat != GL_RGBA &&
-		   colorbufferFormat != GL_RGBA4 &&
-		   colorbufferFormat != GL_RGB5_A1 &&
-		   colorbufferFormat != GL_RGBA8_OES &&
-		   colorbufferFormat != GL_RGB16F_EXT &&
-		   colorbufferFormat != GL_RGB32F_EXT &&
-		   colorbufferFormat != GL_BGRA8_EXT &&
-		   colorbufferFormat != GL_RGBA16F_EXT &&
-		   colorbufferFormat != GL_RGBA32F_EXT)
-		{
-			return error(GL_INVALID_OPERATION, false);
-		}
-		break;
-	case GL_LUMINANCE_ALPHA:
-	case GL_RGBA:
-		if(colorbufferFormat != GL_RGBA &&
-		   colorbufferFormat != GL_RGBA4 &&
-		   colorbufferFormat != GL_RGB5_A1 &&
-		   colorbufferFormat != GL_RGBA8_OES &&
-		   colorbufferFormat != GL_BGRA8_EXT &&
-		   colorbufferFormat != GL_RGBA16F_EXT &&
-		   colorbufferFormat != GL_RGBA32F_EXT)
-		{
-			return error(GL_INVALID_OPERATION, false);
-		}
-		break;
-	case GL_DEPTH_COMPONENT:
-	case GL_DEPTH_STENCIL_OES:
-		return error(GL_INVALID_OPERATION, false);
-	default:
-		return error(GL_INVALID_ENUM, false);
-	}
-	return true;
-}
-
 void ActiveTexture(GLenum texture)
 {
 	TRACE("(GLenum texture = 0x%X)", texture);
@@ -307,7 +245,7 @@
 {
 	TRACE("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer);
 
-	if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+	if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
 	{
 		return error(GL_INVALID_ENUM);
 	}
@@ -316,12 +254,12 @@
 
 	if(context)
 	{
-		if(target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
+		if(target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER)
 		{
 			context->bindReadFramebuffer(framebuffer);
 		}
 
-		if(target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
+		if(target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER)
 		{
 			context->bindDrawFramebuffer(framebuffer);
 		}
@@ -369,23 +307,26 @@
 		switch(target)
 		{
 		case GL_TEXTURE_2D:
-			context->bindTexture2D(texture);
+			context->bindTexture(TEXTURE_2D, texture);
 			break;
 		case GL_TEXTURE_CUBE_MAP:
-			context->bindTextureCubeMap(texture);
+			context->bindTexture(TEXTURE_CUBE, texture);
 			break;
 		case GL_TEXTURE_EXTERNAL_OES:
-			context->bindTextureExternal(texture);
+			context->bindTexture(TEXTURE_EXTERNAL, texture);
 			break;
 		case GL_TEXTURE_2D_ARRAY:
 			if(clientVersion < 3)
 			{
 				return error(GL_INVALID_ENUM);
 			}
-			context->bindTexture2DArray(texture);
+			context->bindTexture(TEXTURE_2D_ARRAY, texture);
 			break;
-		case GL_TEXTURE_3D_OES:
-			context->bindTexture3D(texture);
+		case GL_TEXTURE_3D:
+			context->bindTexture(TEXTURE_3D, texture);
+			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			context->bindTexture(TEXTURE_2D_RECT, texture);
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -649,6 +590,12 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(buffer->isMapped())
+		{
+			// It is an invalid operation to update an already mapped buffer
+			return error(GL_INVALID_OPERATION);
+		}
+
 		if((size_t)size + offset > buffer->size())
 		{
 			return error(GL_INVALID_VALUE);
@@ -662,7 +609,7 @@
 {
 	TRACE("(GLenum target = 0x%X)", target);
 
-	if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+	if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
 	{
 		return error(GL_INVALID_ENUM, 0);
 	}
@@ -672,7 +619,7 @@
 	if(context)
 	{
 		es2::Framebuffer *framebuffer = nullptr;
-		if(target == GL_READ_FRAMEBUFFER_ANGLE)
+		if(target == GL_READ_FRAMEBUFFER)
 		{
 			framebuffer = context->getReadFramebuffer();
 		}
@@ -792,23 +739,9 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	switch(internalformat)
+	if(!IsCompressed(internalformat, egl::getClientVersion()))
 	{
-	case GL_DEPTH_COMPONENT:
-	case GL_DEPTH_COMPONENT16:
-	case GL_DEPTH_COMPONENT32_OES:
-	case GL_DEPTH_STENCIL_OES:
-	case GL_DEPTH24_STENCIL8_OES:
-		return error(GL_INVALID_OPERATION);
-	default:
-		{
-			GLenum validationError = ValidateCompressedFormat(internalformat, egl::getClientVersion(), true);
-			if(validationError != GL_NONE)
-			{
-				return error(validationError);
-			}
-		}
-		break;
+		return error(GL_INVALID_ENUM);
 	}
 
 	if(border != 0)
@@ -851,18 +784,25 @@
 				return error(GL_INVALID_VALUE);
 			}
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB: // Rectangle textures cannot be compressed
 		default:
 			return error(GL_INVALID_ENUM);
 		}
 
-		if(imageSize != egl::ComputeCompressedSize(width, height, internalformat))
+		if(imageSize != gl::ComputeCompressedSize(width, height, internalformat))
 		{
 			return error(GL_INVALID_VALUE);
 		}
 
-		if(target == GL_TEXTURE_2D)
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
+		if(validationError != GL_NO_ERROR)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			return error(validationError);
+		}
+
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
+		{
+			es2::Texture2D *texture = context->getTexture2D(target);
 
 			if(!texture)
 			{
@@ -871,7 +811,7 @@
 
 			texture->setCompressedImage(level, internalformat, width, height, imageSize, data);
 		}
-		else
+		else if(es2::IsCubemapTextureTarget(target))
 		{
 			es2::TextureCubeMap *texture = context->getTextureCubeMap();
 
@@ -880,19 +820,9 @@
 				return error(GL_INVALID_OPERATION);
 			}
 
-			switch(target)
-			{
-			case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-			case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-			case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-			case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-			case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-			case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-				texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
-				break;
-			default: UNREACHABLE(target);
-			}
+			texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
 		}
+		else UNREACHABLE(target);
 	}
 }
 
@@ -919,63 +849,50 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	GLenum validationError = ValidateCompressedFormat(format, egl::getClientVersion(), true);
-	if(validationError != GL_NONE)
+	if(imageSize != gl::ComputeCompressedSize(width, height, format))
 	{
-		return error(validationError);
-	}
-
-	if(width == 0 || height == 0 || !data)
-	{
-		return;
+		return error(GL_INVALID_VALUE);
 	}
 
 	es2::Context *context = es2::getContext();
 
 	if(context)
 	{
-		if(imageSize != egl::ComputeCompressedSize(width, height, format))
-		{
-			return error(GL_INVALID_VALUE);
-		}
-
 		if(xoffset % 4 != 0 || yoffset % 4 != 0)
 		{
 			// We wait to check the offsets until this point, because the multiple-of-four restriction does not exist unless DXT1 textures are supported
 			return error(GL_INVALID_OPERATION);
 		}
 
-		GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_NONE);
-
-		if(target == GL_TEXTURE_2D)
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
+		if(validationError != GL_NO_ERROR)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			return error(validationError);
+		}
 
-			GLenum validationError = ValidateSubImageParams(true, width, height, xoffset, yoffset, target, level, sizedInternalFormat, texture);
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
+		{
+			es2::Texture2D *texture = context->getTexture2D(target);
 
-			if(validationError == GL_NONE)
-			{
-				texture->subImageCompressed(level, xoffset, yoffset, width, height, sizedInternalFormat, imageSize, context->getPixels(data));
-			}
-			else
+			GLenum validationError = ValidateSubImageParams(true, false, target, level, xoffset, yoffset, width, height, format, GL_NONE, texture, context->getClientVersion());
+			if(validationError != GL_NO_ERROR)
 			{
 				return error(validationError);
 			}
+
+			texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
 		}
 		else if(es2::IsCubemapTextureTarget(target))
 		{
 			es2::TextureCubeMap *texture = context->getTextureCubeMap();
 
-			GLenum validationError = ValidateSubImageParams(true, width, height, xoffset, yoffset, target, level, sizedInternalFormat, texture);
-
-			if(validationError == GL_NONE)
-			{
-				texture->subImageCompressed(target, level, xoffset, yoffset, width, height, sizedInternalFormat, imageSize, context->getPixels(data));
-			}
-			else
+			GLenum validationError = ValidateSubImageParams(true, false, target, level, xoffset, yoffset, width, height, format, GL_NONE, texture, context->getClientVersion());
+			if(validationError != GL_NO_ERROR)
 			{
 				return error(validationError);
 			}
+
+			texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
 		}
 		else UNREACHABLE(target);
 	}
@@ -1003,6 +920,12 @@
 	{
 		switch(target)
 		{
+		case GL_TEXTURE_RECTANGLE_ARB:
+			if(level != 0)
+			{
+				return error(GL_INVALID_VALUE);
+			}
+			// Fall through
 		case GL_TEXTURE_2D:
 			if(width > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
 			   height > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))
@@ -1047,21 +970,40 @@
 
 		GLenum colorbufferFormat = source->getFormat();
 
-		if(!validateColorBufferFormat(internalformat, colorbufferFormat))
+		// Determine the sized internal format.
+		if(gl::IsUnsizedInternalFormat(internalformat))
+		{
+			if(gl::GetBaseInternalFormat(colorbufferFormat) == internalformat)
+			{
+				internalformat = colorbufferFormat;
+			}
+			else if(GetRedSize(colorbufferFormat) == 8)
+			{
+				internalformat = gl::GetSizedInternalFormat(internalformat, GL_UNSIGNED_BYTE);
+			}
+			else
+			{
+				UNIMPLEMENTED();
+
+				return error(GL_INVALID_OPERATION);
+			}
+		}
+
+		if(!ValidateCopyFormats(internalformat, colorbufferFormat))
 		{
 			return;
 		}
 
-		if(target == GL_TEXTURE_2D)
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			es2::Texture2D *texture = context->getTexture2D(target);
 
 			if(!texture)
 			{
 				return error(GL_INVALID_OPERATION);
 			}
 
-			texture->copyImage(level, internalformat, x, y, width, height, framebuffer);
+			texture->copyImage(level, internalformat, x, y, width, height, source);
 		}
 		else if(es2::IsCubemapTextureTarget(target))
 		{
@@ -1072,7 +1014,7 @@
 				return error(GL_INVALID_OPERATION);
 			}
 
-			texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer);
+			texture->copyImage(target, level, internalformat, x, y, width, height, source);
 		}
 		else UNREACHABLE(target);
 	}
@@ -1104,11 +1046,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(width == 0 || height == 0)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1129,9 +1066,9 @@
 
 		es2::Texture *texture = nullptr;
 
-		if(target == GL_TEXTURE_2D)
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
-			texture = context->getTexture2D();
+			texture = context->getTexture2D(target);
 		}
 		else if(es2::IsCubemapTextureTarget(target))
 		{
@@ -1139,13 +1076,13 @@
 		}
 		else UNREACHABLE(target);
 
-		GLenum validationError = ValidateSubImageParams(false, width, height, xoffset, yoffset, target, level, GL_NONE, texture);
-		if(validationError != GL_NONE)
+		GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, width, height, GL_NONE, GL_NONE, texture, context->getClientVersion());
+		if(validationError != GL_NO_ERROR)
 		{
 			return error(validationError);
 		}
 
-		texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer);
+		texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, source);
 	}
 }
 
@@ -1946,7 +1883,7 @@
 	TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, "
 	      "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer);
 
-	if((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) ||
+	if((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER) ||
 	   (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
 	{
 		return error(GL_INVALID_ENUM);
@@ -1958,7 +1895,7 @@
 	{
 		es2::Framebuffer *framebuffer = nullptr;
 		GLuint framebufferName = 0;
-		if(target == GL_READ_FRAMEBUFFER_ANGLE)
+		if(target == GL_READ_FRAMEBUFFER)
 		{
 			framebuffer = context->getReadFramebuffer();
 			framebufferName = context->getReadFramebufferName();
@@ -2053,7 +1990,7 @@
 	TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, "
 	      "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level);
 
-	if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+	if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
 	{
 		return error(GL_INVALID_ENUM);
 	}
@@ -2085,6 +2022,12 @@
 					return error(GL_INVALID_OPERATION);
 				}
 				break;
+			case GL_TEXTURE_RECTANGLE_ARB:
+				if(tex->getTarget() != GL_TEXTURE_RECTANGLE_ARB)
+				{
+					return error(GL_INVALID_OPERATION);
+				}
+				break;
 			case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
 			case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
 			case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@@ -2100,7 +2043,7 @@
 				return error(GL_INVALID_ENUM);
 			}
 
-			if((level != 0) && (clientVersion < 3))
+			if((level != 0) && ((clientVersion < 3) || (textarget == GL_TEXTURE_RECTANGLE_ARB)))
 			{
 				return error(GL_INVALID_VALUE);
 			}
@@ -2118,7 +2061,7 @@
 
 		es2::Framebuffer *framebuffer = nullptr;
 		GLuint framebufferName = 0;
-		if(target == GL_READ_FRAMEBUFFER_ANGLE)
+		if(target == GL_READ_FRAMEBUFFER)
 		{
 			framebuffer = context->getReadFramebuffer();
 			framebufferName = context->getReadFramebufferName();
@@ -2250,7 +2193,15 @@
 			texture = context->getTexture2D();
 			break;
 		case GL_TEXTURE_CUBE_MAP:
-			texture = context->getTextureCubeMap();
+			{
+				TextureCubeMap *cube = context->getTextureCubeMap();
+				texture = cube;
+
+				if(!cube->isCubeComplete())
+				{
+					return error(GL_INVALID_OPERATION);
+				}
+			}
 			break;
 		case GL_TEXTURE_2D_ARRAY:
 			if(clientVersion < 3)
@@ -2262,14 +2213,17 @@
 				texture = context->getTexture2DArray();
 			}
 			break;
-		case GL_TEXTURE_3D_OES:
+		case GL_TEXTURE_3D:
 			texture = context->getTexture3D();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
 
-		if(texture->isCompressed(target, 0) || texture->isDepth(target, 0))
+		if(!IsMipmappable(texture->getFormat(target, texture->getBaseLevel()), clientVersion))
 		{
 			return error(GL_INVALID_OPERATION);
 		}
@@ -2740,121 +2694,86 @@
 			return error(GL_INVALID_ENUM);
 		}
 
-		GLint clientVersion = context->getClientVersion();
+		GLuint framebufferName = 0;
 
-		es2::Framebuffer *framebuffer = nullptr;
 		if(target == GL_READ_FRAMEBUFFER)
 		{
-			if(context->getReadFramebufferName() == 0)
-			{
-				if(clientVersion < 3)
-				{
-					return error(GL_INVALID_OPERATION);
-				}
-				else
-				{
-					switch(attachment)
-					{
-					case GL_BACK:
-					case GL_DEPTH:
-					case GL_STENCIL:
-						break;
-					default:
-						return error(GL_INVALID_ENUM);
-					}
-				}
-			}
-
-			framebuffer = context->getReadFramebuffer();
+			framebufferName = context->getReadFramebufferName();
 		}
 		else
 		{
-			if(context->getDrawFramebufferName() == 0)
-			{
-				if(clientVersion < 3)
-				{
-					return error(GL_INVALID_OPERATION);
-				}
-				else
-				{
-					switch(attachment)
-					{
-					case GL_BACK:
-					case GL_DEPTH:
-					case GL_STENCIL:
-						break;
-					default:
-						return error(GL_INVALID_ENUM);
-					}
-				}
-			}
-
-			framebuffer = context->getDrawFramebuffer();
+			framebufferName = context->getDrawFramebufferName();
 		}
 
-		GLenum attachmentType;
-		GLuint attachmentHandle;
-		GLint attachmentLayer;
-		Renderbuffer* renderbuffer = nullptr;
+		GLint clientVersion = context->getClientVersion();
+
+		if(framebufferName == 0)   // Default framebuffer.
+		{
+			if(clientVersion < 3)
+			{
+				return error(GL_INVALID_OPERATION);
+			}
+		}
+
 		switch(attachment)
 		{
 		case GL_BACK:
-			if(clientVersion >= 3)
-			{
-				attachmentType = framebuffer->getColorbufferType(0);
-				attachmentHandle = framebuffer->getColorbufferName(0);
-				attachmentLayer = framebuffer->getColorbufferLayer(0);
-				renderbuffer = framebuffer->getColorbuffer(0);
-			}
-			else return error(GL_INVALID_ENUM);
-			break;
-		case GL_COLOR_ATTACHMENT0:
-		case GL_COLOR_ATTACHMENT1:
-		case GL_COLOR_ATTACHMENT2:
-		case GL_COLOR_ATTACHMENT3:
-		case GL_COLOR_ATTACHMENT4:
-		case GL_COLOR_ATTACHMENT5:
-		case GL_COLOR_ATTACHMENT6:
-		case GL_COLOR_ATTACHMENT7:
-		case GL_COLOR_ATTACHMENT8:
-		case GL_COLOR_ATTACHMENT9:
-		case GL_COLOR_ATTACHMENT10:
-		case GL_COLOR_ATTACHMENT11:
-		case GL_COLOR_ATTACHMENT12:
-		case GL_COLOR_ATTACHMENT13:
-		case GL_COLOR_ATTACHMENT14:
-		case GL_COLOR_ATTACHMENT15:
-		case GL_COLOR_ATTACHMENT16:
-		case GL_COLOR_ATTACHMENT17:
-		case GL_COLOR_ATTACHMENT18:
-		case GL_COLOR_ATTACHMENT19:
-		case GL_COLOR_ATTACHMENT20:
-		case GL_COLOR_ATTACHMENT21:
-		case GL_COLOR_ATTACHMENT22:
-		case GL_COLOR_ATTACHMENT23:
-		case GL_COLOR_ATTACHMENT24:
-		case GL_COLOR_ATTACHMENT25:
-		case GL_COLOR_ATTACHMENT26:
-		case GL_COLOR_ATTACHMENT27:
-		case GL_COLOR_ATTACHMENT28:
-		case GL_COLOR_ATTACHMENT29:
-		case GL_COLOR_ATTACHMENT30:
-		case GL_COLOR_ATTACHMENT31:
-			if((attachment - GL_COLOR_ATTACHMENT0) >= MAX_COLOR_ATTACHMENTS)
-			{
-				return error(GL_INVALID_ENUM);
-			}
-			attachmentType = framebuffer->getColorbufferType(attachment - GL_COLOR_ATTACHMENT0);
-			attachmentHandle = framebuffer->getColorbufferName(attachment - GL_COLOR_ATTACHMENT0);
-			attachmentLayer = framebuffer->getColorbufferLayer(attachment - GL_COLOR_ATTACHMENT0);
-			renderbuffer = framebuffer->getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
-			break;
 		case GL_DEPTH:
+		case GL_STENCIL:
 			if(clientVersion < 3)
 			{
 				return error(GL_INVALID_ENUM);
 			}
-			// fall through
+
+			if(framebufferName != 0)
+			{
+				return error(GL_INVALID_OPERATION);
+			}
+			break;
+		case GL_DEPTH_ATTACHMENT:
+		case GL_STENCIL_ATTACHMENT:
+			if(framebufferName == 0)
+			{
+				return error(GL_INVALID_OPERATION);
+			}
+			break;
+		case GL_DEPTH_STENCIL_ATTACHMENT:
+			if(clientVersion < 3)
+			{
+				return error(GL_INVALID_ENUM);
+			}
+
+			if(framebufferName == 0)
+			{
+				return error(GL_INVALID_OPERATION);
+			}
+			break;
+		default:
+			if((unsigned int)(attachment - GL_COLOR_ATTACHMENT0) < MAX_COLOR_ATTACHMENTS)
+			{
+				if(framebufferName == 0)
+				{
+					return error(GL_INVALID_OPERATION);
+				}
+			}
+			else return error(GL_INVALID_ENUM);
+		}
+
+		es2::Framebuffer *framebuffer = context->getFramebuffer(framebufferName);
+
+		GLenum attachmentType;
+		GLuint attachmentHandle;
+		GLint attachmentLayer;
+		Renderbuffer *renderbuffer = nullptr;
+		switch(attachment)
+		{
+		case GL_BACK:
+			attachmentType = framebuffer->getColorbufferType(0);
+			attachmentHandle = framebuffer->getColorbufferName(0);
+			attachmentLayer = framebuffer->getColorbufferLayer(0);
+			renderbuffer = framebuffer->getColorbuffer(0);
+			break;
+		case GL_DEPTH:
 		case GL_DEPTH_ATTACHMENT:
 			attachmentType = framebuffer->getDepthbufferType();
 			attachmentHandle = framebuffer->getDepthbufferName();
@@ -2862,11 +2781,6 @@
 			renderbuffer = framebuffer->getDepthbuffer();
 			break;
 		case GL_STENCIL:
-			if(clientVersion < 3)
-			{
-				return error(GL_INVALID_ENUM);
-			}
-			// fall through
 		case GL_STENCIL_ATTACHMENT:
 			attachmentType = framebuffer->getStencilbufferType();
 			attachmentHandle = framebuffer->getStencilbufferName();
@@ -2874,26 +2788,32 @@
 			renderbuffer = framebuffer->getStencilbuffer();
 			break;
 		case GL_DEPTH_STENCIL_ATTACHMENT:
-			if(clientVersion >= 3)
+			attachmentType = framebuffer->getDepthbufferType();
+			attachmentHandle = framebuffer->getDepthbufferName();
+			attachmentLayer = framebuffer->getDepthbufferLayer();
+			renderbuffer = framebuffer->getDepthbuffer();
+
+			if(attachmentHandle != framebuffer->getStencilbufferName())
 			{
-				attachmentType = framebuffer->getDepthbufferType();
-				attachmentHandle = framebuffer->getDepthbufferName();
-				attachmentLayer = framebuffer->getDepthbufferLayer();
-				if(attachmentHandle != framebuffer->getStencilbufferName())
-				{
-					// Different attachments to DEPTH and STENCIL, query fails
-					return error(GL_INVALID_OPERATION);
-				}
-				renderbuffer = framebuffer->getDepthbuffer();
+				// Different attachments to DEPTH and STENCIL, query fails
+				return error(GL_INVALID_OPERATION);
 			}
-			else return error(GL_INVALID_ENUM);
 			break;
 		default:
-			return error(GL_INVALID_ENUM);
+			ASSERT((unsigned int)(attachment - GL_COLOR_ATTACHMENT0) < MAX_COLOR_ATTACHMENTS);
+			attachmentType = framebuffer->getColorbufferType(attachment - GL_COLOR_ATTACHMENT0);
+			attachmentHandle = framebuffer->getColorbufferName(attachment - GL_COLOR_ATTACHMENT0);
+			attachmentLayer = framebuffer->getColorbufferLayer(attachment - GL_COLOR_ATTACHMENT0);
+			renderbuffer = framebuffer->getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
+			break;
 		}
 
 		GLenum attachmentObjectType = GL_NONE;   // Type category
-		if(attachmentType == GL_NONE || Framebuffer::IsRenderbuffer(attachmentType))
+		if(framebufferName == 0)
+		{
+			attachmentObjectType = GL_FRAMEBUFFER_DEFAULT;
+		}
+		else if(attachmentType == GL_NONE || Framebuffer::IsRenderbuffer(attachmentType))
 		{
 			attachmentObjectType = attachmentType;
 		}
@@ -2911,7 +2831,7 @@
 				*params = attachmentObjectType;
 				break;
 			case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
-				if(Framebuffer::IsRenderbuffer(attachmentObjectType) || attachmentObjectType == GL_TEXTURE)
+				if(attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE)
 				{
 					*params = attachmentHandle;
 				}
@@ -2923,7 +2843,7 @@
 			case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
 				if(attachmentObjectType == GL_TEXTURE)
 				{
-					*params = clientVersion < 3 ? 0 : renderbuffer->getLevel(); // FramebufferTexture2D will not allow level to be set to anything else in GL ES 2.0
+					*params = clientVersion < 3 ? 0 : renderbuffer->getLevel();   // glFramebufferTexture2D does not allow level to be set to anything else in GL ES 2.0
 				}
 				else
 				{
@@ -3003,12 +2923,12 @@
 					return error(GL_INVALID_OPERATION);
 				}
 
-				*params = sw2es::GetComponentType(renderbuffer->getInternalFormat(), attachment);
+				*params = GetComponentType(renderbuffer->getFormat(), attachment);
 				break;
 			case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
 				if(clientVersion >= 3)
 				{
-					*params = GL_LINEAR; // FIXME: GL_SRGB will also be possible, when sRGB is added
+					*params = GetColorEncoding(renderbuffer->getFormat());
 				}
 				else return error(GL_INVALID_ENUM);
 				break;
@@ -3030,7 +2950,6 @@
 			case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
 				*params = GL_NONE;
 				break;
-
 			case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
 				if(clientVersion < 3)
 				{
@@ -3038,7 +2957,6 @@
 				}
 				*params = 0;
 				break;
-
 			default:
 				if(clientVersion < 3)
 				{
@@ -3128,7 +3046,7 @@
 				{
 					if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
 					{
-						params[i] = convert_float_int(floatParams[i]);
+						params[i] = convert_float_fixed(floatParams[i]);
 					}
 					else
 					{
@@ -3369,14 +3287,19 @@
 		{
 		case GL_RENDERBUFFER_WIDTH:           *params = renderbuffer->getWidth();       break;
 		case GL_RENDERBUFFER_HEIGHT:          *params = renderbuffer->getHeight();      break;
-		case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getFormat();      break;
+		case GL_RENDERBUFFER_INTERNAL_FORMAT:
+			{
+				GLint internalformat = renderbuffer->getFormat();
+				*params = (internalformat == GL_NONE) ? GL_RGBA4 : internalformat;
+			}
+			break;
 		case GL_RENDERBUFFER_RED_SIZE:        *params = renderbuffer->getRedSize();     break;
 		case GL_RENDERBUFFER_GREEN_SIZE:      *params = renderbuffer->getGreenSize();   break;
 		case GL_RENDERBUFFER_BLUE_SIZE:       *params = renderbuffer->getBlueSize();    break;
 		case GL_RENDERBUFFER_ALPHA_SIZE:      *params = renderbuffer->getAlphaSize();   break;
 		case GL_RENDERBUFFER_DEPTH_SIZE:      *params = renderbuffer->getDepthSize();   break;
 		case GL_RENDERBUFFER_STENCIL_SIZE:    *params = renderbuffer->getStencilSize(); break;
-		case GL_RENDERBUFFER_SAMPLES_ANGLE:   *params = renderbuffer->getSamples();     break;
+		case GL_RENDERBUFFER_SAMPLES:         *params = renderbuffer->getSamples();     break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -3596,9 +3519,12 @@
 				texture = context->getTexture2DArray();
 			}
 			break;
-		case GL_TEXTURE_3D_OES:
+		case GL_TEXTURE_3D:
 			texture = context->getTexture3D();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -3749,9 +3675,12 @@
 				texture = context->getTexture2DArray();
 			}
 			break;
-		case GL_TEXTURE_3D_OES:
+		case GL_TEXTURE_3D:
 			texture = context->getTexture3D();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -4104,22 +4033,7 @@
 		case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
 			if(clientVersion >= 3)
 			{
-				switch(attribState.mType)
-				{
-				case GL_BYTE:
-				case GL_UNSIGNED_BYTE:
-				case GL_SHORT:
-				case GL_UNSIGNED_SHORT:
-				case GL_INT:
-				case GL_INT_2_10_10_10_REV:
-				case GL_UNSIGNED_INT:
-				case GL_FIXED:
-					*params = (GLfloat)GL_TRUE;
-					break;
-				default:
-					*params = (GLfloat)GL_FALSE;
-					break;
-				}
+				*params = (GLfloat)(attribState.mPureInteger ? GL_TRUE : GL_FALSE);
 				break;
 			}
 			else return error(GL_INVALID_ENUM);
@@ -4178,22 +4092,7 @@
 		case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
 			if(clientVersion >= 3)
 			{
-				switch(attribState.mType)
-				{
-				case GL_BYTE:
-				case GL_UNSIGNED_BYTE:
-				case GL_SHORT:
-				case GL_UNSIGNED_SHORT:
-				case GL_INT:
-				case GL_INT_2_10_10_10_REV:
-				case GL_UNSIGNED_INT:
-				case GL_FIXED:
-					*params = GL_TRUE;
-					break;
-				default:
-					*params = GL_FALSE;
-					break;
-				}
+				*params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
 				break;
 			}
 			else return error(GL_INVALID_ENUM);
@@ -4239,19 +4138,23 @@
 	}
 
 	es2::Context *context = es2::getContext();
-	switch(target)
+
+	if(context)
 	{
-	case GL_GENERATE_MIPMAP_HINT:
-		if(context) context->setGenerateMipmapHint(mode);
-		break;
-	case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
-		if(context) context->setFragmentShaderDerivativeHint(mode);
-		break;
-	case GL_TEXTURE_FILTERING_HINT_CHROMIUM:
-		if(context) context->setTextureFilteringHint(mode);
-		break;
-	default:
-		return error(GL_INVALID_ENUM);
+		switch(target)
+		{
+		case GL_GENERATE_MIPMAP_HINT:
+			context->setGenerateMipmapHint(mode);
+			break;
+		case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
+			context->setFragmentShaderDerivativeHint(mode);
+			break;
+		case GL_TEXTURE_FILTERING_HINT_CHROMIUM:
+			context->setTextureFilteringHint(mode);
+			break;
+		default:
+			return error(GL_INVALID_ENUM);
+		}
 	}
 }
 
@@ -4494,6 +4397,15 @@
 			}
 		}
 
+		if(programObject == context->getCurrentProgram())
+		{
+			es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
+			if(transformFeedback && transformFeedback->isActive())
+			{
+				return error(GL_INVALID_OPERATION);
+			}
+		}
+
 		programObject->link();
 	}
 }
@@ -4688,22 +4600,23 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(width < 0 || height < 0 || samples < 0)
+	if(width < 0 || height < 0 || samples < 0 ||
+	   width > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE ||
+	   height > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
 	{
 		return error(GL_INVALID_VALUE);
 	}
 
+	if(samples > es2::IMPLEMENTATION_MAX_SAMPLES ||
+	   (IsNonNormalizedInteger(internalformat) && samples > 0))
+	{
+		return error(GL_INVALID_OPERATION);
+	}
+
 	es2::Context *context = es2::getContext();
 
 	if(context)
 	{
-		if(width > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE ||
-		   height > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE ||
-		   samples > es2::IMPLEMENTATION_MAX_SAMPLES)
-		{
-			return error(GL_INVALID_VALUE);
-		}
-
 		GLuint handle = context->getRenderbufferName();
 		if(handle == 0)
 		{
@@ -4712,7 +4625,7 @@
 
 		GLint clientVersion = context->getClientVersion();
 
-		if(IsColorRenderable(internalformat, clientVersion, false))
+		if(IsColorRenderable(internalformat, clientVersion))
 		{
 			context->setRenderbufferStorage(new es2::Colorbuffer(width, height, internalformat, samples));
 		}
@@ -5040,26 +4953,30 @@
 
 	if(context)
 	{
+		// Core OpenGL ES 2.0 requires format and internalformat to be equal (checked below),
+		// but GL_APPLE_texture_format_BGRA8888 allows (only) GL_BGRA_EXT / GL_RGBA, while
+		// GL_EXT_texture_format_BGRA8888 also allows GL_BGRA_EXT / GL_BGRA_EXT.
+		if(format == GL_BGRA_EXT && internalformat == GL_RGBA)
+		{
+			internalformat = GL_BGRA_EXT;
+		}
+
 		GLint clientVersion = context->getClientVersion();
 		if(clientVersion < 3)
 		{
-			if(internalformat != (GLint)format)
+			if((internalformat != (GLint)format) &&
+			   !((type == GL_FLOAT) && (format == GL_RGBA) && (internalformat == GL_RGBA32F))) // CHROMIUM_color_buffer_float_rgba
 			{
 				return error(GL_INVALID_OPERATION);
 			}
 		}
 
-		GLenum validationError = ValidateCompressedFormat(format, clientVersion, false);
-		if(validationError != GL_NONE)
+		GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target, context->getClientVersion());
+		if(validationError != GL_NO_ERROR)
 		{
 			return error(validationError);
 		}
 
-		if(!ValidateTextureFormatType(format, type, internalformat, egl::getClientVersion()))
-		{
-			return;
-		}
-
 		if(border != 0)
 		{
 			return error(GL_INVALID_VALUE);
@@ -5067,6 +4984,12 @@
 
 		switch(target)
 		{
+		case GL_TEXTURE_RECTANGLE_ARB:
+			if(level != 0)
+			{
+				return error(GL_INVALID_VALUE); // Defining level other than 0 is not allowed
+			}
+			// Fall through
 		case GL_TEXTURE_2D:
 			if(width > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
 			   height > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))
@@ -5095,18 +5018,24 @@
 			return error(GL_INVALID_ENUM);
 		}
 
-		GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
+		GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
 
-		if(target == GL_TEXTURE_2D)
+		validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
+		if(validationError != GL_NO_ERROR)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			return error(validationError);
+		}
+
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
+		{
+			es2::Texture2D *texture = context->getTexture2D(target);
 
 			if(!texture)
 			{
 				return error(GL_INVALID_OPERATION);
 			}
 
-			texture->setImage(context, level, width, height, sizedInternalFormat, type, context->getUnpackInfo(), context->getPixels(data));
+			texture->setImage(level, width, height, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
 		}
 		else
 		{
@@ -5117,7 +5046,7 @@
 				return error(GL_INVALID_OPERATION);
 			}
 
-			texture->setImage(context, target, level, width, height, sizedInternalFormat, type, context->getUnpackInfo(), context->getPixels(data));
+			texture->setImage(target, level, width, height, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
 		}
 	}
 }
@@ -5149,7 +5078,7 @@
 				texture = context->getTexture2DArray();
 			}
 			break;
-		case GL_TEXTURE_3D_OES:
+		case GL_TEXTURE_3D:
 			texture = context->getTexture3D();
 			break;
 		case GL_TEXTURE_CUBE_MAP:
@@ -5158,6 +5087,9 @@
 		case GL_TEXTURE_EXTERNAL_OES:
 			texture = context->getTextureExternal();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -5298,7 +5230,7 @@
 				texture = context->getTexture2DArray();
 			}
 			break;
-		case GL_TEXTURE_3D_OES:
+		case GL_TEXTURE_3D:
 			texture = context->getTexture3D();
 			break;
 		case GL_TEXTURE_CUBE_MAP:
@@ -5307,6 +5239,9 @@
 		case GL_TEXTURE_EXTERNAL_OES:
 			texture = context->getTextureExternal();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -5350,6 +5285,10 @@
 			}
 			break;
 		case GL_TEXTURE_BASE_LEVEL:
+			if((texture->getTarget() == GL_TEXTURE_RECTANGLE_ARB) && (param != 0))
+			{
+				return error(GL_INVALID_OPERATION); // Base level has to be 0
+			}
 			if(clientVersion < 3 || !texture->setBaseLevel(param))
 			{
 				return error(GL_INVALID_VALUE);
@@ -5448,51 +5387,45 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(!ValidateTextureFormatType(format, type, format, egl::getClientVersion()))
-	{
-		return;
-	}
-
-	if(width == 0 || height == 0)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
 	{
-		GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
-
-		if(target == GL_TEXTURE_2D)
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			es2::Texture2D *texture = context->getTexture2D(target);
 
-			GLenum validationError = ValidateSubImageParams(false, width, height, xoffset, yoffset, target, level, sizedInternalFormat, texture);
-
-			if(validationError == GL_NONE)
-			{
-				texture->subImage(context, level, xoffset, yoffset, width, height, sizedInternalFormat, type, context->getUnpackInfo(), context->getPixels(data));
-			}
-			else
+			GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, width, height, format, type, texture, context->getClientVersion());
+			if(validationError != GL_NO_ERROR)
 			{
 				return error(validationError);
 			}
+
+			validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
+			if(validationError != GL_NO_ERROR)
+			{
+				return error(validationError);
+			}
+
+			texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackParameters(), data);
 		}
 		else if(es2::IsCubemapTextureTarget(target))
 		{
 			es2::TextureCubeMap *texture = context->getTextureCubeMap();
 
-			GLenum validationError = ValidateSubImageParams(false, width, height, xoffset, yoffset, target, level, sizedInternalFormat, texture);
-
-			if(validationError == GL_NONE)
-			{
-				texture->subImage(context, target, level, xoffset, yoffset, width, height, sizedInternalFormat, type, context->getUnpackInfo(), context->getPixels(data));
-			}
-			else
+			GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, width, height, format, type, texture, context->getClientVersion());
+			if(validationError != GL_NO_ERROR)
 			{
 				return error(validationError);
 			}
+
+			validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
+			if(validationError != GL_NO_ERROR)
+			{
+				return error(validationError);
+			}
+
+			texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackParameters(), data);
 		}
 		else UNREACHABLE(target);
 	}
@@ -5512,11 +5445,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5528,6 +5456,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform1fv(location, count, v))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5549,11 +5482,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5565,6 +5493,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform1iv(location, count, v))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5588,11 +5521,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5604,6 +5532,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform2fv(location, count, v))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5627,11 +5560,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5643,6 +5571,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform2iv(location, count, v))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5666,11 +5599,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5682,6 +5610,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform3fv(location, count, v))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5705,11 +5638,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5721,6 +5649,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform3iv(location, count, v))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5744,11 +5677,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5760,6 +5688,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform4fv(location, count, v))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5783,11 +5716,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5799,6 +5727,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform4iv(location, count, v))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5816,11 +5749,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5837,6 +5765,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniformMatrix2fv(location, count, transpose, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5854,11 +5787,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5875,6 +5803,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniformMatrix3fv(location, count, transpose, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5892,11 +5825,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -5913,6 +5841,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniformMatrix4fv(location, count, transpose, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -5928,6 +5861,12 @@
 
 	if(context)
 	{
+		es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
+		if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
+		{
+			return error(GL_INVALID_OPERATION);
+		}
+
 		es2::Program *programObject = context->getProgram(program);
 
 		if(!programObject && program != 0)
@@ -6180,7 +6119,15 @@
 
 	if(context)
 	{
-		context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized == GL_TRUE), stride, ptr);
+		es2::VertexArray* vertexArray = context->getCurrentVertexArray();
+		if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && ptr)
+		{
+			// GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
+			// to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
+			return error(GL_INVALID_OPERATION);
+		}
+
+		context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized == GL_TRUE), false, stride, ptr);
 	}
 }
 
@@ -6262,7 +6209,7 @@
 
 	switch(target)
 	{
-	case GL_TEXTURE_3D_OES:
+	case GL_TEXTURE_3D:
 		switch(format)
 		{
 		case GL_DEPTH_COMPONENT:
@@ -6276,9 +6223,15 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(!ValidateTextureFormatType(format, type, internalformat, egl::getClientVersion()))
+	if(internalformat != format)
 	{
-		return;
+		return error(GL_INVALID_OPERATION);
+	}
+
+	GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target, egl::getClientVersion());
+	if(validationError != GL_NO_ERROR)
+	{
+		return error(validationError);
 	}
 
 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
@@ -6308,7 +6261,14 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		texture->setImage(context, level, width, height, depth, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), context->getPixels(data));
+		GLenum validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
+		if(validationError != GL_NO_ERROR)
+		{
+			return error(validationError);
+		}
+
+		GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
+		texture->setImage(level, width, height, depth, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
 	}
 }
 
@@ -6321,17 +6281,12 @@
 
 	switch(target)
 	{
-	case GL_TEXTURE_3D_OES:
+	case GL_TEXTURE_3D:
 		break;
 	default:
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(!ValidateTextureFormatType(format, type, format, egl::getClientVersion()))
-	{
-		return;
-	}
-
 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
 	{
 		return error(GL_INVALID_VALUE);
@@ -6348,17 +6303,19 @@
 	{
 		es2::Texture3D *texture = context->getTexture3D();
 
-		GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
-
-		GLenum validationError = ValidateSubImageParams(false, width, height, depth, xoffset, yoffset, zoffset, target, level, sizedInternalFormat, texture);
-		if(validationError == GL_NONE)
-		{
-			texture->subImage(context, level, xoffset, yoffset, zoffset, width, height, depth, sizedInternalFormat, type, context->getUnpackInfo(), context->getPixels(data));
-		}
-		else
+		GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texture, context->getClientVersion());
+		if(validationError != GL_NO_ERROR)
 		{
 			return error(validationError);
 		}
+
+		validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
+		if(validationError != GL_NO_ERROR)
+		{
+			return error(validationError);
+		}
+
+		texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackParameters(), data);
 	}
 }
 
@@ -6370,7 +6327,7 @@
 
 	switch(target)
 	{
-	case GL_TEXTURE_3D_OES:
+	case GL_TEXTURE_3D:
 		break;
 	default:
 		return error(GL_INVALID_ENUM);
@@ -6401,14 +6358,13 @@
 
 		es2::Texture3D *texture = context->getTexture3D();
 
-		GLenum validationError = ValidateSubImageParams(false, width, height, 1, xoffset, yoffset, zoffset, target, level, GL_NONE, texture);
-
-		if(validationError != GL_NONE)
+		GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, zoffset, width, height, 1, GL_NONE, GL_NONE, texture, context->getClientVersion());
+		if(validationError != GL_NO_ERROR)
 		{
 			return error(validationError);
 		}
 
-		texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer);
+		texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source);
 	}
 }
 
@@ -6420,7 +6376,7 @@
 
 	switch(target)
 	{
-	case GL_TEXTURE_3D_OES:
+	case GL_TEXTURE_3D:
 		break;
 	default:
 		return error(GL_INVALID_ENUM);
@@ -6437,25 +6393,12 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	switch(internalformat)
+	if(!IsCompressed(internalformat, egl::getClientVersion()))
 	{
-	case GL_DEPTH_COMPONENT:
-	case GL_DEPTH_COMPONENT16:
-	case GL_DEPTH_COMPONENT32_OES:
-	case GL_DEPTH_STENCIL_OES:
-	case GL_DEPTH24_STENCIL8_OES:
-		return error(GL_INVALID_OPERATION);
-	default:
-		{
-			GLenum validationError = ValidateCompressedFormat(internalformat, egl::getClientVersion(), true);
-			if(validationError != GL_NONE)
-			{
-				return error(validationError);
-			}
-		}
+		return error(GL_INVALID_ENUM);
 	}
 
-	if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth)
+	if(imageSize != gl::ComputeCompressedSize(width, height, internalformat) * depth)
 	{
 		return error(GL_INVALID_VALUE);
 	}
@@ -6471,6 +6414,13 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
+
+		if(validationError != GL_NO_ERROR)
+		{
+			return error(validationError);
+		}
+
 		texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data);
 	}
 }
@@ -6484,7 +6434,7 @@
 
 	switch(target)
 	{
-	case GL_TEXTURE_3D_OES:
+	case GL_TEXTURE_3D:
 		break;
 	default:
 		return error(GL_INVALID_ENUM);
@@ -6500,15 +6450,14 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	GLenum validationError = ValidateCompressedFormat(format, egl::getClientVersion(), true);
-	if(validationError != GL_NONE)
+	if(!IsCompressed(format, egl::getClientVersion()))
 	{
-		return error(validationError);
+		return error(GL_INVALID_ENUM);
 	}
 
-	if(width == 0 || height == 0 || depth == 0 || !data)
+	if(imageSize != gl::ComputeCompressedSize(width, height, format) * depth)
 	{
-		return;
+		return error(GL_INVALID_VALUE);
 	}
 
 	es2::Context *context = es2::getContext();
@@ -6522,7 +6471,13 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, context->getPixels(data));
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
+		if(validationError != GL_NO_ERROR)
+		{
+			return error(validationError);
+		}
+
+		texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
 	}
 }
 
@@ -6531,7 +6486,7 @@
 	TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, "
 	      "GLuint texture = %d, GLint level = %d, GLint zoffset = %d)", target, attachment, textarget, texture, level, zoffset);
 
-	if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+	if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
 	{
 		return error(GL_INVALID_ENUM);
 	}
@@ -6560,8 +6515,8 @@
 
 			switch(textarget)
 			{
-			case GL_TEXTURE_3D_OES:
-				if(tex->getTarget() != GL_TEXTURE_3D_OES)
+			case GL_TEXTURE_3D:
+				if(tex->getTarget() != GL_TEXTURE_3D)
 				{
 					return error(GL_INVALID_OPERATION);
 				}
@@ -6578,7 +6533,7 @@
 
 		es2::Framebuffer *framebuffer = nullptr;
 		GLuint framebufferName = 0;
-		if(target == GL_READ_FRAMEBUFFER_ANGLE)
+		if(target == GL_READ_FRAMEBUFFER)
 		{
 			framebuffer = context->getReadFramebuffer();
 			framebufferName = context->getReadFramebufferName();
@@ -6661,6 +6616,7 @@
 	switch(target)
 	{
 	case GL_TEXTURE_2D:
+	case GL_TEXTURE_RECTANGLE_ARB:
 	case GL_TEXTURE_EXTERNAL_OES:
 		break;
 	default:
@@ -6671,14 +6627,7 @@
 
 	if(context)
 	{
-		es2::Texture2D *texture = nullptr;
-
-		switch(target)
-		{
-		case GL_TEXTURE_2D:           texture = context->getTexture2D();       break;
-		case GL_TEXTURE_EXTERNAL_OES: texture = context->getTextureExternal(); break;
-		default:                      UNREACHABLE(target);
-		}
+		es2::Texture2D *texture = context->getTexture2D(target);
 
 		if(!texture)
 		{
@@ -6858,71 +6807,327 @@
 
 extern "C" NO_SANITIZE_FUNCTION __eglMustCastToProperFunctionPointerType es2GetProcAddress(const char *procname)
 {
-	struct Extension
+	struct Function
 	{
 		const char *name;
 		__eglMustCastToProperFunctionPointerType address;
 	};
 
-	static const Extension glExtensions[] =
+	struct CompareFunctor
 	{
-		#define EXTENSION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
-
-		EXTENSION(glTexImage3DOES),
-		EXTENSION(glBlitFramebufferANGLE),
-		EXTENSION(glBlitFramebufferNV),
-		EXTENSION(glRenderbufferStorageMultisampleANGLE),
-		EXTENSION(glDeleteFencesNV),
-		EXTENSION(glGenFencesNV),
-		EXTENSION(glIsFenceNV),
-		EXTENSION(glTestFenceNV),
-		EXTENSION(glGetFenceivNV),
-		EXTENSION(glFinishFenceNV),
-		EXTENSION(glSetFenceNV),
-		EXTENSION(glGetGraphicsResetStatusEXT),
-		EXTENSION(glReadnPixelsEXT),
-		EXTENSION(glGetnUniformfvEXT),
-		EXTENSION(glGetnUniformivEXT),
-		EXTENSION(glGenQueriesEXT),
-		EXTENSION(glDeleteQueriesEXT),
-		EXTENSION(glIsQueryEXT),
-		EXTENSION(glBeginQueryEXT),
-		EXTENSION(glEndQueryEXT),
-		EXTENSION(glGetQueryivEXT),
-		EXTENSION(glGetQueryObjectuivEXT),
-		EXTENSION(glEGLImageTargetTexture2DOES),
-		EXTENSION(glEGLImageTargetRenderbufferStorageOES),
-		EXTENSION(glDrawElementsInstancedEXT),
-		EXTENSION(glDrawArraysInstancedEXT),
-		EXTENSION(glVertexAttribDivisorEXT),
-		EXTENSION(glDrawArraysInstancedANGLE),
-		EXTENSION(glDrawElementsInstancedANGLE),
-		EXTENSION(glVertexAttribDivisorANGLE),
-		EXTENSION(glIsRenderbufferOES),
-		EXTENSION(glBindRenderbufferOES),
-		EXTENSION(glDeleteRenderbuffersOES),
-		EXTENSION(glGenRenderbuffersOES),
-		EXTENSION(glRenderbufferStorageOES),
-		EXTENSION(glGetRenderbufferParameterivOES),
-		EXTENSION(glIsFramebufferOES),
-		EXTENSION(glBindFramebufferOES),
-		EXTENSION(glDeleteFramebuffersOES),
-		EXTENSION(glGenFramebuffersOES),
-		EXTENSION(glCheckFramebufferStatusOES),
-		EXTENSION(glFramebufferRenderbufferOES),
-		EXTENSION(glFramebufferTexture2DOES),
-		EXTENSION(glGetFramebufferAttachmentParameterivOES),
-		EXTENSION(glGenerateMipmapOES),
-		EXTENSION(glDrawBuffersEXT),
-
-		#undef EXTENSION
+		bool operator()(const Function &a, const Function &b) const
+		{
+			return strcmp(a.name, b.name) < 0;
+		}
 	};
 
-	for(unsigned int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++)
+	// This array must be kept sorted with respect to strcmp(), so that binary search works correctly.
+	// The Unix command "LC_COLLATE=C sort" will generate the correct order.
+	static const Function glFunctions[] =
 	{
-		if(strcmp(procname, glExtensions[ext].name) == 0)
+		#define FUNCTION(name) {#name, (__eglMustCastToProperFunctionPointerType)name}
+
+		FUNCTION(glActiveTexture),
+		FUNCTION(glAttachShader),
+		FUNCTION(glBeginQuery),
+		FUNCTION(glBeginQueryEXT),
+		FUNCTION(glBeginTransformFeedback),
+		FUNCTION(glBindAttribLocation),
+		FUNCTION(glBindBuffer),
+		FUNCTION(glBindBufferBase),
+		FUNCTION(glBindBufferRange),
+		FUNCTION(glBindFramebuffer),
+		FUNCTION(glBindFramebufferOES),
+		FUNCTION(glBindRenderbuffer),
+		FUNCTION(glBindRenderbufferOES),
+		FUNCTION(glBindSampler),
+		FUNCTION(glBindTexture),
+		FUNCTION(glBindTransformFeedback),
+		FUNCTION(glBindVertexArray),
+		FUNCTION(glBlendColor),
+		FUNCTION(glBlendEquation),
+		FUNCTION(glBlendEquationSeparate),
+		FUNCTION(glBlendFunc),
+		FUNCTION(glBlendFuncSeparate),
+		FUNCTION(glBlitFramebuffer),
+		FUNCTION(glBlitFramebufferANGLE),
+		FUNCTION(glBufferData),
+		FUNCTION(glBufferSubData),
+		FUNCTION(glCheckFramebufferStatus),
+		FUNCTION(glCheckFramebufferStatusOES),
+		FUNCTION(glClear),
+		FUNCTION(glClearBufferfi),
+		FUNCTION(glClearBufferfv),
+		FUNCTION(glClearBufferiv),
+		FUNCTION(glClearBufferuiv),
+		FUNCTION(glClearColor),
+		FUNCTION(glClearDepthf),
+		FUNCTION(glClearStencil),
+		FUNCTION(glClientWaitSync),
+		FUNCTION(glColorMask),
+		FUNCTION(glCompileShader),
+		FUNCTION(glCompressedTexImage2D),
+		FUNCTION(glCompressedTexImage3D),
+		FUNCTION(glCompressedTexSubImage2D),
+		FUNCTION(glCompressedTexSubImage3D),
+		FUNCTION(glCopyBufferSubData),
+		FUNCTION(glCopyTexImage2D),
+		FUNCTION(glCopyTexSubImage2D),
+		FUNCTION(glCopyTexSubImage3D),
+		FUNCTION(glCreateProgram),
+		FUNCTION(glCreateShader),
+		FUNCTION(glCullFace),
+		FUNCTION(glDeleteBuffers),
+		FUNCTION(glDeleteFencesNV),
+		FUNCTION(glDeleteFramebuffers),
+		FUNCTION(glDeleteFramebuffersOES),
+		FUNCTION(glDeleteProgram),
+		FUNCTION(glDeleteQueries),
+		FUNCTION(glDeleteQueriesEXT),
+		FUNCTION(glDeleteRenderbuffers),
+		FUNCTION(glDeleteRenderbuffersOES),
+		FUNCTION(glDeleteSamplers),
+		FUNCTION(glDeleteShader),
+		FUNCTION(glDeleteSync),
+		FUNCTION(glDeleteTextures),
+		FUNCTION(glDeleteTransformFeedbacks),
+		FUNCTION(glDeleteVertexArrays),
+		FUNCTION(glDepthFunc),
+		FUNCTION(glDepthMask),
+		FUNCTION(glDepthRangef),
+		FUNCTION(glDetachShader),
+		FUNCTION(glDisable),
+		FUNCTION(glDisableVertexAttribArray),
+		FUNCTION(glDrawArrays),
+		FUNCTION(glDrawArraysInstanced),
+		FUNCTION(glDrawBuffers),
+		FUNCTION(glDrawBuffersEXT),
+		FUNCTION(glDrawElements),
+		FUNCTION(glDrawElementsInstanced),
+		FUNCTION(glDrawRangeElements),
+		FUNCTION(glEGLImageTargetRenderbufferStorageOES),
+		FUNCTION(glEGLImageTargetTexture2DOES),
+		FUNCTION(glEnable),
+		FUNCTION(glEnableVertexAttribArray),
+		FUNCTION(glEndQuery),
+		FUNCTION(glEndQueryEXT),
+		FUNCTION(glEndTransformFeedback),
+		FUNCTION(glFenceSync),
+		FUNCTION(glFinish),
+		FUNCTION(glFinishFenceNV),
+		FUNCTION(glFlush),
+		FUNCTION(glFlushMappedBufferRange),
+		FUNCTION(glFramebufferRenderbuffer),
+		FUNCTION(glFramebufferRenderbufferOES),
+		FUNCTION(glFramebufferTexture2D),
+		FUNCTION(glFramebufferTexture2DOES),
+		FUNCTION(glFramebufferTextureLayer),
+		FUNCTION(glFrontFace),
+		FUNCTION(glGenBuffers),
+		FUNCTION(glGenFencesNV),
+		FUNCTION(glGenFramebuffers),
+		FUNCTION(glGenFramebuffersOES),
+		FUNCTION(glGenQueries),
+		FUNCTION(glGenQueriesEXT),
+		FUNCTION(glGenRenderbuffers),
+		FUNCTION(glGenRenderbuffersOES),
+		FUNCTION(glGenSamplers),
+		FUNCTION(glGenTextures),
+		FUNCTION(glGenTransformFeedbacks),
+		FUNCTION(glGenVertexArrays),
+		FUNCTION(glGenerateMipmap),
+		FUNCTION(glGenerateMipmapOES),
+		FUNCTION(glGetActiveAttrib),
+		FUNCTION(glGetActiveUniform),
+		FUNCTION(glGetActiveUniformBlockName),
+		FUNCTION(glGetActiveUniformBlockiv),
+		FUNCTION(glGetActiveUniformsiv),
+		FUNCTION(glGetAttachedShaders),
+		FUNCTION(glGetAttribLocation),
+		FUNCTION(glGetBooleanv),
+		FUNCTION(glGetBufferParameteri64v),
+		FUNCTION(glGetBufferParameteriv),
+		FUNCTION(glGetBufferPointerv),
+		FUNCTION(glGetError),
+		FUNCTION(glGetFenceivNV),
+		FUNCTION(glGetFloatv),
+		FUNCTION(glGetFragDataLocation),
+		FUNCTION(glGetFramebufferAttachmentParameteriv),
+		FUNCTION(glGetFramebufferAttachmentParameterivOES),
+		FUNCTION(glGetGraphicsResetStatusEXT),
+		FUNCTION(glGetInteger64i_v),
+		FUNCTION(glGetInteger64v),
+		FUNCTION(glGetIntegeri_v),
+		FUNCTION(glGetIntegerv),
+		FUNCTION(glGetInternalformativ),
+		FUNCTION(glGetProgramBinary),
+		FUNCTION(glGetProgramInfoLog),
+		FUNCTION(glGetProgramiv),
+		FUNCTION(glGetQueryObjectuiv),
+		FUNCTION(glGetQueryObjectuivEXT),
+		FUNCTION(glGetQueryiv),
+		FUNCTION(glGetQueryivEXT),
+		FUNCTION(glGetRenderbufferParameteriv),
+		FUNCTION(glGetRenderbufferParameterivOES),
+		FUNCTION(glGetSamplerParameterfv),
+		FUNCTION(glGetSamplerParameteriv),
+		FUNCTION(glGetShaderInfoLog),
+		FUNCTION(glGetShaderPrecisionFormat),
+		FUNCTION(glGetShaderSource),
+		FUNCTION(glGetShaderiv),
+		FUNCTION(glGetString),
+		FUNCTION(glGetStringi),
+		FUNCTION(glGetSynciv),
+		FUNCTION(glGetTexParameterfv),
+		FUNCTION(glGetTexParameteriv),
+		FUNCTION(glGetTransformFeedbackVarying),
+		FUNCTION(glGetUniformBlockIndex),
+		FUNCTION(glGetUniformIndices),
+		FUNCTION(glGetUniformLocation),
+		FUNCTION(glGetUniformfv),
+		FUNCTION(glGetUniformiv),
+		FUNCTION(glGetUniformuiv),
+		FUNCTION(glGetVertexAttribIiv),
+		FUNCTION(glGetVertexAttribIuiv),
+		FUNCTION(glGetVertexAttribPointerv),
+		FUNCTION(glGetVertexAttribfv),
+		FUNCTION(glGetVertexAttribiv),
+		FUNCTION(glGetnUniformfvEXT),
+		FUNCTION(glGetnUniformivEXT),
+		FUNCTION(glHint),
+		FUNCTION(glInvalidateFramebuffer),
+		FUNCTION(glInvalidateSubFramebuffer),
+		FUNCTION(glIsBuffer),
+		FUNCTION(glIsEnabled),
+		FUNCTION(glIsFenceNV),
+		FUNCTION(glIsFramebuffer),
+		FUNCTION(glIsFramebufferOES),
+		FUNCTION(glIsProgram),
+		FUNCTION(glIsQuery),
+		FUNCTION(glIsQueryEXT),
+		FUNCTION(glIsRenderbuffer),
+		FUNCTION(glIsRenderbufferOES),
+		FUNCTION(glIsSampler),
+		FUNCTION(glIsShader),
+		FUNCTION(glIsSync),
+		FUNCTION(glIsTexture),
+		FUNCTION(glIsTransformFeedback),
+		FUNCTION(glIsVertexArray),
+		FUNCTION(glLineWidth),
+		FUNCTION(glLinkProgram),
+		FUNCTION(glMapBufferRange),
+		FUNCTION(glPauseTransformFeedback),
+		FUNCTION(glPixelStorei),
+		FUNCTION(glPolygonOffset),
+		FUNCTION(glProgramBinary),
+		FUNCTION(glProgramParameteri),
+		FUNCTION(glReadBuffer),
+		FUNCTION(glReadPixels),
+		FUNCTION(glReadnPixelsEXT),
+		FUNCTION(glReleaseShaderCompiler),
+		FUNCTION(glRenderbufferStorage),
+		FUNCTION(glRenderbufferStorageMultisample),
+		FUNCTION(glRenderbufferStorageMultisampleANGLE),
+		FUNCTION(glRenderbufferStorageOES),
+		FUNCTION(glResumeTransformFeedback),
+		FUNCTION(glSampleCoverage),
+		FUNCTION(glSamplerParameterf),
+		FUNCTION(glSamplerParameterfv),
+		FUNCTION(glSamplerParameteri),
+		FUNCTION(glSamplerParameteriv),
+		FUNCTION(glScissor),
+		FUNCTION(glSetFenceNV),
+		FUNCTION(glShaderBinary),
+		FUNCTION(glShaderSource),
+		FUNCTION(glStencilFunc),
+		FUNCTION(glStencilFuncSeparate),
+		FUNCTION(glStencilMask),
+		FUNCTION(glStencilMaskSeparate),
+		FUNCTION(glStencilOp),
+		FUNCTION(glStencilOpSeparate),
+		FUNCTION(glTestFenceNV),
+		FUNCTION(glTexImage2D),
+		FUNCTION(glTexImage3D),
+		FUNCTION(glTexImage3DOES),
+		FUNCTION(glTexParameterf),
+		FUNCTION(glTexParameterfv),
+		FUNCTION(glTexParameteri),
+		FUNCTION(glTexParameteriv),
+		FUNCTION(glTexStorage2D),
+		FUNCTION(glTexStorage3D),
+		FUNCTION(glTexSubImage2D),
+		FUNCTION(glTexSubImage3D),
+		FUNCTION(glTransformFeedbackVaryings),
+		FUNCTION(glUniform1f),
+		FUNCTION(glUniform1fv),
+		FUNCTION(glUniform1i),
+		FUNCTION(glUniform1iv),
+		FUNCTION(glUniform1ui),
+		FUNCTION(glUniform1uiv),
+		FUNCTION(glUniform2f),
+		FUNCTION(glUniform2fv),
+		FUNCTION(glUniform2i),
+		FUNCTION(glUniform2iv),
+		FUNCTION(glUniform2ui),
+		FUNCTION(glUniform2uiv),
+		FUNCTION(glUniform3f),
+		FUNCTION(glUniform3fv),
+		FUNCTION(glUniform3i),
+		FUNCTION(glUniform3iv),
+		FUNCTION(glUniform3ui),
+		FUNCTION(glUniform3uiv),
+		FUNCTION(glUniform4f),
+		FUNCTION(glUniform4fv),
+		FUNCTION(glUniform4i),
+		FUNCTION(glUniform4iv),
+		FUNCTION(glUniform4ui),
+		FUNCTION(glUniform4uiv),
+		FUNCTION(glUniformBlockBinding),
+		FUNCTION(glUniformMatrix2fv),
+		FUNCTION(glUniformMatrix2x3fv),
+		FUNCTION(glUniformMatrix2x4fv),
+		FUNCTION(glUniformMatrix3fv),
+		FUNCTION(glUniformMatrix3x2fv),
+		FUNCTION(glUniformMatrix3x4fv),
+		FUNCTION(glUniformMatrix4fv),
+		FUNCTION(glUniformMatrix4x2fv),
+		FUNCTION(glUniformMatrix4x3fv),
+		FUNCTION(glUnmapBuffer),
+		FUNCTION(glUseProgram),
+		FUNCTION(glValidateProgram),
+		FUNCTION(glVertexAttrib1f),
+		FUNCTION(glVertexAttrib1fv),
+		FUNCTION(glVertexAttrib2f),
+		FUNCTION(glVertexAttrib2fv),
+		FUNCTION(glVertexAttrib3f),
+		FUNCTION(glVertexAttrib3fv),
+		FUNCTION(glVertexAttrib4f),
+		FUNCTION(glVertexAttrib4fv),
+		FUNCTION(glVertexAttribDivisor),
+		FUNCTION(glVertexAttribI4i),
+		FUNCTION(glVertexAttribI4iv),
+		FUNCTION(glVertexAttribI4ui),
+		FUNCTION(glVertexAttribI4uiv),
+		FUNCTION(glVertexAttribIPointer),
+		FUNCTION(glVertexAttribPointer),
+		FUNCTION(glViewport),
+		FUNCTION(glWaitSync),
+
+		#undef FUNCTION
+	};
+
+	static const size_t numFunctions = sizeof glFunctions / sizeof(Function);
+	static const Function *const glFunctionsEnd = glFunctions + numFunctions;
+
+	Function needle;
+	needle.name = procname;
+
+	if(procname && strncmp("gl", procname, 2) == 0)
+	{
+		const Function *result = std::lower_bound(glFunctions, glFunctionsEnd, needle, CompareFunctor());
+		if(result != glFunctionsEnd && strcmp(procname, result->name) == 0)
 		{
-			return (__eglMustCastToProperFunctionPointerType)glExtensions[ext].address;
+			return (__eglMustCastToProperFunctionPointerType)result->address;
 		}
 	}
 
diff --git a/src/OpenGL/libGLESv2/libGLESv2.hpp b/src/OpenGL/libGLESv2/libGLESv2.hpp
index 42febd8..cb14319 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.hpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.hpp
@@ -302,6 +302,8 @@
 				#else
 					const char *libGLESv2_lib[] = {"libGLES_V2_translator.dylib", "libGLESv2.dylib", "libswiftshader_libGLESv2.dylib"};
 				#endif
+			#elif defined(__Fuchsia__)
+				const char *libGLESv2_lib[] = {"libGLESv2.so"};
 			#else
 				#error "libGLESv2::loadExports unimplemented for this platform"
 			#endif
diff --git a/src/OpenGL/libGLESv2/exports.map b/src/OpenGL/libGLESv2/libGLESv2.lds
similarity index 99%
rename from src/OpenGL/libGLESv2/exports.map
rename to src/OpenGL/libGLESv2/libGLESv2.lds
index adc4ff5..483efc2 100644
--- a/src/OpenGL/libGLESv2/exports.map
+++ b/src/OpenGL/libGLESv2/libGLESv2.lds
@@ -302,4 +302,4 @@
 
 local:
 	*;
-};
+};
\ No newline at end of file
diff --git a/src/OpenGL/libGLESv2/libGLESv2.vcxproj b/src/OpenGL/libGLESv2/libGLESv2.vcxproj
index bae560e..fcd5093 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.vcxproj
+++ b/src/OpenGL/libGLESv2/libGLESv2.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -30,41 +30,42 @@
     <ProjectGuid>{B5871A7A-968C-42E3-A33B-981E6F448E78}</ProjectGuid>

     <RootNamespace>libGLESv2</RootNamespace>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>DynamicLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

@@ -124,7 +125,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

     <ClCompile>

       <Optimization>Disabled</Optimization>

-      <AdditionalIncludeDirectories>$(SolutionDir)\src;$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;GL_API=;GL_APICALL=;GL_GLEXT_PROTOTYPES;NO_SANITIZE_FUNCTION=;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <MinimalRebuild>true</MinimalRebuild>

       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

@@ -137,6 +138,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;%(DisableSpecificWarnings)</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -155,7 +157,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

     <ClCompile>

       <Optimization>Disabled</Optimization>

-      <AdditionalIncludeDirectories>$(SolutionDir)\src;$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>$(ProjectDir)/..;$(ProjectDir)/../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;GL_API=;GL_APICALL=;GL_GLEXT_PROTOTYPES;NO_SANITIZE_FUNCTION=;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

@@ -167,6 +169,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;%(DisableSpecificWarnings)</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -204,6 +207,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;%(DisableSpecificWarnings)</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -242,6 +246,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;%(DisableSpecificWarnings)</DisableSpecificWarnings>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -280,6 +285,7 @@
       <IntrinsicFunctions>false</IntrinsicFunctions>

       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -316,6 +322,7 @@
       <IntrinsicFunctions>false</IntrinsicFunctions>

       <TreatWarningAsError>true</TreatWarningAsError>

       <DisableSpecificWarnings>5030;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <AdditionalDependencies>dxguid.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

@@ -343,6 +350,7 @@
     <ClCompile Include="Context.cpp" />

     <ClCompile Include="..\common\debug.cpp" />

     <ClCompile Include="Device.cpp" />

+    <ClCompile Include="entry_points.cpp" />

     <ClCompile Include="Fence.cpp" />

     <ClCompile Include="Framebuffer.cpp" />

     <ClCompile Include="IndexDataManager.cpp" />

diff --git a/src/OpenGL/libGLESv2/libGLESv2.vcxproj.filters b/src/OpenGL/libGLESv2/libGLESv2.vcxproj.filters
index e297714..615363b 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.vcxproj.filters
+++ b/src/OpenGL/libGLESv2/libGLESv2.vcxproj.filters
@@ -77,6 +77,9 @@
     <ClCompile Include="..\common\Image.cpp">

       <Filter>Source Files</Filter>

     </ClCompile>

+    <ClCompile Include="entry_points.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

   </ItemGroup>

   <ItemGroup>

     <ClInclude Include="Buffer.h">

diff --git a/src/OpenGL/libGLESv2/libGLESv3.cpp b/src/OpenGL/libGLESv2/libGLESv3.cpp
index f995d2d..f5f3264 100644
--- a/src/OpenGL/libGLESv2/libGLESv3.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv3.cpp
@@ -24,6 +24,7 @@
 #include "Texture.h"
 #include "mathutil.h"
 #include "TransformFeedback.h"
+#include "VertexArray.h"
 #include "common/debug.h"
 
 #include <GLES3/gl3.h>
@@ -33,15 +34,6 @@
 
 using namespace es2;
 
-typedef std::pair<GLenum, GLenum> InternalFormatTypePair;
-typedef std::map<InternalFormatTypePair, GLenum> FormatMap;
-
-// A helper function to insert data into the format map with fewer characters.
-static void InsertFormatMapping(FormatMap& map, GLenum internalformat, GLenum format, GLenum type)
-{
-	map[InternalFormatTypePair(internalformat, type)] = format;
-}
-
 static bool validImageSize(GLint level, GLsizei width, GLsizei height)
 {
 	if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || width < 0 || height < 0)
@@ -52,290 +44,6 @@
 	return true;
 }
 
-static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFormat)
-{
-	GLenum validationError = ValidateCompressedFormat(textureFormat, egl::getClientVersion(), false);
-	if(validationError != GL_NONE)
-	{
-		return error(validationError, false);
-	}
-
-	switch(textureFormat)
-	{
-	case GL_ALPHA:
-		if(colorbufferFormat != GL_ALPHA &&
-		   colorbufferFormat != GL_RGBA &&
-		   colorbufferFormat != GL_RGBA4 &&
-		   colorbufferFormat != GL_RGB5_A1 &&
-		   colorbufferFormat != GL_RGBA8)
-		{
-			return error(GL_INVALID_OPERATION, false);
-		}
-		break;
-	case GL_LUMINANCE:
-	case GL_RGB:
-		if(colorbufferFormat != GL_RGB &&
-		   colorbufferFormat != GL_RGB565 &&
-		   colorbufferFormat != GL_RGB8 &&
-		   colorbufferFormat != GL_RGBA &&
-		   colorbufferFormat != GL_RGBA4 &&
-		   colorbufferFormat != GL_RGB5_A1 &&
-		   colorbufferFormat != GL_RGBA8)
-		{
-			return error(GL_INVALID_OPERATION, false);
-		}
-		break;
-	case GL_LUMINANCE_ALPHA:
-	case GL_RGBA:
-		if(colorbufferFormat != GL_RGBA &&
-		   colorbufferFormat != GL_RGBA4 &&
-		   colorbufferFormat != GL_RGB5_A1 &&
-		   colorbufferFormat != GL_RGBA8)
-		{
-			return error(GL_INVALID_OPERATION, false);
-		}
-		break;
-	case GL_DEPTH_COMPONENT:
-	case GL_DEPTH_STENCIL:
-		return error(GL_INVALID_OPERATION, false);
-	default:
-		return error(GL_INVALID_ENUM, false);
-	}
-	return true;
-}
-
-static FormatMap BuildFormatMap3D()
-{
-	FormatMap map;
-
-	//                       Internal format | Format | Type
-	InsertFormatMapping(map, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
-	InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);
-	InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
-	InsertFormatMapping(map, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_R8, GL_RED, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_R8_SNORM, GL_RED, GL_BYTE);
-	InsertFormatMapping(map, GL_R16F, GL_RED, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_R16F, GL_RED, GL_FLOAT);
-	InsertFormatMapping(map, GL_R32F, GL_RED, GL_FLOAT);
-	InsertFormatMapping(map, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_R8I, GL_RED_INTEGER, GL_BYTE);
-	InsertFormatMapping(map, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_R16I, GL_RED_INTEGER, GL_SHORT);
-	InsertFormatMapping(map, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_R32I, GL_RED_INTEGER, GL_INT);
-	InsertFormatMapping(map, GL_RG8, GL_RG, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RG8_SNORM, GL_RG, GL_BYTE);
-	InsertFormatMapping(map, GL_RG16F, GL_RG, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_RG16F, GL_RG, GL_FLOAT);
-	InsertFormatMapping(map, GL_RG32F, GL_RG, GL_FLOAT);
-	InsertFormatMapping(map, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RG8I, GL_RG_INTEGER, GL_BYTE);
-	InsertFormatMapping(map, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_RG16I, GL_RG_INTEGER, GL_SHORT);
-	InsertFormatMapping(map, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_RG32I, GL_RG_INTEGER, GL_INT);
-	InsertFormatMapping(map, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
-	InsertFormatMapping(map, GL_RGB8_SNORM, GL_RGB, GL_BYTE);
-	InsertFormatMapping(map, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV);
-	InsertFormatMapping(map, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV);
-	InsertFormatMapping(map, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_RGB9_E5, GL_RGB, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGB16F, GL_RGB, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_RGB16F, GL_RGB, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGB32F, GL_RGB, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE);
-	InsertFormatMapping(map, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT);
-	InsertFormatMapping(map, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_RGB32I, GL_RGB_INTEGER, GL_INT);
-	InsertFormatMapping(map, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
-	InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatMapping(map, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE);
-	InsertFormatMapping(map, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);
-	InsertFormatMapping(map, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatMapping(map, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT);
-	InsertFormatMapping(map, GL_RGBA16F, GL_RGBA, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGBA32F, GL_RGBA, GL_FLOAT);
-	InsertFormatMapping(map, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE);
-	InsertFormatMapping(map, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE);
-	InsertFormatMapping(map, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatMapping(map, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT);
-	InsertFormatMapping(map, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT);
-
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT);
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
-	InsertFormatMapping(map, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT);
-	InsertFormatMapping(map, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
-	InsertFormatMapping(map, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
-
-	return map;
-}
-
-static bool ValidateType3D(GLenum type)
-{
-	switch(type)
-	{
-	case GL_UNSIGNED_BYTE:
-	case GL_BYTE:
-	case GL_UNSIGNED_SHORT:
-	case GL_SHORT:
-	case GL_UNSIGNED_INT:
-	case GL_INT:
-	case GL_HALF_FLOAT:
-	case GL_FLOAT:
-	case GL_UNSIGNED_SHORT_5_6_5:
-	case GL_UNSIGNED_SHORT_4_4_4_4:
-	case GL_UNSIGNED_SHORT_5_5_5_1:
-	case GL_UNSIGNED_INT_2_10_10_10_REV:
-	case GL_UNSIGNED_INT_10F_11F_11F_REV:
-	case GL_UNSIGNED_INT_5_9_9_9_REV:
-	case GL_UNSIGNED_INT_24_8:
-	case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-		return true;
-	default:
-		break;
-	}
-	return false;
-}
-
-static bool ValidateFormat3D(GLenum format)
-{
-	switch(format)
-	{
-	case GL_RED:
-	case GL_RG:
-	case GL_RGB:
-	case GL_RGBA:
-	case GL_DEPTH_COMPONENT:
-	case GL_DEPTH_STENCIL:
-	case GL_LUMINANCE_ALPHA:
-	case GL_LUMINANCE:
-	case GL_ALPHA:
-	case GL_RED_INTEGER:
-	case GL_RG_INTEGER:
-	case GL_RGB_INTEGER:
-	case GL_RGBA_INTEGER:
-		return true;
-	default:
-		break;
-	}
-	return false;
-}
-
-static bool ValidateInternalFormat3D(GLenum internalformat, GLenum format, GLenum type)
-{
-	static const FormatMap formatMap = BuildFormatMap3D();
-	FormatMap::const_iterator iter = formatMap.find(InternalFormatTypePair(internalformat, type));
-	if(iter != formatMap.end())
-	{
-		return iter->second == format;
-	}
-	return false;
-}
-
-typedef std::map<GLenum, GLenum> FormatMapStorage;
-
-// A helper function to insert data into the format map with fewer characters.
-static void InsertFormatStorageMapping(FormatMapStorage& map, GLenum internalformat, GLenum type)
-{
-	map[internalformat] = type;
-}
-
-static FormatMapStorage BuildFormatMapStorage2D()
-{
-	FormatMapStorage map;
-
-	//                              Internal format | Type
-	InsertFormatStorageMapping(map, GL_R8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_R8_SNORM, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_R16F, GL_HALF_FLOAT);
-	InsertFormatStorageMapping(map, GL_R32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_R8UI, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_R8I, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_R16UI, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_R16I, GL_SHORT);
-	InsertFormatStorageMapping(map, GL_R32UI, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_R32I, GL_INT);
-	InsertFormatStorageMapping(map, GL_RG8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RG8_SNORM, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RG16F, GL_HALF_FLOAT);
-	InsertFormatStorageMapping(map, GL_RG32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_RG8UI, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RG8I, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RG16UI, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_RG16I, GL_SHORT);
-	InsertFormatStorageMapping(map, GL_RG32UI, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_RG32I, GL_INT);
-	InsertFormatStorageMapping(map, GL_RGB8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_SRGB8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5);
-	InsertFormatStorageMapping(map, GL_RGB8_SNORM, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV);
-	InsertFormatStorageMapping(map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV);
-	InsertFormatStorageMapping(map, GL_RGB16F, GL_HALF_FLOAT);
-	InsertFormatStorageMapping(map, GL_RGB32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_RGB8UI, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB8I, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB16UI, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_RGB16I, GL_SHORT);
-	InsertFormatStorageMapping(map, GL_RGB32UI, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_RGB32I, GL_INT);
-	InsertFormatStorageMapping(map, GL_RGBA8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RGBA8_SNORM, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1);
-	InsertFormatStorageMapping(map, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4);
-	InsertFormatStorageMapping(map, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatStorageMapping(map, GL_RGBA16F, GL_HALF_FLOAT);
-	InsertFormatStorageMapping(map, GL_RGBA32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_RGBA8UI, GL_UNSIGNED_BYTE);
-	InsertFormatStorageMapping(map, GL_RGBA8I, GL_BYTE);
-	InsertFormatStorageMapping(map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV);
-	InsertFormatStorageMapping(map, GL_RGBA16UI, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_RGBA16I, GL_SHORT);
-	InsertFormatStorageMapping(map, GL_RGBA32UI, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_RGBA32I, GL_INT);
-
-	InsertFormatStorageMapping(map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT);
-	InsertFormatStorageMapping(map, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT);
-	InsertFormatStorageMapping(map, GL_DEPTH_COMPONENT32F, GL_FLOAT);
-	InsertFormatStorageMapping(map, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8);
-	InsertFormatStorageMapping(map, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
-
-	return map;
-}
-
-static bool GetStorageType(GLenum internalformat, GLenum& type)
-{
-	static const FormatMapStorage formatMap = BuildFormatMapStorage2D();
-	FormatMapStorage::const_iterator iter = formatMap.find(internalformat);
-	if(iter != formatMap.end())
-	{
-		type = iter->second;
-		return true;
-	}
-	return false;
-}
-
 static bool ValidateQueryTarget(GLenum target)
 {
 	switch(target)
@@ -560,7 +268,7 @@
 			GLuint index = (src - GL_COLOR_ATTACHMENT0);
 			if(index >= MAX_COLOR_ATTACHMENTS)
 			{
-				return error(GL_INVALID_ENUM);
+				return error(GL_INVALID_OPERATION);
 			}
 			if(readFramebufferName == 0)
 			{
@@ -570,7 +278,7 @@
 		}
 			break;
 		default:
-			error(GL_INVALID_ENUM);
+			return error(GL_INVALID_ENUM);
 		}
 	}
 }
@@ -640,11 +348,6 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(!ValidateType3D(type) || !ValidateFormat3D(format))
-	{
-		return error(GL_INVALID_ENUM);
-	}
-
 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
 	{
 		return error(GL_INVALID_VALUE);
@@ -661,15 +364,16 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(!ValidateInternalFormat3D(internalformat, format, type))
-	{
-		return error(GL_INVALID_OPERATION);
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
 	{
+		GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target, context->getClientVersion());
+		if(validationError != GL_NO_ERROR)
+		{
+			return error(validationError);
+		}
+
 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
 
 		if(!texture)
@@ -677,7 +381,14 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		texture->setImage(context, level, width, height, depth, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), context->getPixels(data));
+		validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
+		if(validationError != GL_NO_ERROR)
+		{
+			return error(validationError);
+		}
+
+		GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
+		texture->setImage(level, width, height, depth, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
 	}
 }
 
@@ -697,11 +408,6 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(!ValidateType3D(type) || !ValidateFormat3D(format))
-	{
-		return error(GL_INVALID_ENUM);
-	}
-
 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
 	{
 		return error(GL_INVALID_VALUE);
@@ -718,17 +424,19 @@
 	{
 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
 
-		GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
-
-		GLenum validationError = ValidateSubImageParams(false, width, height, depth, xoffset, yoffset, zoffset, target, level, sizedInternalFormat, texture);
-		if(validationError == GL_NONE)
-		{
-			texture->subImage(context, level, xoffset, yoffset, zoffset, width, height, depth, sizedInternalFormat, type, context->getUnpackInfo(), context->getPixels(data));
-		}
-		else
+		GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texture, context->getClientVersion());
+		if(validationError != GL_NO_ERROR)
 		{
 			return error(validationError);
 		}
+
+		validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
+		if(validationError != GL_NO_ERROR)
+		{
+			return error(validationError);
+		}
+
+		texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackParameters(), data);
 	}
 }
 
@@ -778,20 +486,20 @@
 		GLenum colorbufferFormat = source->getFormat();
 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
 
-		GLenum validationError = ValidateSubImageParams(false, width, height, 1, xoffset, yoffset, zoffset, target, level, GL_NONE, texture);
-		if(validationError != GL_NONE)
+		GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, zoffset, width, height, 1, GL_NONE, GL_NONE, texture, context->getClientVersion());
+		if(validationError != GL_NO_ERROR)
 		{
 			return error(validationError);
 		}
 
 		GLenum textureFormat = texture->getFormat(target, level);
 
-		if(!validateColorBufferFormat(textureFormat, colorbufferFormat))
+		if(!ValidateCopyFormats(textureFormat, colorbufferFormat))
 		{
 			return;
 		}
 
-		texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer);
+		texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source);
 	}
 }
 
@@ -821,25 +529,12 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	switch(internalformat)
+	if(!IsCompressed(internalformat, egl::getClientVersion()))
 	{
-	case GL_DEPTH_COMPONENT:
-	case GL_DEPTH_COMPONENT16:
-	case GL_DEPTH_COMPONENT32_OES:
-	case GL_DEPTH_STENCIL:
-	case GL_DEPTH24_STENCIL8:
-		return error(GL_INVALID_OPERATION);
-	default:
-		{
-			GLenum validationError = ValidateCompressedFormat(internalformat, egl::getClientVersion(), true);
-			if(validationError != GL_NONE)
-			{
-				return error(validationError);
-			}
-		}
+		return error(GL_INVALID_ENUM);
 	}
 
-	if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth)
+	if(imageSize != gl::ComputeCompressedSize(width, height, internalformat) * depth)
 	{
 		return error(GL_INVALID_VALUE);
 	}
@@ -855,6 +550,12 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
+		if(validationError != GL_NO_ERROR)
+		{
+			return error(validationError);
+		}
+
 		texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data);
 	}
 }
@@ -885,15 +586,44 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	GLenum validationError = ValidateCompressedFormat(format, egl::getClientVersion(), true);
-	if(validationError != GL_NONE)
+	if(!IsCompressed(format, egl::getClientVersion()))
 	{
-		return error(validationError);
+		return error(GL_INVALID_ENUM);
 	}
 
-	if(width == 0 || height == 0 || depth == 0 || !data)
+	if(imageSize != gl::ComputeCompressedSize(width, height, format) * depth)
 	{
-		return;
+		return error(GL_INVALID_VALUE);
+	}
+
+	bool is_ETC2_EAC = false;
+	switch(format)
+	{
+	case GL_COMPRESSED_R11_EAC:
+	case GL_COMPRESSED_SIGNED_R11_EAC:
+	case GL_COMPRESSED_RG11_EAC:
+	case GL_COMPRESSED_SIGNED_RG11_EAC:
+	case GL_COMPRESSED_RGB8_ETC2:
+	case GL_COMPRESSED_SRGB8_ETC2:
+	case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+	case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+	case GL_COMPRESSED_RGBA8_ETC2_EAC:
+	case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+		if(target != GL_TEXTURE_2D_ARRAY)
+		{
+			return error(GL_INVALID_OPERATION);
+		}
+
+		if(((width % 4) != 0) || ((height % 4) != 0) ||
+		   ((xoffset % 4) != 0) || ((yoffset % 4) != 0))
+		{
+			return error(GL_INVALID_OPERATION);
+		}
+
+		is_ETC2_EAC = true;
+		break;
+	default:
+		break;
 	}
 
 	es2::Context *context = es2::getContext();
@@ -907,7 +637,23 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, context->getPixels(data));
+		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
+		if(validationError != GL_NO_ERROR)
+		{
+			return error(validationError);
+		}
+
+		if(is_ETC2_EAC)
+		{
+			if(((width + xoffset) != texture->getWidth(target, level)) ||
+			   ((height + yoffset) != texture->getHeight(target, level)) ||
+			   ((depth + zoffset) != texture->getDepth(target, level)))
+			{
+				return error(GL_INVALID_OPERATION);
+			}
+		}
+
+		texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
 	}
 }
 
@@ -1096,6 +842,12 @@
 			return error(GL_INVALID_OPERATION, GL_TRUE);
 		}
 
+		if(!buffer->isMapped())
+		{
+			// Already unmapped
+			return error(GL_INVALID_OPERATION, GL_TRUE);
+		}
+
 		return buffer->unmap() ? GL_TRUE : GL_FALSE;
 	}
 
@@ -1233,11 +985,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1249,6 +996,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniformMatrix2x3fv(location, count, transpose, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -1265,11 +1017,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1281,6 +1028,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniformMatrix3x2fv(location, count, transpose, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -1297,11 +1049,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1313,6 +1060,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniformMatrix2x4fv(location, count, transpose, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -1329,11 +1081,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1345,6 +1092,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniformMatrix4x2fv(location, count, transpose, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -1361,11 +1113,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1377,6 +1124,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniformMatrix3x4fv(location, count, transpose, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -1393,11 +1145,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1409,6 +1156,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniformMatrix4x3fv(location, count, transpose, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -1426,7 +1178,12 @@
 	switch(filter)
 	{
 	case GL_NEAREST:
+		break;
 	case GL_LINEAR:
+		if((mask & GL_DEPTH_BUFFER_BIT) || (mask & GL_STENCIL_BUFFER_BIT))
+		{
+			return error(GL_INVALID_OPERATION);
+		}
 		break;
 	default:
 		return error(GL_INVALID_ENUM);
@@ -1475,7 +1232,7 @@
 		{
 			if(!textureObject)
 			{
-				return error(GL_INVALID_VALUE);
+				return error(GL_INVALID_OPERATION);
 			}
 
 			textarget = textureObject->getTarget();
@@ -1503,9 +1260,17 @@
 		{
 		case GL_DRAW_FRAMEBUFFER:
 		case GL_FRAMEBUFFER:
+			if(context->getDrawFramebufferName() == 0)
+			{
+				return error(GL_INVALID_OPERATION);
+			}
 			framebuffer = context->getDrawFramebuffer();
 			break;
 		case GL_READ_FRAMEBUFFER:
+			if(context->getReadFramebufferName() == 0)
+			{
+				return error(GL_INVALID_OPERATION);
+			}
 			framebuffer = context->getReadFramebuffer();
 			break;
 		default:
@@ -1574,6 +1339,27 @@
 	TRACE("(GLenum target = 0x%X,  GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = %X)",
 	      target, offset, length, access);
 
+	if((offset < 0) || (length < 0))
+	{
+		return error(GL_INVALID_VALUE, nullptr);
+	}
+
+	if(!(access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)))
+	{
+		// Must be able to read or write the buffer
+		return error(GL_INVALID_OPERATION, nullptr);
+	}
+	else if((access & GL_MAP_READ_BIT) && (access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT)))
+	{
+		// GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT and GL_MAP_UNSYNCHRONIZED_BIT can't be used with GL_MAP_READ_BIT
+		return error(GL_INVALID_OPERATION, nullptr);
+	}
+	else if((!(access & GL_MAP_WRITE_BIT)) && (access & GL_MAP_FLUSH_EXPLICIT_BIT))
+	{
+		// GL_MAP_FLUSH_EXPLICIT_BIT can't be used without GL_MAP_WRITE_BIT
+		return error(GL_INVALID_OPERATION, nullptr);
+	}
+
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1590,10 +1376,16 @@
 			return error(GL_INVALID_OPERATION, nullptr);
 		}
 
-		GLsizeiptr bufferSize = buffer->size();
-		if((offset < 0) || (length < 0) || ((offset + length) > bufferSize))
+		if(buffer->isMapped())
 		{
-			error(GL_INVALID_VALUE);
+			// It is an invalid operation to map an already mapped buffer
+			return error(GL_INVALID_OPERATION, nullptr);
+		}
+
+		GLsizeiptr bufferSize = buffer->size();
+		if((offset + length) > bufferSize)
+		{
+			return error(GL_INVALID_VALUE, nullptr);
 		}
 
 		if((access & ~(GL_MAP_READ_BIT |
@@ -1603,7 +1395,7 @@
 		               GL_MAP_FLUSH_EXPLICIT_BIT |
 		               GL_MAP_UNSYNCHRONIZED_BIT)) != 0)
 		{
-			error(GL_INVALID_VALUE);
+			return error(GL_INVALID_VALUE, nullptr);
 		}
 
 		return buffer->mapRange(offset, length, access);
@@ -1617,6 +1409,11 @@
 	TRACE("(GLenum target = 0x%X,  GLintptr offset = %d, GLsizeiptr length = %d)",
 	      target, offset, length);
 
+	if((offset < 0) || (length < 0))
+	{
+		return error(GL_INVALID_VALUE);
+	}
+
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1633,10 +1430,22 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		GLsizeiptr bufferSize = buffer->size();
-		if((offset < 0) || (length < 0) || ((offset + length) > bufferSize))
+		if(!buffer->isMapped())
 		{
-			error(GL_INVALID_VALUE);
+			// Buffer must be mapped
+			return error(GL_INVALID_OPERATION);
+		}
+
+		GLsizeiptr bufferSize = buffer->length();
+		if((offset + length) > bufferSize)
+		{
+			return error(GL_INVALID_VALUE);
+		}
+
+		if(!(buffer->access() & GL_MAP_FLUSH_EXPLICIT_BIT))
+		{
+			// Flush must be explicitly allowed
+			return error(GL_INVALID_OPERATION);
 		}
 
 		buffer->flushMappedRange(offset, length);
@@ -1647,11 +1456,6 @@
 {
 	TRACE("(GLuint array = %d)", array);
 
-	if(array == 0)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -1775,7 +1579,7 @@
 				{
 					if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
 					{
-						data[i] = convert_float_int(floatParams[i]);
+						data[i] = convert_float_fixed(floatParams[i]);
 					}
 					else
 					{
@@ -2023,7 +1827,15 @@
 
 	if(context)
 	{
-		context->setVertexAttribState(index, context->getArrayBuffer(), size, type, false, stride, pointer);
+		es2::VertexArray* vertexArray = context->getCurrentVertexArray();
+		if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && pointer)
+		{
+			// GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
+			// to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
+			return error(GL_INVALID_OPERATION);
+		}
+
+		context->setVertexAttribState(index, context->getArrayBuffer(), size, type, false, true, stride, pointer);
 	}
 }
 
@@ -2073,22 +1885,7 @@
 			}
 			break;
 		case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
-			switch(attribState.mType)
-			{
-			case GL_BYTE:
-			case GL_UNSIGNED_BYTE:
-			case GL_SHORT:
-			case GL_UNSIGNED_SHORT:
-			case GL_INT:
-			case GL_INT_2_10_10_10_REV:
-			case GL_UNSIGNED_INT:
-			case GL_FIXED:
-				*params = GL_TRUE;
-				break;
-			default:
-				*params = GL_FALSE;
-				break;
-			}
+			*params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
 			break;
 		case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
 			*params = attribState.mDivisor;
@@ -2144,22 +1941,7 @@
 			}
 			break;
 		case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
-			switch(attribState.mType)
-			{
-			case GL_BYTE:
-			case GL_UNSIGNED_BYTE:
-			case GL_SHORT:
-			case GL_UNSIGNED_SHORT:
-			case GL_INT:
-			case GL_INT_2_10_10_10_REV:
-			case GL_UNSIGNED_INT:
-			case GL_FIXED:
-				*params = GL_TRUE;
-				break;
-			default:
-				*params = GL_FALSE;
-				break;
-			}
+			*params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
 			break;
 		case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
 			*params = attribState.mDivisor;
@@ -2250,19 +2032,21 @@
 
 	if(context)
 	{
-		if(program == 0)
-		{
-			return error(GL_INVALID_VALUE);
-		}
-
 		es2::Program *programObject = context->getProgram(program);
 
-		if(!programObject || !programObject->isLinked())
+		if(!programObject)
 		{
-			return error(GL_INVALID_OPERATION);
+			if(context->getShader(program))
+			{
+				return error(GL_INVALID_OPERATION);
+			}
+			else
+			{
+				return error(GL_INVALID_VALUE);
+			}
 		}
 
-		if(!programObject)
+		if(!programObject->isLinked())
 		{
 			return error(GL_INVALID_OPERATION);
 		}
@@ -2343,11 +2127,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -2359,6 +2138,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform1uiv(location, count, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -2376,11 +2160,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -2392,6 +2171,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform2uiv(location, count, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -2409,11 +2193,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -2425,6 +2204,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform3uiv(location, count, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -2442,11 +2226,6 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	if(location == -1)
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -2458,6 +2237,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(location == -1)
+		{
+			return;
+		}
+
 		if(!program->setUniform4uiv(location, count, value))
 		{
 			return error(GL_INVALID_OPERATION);
@@ -2682,7 +2466,14 @@
 
 		if(!programObject)
 		{
-			return error(GL_INVALID_OPERATION);
+			if(context->getShader(program))
+			{
+				return error(GL_INVALID_OPERATION);
+			}
+			else
+			{
+				return error(GL_INVALID_VALUE);
+			}
 		}
 
 		if(!programObject->isLinked())
@@ -2735,7 +2526,14 @@
 
 		if(!programObject)
 		{
-			return error(GL_INVALID_OPERATION);
+			if(context->getShader(program))
+			{
+				return error(GL_INVALID_OPERATION);
+			}
+			else
+			{
+				return error(GL_INVALID_VALUE);
+			}
 		}
 
 		for(int uniformId = 0; uniformId < uniformCount; uniformId++)
@@ -2769,7 +2567,14 @@
 
 		if(!programObject)
 		{
-			return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);
+			if(context->getShader(program))
+			{
+				return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);
+			}
+			else
+			{
+				return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
+			}
 		}
 
 		return programObject->getUniformBlockIndex(uniformBlockName);
@@ -2999,10 +2804,20 @@
 {
 	TRACE("(GLsync sync = %p)", sync);
 
+	if(!sync)
+	{
+		return;
+	}
+
 	es2::Context *context = es2::getContext();
 
 	if(context)
 	{
+		if(!context->getFenceSync(sync))
+		{
+			return error(GL_INVALID_VALUE);
+		}
+
 		context->deleteFenceSync(sync);
 	}
 }
@@ -3013,7 +2828,7 @@
 
 	if((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
 	{
-		error(GL_INVALID_VALUE);
+		return error(GL_INVALID_VALUE, GL_FALSE);
 	}
 
 	es2::Context *context = es2::getContext();
@@ -3109,7 +2924,7 @@
 				{
 					if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
 					{
-						data[i] = (GLint64)(convert_float_int(floatParams[i]));
+						data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
 					}
 					else
 					{
@@ -3192,7 +3007,7 @@
 				{
 					if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
 					{
-						data[i] = (GLint64)(convert_float_int(floatParams[i]));
+						data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
 					}
 					else
 					{
@@ -3391,11 +3206,6 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	if(!ValidateTexParamParameters(pname, static_cast<GLint>(roundf(*param))))
-	{
-		return;
-	}
-
 	es2::Context *context = es2::getContext();
 
 	if(context)
@@ -3405,7 +3215,10 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		context->samplerParameterf(sampler, pname, *param);
+		if(ValidateTexParamParameters(pname, static_cast<GLint>(roundf(*param))))
+		{
+			context->samplerParameterf(sampler, pname, *param);
+		}
 	}
 }
 
@@ -3425,7 +3238,7 @@
 	{
 		if(!context->isSampler(sampler))
 		{
-			return error(GL_INVALID_VALUE);
+			return error(GL_INVALID_OPERATION);
 		}
 
 		*params = context->getSamplerParameteri(sampler, pname);
@@ -3448,7 +3261,7 @@
 	{
 		if(!context->isSampler(sampler))
 		{
-			return error(GL_INVALID_VALUE);
+			return error(GL_INVALID_OPERATION);
 		}
 
 		*params = context->getSamplerParameterf(sampler, pname);
@@ -3492,6 +3305,11 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
+		if(!context->isTransformFeedback(id))
+		{
+			return error(GL_INVALID_OPERATION);
+		}
+
 		context->bindTransformFeedback(id);
 	}
 }
@@ -3513,6 +3331,13 @@
 		{
 			if(ids[i] != 0)
 			{
+				es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(ids[i]);
+
+				if(transformFeedbackObject && transformFeedbackObject->isActive())
+				{
+					return error(GL_INVALID_OPERATION);
+				}
+
 				context->deleteTransformFeedback(ids[i]);
 			}
 		}
@@ -3615,7 +3440,20 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	UNIMPLEMENTED();
+	es2::Context *context = es2::getContext();
+
+	if(context)
+	{
+		es2::Program *programObject = context->getProgram(program);
+
+		if(!programObject || !programObject->isLinked())
+		{
+			return error(GL_INVALID_OPERATION);
+		}
+	}
+
+	// SwiftShader doesn't return a program binary and sets the program binay size to 0, so any attempt at getting one is invalid.
+	return error(GL_INVALID_OPERATION);
 }
 
 GL_APICALL void GL_APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length)
@@ -3628,7 +3466,20 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	UNIMPLEMENTED();
+	es2::Context *context = es2::getContext();
+
+	if(context)
+	{
+		es2::Program *programObject = context->getProgram(program);
+
+		if(!programObject)
+		{
+			return error(GL_INVALID_OPERATION);
+		}
+	}
+
+	// Regardless of what the binaryFormat is, it is unrecognized by SwiftShader, since it supports no format.
+	return error(GL_INVALID_ENUM);
 }
 
 GL_APICALL void GL_APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value)
@@ -3644,12 +3495,16 @@
 
 		if(!programObject)
 		{
-			return error(GL_INVALID_OPERATION);
+			return error(GL_INVALID_VALUE);
 		}
 
 		switch(pname)
 		{
 		case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
+			if((value != GL_TRUE) && (value != GL_FALSE))
+			{
+				return error(GL_INVALID_VALUE);
+			}
 			programObject->setBinaryRetrievable(value != GL_FALSE);
 			break;
 		default:
@@ -3686,6 +3541,7 @@
 		case GL_DRAW_FRAMEBUFFER:
 		case GL_FRAMEBUFFER:
 			framebuffer = context->getDrawFramebuffer();
+			break;
 		case GL_READ_FRAMEBUFFER:
 			framebuffer = context->getReadFramebuffer();
 			break;
@@ -3738,7 +3594,7 @@
 	TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
 	      target, levels, internalformat, width, height);
 
-	if(width < 1 || height < 1 || levels < 1)
+	if(width < 1 || height < 1 || levels < 1 || ((target == GL_TEXTURE_RECTANGLE_ARB) && (levels != 1)))
 	{
 		return error(GL_INVALID_VALUE);
 	}
@@ -3748,8 +3604,8 @@
 		return error(GL_INVALID_OPERATION);
 	}
 
-	GLenum type;
-	if(!GetStorageType(internalformat, type))
+	bool isCompressed = IsCompressed(internalformat, egl::getClientVersion());
+	if(!IsSizedInternalFormat(internalformat) && !isCompressed)
 	{
 		return error(GL_INVALID_ENUM);
 	}
@@ -3760,42 +3616,59 @@
 	{
 		switch(target)
 		{
+		case GL_TEXTURE_RECTANGLE_ARB:
+			if(isCompressed) // Rectangle textures cannot be compressed
+			{
+				return error(GL_INVALID_ENUM);
+			}
 		case GL_TEXTURE_2D:
-		{
-			es2::Texture2D *texture = context->getTexture2D();
-			if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
 			{
-				return error(GL_INVALID_OPERATION);
-			}
+				if((width > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE) ||
+				   (height > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE))
+				{
+					return error(GL_INVALID_VALUE);
+				}
 
-			for(int level = 0; level < levels; ++level)
-			{
-				texture->setImage(context, level, width, height, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
-				width = std::max(1, (width / 2));
-				height = std::max(1, (height / 2));
+				es2::Texture2D *texture = context->getTexture2D(target);
+				if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
+				{
+					return error(GL_INVALID_OPERATION);
+				}
+
+				for(int level = 0; level < levels; level++)
+				{
+					texture->setImage(level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
+					width = std::max(1, (width / 2));
+					height = std::max(1, (height / 2));
+				}
+				texture->makeImmutable(levels);
 			}
-			texture->makeImmutable(levels);
-		}
 			break;
 		case GL_TEXTURE_CUBE_MAP:
-		{
-			es2::TextureCubeMap *texture = context->getTextureCubeMap();
-			if(!texture || texture->name == 0 || texture->getImmutableFormat())
 			{
-				return error(GL_INVALID_OPERATION);
-			}
-
-			for(int level = 0; level < levels; ++level)
-			{
-				for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++face)
+				if((width > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE) ||
+				   (height > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE))
 				{
-					texture->setImage(context, face, level, width, height, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
+					return error(GL_INVALID_VALUE);
 				}
-				width = std::max(1, (width / 2));
-				height = std::max(1, (height / 2));
+
+				es2::TextureCubeMap *texture = context->getTextureCubeMap();
+				if(!texture || texture->name == 0 || texture->getImmutableFormat())
+				{
+					return error(GL_INVALID_OPERATION);
+				}
+
+				for(int level = 0; level < levels; level++)
+				{
+					for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
+					{
+						texture->setImage(face, level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
+					}
+					width = std::max(1, (width / 2));
+					height = std::max(1, (height / 2));
+				}
+				texture->makeImmutable(levels);
 			}
-			texture->makeImmutable(levels);
-		}
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -3813,8 +3686,7 @@
 		return error(GL_INVALID_VALUE);
 	}
 
-	GLenum type;
-	if(!GetStorageType(internalformat, type))
+	if(!IsSizedInternalFormat(internalformat) && !IsCompressed(internalformat, egl::getClientVersion()))
 	{
 		return error(GL_INVALID_ENUM);
 	}
@@ -3826,52 +3698,52 @@
 		switch(target)
 		{
 		case GL_TEXTURE_3D:
-		{
-			if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
 			{
-				return error(GL_INVALID_OPERATION);
-			}
+				if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
+				{
+					return error(GL_INVALID_OPERATION);
+				}
 
-			es2::Texture3D *texture = context->getTexture3D();
-			if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
-			{
-				return error(GL_INVALID_OPERATION);
-			}
+				es2::Texture3D *texture = context->getTexture3D();
+				if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
+				{
+					return error(GL_INVALID_OPERATION);
+				}
 
-			for(int level = 0; level < levels; ++level)
-			{
-				texture->setImage(context, level, width, height, depth, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
-				width = std::max(1, (width / 2));
-				height = std::max(1, (height / 2));
-				depth = std::max(1, (depth / 2));
+				for(int level = 0; level < levels; level++)
+				{
+					texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
+					width = std::max(1, (width / 2));
+					height = std::max(1, (height / 2));
+					depth = std::max(1, (depth / 2));
+				}
+				texture->makeImmutable(levels);
 			}
-			texture->makeImmutable(levels);
-		}
 			break;
 		case GL_TEXTURE_2D_ARRAY:
-		{
-			if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
 			{
-				return error(GL_INVALID_OPERATION);
-			}
-
-			es2::Texture3D *texture = context->getTexture2DArray();
-			if(!texture || texture->name == 0 || texture->getImmutableFormat())
-			{
-				return error(GL_INVALID_OPERATION);
-			}
-
-			for(int level = 0; level < levels; ++level)
-			{
-				for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++face)
+				if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
 				{
-					texture->setImage(context, level, width, height, depth, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
+					return error(GL_INVALID_OPERATION);
 				}
-				width = std::max(1, (width / 2));
-				height = std::max(1, (height / 2));
+
+				es2::Texture3D *texture = context->getTexture2DArray();
+				if(!texture || texture->name == 0 || texture->getImmutableFormat())
+				{
+					return error(GL_INVALID_OPERATION);
+				}
+
+				for(int level = 0; level < levels; level++)
+				{
+					for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
+					{
+						texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
+					}
+					width = std::max(1, (width / 2));
+					height = std::max(1, (height / 2));
+				}
+				texture->makeImmutable(levels);
 			}
-			texture->makeImmutable(levels);
-		}
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -3894,7 +3766,13 @@
 		return;
 	}
 
-	if(!IsColorRenderable(internalformat, egl::getClientVersion(), false) &&
+	// OpenGL ES 3.0, section 4.4.4: "An internal format is color-renderable if it is one of the formats
+	// from table 3.13 noted as color-renderable or if it is unsized format RGBA or RGB."
+	// Since we only use sized formats internally, replace them here (assuming type = GL_UNSIGNED_BYTE).
+	if(internalformat == GL_RGB)  internalformat = GL_RGB8;
+	if(internalformat == GL_RGBA) internalformat = GL_RGBA8;
+
+	if(!IsColorRenderable(internalformat, egl::getClientVersion()) &&
 	   !IsDepthRenderable(internalformat, egl::getClientVersion()) &&
 	   !IsStencilRenderable(internalformat, egl::getClientVersion()))
 	{
@@ -3909,39 +3787,13 @@
 		return error(GL_INVALID_ENUM);
 	}
 
-	// Integer types have no multisampling
 	GLint numMultisampleCounts = NUM_MULTISAMPLE_COUNTS;
-	switch(internalformat)
+
+	// Integer types have no multisampling
+	GLenum type = GetColorComponentType(internalformat);
+	if(type != GL_UNSIGNED_NORMALIZED && type != GL_FLOAT)
 	{
-	case GL_R8UI:
-	case GL_R8I:
-	case GL_R16UI:
-	case GL_R16I:
-	case GL_R32UI:
-	case GL_R32I:
-	case GL_RG8UI:
-	case GL_RG8I:
-	case GL_RG16UI:
-	case GL_RG16I:
-	case GL_RG32UI:
-	case GL_RG32I:
-	case GL_RGB8UI:
-	case GL_RGB8I:
-	case GL_RGB16UI:
-	case GL_RGB16I:
-	case GL_RGB32UI:
-	case GL_RGB32I:
-	case GL_RGBA8UI:
-	case GL_RGBA8I:
-	case GL_RGB10_A2UI:
-	case GL_RGBA16UI:
-	case GL_RGBA16I:
-	case GL_RGBA32UI:
-	case GL_RGBA32I:
 		numMultisampleCounts = 0;
-		break;
-	default:
-		break;
 	}
 
 	switch(pname)
diff --git a/src/OpenGL/libGLESv2/main.cpp b/src/OpenGL/libGLESv2/main.cpp
index 81b1689..0924a75 100644
--- a/src/OpenGL/libGLESv2/main.cpp
+++ b/src/OpenGL/libGLESv2/main.cpp
@@ -12,18 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// main.cpp: DLL entry point and management of thread-local data.
+// main.cpp: DLLMain and management of thread-local data.
 
 #include "main.h"
 
-#include "libGLESv2.hpp"
-#include "Framebuffer.h"
-#include "libEGL/main.h"
-#include "common/Surface.hpp"
-#include "Common/Thread.hpp"
-#include "Common/SharedLibrary.hpp"
-#include "common/debug.h"
-
 #if !defined(_MSC_VER)
 #define CONSTRUCTOR __attribute__((constructor))
 #define DESTRUCTOR __attribute__((destructor))
@@ -147,1412 +139,3 @@
 	return context ? context->getClientVersion() : 0;
 }
 }
-
-namespace es2
-{
-void ActiveTexture(GLenum texture);
-void AttachShader(GLuint program, GLuint shader);
-void BeginQueryEXT(GLenum target, GLuint name);
-void BindAttribLocation(GLuint program, GLuint index, const GLchar* name);
-void BindBuffer(GLenum target, GLuint buffer);
-void BindFramebuffer(GLenum target, GLuint framebuffer);
-void BindRenderbuffer(GLenum target, GLuint renderbuffer);
-void BindTexture(GLenum target, GLuint texture);
-void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
-void BlendEquation(GLenum mode);
-void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
-void BlendFunc(GLenum sfactor, GLenum dfactor);
-void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
-void BufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
-void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
-GLenum CheckFramebufferStatus(GLenum target);
-void Clear(GLbitfield mask);
-void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
-void ClearDepthf(GLclampf depth);
-void ClearStencil(GLint s);
-void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
-void CompileShader(GLuint shader);
-void CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
-                          GLint border, GLsizei imageSize, const GLvoid* data);
-void CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                             GLenum format, GLsizei imageSize, const GLvoid* data);
-void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
-void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-GLuint CreateProgram(void);
-GLuint CreateShader(GLenum type);
-void CullFace(GLenum mode);
-void DeleteBuffers(GLsizei n, const GLuint* buffers);
-void DeleteFencesNV(GLsizei n, const GLuint* fences);
-void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
-void DeleteProgram(GLuint program);
-void DeleteQueriesEXT(GLsizei n, const GLuint *ids);
-void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
-void DeleteShader(GLuint shader);
-void DeleteTextures(GLsizei n, const GLuint* textures);
-void DepthFunc(GLenum func);
-void DepthMask(GLboolean flag);
-void DepthRangef(GLclampf zNear, GLclampf zFar);
-void DetachShader(GLuint program, GLuint shader);
-void Disable(GLenum cap);
-void DisableVertexAttribArray(GLuint index);
-void DrawArrays(GLenum mode, GLint first, GLsizei count);
-void DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
-void DrawArraysInstancedEXT(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
-void DrawElementsInstancedEXT(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount);
-void VertexAttribDivisorEXT(GLuint index, GLuint divisor);
-void DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
-void DrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount);
-void VertexAttribDivisorANGLE(GLuint index, GLuint divisor);
-void Enable(GLenum cap);
-void EnableVertexAttribArray(GLuint index);
-void EndQueryEXT(GLenum target);
-void FinishFenceNV(GLuint fence);
-void Finish(void);
-void Flush(void);
-void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
-void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-void FrontFace(GLenum mode);
-void GenBuffers(GLsizei n, GLuint* buffers);
-void GenerateMipmap(GLenum target);
-void GenFencesNV(GLsizei n, GLuint* fences);
-void GenFramebuffers(GLsizei n, GLuint* framebuffers);
-void GenQueriesEXT(GLsizei n, GLuint* ids);
-void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
-void GenTextures(GLsizei n, GLuint* textures);
-void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
-void GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
-void GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
-int GetAttribLocation(GLuint program, const GLchar* name);
-void GetBooleanv(GLenum pname, GLboolean* params);
-void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
-GLenum GetError(void);
-void GetFenceivNV(GLuint fence, GLenum pname, GLint *params);
-void GetFloatv(GLenum pname, GLfloat* params);
-void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
-GLenum GetGraphicsResetStatusEXT(void);
-void GetIntegerv(GLenum pname, GLint* params);
-void GetProgramiv(GLuint program, GLenum pname, GLint* params);
-void GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-void GetQueryivEXT(GLenum target, GLenum pname, GLint *params);
-void GetQueryObjectuivEXT(GLuint name, GLenum pname, GLuint *params);
-void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
-void GetShaderiv(GLuint shader, GLenum pname, GLint* params);
-void GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-void GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
-void GetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
-const GLubyte* GetString(GLenum name);
-void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params);
-void GetTexParameteriv(GLenum target, GLenum pname, GLint* params);
-void GetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params);
-void GetUniformfv(GLuint program, GLint location, GLfloat* params);
-void GetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params);
-void GetUniformiv(GLuint program, GLint location, GLint* params);
-int GetUniformLocation(GLuint program, const GLchar* name);
-void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params);
-void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params);
-void GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer);
-void Hint(GLenum target, GLenum mode);
-GLboolean IsBuffer(GLuint buffer);
-GLboolean IsEnabled(GLenum cap);
-GLboolean IsFenceNV(GLuint fence);
-GLboolean IsFramebuffer(GLuint framebuffer);
-GLboolean IsProgram(GLuint program);
-GLboolean IsQueryEXT(GLuint name);
-GLboolean IsRenderbuffer(GLuint renderbuffer);
-GLboolean IsShader(GLuint shader);
-GLboolean IsTexture(GLuint texture);
-void LineWidth(GLfloat width);
-void LinkProgram(GLuint program);
-void PixelStorei(GLenum pname, GLint param);
-void PolygonOffset(GLfloat factor, GLfloat units);
-void ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
-                    GLenum format, GLenum type, GLsizei bufSize, GLvoid *data);
-void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
-void ReleaseShaderCompiler(void);
-void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-void RenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-void SampleCoverage(GLclampf value, GLboolean invert);
-void SetFenceNV(GLuint fence, GLenum condition);
-void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
-void ShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
-void ShaderSource(GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length);
-void StencilFunc(GLenum func, GLint ref, GLuint mask);
-void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
-void StencilMask(GLuint mask);
-void StencilMaskSeparate(GLenum face, GLuint mask);
-void StencilOp(GLenum fail, GLenum zfail, GLenum zpass);
-void StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
-GLboolean TestFenceNV(GLuint fence);
-void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
-                GLint border, GLenum format, GLenum type, const GLvoid* pixels);
-void TexParameterf(GLenum target, GLenum pname, GLfloat param);
-void TexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
-void TexParameteri(GLenum target, GLenum pname, GLint param);
-void TexParameteriv(GLenum target, GLenum pname, const GLint* params);
-void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                   GLenum format, GLenum type, const GLvoid* pixels);
-void Uniform1f(GLint location, GLfloat x);
-void Uniform1fv(GLint location, GLsizei count, const GLfloat* v);
-void Uniform1i(GLint location, GLint x);
-void Uniform1iv(GLint location, GLsizei count, const GLint* v);
-void Uniform2f(GLint location, GLfloat x, GLfloat y);
-void Uniform2fv(GLint location, GLsizei count, const GLfloat* v);
-void Uniform2i(GLint location, GLint x, GLint y);
-void Uniform2iv(GLint location, GLsizei count, const GLint* v);
-void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z);
-void Uniform3fv(GLint location, GLsizei count, const GLfloat* v);
-void Uniform3i(GLint location, GLint x, GLint y, GLint z);
-void Uniform3iv(GLint location, GLsizei count, const GLint* v);
-void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-void Uniform4fv(GLint location, GLsizei count, const GLfloat* v);
-void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w);
-void Uniform4iv(GLint location, GLsizei count, const GLint* v);
-void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-void UseProgram(GLuint program);
-void ValidateProgram(GLuint program);
-void VertexAttrib1f(GLuint index, GLfloat x);
-void VertexAttrib1fv(GLuint index, const GLfloat* values);
-void VertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
-void VertexAttrib2fv(GLuint index, const GLfloat* values);
-void VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
-void VertexAttrib3fv(GLuint index, const GLfloat* values);
-void VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-void VertexAttrib4fv(GLuint index, const GLfloat* values);
-GL_APICALL void VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
-GL_APICALL void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
-GL_APICALL void BlitFramebufferNV(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
-GL_APICALL void BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
-                                     GLbitfield mask, GLenum filter);
-GL_APICALL void TexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
-                              GLint border, GLenum format, GLenum type, const GLvoid* pixels);
-GL_APICALL void TexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
-GL_APICALL void CopyTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-GL_APICALL void CompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
-GL_APICALL void CompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
-GL_APICALL void FramebufferTexture3DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
-GL_APICALL void EGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
-GL_APICALL void EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
-GL_APICALL GLboolean IsRenderbufferOES(GLuint renderbuffer);
-GL_APICALL void BindRenderbufferOES(GLenum target, GLuint renderbuffer);
-GL_APICALL void DeleteRenderbuffersOES(GLsizei n, const GLuint* renderbuffers);
-GL_APICALL void GenRenderbuffersOES(GLsizei n, GLuint* renderbuffers);
-GL_APICALL void RenderbufferStorageOES(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-GL_APICALL void GetRenderbufferParameterivOES(GLenum target, GLenum pname, GLint* params);
-GL_APICALL GLboolean IsFramebufferOES(GLuint framebuffer);
-GL_APICALL void BindFramebufferOES(GLenum target, GLuint framebuffer);
-GL_APICALL void DeleteFramebuffersOES(GLsizei n, const GLuint* framebuffers);
-GL_APICALL void GenFramebuffersOES(GLsizei n, GLuint* framebuffers);
-GL_APICALL GLenum CheckFramebufferStatusOES(GLenum target);
-GL_APICALL void FramebufferRenderbufferOES(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
-GL_APICALL void FramebufferTexture2DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-GL_APICALL void GetFramebufferAttachmentParameterivOES(GLenum target, GLenum attachment, GLenum pname, GLint* params);
-GL_APICALL void GenerateMipmapOES(GLenum target);
-GL_APICALL void DrawBuffersEXT(GLsizei n, const GLenum *bufs);
-}
-
-extern "C"
-{
-GL_APICALL void GL_APIENTRY glActiveTexture(GLenum texture)
-{
-	return es2::ActiveTexture(texture);
-}
-
-GL_APICALL void GL_APIENTRY glAttachShader(GLuint program, GLuint shader)
-{
-	return es2::AttachShader(program, shader);
-}
-
-GL_APICALL void GL_APIENTRY glBeginQueryEXT(GLenum target, GLuint name)
-{
-	return es2::BeginQueryEXT(target, name);
-}
-
-GL_APICALL void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
-{
-	return es2::BindAttribLocation(program, index, name);
-}
-
-GL_APICALL void GL_APIENTRY glBindBuffer(GLenum target, GLuint buffer)
-{
-	return es2::BindBuffer(target, buffer);
-}
-
-GL_APICALL void GL_APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer)
-{
-	return es2::BindFramebuffer(target, framebuffer);
-}
-
-GL_APICALL void GL_APIENTRY glBindFramebufferOES(GLenum target, GLuint framebuffer)
-{
-	return es2::BindFramebuffer(target, framebuffer);
-}
-
-GL_APICALL void GL_APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer)
-{
-	return es2::BindRenderbuffer(target, renderbuffer);
-}
-
-GL_APICALL void GL_APIENTRY glBindRenderbufferOES(GLenum target, GLuint renderbuffer)
-{
-	return es2::BindRenderbuffer(target, renderbuffer);
-}
-
-GL_APICALL void GL_APIENTRY glBindTexture(GLenum target, GLuint texture)
-{
-	return es2::BindTexture(target, texture);
-}
-
-GL_APICALL void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
-	return es2::BlendColor(red, green, blue, alpha);
-}
-
-GL_APICALL void GL_APIENTRY glBlendEquation(GLenum mode)
-{
-	return es2::BlendEquation(mode);
-}
-
-GL_APICALL void GL_APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
-{
-	return es2::BlendEquationSeparate(modeRGB, modeAlpha);
-}
-
-GL_APICALL void GL_APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor)
-{
-	return es2::BlendFunc(sfactor, dfactor);
-}
-
-GL_APICALL void GL_APIENTRY glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
-{
-	return es2::BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
-}
-
-GL_APICALL void GL_APIENTRY glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
-{
-	return es2::BufferData(target, size, data, usage);
-}
-
-GL_APICALL void GL_APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
-	return es2::BufferSubData(target, offset, size, data);
-}
-
-GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus(GLenum target)
-{
-	return es2::CheckFramebufferStatus(target);
-}
-
-GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatusOES(GLenum target)
-{
-	return es2::CheckFramebufferStatus(target);
-}
-
-GL_APICALL void GL_APIENTRY glClear(GLbitfield mask)
-{
-	return es2::Clear(mask);
-}
-
-GL_APICALL void GL_APIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
-	return es2::ClearColor(red, green, blue, alpha);
-}
-
-GL_APICALL void GL_APIENTRY glClearDepthf(GLclampf depth)
-{
-	return es2::ClearDepthf(depth);
-}
-
-GL_APICALL void GL_APIENTRY glClearStencil(GLint s)
-{
-	return es2::ClearStencil(s);
-}
-
-GL_APICALL void GL_APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
-{
-	return es2::ColorMask(red, green, blue, alpha);
-}
-
-GL_APICALL void GL_APIENTRY glCompileShader(GLuint shader)
-{
-	return es2::CompileShader(shader);
-}
-
-GL_APICALL void GL_APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
-                                                   GLint border, GLsizei imageSize, const GLvoid* data)
-{
-	return es2::CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
-}
-
-GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                                      GLenum format, GLsizei imageSize, const GLvoid* data)
-{
-	return es2::CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
-}
-
-GL_APICALL void GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
-{
-	return es2::CopyTexImage2D(target, level, internalformat, x, y, width, height, border);
-}
-
-GL_APICALL void GL_APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
-{
-	return es2::CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
-}
-
-GL_APICALL GLuint GL_APIENTRY glCreateProgram(void)
-{
-	return es2::CreateProgram();
-}
-
-GL_APICALL GLuint GL_APIENTRY glCreateShader(GLenum type)
-{
-	return es2::CreateShader(type);
-}
-
-GL_APICALL void GL_APIENTRY glCullFace(GLenum mode)
-{
-	return es2::CullFace(mode);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers)
-{
-	return es2::DeleteBuffers(n, buffers);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteFencesNV(GLsizei n, const GLuint* fences)
-{
-	return es2::DeleteFencesNV(n, fences);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
-{
-	return es2::DeleteFramebuffers(n, framebuffers);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteFramebuffersOES(GLsizei n, const GLuint* framebuffers)
-{
-	return es2::DeleteFramebuffers(n, framebuffers);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteProgram(GLuint program)
-{
-	return es2::DeleteProgram(program);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteQueriesEXT(GLsizei n, const GLuint *ids)
-{
-	return es2::DeleteQueriesEXT(n, ids);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
-{
-	return es2::DeleteRenderbuffers(n, renderbuffers);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteRenderbuffersOES(GLsizei n, const GLuint* renderbuffers)
-{
-	return es2::DeleteRenderbuffers(n, renderbuffers);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteShader(GLuint shader)
-{
-	return es2::DeleteShader(shader);
-}
-
-GL_APICALL void GL_APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures)
-{
-	return es2::DeleteTextures(n, textures);
-}
-
-GL_APICALL void GL_APIENTRY glDepthFunc(GLenum func)
-{
-	return es2::DepthFunc(func);
-}
-
-GL_APICALL void GL_APIENTRY glDepthMask(GLboolean flag)
-{
-	return es2::DepthMask(flag);
-}
-
-GL_APICALL void GL_APIENTRY glDepthRangef(GLclampf zNear, GLclampf zFar)
-{
-	return es2::DepthRangef(zNear, zFar);
-}
-
-GL_APICALL void GL_APIENTRY glDetachShader(GLuint program, GLuint shader)
-{
-	return es2::DetachShader(program, shader);
-}
-
-GL_APICALL void GL_APIENTRY glDisable(GLenum cap)
-{
-	return es2::Disable(cap);
-}
-
-GL_APICALL void GL_APIENTRY glDisableVertexAttribArray(GLuint index)
-{
-	return es2::DisableVertexAttribArray(index);
-}
-
-GL_APICALL void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count)
-{
-	return es2::DrawArrays(mode, first, count);
-}
-
-GL_APICALL void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
-{
-	return es2::DrawElements(mode, count, type, indices);
-}
-
-GL_APICALL void GL_APIENTRY glDrawArraysInstancedEXT(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
-{
-	return es2::DrawArraysInstancedEXT(mode, first, count, instanceCount);
-}
-
-GL_APICALL void GL_APIENTRY glDrawElementsInstancedEXT(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
-{
-	return es2::DrawElementsInstancedEXT(mode, count, type, indices, instanceCount);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttribDivisorEXT(GLuint index, GLuint divisor)
-{
-	return es2::VertexAttribDivisorEXT(index, divisor);
-}
-
-GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
-{
-	return es2::DrawArraysInstancedANGLE(mode, first, count, instanceCount);
-}
-
-GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
-{
-	return es2::DrawElementsInstancedANGLE(mode, count, type, indices, instanceCount);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE(GLuint index, GLuint divisor)
-{
-	return es2::VertexAttribDivisorANGLE(index, divisor);
-}
-
-GL_APICALL void GL_APIENTRY glEnable(GLenum cap)
-{
-	return es2::Enable(cap);
-}
-
-GL_APICALL void GL_APIENTRY glEnableVertexAttribArray(GLuint index)
-{
-	return es2::EnableVertexAttribArray(index);
-}
-
-GL_APICALL void GL_APIENTRY glEndQueryEXT(GLenum target)
-{
-	return es2::EndQueryEXT(target);
-}
-
-GL_APICALL void GL_APIENTRY glFinishFenceNV(GLuint fence)
-{
-	return es2::FinishFenceNV(fence);
-}
-
-GL_APICALL void GL_APIENTRY glFinish(void)
-{
-	return es2::Finish();
-}
-
-GL_APICALL void GL_APIENTRY glFlush(void)
-{
-	return es2::Flush();
-}
-
-GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
-{
-	return es2::FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
-}
-
-GL_APICALL void GL_APIENTRY glFramebufferRenderbufferOES(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
-{
-	return es2::FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
-}
-
-GL_APICALL void GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
-{
-	return es2::FramebufferTexture2D(target, attachment, textarget, texture, level);
-}
-
-GL_APICALL void GL_APIENTRY glFramebufferTexture2DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
-{
-	return es2::FramebufferTexture2D(target, attachment, textarget, texture, level);
-}
-
-GL_APICALL void GL_APIENTRY glFrontFace(GLenum mode)
-{
-	return es2::FrontFace(mode);
-}
-
-GL_APICALL void GL_APIENTRY glGenBuffers(GLsizei n, GLuint* buffers)
-{
-	return es2::GenBuffers(n, buffers);
-}
-
-GL_APICALL void GL_APIENTRY glGenerateMipmap(GLenum target)
-{
-	return es2::GenerateMipmap(target);
-}
-
-GL_APICALL void GL_APIENTRY glGenerateMipmapOES(GLenum target)
-{
-	return es2::GenerateMipmap(target);
-}
-
-GL_APICALL void GL_APIENTRY glGenFencesNV(GLsizei n, GLuint* fences)
-{
-	return es2::GenFencesNV(n, fences);
-}
-
-GL_APICALL void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers)
-{
-	return es2::GenFramebuffers(n, framebuffers);
-}
-
-GL_APICALL void GL_APIENTRY glGenFramebuffersOES(GLsizei n, GLuint* framebuffers)
-{
-	return es2::GenFramebuffers(n, framebuffers);
-}
-
-GL_APICALL void GL_APIENTRY glGenQueriesEXT(GLsizei n, GLuint* ids)
-{
-	return es2::GenQueriesEXT(n, ids);
-}
-
-GL_APICALL void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
-{
-	return es2::GenRenderbuffers(n, renderbuffers);
-}
-
-GL_APICALL void GL_APIENTRY glGenRenderbuffersOES(GLsizei n, GLuint* renderbuffers)
-{
-	return es2::GenRenderbuffers(n, renderbuffers);
-}
-
-GL_APICALL void GL_APIENTRY glGenTextures(GLsizei n, GLuint* textures)
-{
-	return es2::GenTextures(n, textures);
-}
-
-GL_APICALL void GL_APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
-{
-	return es2::GetActiveAttrib(program, index, bufsize, length, size, type, name);
-}
-
-GL_APICALL void GL_APIENTRY glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
-{
-	return es2::GetActiveUniform(program, index, bufsize, length, size, type, name);
-}
-
-GL_APICALL void GL_APIENTRY glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
-{
-	return es2::GetAttachedShaders(program, maxcount, count, shaders);
-}
-
-GL_APICALL int GL_APIENTRY glGetAttribLocation(GLuint program, const GLchar* name)
-{
-	return es2::GetAttribLocation(program, name);
-}
-
-GL_APICALL void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean* params)
-{
-	return es2::GetBooleanv(pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
-{
-	return es2::GetBufferParameteriv(target, pname, params);
-}
-
-GL_APICALL GLenum GL_APIENTRY glGetError(void)
-{
-	return es2::GetError();
-}
-
-GL_APICALL void GL_APIENTRY glGetFenceivNV(GLuint fence, GLenum pname, GLint *params)
-{
-	return es2::GetFenceivNV(fence, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetFloatv(GLenum pname, GLfloat* params)
-{
-	return es2::GetFloatv(pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
-{
-	return es2::GetFramebufferAttachmentParameteriv(target, attachment, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameterivOES(GLenum target, GLenum attachment, GLenum pname, GLint* params)
-{
-	return es2::GetFramebufferAttachmentParameteriv(target, attachment, pname, params);
-}
-
-GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT(void)
-{
-	return es2::GetGraphicsResetStatusEXT();
-}
-
-GL_APICALL void GL_APIENTRY glGetIntegerv(GLenum pname, GLint* params)
-{
-	return es2::GetIntegerv(pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params)
-{
-	return es2::GetProgramiv(program, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
-	return es2::GetProgramInfoLog(program, bufsize, length, infolog);
-}
-
-GL_APICALL void GL_APIENTRY glGetQueryivEXT(GLenum target, GLenum pname, GLint *params)
-{
-	return es2::GetQueryivEXT(target, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT(GLuint name, GLenum pname, GLuint *params)
-{
-	return es2::GetQueryObjectuivEXT(name, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
-{
-	return es2::GetRenderbufferParameteriv(target, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetRenderbufferParameterivOES(GLenum target, GLenum pname, GLint* params)
-{
-	return es2::GetRenderbufferParameteriv(target, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
-{
-	return es2::GetShaderiv(shader, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
-	return es2::GetShaderInfoLog(shader, bufsize, length, infolog);
-}
-
-GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
-{
-	return es2::GetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
-}
-
-GL_APICALL void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
-{
-	return es2::GetShaderSource(shader, bufsize, length, source);
-}
-
-GL_APICALL const GLubyte* GL_APIENTRY glGetString(GLenum name)
-{
-	return es2::GetString(name);
-}
-
-GL_APICALL void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
-{
-	return es2::GetTexParameterfv(target, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
-{
-	return es2::GetTexParameteriv(target, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
-{
-	return es2::GetnUniformfvEXT(program, location, bufSize, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params)
-{
-	return es2::GetUniformfv(program, location, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params)
-{
-	return es2::GetnUniformivEXT(program, location, bufSize, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params)
-{
-	return es2::GetUniformiv(program, location, params);
-}
-
-GL_APICALL int GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar* name)
-{
-	return es2::GetUniformLocation(program, name);
-}
-
-GL_APICALL void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
-{
-	return es2::GetVertexAttribfv(index, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
-{
-	return es2::GetVertexAttribiv(index, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
-{
-	return es2::GetVertexAttribPointerv(index, pname, pointer);
-}
-
-GL_APICALL void GL_APIENTRY glHint(GLenum target, GLenum mode)
-{
-	return es2::Hint(target, mode);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsBuffer(GLuint buffer)
-{
-	return es2::IsBuffer(buffer);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsEnabled(GLenum cap)
-{
-	return es2::IsEnabled(cap);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsFenceNV(GLuint fence)
-{
-	return es2::IsFenceNV(fence);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer(GLuint framebuffer)
-{
-	return es2::IsFramebuffer(framebuffer);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsFramebufferOES(GLuint framebuffer)
-{
-	return es2::IsFramebuffer(framebuffer);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsProgram(GLuint program)
-{
-	return es2::IsProgram(program);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT(GLuint name)
-{
-	return es2::IsQueryEXT(name);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer(GLuint renderbuffer)
-{
-	return es2::IsRenderbuffer(renderbuffer);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsRenderbufferOES(GLuint renderbuffer)
-{
-	return es2::IsRenderbuffer(renderbuffer);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsShader(GLuint shader)
-{
-	return es2::IsShader(shader);
-}
-
-GL_APICALL GLboolean GL_APIENTRY glIsTexture(GLuint texture)
-{
-	return es2::IsTexture(texture);
-}
-
-GL_APICALL void GL_APIENTRY glLineWidth(GLfloat width)
-{
-	return es2::LineWidth(width);
-}
-
-GL_APICALL void GL_APIENTRY glLinkProgram(GLuint program)
-{
-	return es2::LinkProgram(program);
-}
-
-GL_APICALL void GL_APIENTRY glPixelStorei(GLenum pname, GLint param)
-{
-	return es2::PixelStorei(pname, param);
-}
-
-GL_APICALL void GL_APIENTRY glPolygonOffset(GLfloat factor, GLfloat units)
-{
-	return es2::PolygonOffset(factor, units);
-}
-
-GL_APICALL void GL_APIENTRY glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
-                                             GLenum format, GLenum type, GLsizei bufSize, GLvoid *data)
-{
-	return es2::ReadnPixelsEXT(x, y, width, height, format, type, bufSize, data);
-}
-
-GL_APICALL void GL_APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
-{
-	return es2::ReadPixels(x, y, width, height, format, type, pixels);
-}
-
-GL_APICALL void GL_APIENTRY glReleaseShaderCompiler(void)
-{
-	return es2::ReleaseShaderCompiler();
-}
-
-GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
-{
-	return es2::RenderbufferStorageMultisample(target, samples, internalformat, width, height);
-}
-
-GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
-{
-	return es2::RenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height);
-}
-
-GL_APICALL void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
-{
-	return es2::RenderbufferStorage(target, internalformat, width, height);
-}
-
-GL_APICALL void GL_APIENTRY glRenderbufferStorageOES(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
-{
-	return es2::RenderbufferStorage(target, internalformat, width, height);
-}
-
-GL_APICALL void GL_APIENTRY glSampleCoverage(GLclampf value, GLboolean invert)
-{
-	return es2::SampleCoverage(value, invert);
-}
-
-GL_APICALL void GL_APIENTRY glSetFenceNV(GLuint fence, GLenum condition)
-{
-	return es2::SetFenceNV(fence, condition);
-}
-
-GL_APICALL void GL_APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
-{
-	return es2::Scissor(x, y, width, height);
-}
-
-GL_APICALL void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
-{
-	return es2::ShaderBinary(n, shaders, binaryformat, binary, length);
-}
-
-GL_APICALL void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length)
-{
-	return es2::ShaderSource(shader, count, string, length);
-}
-
-GL_APICALL void GL_APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask)
-{
-	return es2::StencilFunc(func, ref, mask);
-}
-
-GL_APICALL void GL_APIENTRY glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
-{
-	return es2::StencilFuncSeparate(face, func, ref, mask);
-}
-
-GL_APICALL void GL_APIENTRY glStencilMask(GLuint mask)
-{
-	return es2::StencilMask(mask);
-}
-
-GL_APICALL void GL_APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask)
-{
-	return es2::StencilMaskSeparate(face, mask);
-}
-
-GL_APICALL void GL_APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
-{
-	return es2::StencilOp(fail, zfail, zpass);
-}
-
-GL_APICALL void GL_APIENTRY glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
-{
-	return es2::StencilOpSeparate(face, fail, zfail, zpass);
-}
-
-GLboolean GL_APIENTRY glTestFenceNV(GLuint fence)
-{
-	return es2::TestFenceNV(fence);
-}
-
-GL_APICALL void GL_APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
-                                         GLint border, GLenum format, GLenum type, const GLvoid* pixels)
-{
-	return es2::TexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
-}
-
-GL_APICALL void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param)
-{
-	return es2::TexParameterf(target, pname, param);
-}
-
-GL_APICALL void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
-{
-	return es2::TexParameterfv(target, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param)
-{
-	return es2::TexParameteri(target, pname, param);
-}
-
-GL_APICALL void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
-{
-	return es2::TexParameteriv(target, pname, params);
-}
-
-GL_APICALL void GL_APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                            GLenum format, GLenum type, const GLvoid* pixels)
-{
-	return es2::TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
-}
-
-GL_APICALL void GL_APIENTRY glUniform1f(GLint location, GLfloat x)
-{
-	return es2::Uniform1f(location, x);
-}
-
-GL_APICALL void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
-{
-	return es2::Uniform1fv(location, count, v);
-}
-
-GL_APICALL void GL_APIENTRY glUniform1i(GLint location, GLint x)
-{
-	return es2::Uniform1i(location, x);
-}
-
-GL_APICALL void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v)
-{
-	return es2::Uniform1iv(location, count, v);
-}
-
-GL_APICALL void GL_APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y)
-{
-	return es2::Uniform2f(location, x, y);
-}
-
-GL_APICALL void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
-{
-	return es2::Uniform2fv(location, count, v);
-}
-
-GL_APICALL void GL_APIENTRY glUniform2i(GLint location, GLint x, GLint y)
-{
-	return es2::Uniform2i(location, x, y);
-}
-
-GL_APICALL void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v)
-{
-	return es2::Uniform2iv(location, count, v);
-}
-
-GL_APICALL void GL_APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
-{
-	return es2::Uniform3f(location, x, y, z);
-}
-
-GL_APICALL void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
-{
-	return es2::Uniform3fv(location, count, v);
-}
-
-GL_APICALL void GL_APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z)
-{
-	return es2::Uniform3i(location, x, y, z);
-}
-
-GL_APICALL void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v)
-{
-	return es2::Uniform3iv(location, count, v);
-}
-
-GL_APICALL void GL_APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-	return es2::Uniform4f(location, x, y, z, w);
-}
-
-GL_APICALL void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
-{
-	return es2::Uniform4fv(location, count, v);
-}
-
-GL_APICALL void GL_APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
-{
-	return es2::Uniform4i(location, x, y, z, w);
-}
-
-GL_APICALL void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v)
-{
-	return es2::Uniform4iv(location, count, v);
-}
-
-GL_APICALL void GL_APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-	return es2::UniformMatrix2fv(location, count, transpose, value);
-}
-
-GL_APICALL void GL_APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-	return es2::UniformMatrix3fv(location, count, transpose, value);
-}
-
-GL_APICALL void GL_APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-	return es2::UniformMatrix4fv(location, count, transpose, value);
-}
-
-GL_APICALL void GL_APIENTRY glUseProgram(GLuint program)
-{
-	return es2::UseProgram(program);
-}
-
-GL_APICALL void GL_APIENTRY glValidateProgram(GLuint program)
-{
-	return es2::ValidateProgram(program);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttrib1f(GLuint index, GLfloat x)
-{
-	return es2::VertexAttrib1f(index, x);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttrib1fv(GLuint index, const GLfloat* values)
-{
-	return es2::VertexAttrib1fv(index, values);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y)
-{
-	return es2::VertexAttrib2f(index, x, y);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttrib2fv(GLuint index, const GLfloat* values)
-{
-	return es2::VertexAttrib2fv(index, values);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)
-{
-	return es2::VertexAttrib3f(index, x, y, z);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttrib3fv(GLuint index, const GLfloat* values)
-{
-	return es2::VertexAttrib3fv(index, values);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-	return es2::VertexAttrib4f(index, x, y, z, w);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttrib4fv(GLuint index, const GLfloat* values)
-{
-	return es2::VertexAttrib4fv(index, values);
-}
-
-GL_APICALL void GL_APIENTRY glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
-{
-	return es2::VertexAttribPointer(index, size, type, normalized, stride, ptr);
-}
-
-GL_APICALL void GL_APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
-{
-	return es2::Viewport(x, y, width, height);
-}
-
-GL_APICALL void GL_APIENTRY glBlitFramebufferNV(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
-{
-	return es2::BlitFramebufferNV(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
-}
-
-GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
-                                                   GLbitfield mask, GLenum filter)
-{
-	return es2::BlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
-}
-
-GL_APICALL void GL_APIENTRY glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
-                                            GLint border, GLenum format, GLenum type, const GLvoid* pixels)
-{
-	return es2::TexImage3DOES(target, level, internalformat, width, height, depth, border, format, type, pixels);
-}
-
-GL_APICALL void GL_APIENTRY glTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels)
-{
-	return es2::TexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
-}
-
-GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
-{
-	return es2::CopyTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, x, y, width, height);
-}
-
-GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data)
-{
-	return es2::CompressedTexImage3DOES(target, level,internalformat, width, height, depth, border, imageSize, data);
-}
-
-GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)
-{
-	return es2::CompressedTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
-}
-
-GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
-{
-	return es2::FramebufferTexture3DOES(target, attachment, textarget, texture, level, zoffset);
-}
-
-GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
-{
-	return es2::EGLImageTargetTexture2DOES(target, image);
-}
-
-GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
-{
-	return es2::EGLImageTargetRenderbufferStorageOES(target, image);
-}
-
-GL_APICALL void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs)
-{
-	return es2::DrawBuffersEXT(n, bufs);
-}
-
-void GL_APIENTRY Register(const char *licenseKey)
-{
-	// Nothing to do, SwiftShader is open-source
-}
-}
-
-egl::Context *es2CreateContext(egl::Display *display, const egl::Context *shareContext, int clientVersion, const egl::Config *config);
-extern "C" __eglMustCastToProperFunctionPointerType es2GetProcAddress(const char *procname);
-egl::Image *createBackBuffer(int width, int height, sw::Format format, int multiSampleDepth);
-egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth);
-sw::FrameBuffer *createFrameBuffer(void *nativeDisplay, EGLNativeWindowType window, int width, int height);
-
-LibGLESv2exports::LibGLESv2exports()
-{
-	this->glActiveTexture = es2::ActiveTexture;
-	this->glAttachShader = es2::AttachShader;
-	this->glBeginQueryEXT = es2::BeginQueryEXT;
-	this->glBindAttribLocation = es2::BindAttribLocation;
-	this->glBindBuffer = es2::BindBuffer;
-	this->glBindFramebuffer = es2::BindFramebuffer;
-	this->glBindRenderbuffer = es2::BindRenderbuffer;
-	this->glBindTexture = es2::BindTexture;
-	this->glBlendColor = es2::BlendColor;
-	this->glBlendEquation = es2::BlendEquation;
-	this->glBlendEquationSeparate = es2::BlendEquationSeparate;
-	this->glBlendFunc = es2::BlendFunc;
-	this->glBlendFuncSeparate = es2::BlendFuncSeparate;
-	this->glBufferData = es2::BufferData;
-	this->glBufferSubData = es2::BufferSubData;
-	this->glCheckFramebufferStatus = es2::CheckFramebufferStatus;
-	this->glClear = es2::Clear;
-	this->glClearColor = es2::ClearColor;
-	this->glClearDepthf = es2::ClearDepthf;
-	this->glClearStencil = es2::ClearStencil;
-	this->glColorMask = es2::ColorMask;
-	this->glCompileShader = es2::CompileShader;
-	this->glCompressedTexImage2D = es2::CompressedTexImage2D;
-	this->glCompressedTexSubImage2D = es2::CompressedTexSubImage2D;
-	this->glCopyTexImage2D = es2::CopyTexImage2D;
-	this->glCopyTexSubImage2D = es2::CopyTexSubImage2D;
-	this->glCreateProgram = es2::CreateProgram;
-	this->glCreateShader = es2::CreateShader;
-	this->glCullFace = es2::CullFace;
-	this->glDeleteBuffers = es2::DeleteBuffers;
-	this->glDeleteFencesNV = es2::DeleteFencesNV;
-	this->glDeleteFramebuffers = es2::DeleteFramebuffers;
-	this->glDeleteProgram = es2::DeleteProgram;
-	this->glDeleteQueriesEXT = es2::DeleteQueriesEXT;
-	this->glDeleteRenderbuffers = es2::DeleteRenderbuffers;
-	this->glDeleteShader = es2::DeleteShader;
-	this->glDeleteTextures = es2::DeleteTextures;
-	this->glDepthFunc = es2::DepthFunc;
-	this->glDepthMask = es2::DepthMask;
-	this->glDepthRangef = es2::DepthRangef;
-	this->glDetachShader = es2::DetachShader;
-	this->glDisable = es2::Disable;
-	this->glDisableVertexAttribArray = es2::DisableVertexAttribArray;
-	this->glDrawArrays = es2::DrawArrays;
-	this->glDrawElements = es2::DrawElements;
-	this->glDrawArraysInstancedEXT = es2::DrawArraysInstancedEXT;
-	this->glDrawElementsInstancedEXT = es2::DrawElementsInstancedEXT;
-	this->glVertexAttribDivisorEXT = es2::VertexAttribDivisorEXT;
-	this->glDrawArraysInstancedANGLE = es2::DrawArraysInstancedANGLE;
-	this->glDrawElementsInstancedANGLE = es2::DrawElementsInstancedANGLE;
-	this->glVertexAttribDivisorANGLE = es2::VertexAttribDivisorANGLE;
-	this->glEnable = es2::Enable;
-	this->glEnableVertexAttribArray = es2::EnableVertexAttribArray;
-	this->glEndQueryEXT = es2::EndQueryEXT;
-	this->glFinishFenceNV = es2::FinishFenceNV;
-	this->glFinish = es2::Finish;
-	this->glFlush = es2::Flush;
-	this->glFramebufferRenderbuffer = es2::FramebufferRenderbuffer;
-	this->glFramebufferTexture2D = es2::FramebufferTexture2D;
-	this->glFrontFace = es2::FrontFace;
-	this->glGenBuffers = es2::GenBuffers;
-	this->glGenerateMipmap = es2::GenerateMipmap;
-	this->glGenFencesNV = es2::GenFencesNV;
-	this->glGenFramebuffers = es2::GenFramebuffers;
-	this->glGenQueriesEXT = es2::GenQueriesEXT;
-	this->glGenRenderbuffers = es2::GenRenderbuffers;
-	this->glGenTextures = es2::GenTextures;
-	this->glGetActiveAttrib = es2::GetActiveAttrib;
-	this->glGetActiveUniform = es2::GetActiveUniform;
-	this->glGetAttachedShaders = es2::GetAttachedShaders;
-	this->glGetAttribLocation = es2::GetAttribLocation;
-	this->glGetBooleanv = es2::GetBooleanv;
-	this->glGetBufferParameteriv = es2::GetBufferParameteriv;
-	this->glGetError = es2::GetError;
-	this->glGetFenceivNV = es2::GetFenceivNV;
-	this->glGetFloatv = es2::GetFloatv;
-	this->glGetFramebufferAttachmentParameteriv = es2::GetFramebufferAttachmentParameteriv;
-	this->glGetGraphicsResetStatusEXT = es2::GetGraphicsResetStatusEXT;
-	this->glGetIntegerv = es2::GetIntegerv;
-	this->glGetProgramiv = es2::GetProgramiv;
-	this->glGetProgramInfoLog = es2::GetProgramInfoLog;
-	this->glGetQueryivEXT = es2::GetQueryivEXT;
-	this->glGetQueryObjectuivEXT = es2::GetQueryObjectuivEXT;
-	this->glGetRenderbufferParameteriv = es2::GetRenderbufferParameteriv;
-	this->glGetShaderiv = es2::GetShaderiv;
-	this->glGetShaderInfoLog = es2::GetShaderInfoLog;
-	this->glGetShaderPrecisionFormat = es2::GetShaderPrecisionFormat;
-	this->glGetShaderSource = es2::GetShaderSource;
-	this->glGetString = es2::GetString;
-	this->glGetTexParameterfv = es2::GetTexParameterfv;
-	this->glGetTexParameteriv = es2::GetTexParameteriv;
-	this->glGetnUniformfvEXT = es2::GetnUniformfvEXT;
-	this->glGetUniformfv = es2::GetUniformfv;
-	this->glGetnUniformivEXT = es2::GetnUniformivEXT;
-	this->glGetUniformiv = es2::GetUniformiv;
-	this->glGetUniformLocation = es2::GetUniformLocation;
-	this->glGetVertexAttribfv = es2::GetVertexAttribfv;
-	this->glGetVertexAttribiv = es2::GetVertexAttribiv;
-	this->glGetVertexAttribPointerv = es2::GetVertexAttribPointerv;
-	this->glHint = es2::Hint;
-	this->glIsBuffer = es2::IsBuffer;
-	this->glIsEnabled = es2::IsEnabled;
-	this->glIsFenceNV = es2::IsFenceNV;
-	this->glIsFramebuffer = es2::IsFramebuffer;
-	this->glIsProgram = es2::IsProgram;
-	this->glIsQueryEXT = es2::IsQueryEXT;
-	this->glIsRenderbuffer = es2::IsRenderbuffer;
-	this->glIsShader = es2::IsShader;
-	this->glIsTexture = es2::IsTexture;
-	this->glLineWidth = es2::LineWidth;
-	this->glLinkProgram = es2::LinkProgram;
-	this->glPixelStorei = es2::PixelStorei;
-	this->glPolygonOffset = es2::PolygonOffset;
-	this->glReadnPixelsEXT = es2::ReadnPixelsEXT;
-	this->glReadPixels = es2::ReadPixels;
-	this->glReleaseShaderCompiler = es2::ReleaseShaderCompiler;
-	this->glRenderbufferStorageMultisample = es2::RenderbufferStorageMultisample;
-	this->glRenderbufferStorageMultisampleANGLE = es2::RenderbufferStorageMultisampleANGLE;
-	this->glRenderbufferStorage = es2::RenderbufferStorage;
-	this->glSampleCoverage = es2::SampleCoverage;
-	this->glSetFenceNV = es2::SetFenceNV;
-	this->glScissor = es2::Scissor;
-	this->glShaderBinary = es2::ShaderBinary;
-	this->glShaderSource = es2::ShaderSource;
-	this->glStencilFunc = es2::StencilFunc;
-	this->glStencilFuncSeparate = es2::StencilFuncSeparate;
-	this->glStencilMask = es2::StencilMask;
-	this->glStencilMaskSeparate = es2::StencilMaskSeparate;
-	this->glStencilOp = es2::StencilOp;
-	this->glStencilOpSeparate = es2::StencilOpSeparate;
-	this->glTestFenceNV = es2::TestFenceNV;
-	this->glTexImage2D = es2::TexImage2D;
-	this->glTexParameterf = es2::TexParameterf;
-	this->glTexParameterfv = es2::TexParameterfv;
-	this->glTexParameteri = es2::TexParameteri;
-	this->glTexParameteriv = es2::TexParameteriv;
-	this->glTexSubImage2D = es2::TexSubImage2D;
-	this->glUniform1f = es2::Uniform1f;
-	this->glUniform1fv = es2::Uniform1fv;
-	this->glUniform1i = es2::Uniform1i;
-	this->glUniform1iv = es2::Uniform1iv;
-	this->glUniform2f = es2::Uniform2f;
-	this->glUniform2fv = es2::Uniform2fv;
-	this->glUniform2i = es2::Uniform2i;
-	this->glUniform2iv = es2::Uniform2iv;
-	this->glUniform3f = es2::Uniform3f;
-	this->glUniform3fv = es2::Uniform3fv;
-	this->glUniform3i = es2::Uniform3i;
-	this->glUniform3iv = es2::Uniform3iv;
-	this->glUniform4f = es2::Uniform4f;
-	this->glUniform4fv = es2::Uniform4fv;
-	this->glUniform4i = es2::Uniform4i;
-	this->glUniform4iv = es2::Uniform4iv;
-	this->glUniformMatrix2fv = es2::UniformMatrix2fv;
-	this->glUniformMatrix3fv = es2::UniformMatrix3fv;
-	this->glUniformMatrix4fv = es2::UniformMatrix4fv;
-	this->glUseProgram = es2::UseProgram;
-	this->glValidateProgram = es2::ValidateProgram;
-	this->glVertexAttrib1f = es2::VertexAttrib1f;
-	this->glVertexAttrib1fv = es2::VertexAttrib1fv;
-	this->glVertexAttrib2f = es2::VertexAttrib2f;
-	this->glVertexAttrib2fv = es2::VertexAttrib2fv;
-	this->glVertexAttrib3f = es2::VertexAttrib3f;
-	this->glVertexAttrib3fv = es2::VertexAttrib3fv;
-	this->glVertexAttrib4f = es2::VertexAttrib4f;
-	this->glVertexAttrib4fv = es2::VertexAttrib4fv;
-	this->glVertexAttribPointer = es2::VertexAttribPointer;
-	this->glViewport = es2::Viewport;
-	this->glBlitFramebufferNV = es2::BlitFramebufferNV;
-	this->glBlitFramebufferANGLE = es2::BlitFramebufferANGLE;
-	this->glTexImage3DOES = es2::TexImage3DOES;
-	this->glTexSubImage3DOES = es2::TexSubImage3DOES;
-	this->glCopyTexSubImage3DOES = es2::CopyTexSubImage3DOES;
-	this->glCompressedTexImage3DOES = es2::CompressedTexImage3DOES;
-	this->glCompressedTexSubImage3DOES = es2::CompressedTexSubImage3DOES;
-	this->glFramebufferTexture3DOES = es2::FramebufferTexture3DOES;
-	this->glEGLImageTargetTexture2DOES = es2::EGLImageTargetTexture2DOES;
-	this->glEGLImageTargetRenderbufferStorageOES = es2::EGLImageTargetRenderbufferStorageOES;
-	this->glIsRenderbufferOES = es2::IsRenderbufferOES;
-	this->glBindRenderbufferOES = es2::BindRenderbufferOES;
-	this->glDeleteRenderbuffersOES = es2::DeleteRenderbuffersOES;
-	this->glGenRenderbuffersOES = es2::GenRenderbuffersOES;
-	this->glRenderbufferStorageOES = es2::RenderbufferStorageOES;
-	this->glGetRenderbufferParameterivOES = es2::GetRenderbufferParameterivOES;
-	this->glIsFramebufferOES = es2::IsFramebufferOES;
-	this->glBindFramebufferOES = es2::BindFramebufferOES;
-	this->glDeleteFramebuffersOES = es2::DeleteFramebuffersOES;
-	this->glGenFramebuffersOES = es2::GenFramebuffersOES;
-	this->glCheckFramebufferStatusOES = es2::CheckFramebufferStatusOES;
-	this->glFramebufferRenderbufferOES = es2::FramebufferRenderbufferOES;
-	this->glFramebufferTexture2DOES = es2::FramebufferTexture2DOES;
-	this->glGetFramebufferAttachmentParameterivOES = es2::GetFramebufferAttachmentParameterivOES;
-	this->glGenerateMipmapOES = es2::GenerateMipmapOES;
-	this->glDrawBuffersEXT = es2::DrawBuffersEXT;
-
-	this->es2CreateContext = ::es2CreateContext;
-	this->es2GetProcAddress = ::es2GetProcAddress;
-	this->createBackBuffer = ::createBackBuffer;
-	this->createDepthStencil = ::createDepthStencil;
-	this->createFrameBuffer = ::createFrameBuffer;
-}
-
-extern "C" GL_APICALL LibGLESv2exports *libGLESv2_swiftshader()
-{
-	static LibGLESv2exports libGLESv2;
-	return &libGLESv2;
-}
-
-LibEGL libEGL;
-LibGLES_CM libGLES_CM;
\ No newline at end of file
diff --git a/src/OpenGL/libGLESv2/mathutil.h b/src/OpenGL/libGLESv2/mathutil.h
index 3c820a1..1b0280e 100644
--- a/src/OpenGL/libGLESv2/mathutil.h
+++ b/src/OpenGL/libGLESv2/mathutil.h
@@ -90,6 +90,11 @@
 
 	return static_cast<int>(roundf(x));
 }
+
+inline int convert_float_fixed(float x)
+{
+	return convert_float_int(static_cast<float>(0x7FFFFFFF) * x);
+}
 }
 
 #endif   // LIBGLESV2_MATHUTIL_H_
diff --git a/src/OpenGL/libGLESv2/utilities.cpp b/src/OpenGL/libGLESv2/utilities.cpp
index 4257b69..facc550 100644
--- a/src/OpenGL/libGLESv2/utilities.cpp
+++ b/src/OpenGL/libGLESv2/utilities.cpp
@@ -20,6 +20,7 @@
 #include "main.h"
 #include "mathutil.h"
 #include "Context.h"
+#include "Shader.h"
 #include "common/debug.h"
 
 #include <limits>
@@ -28,153 +29,6 @@
 
 namespace es2
 {
-	// ES2 requires that format is equal to internal format at all glTex*Image2D entry points and the implementation
-	// can decide the true, sized, internal format. The ES2FormatMap determines the internal format for all valid
-	// format and type combinations.
-
-	typedef std::pair<GLenum, GLenum> FormatTypePair;
-	typedef std::pair<FormatTypePair, GLenum> FormatPair;
-	typedef std::map<FormatTypePair, GLenum> FormatMap;
-
-	// A helper function to insert data into the format map with fewer characters.
-	static inline void InsertFormatMapping(FormatMap *map, GLenum format, GLenum type, GLenum internalFormat)
-	{
-		map->insert(FormatPair(FormatTypePair(format, type), internalFormat));
-	}
-
-	FormatMap BuildFormatMap()
-	{
-		static const GLenum GL_BGRA4_ANGLEX = 0x6ABC;
-		static const GLenum GL_BGR5_A1_ANGLEX = 0x6ABD;
-
-		FormatMap map;
-
-		//                       | Format | Type | Internal format |
-		InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA8);
-		InsertFormatMapping(&map, GL_RGBA, GL_BYTE, GL_RGBA8_SNORM);
-		InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA4);
-		InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGB5_A1);
-		InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2);
-		InsertFormatMapping(&map, GL_RGBA, GL_FLOAT, GL_RGBA32F);
-		InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT, GL_RGBA16F);
-		InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, GL_RGBA16F);
-
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_RGBA8UI);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_BYTE, GL_RGBA8I);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_RGBA16UI);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_SHORT, GL_RGBA16I);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_RGBA32UI);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_INT, GL_RGBA32I);
-		InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2UI);
-
-		InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8);
-		InsertFormatMapping(&map, GL_RGB, GL_BYTE, GL_RGB8_SNORM);
-		InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB565);
-		InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_R11F_G11F_B10F);
-		InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_RGB9_E5);
-		InsertFormatMapping(&map, GL_RGB, GL_FLOAT, GL_RGB32F);
-		InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT, GL_RGB16F);
-		InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, GL_RGB16F);
-
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_RGB8UI);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_BYTE, GL_RGB8I);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_RGB16UI);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_SHORT, GL_RGB16I);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_RGB32UI);
-		InsertFormatMapping(&map, GL_RGB_INTEGER, GL_INT, GL_RGB32I);
-
-		InsertFormatMapping(&map, GL_RG, GL_UNSIGNED_BYTE, GL_RG8);
-		InsertFormatMapping(&map, GL_RG, GL_BYTE, GL_RG8_SNORM);
-		InsertFormatMapping(&map, GL_RG, GL_FLOAT, GL_RG32F);
-		InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT, GL_RG16F);
-		InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT_OES, GL_RG16F);
-
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_RG8UI);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_BYTE, GL_RG8I);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_RG16UI);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_SHORT, GL_RG16I);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_RG32UI);
-		InsertFormatMapping(&map, GL_RG_INTEGER, GL_INT, GL_RG32I);
-
-		InsertFormatMapping(&map, GL_RED, GL_UNSIGNED_BYTE, GL_R8);
-		InsertFormatMapping(&map, GL_RED, GL_BYTE, GL_R8_SNORM);
-		InsertFormatMapping(&map, GL_RED, GL_FLOAT, GL_R32F);
-		InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT, GL_R16F);
-		InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT_OES, GL_R16F);
-
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_R8UI);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_BYTE, GL_R8I);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_R16UI);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_SHORT, GL_R16I);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_R32UI);
-		InsertFormatMapping(&map, GL_RED_INTEGER, GL_INT, GL_R32I);
-
-		InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE8_ALPHA8_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE8_EXT);
-		InsertFormatMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA8_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_LUMINANCE_ALPHA32F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE, GL_FLOAT, GL_LUMINANCE32F_EXT);
-		InsertFormatMapping(&map, GL_ALPHA, GL_FLOAT, GL_ALPHA32F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_LUMINANCE_ALPHA16F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_LUMINANCE_ALPHA16F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, GL_LUMINANCE16F_EXT);
-		InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_LUMINANCE16F_EXT);
-		InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT, GL_ALPHA16F_EXT);
-		InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, GL_ALPHA16F_EXT);
-
-		InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_BGRA8_EXT);
-		InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_BGRA4_ANGLEX);
-		InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_BGR5_A1_ANGLEX);
-
-		InsertFormatMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, GL_SRGB8);
-		InsertFormatMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, GL_SRGB8_ALPHA8);
-
-		InsertFormatMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
-		InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
-		InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE);
-		InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE);
-
-		InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_DEPTH_COMPONENT16);
-		InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_DEPTH_COMPONENT32_OES);
-		InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, GL_DEPTH_COMPONENT32F);
-
-		InsertFormatMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, GL_STENCIL_INDEX8);
-
-		InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH24_STENCIL8);
-		InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_DEPTH32F_STENCIL8);
-
-		return map;
-	}
-
-	GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type)
-	{
-		switch(internalFormat)
-		{
-		case GL_ALPHA:
-		case GL_LUMINANCE:
-		case GL_LUMINANCE_ALPHA:
-		case GL_RED:
-		case GL_RG:
-		case GL_RGB:
-		case GL_RGBA:
-		case GL_RED_INTEGER:
-		case GL_RG_INTEGER:
-		case GL_RGB_INTEGER:
-		case GL_RGBA_INTEGER:
-		case GL_BGRA_EXT:
-		case GL_DEPTH_COMPONENT:
-		case GL_DEPTH_STENCIL:
-		case GL_SRGB_EXT:
-		case GL_SRGB_ALPHA_EXT:
-			{
-				static const FormatMap formatMap = BuildFormatMap();
-				FormatMap::const_iterator iter = formatMap.find(FormatTypePair(internalFormat, type));
-				return (iter != formatMap.end()) ? iter->second : GL_NONE;
-			}
-		default:
-			return internalFormat;
-		}
-	}
 
 	unsigned int UniformComponentCount(GLenum type)
 	{
@@ -186,6 +40,7 @@
 		case GL_UNSIGNED_INT:
 		case GL_SAMPLER_2D:
 		case GL_SAMPLER_CUBE:
+		case GL_SAMPLER_2D_RECT_ARB:
 		case GL_SAMPLER_EXTERNAL_OES:
 		case GL_SAMPLER_3D_OES:
 		case GL_SAMPLER_2D_ARRAY:
@@ -263,6 +118,7 @@
 		case GL_INT:
 		case GL_SAMPLER_2D:
 		case GL_SAMPLER_CUBE:
+		case GL_SAMPLER_2D_RECT_ARB:
 		case GL_SAMPLER_EXTERNAL_OES:
 		case GL_SAMPLER_3D_OES:
 		case GL_SAMPLER_2D_ARRAY:
@@ -312,6 +168,7 @@
 		{
 		case GL_SAMPLER_2D:
 		case GL_SAMPLER_CUBE:
+		case GL_SAMPLER_2D_RECT_ARB:
 		case GL_SAMPLER_EXTERNAL_OES:
 		case GL_SAMPLER_3D_OES:
 		case GL_SAMPLER_2D_ARRAY:
@@ -356,6 +213,7 @@
 		case GL_UNSIGNED_INT_VEC4:
 		case GL_SAMPLER_2D:
 		case GL_SAMPLER_CUBE:
+		case GL_SAMPLER_2D_RECT_ARB:
 		case GL_SAMPLER_EXTERNAL_OES:
 		case GL_SAMPLER_3D_OES:
 		case GL_SAMPLER_2D_ARRAY:
@@ -465,22 +323,16 @@
 		return -1;
 	}
 
-	bool IsCompressed(GLenum format, GLint clientVersion)
+	bool IsCompressed(GLint internalformat, GLint clientVersion)
 	{
-		return ValidateCompressedFormat(format, clientVersion, true) == GL_NONE;
-	}
-
-	GLenum ValidateCompressedFormat(GLenum format, GLint clientVersion, bool expectCompressedFormats)
-	{
-		switch(format)
+		switch(internalformat)
 		{
 		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
 		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
 		case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
 		case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-			return S3TC_SUPPORT ? (expectCompressedFormats ? GL_NONE : GL_INVALID_OPERATION) : GL_INVALID_ENUM;
 		case GL_ETC1_RGB8_OES:
-			return expectCompressedFormats ? GL_NONE : GL_INVALID_OPERATION;
+			return true;
 		case GL_COMPRESSED_R11_EAC:
 		case GL_COMPRESSED_SIGNED_R11_EAC:
 		case GL_COMPRESSED_RG11_EAC:
@@ -491,6 +343,7 @@
 		case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
 		case GL_COMPRESSED_RGBA8_ETC2_EAC:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+			return (clientVersion >= 3);
 		case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
 		case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
 		case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
@@ -519,27 +372,106 @@
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
 		case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
-			return (clientVersion >= 3) ? (expectCompressedFormats ? GL_NONE : GL_INVALID_OPERATION) : GL_INVALID_ENUM;
+			return ASTC_SUPPORT && (clientVersion >= 3);
 		default:
-			return expectCompressedFormats ? GL_INVALID_ENUM : GL_NONE; // Not compressed format
+			return false;
 		}
 	}
 
-	GLenum ValidateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum sizedInternalFormat, Texture *texture)
+	bool IsSizedInternalFormat(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_ALPHA8_EXT:
+		case GL_LUMINANCE8_ALPHA8_EXT:
+		case GL_LUMINANCE8_EXT:
+		case GL_R8:
+		case GL_R8UI:
+		case GL_R8I:
+		case GL_R16UI:
+		case GL_R16I:
+		case GL_R32UI:
+		case GL_R32I:
+		case GL_RG8:
+		case GL_RG8UI:
+		case GL_RG8I:
+		case GL_RG16UI:
+		case GL_RG16I:
+		case GL_RG32UI:
+		case GL_RG32I:
+		case GL_SRGB8_ALPHA8:
+		case GL_RGB8UI:
+		case GL_RGB8I:
+		case GL_RGB16UI:
+		case GL_RGB16I:
+		case GL_RGB32UI:
+		case GL_RGB32I:
+		case GL_RG8_SNORM:
+		case GL_R8_SNORM:
+		case GL_RGB10_A2:
+		case GL_RGBA8UI:
+		case GL_RGBA8I:
+		case GL_RGB10_A2UI:
+		case GL_RGBA16UI:
+		case GL_RGBA16I:
+		case GL_RGBA32I:
+		case GL_RGBA32UI:
+		case GL_RGBA4:
+		case GL_RGB5_A1:
+		case GL_RGB565:
+		case GL_RGB8:
+		case GL_RGBA8:
+		case GL_BGRA8_EXT:   // GL_APPLE_texture_format_BGRA8888
+		case GL_R16F:
+		case GL_RG16F:
+		case GL_R11F_G11F_B10F:
+		case GL_RGB16F:
+		case GL_RGBA16F:
+		case GL_R32F:
+		case GL_RG32F:
+		case GL_RGB32F:
+		case GL_RGBA32F:
+		case GL_DEPTH_COMPONENT24:
+		case GL_DEPTH_COMPONENT32_OES:
+		case GL_DEPTH_COMPONENT32F:
+		case GL_DEPTH32F_STENCIL8:
+		case GL_DEPTH_COMPONENT16:
+		case GL_STENCIL_INDEX8:
+		case GL_DEPTH24_STENCIL8_OES:
+		case GL_RGBA8_SNORM:
+		case GL_SRGB8:
+		case GL_RGB8_SNORM:
+		case GL_RGB9_E5:
+			return true;
+		default:
+			return false;
+		}
+	}
+
+	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	                              GLsizei width, GLsizei height, GLenum format, GLenum type, Texture *texture, GLint clientVersion)
 	{
 		if(!texture)
 		{
 			return GL_INVALID_OPERATION;
 		}
 
-		if(compressed != texture->isCompressed(target, level))
-		{
-			return GL_INVALID_OPERATION;
-		}
+		GLenum sizedInternalFormat = texture->getFormat(target, level);
 
-		if(sizedInternalFormat != GL_NONE && sizedInternalFormat != texture->getFormat(target, level))
+		if(compressed)
 		{
-			return GL_INVALID_OPERATION;
+			if(format != sizedInternalFormat)
+			{
+				return GL_INVALID_OPERATION;
+			}
+		}
+		else if(!copy)   // CopyTexSubImage doesn't have format/type parameters.
+		{
+			GLenum validationError = ValidateTextureFormatType(format, type, sizedInternalFormat, target, clientVersion);
+			if(validationError != GL_NO_ERROR)
+			{
+				return validationError;
+			}
 		}
 
 		if(compressed)
@@ -557,10 +489,11 @@
 			return GL_INVALID_VALUE;
 		}
 
-		return GL_NONE;
+		return GL_NO_ERROR;
 	}
 
-	GLenum ValidateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLsizei depth, GLint xoffset, GLint yoffset, GLint zoffset, GLenum target, GLint level, GLenum sizedInternalFormat, Texture *texture)
+	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+	                              GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, Texture *texture, GLint clientVersion)
 	{
 		if(!texture)
 		{
@@ -572,9 +505,15 @@
 			return GL_INVALID_OPERATION;
 		}
 
-		if(sizedInternalFormat != GL_NONE && sizedInternalFormat != GetSizedInternalFormat(texture->getFormat(target, level), texture->getType(target, level)))
+		if(!copy)
 		{
-			return GL_INVALID_OPERATION;
+			GLenum sizedInternalFormat = texture->getFormat(target, level);
+
+			GLenum validationError = ValidateTextureFormatType(format, type, sizedInternalFormat, target, clientVersion);
+			if(validationError != GL_NO_ERROR)
+			{
+				return validationError;
+			}
 		}
 
 		if(compressed)
@@ -594,7 +533,85 @@
 			return GL_INVALID_VALUE;
 		}
 
-		return GL_NONE;
+		return GL_NO_ERROR;
+	}
+
+	bool ValidateCopyFormats(GLenum textureFormat, GLenum colorbufferFormat)
+	{
+		ASSERT(!gl::IsUnsizedInternalFormat(textureFormat));
+		ASSERT(!gl::IsUnsizedInternalFormat(colorbufferFormat));
+
+		if(GetColorComponentType(textureFormat) == GL_NONE)
+		{
+			return error(GL_INVALID_ENUM, false);
+		}
+
+		if(GetColorComponentType(colorbufferFormat) != GetColorComponentType(textureFormat))
+		{
+			return error(GL_INVALID_OPERATION, false);
+		}
+
+		if(GetColorEncoding(colorbufferFormat) != GetColorEncoding(textureFormat))
+		{
+			return error(GL_INVALID_OPERATION, false);
+		}
+
+		GLenum baseTexureFormat = gl::GetBaseInternalFormat(textureFormat);
+		GLenum baseColorbufferFormat = gl::GetBaseInternalFormat(colorbufferFormat);
+
+		// [OpenGL ES 2.0.24] table 3.9
+		// [OpenGL ES 3.0.5] table 3.16
+		switch(baseTexureFormat)
+		{
+		case GL_ALPHA:
+			if(baseColorbufferFormat != GL_ALPHA &&
+			   baseColorbufferFormat != GL_RGBA)
+			{
+				return error(GL_INVALID_OPERATION, false);
+			}
+			break;
+		case GL_LUMINANCE_ALPHA:
+		case GL_RGBA:
+			if(baseColorbufferFormat != GL_RGBA &&
+			   baseColorbufferFormat != GL_BGRA_EXT)   // GL_EXT_texture_format_BGRA8888 / GL_APPLE_texture_format_BGRA8888
+			{
+				return error(GL_INVALID_OPERATION, false);
+			}
+			break;
+		case GL_LUMINANCE:
+		case GL_RED:
+			if(baseColorbufferFormat != GL_RED &&
+			   baseColorbufferFormat != GL_RG &&
+			   baseColorbufferFormat != GL_RGB &&
+			   baseColorbufferFormat != GL_RGBA)
+			{
+				return error(GL_INVALID_OPERATION, false);
+			}
+			break;
+		case GL_RG:
+			if(baseColorbufferFormat != GL_RG &&
+			   baseColorbufferFormat != GL_RGB &&
+			   baseColorbufferFormat != GL_RGBA)
+			{
+				return error(GL_INVALID_OPERATION, false);
+			}
+			break;
+		case GL_RGB:
+			if(baseColorbufferFormat != GL_RGB &&
+			   baseColorbufferFormat != GL_RGBA)
+			{
+				return error(GL_INVALID_OPERATION, false);
+			}
+			break;
+		case GL_DEPTH_COMPONENT:
+		case GL_DEPTH_STENCIL_OES:
+			return error(GL_INVALID_OPERATION, false);
+		case GL_BGRA_EXT:   // GL_EXT_texture_format_BGRA8888 nor GL_APPLE_texture_format_BGRA8888 mention the format to be accepted by glCopyTexImage2D.
+		default:
+			return error(GL_INVALID_ENUM, false);
+		}
+
+		return true;
 	}
 
 	bool IsValidReadPixelsFormatType(const Framebuffer *framebuffer, GLenum format, GLenum type, GLint clientVersion)
@@ -620,16 +637,16 @@
 			}
 		}
 
-		Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0);
+		Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer();
 
 		if(!colorbuffer)
 		{
 			return false;
 		}
 
-		sw::Format internalformat = colorbuffer->getInternalFormat();
+		GLint internalformat = colorbuffer->getFormat();
 
-		if(sw::Surface::isNormalizedInteger(internalformat))
+		if(IsNormalizedInteger(internalformat))
 		{
 			// Combination always supported by normalized fixed-point rendering surfaces.
 			if(format == GL_RGBA && type == GL_UNSIGNED_BYTE)
@@ -648,7 +665,7 @@
 				}
 			}
 		}
-		else if(sw::Surface::isFloatFormat(internalformat))
+		else if(IsFloatFormat(internalformat))
 		{
 			// Combination always supported by floating-point rendering surfaces.
 			// Supported in OpenGL ES 2.0 due to GL_EXT_color_buffer_half_float.
@@ -657,7 +674,7 @@
 				return true;
 			}
 		}
-		else if(sw::Surface::isSignedNonNormalizedInteger(internalformat))
+		else if(IsSignedNonNormalizedInteger(internalformat))
 		{
 			ASSERT(clientVersion >= 3);
 
@@ -666,7 +683,7 @@
 				return true;
 			}
 		}
-		else if(sw::Surface::isUnsignedNonNormalizedInteger(internalformat))
+		else if(IsUnsignedNonNormalizedInteger(internalformat))
 		{
 			ASSERT(clientVersion >= 3);
 
@@ -698,7 +715,7 @@
 		}
 
 		// Additional third combination accepted by OpenGL ES 3.0.
-		if(internalformat == sw::FORMAT_A2B10G10R10)
+		if(internalformat == GL_RGB10_A2)
 		{
 			ASSERT(clientVersion >= 3);
 
@@ -753,10 +770,10 @@
 
 	bool IsTextureTarget(GLenum target)
 	{
-		return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target) || target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY;
+		return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target) || target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_RECTANGLE_ARB;
 	}
 
-	bool ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLint clientVersion)
+	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLenum target, GLint clientVersion)
 	{
 		switch(type)
 		{
@@ -780,11 +797,11 @@
 		case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
 			if(clientVersion < 3)
 			{
-				return error(GL_INVALID_ENUM, false);
+				return GL_INVALID_ENUM;
 			}
 			break;
 		default:
-			return error(GL_INVALID_ENUM, false);
+			return GL_INVALID_ENUM;
 		}
 
 		switch(format)
@@ -795,93 +812,138 @@
 		case GL_LUMINANCE:
 		case GL_LUMINANCE_ALPHA:
 		case GL_BGRA_EXT:          // GL_EXT_texture_format_BGRA8888
-		case GL_DEPTH_STENCIL:     // GL_OES_packed_depth_stencil (GL_DEPTH_STENCIL_OES)
-		case GL_DEPTH_COMPONENT:   // GL_OES_depth_texture
 		case GL_RED_EXT:           // GL_EXT_texture_rg
 		case GL_RG_EXT:            // GL_EXT_texture_rg
 			break;
+		case GL_DEPTH_STENCIL:     // GL_OES_packed_depth_stencil (GL_DEPTH_STENCIL_OES)
+		case GL_DEPTH_COMPONENT:   // GL_OES_depth_texture
+			switch(target)
+			{
+			case GL_TEXTURE_2D:
+			case GL_TEXTURE_2D_ARRAY:
+			case GL_TEXTURE_CUBE_MAP_POSITIVE_X:   // GL_OES_depth_texture_cube_map
+			case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+			case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+			case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+			case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+			case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+				break;
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
 		case GL_RED_INTEGER:
 		case GL_RG_INTEGER:
 		case GL_RGB_INTEGER:
 		case GL_RGBA_INTEGER:
 			if(clientVersion < 3)
 			{
-				return error(GL_INVALID_ENUM, false);
+				return GL_INVALID_ENUM;
 			}
 			break;
 		default:
-			return error(GL_INVALID_ENUM, false);
+			return GL_INVALID_ENUM;
 		}
 
 		if((GLenum)internalformat != format)
 		{
-			if(clientVersion < 3)
+			if(gl::IsUnsizedInternalFormat(internalformat))
 			{
-				return error(GL_INVALID_OPERATION, false);
+				return GL_INVALID_OPERATION;
 			}
 
-			switch(internalformat)
+			if(!IsSizedInternalFormat(internalformat))
 			{
-			case GL_R8:
-			case GL_R8UI:
-			case GL_R8I:
-			case GL_R16UI:
-			case GL_R16I:
-			case GL_R32UI:
-			case GL_R32I:
-			case GL_RG8:
-			case GL_RG8UI:
-			case GL_RG8I:
-			case GL_RG16UI:
-			case GL_RG16I:
-			case GL_RG32UI:
-			case GL_RG32I:
-			case GL_SRGB8_ALPHA8:
-			case GL_RGB8UI:
-			case GL_RGB8I:
-			case GL_RGB16UI:
-			case GL_RGB16I:
-			case GL_RGB32UI:
-			case GL_RGB32I:
-			case GL_RG8_SNORM:
-			case GL_R8_SNORM:
-			case GL_RGB10_A2:
-			case GL_RGBA8UI:
-			case GL_RGBA8I:
-			case GL_RGB10_A2UI:
-			case GL_RGBA16UI:
-			case GL_RGBA16I:
-			case GL_RGBA32I:
-			case GL_RGBA32UI:
-			case GL_RGBA4:
-			case GL_RGB5_A1:
-			case GL_RGB565:
-			case GL_RGB8_OES:
-			case GL_RGBA8_OES:
-			case GL_R16F:
-			case GL_RG16F:
-			case GL_R11F_G11F_B10F:
-			case GL_RGB16F:
-			case GL_RGBA16F:
-			case GL_R32F:
-			case GL_RG32F:
-			case GL_RGB32F:
-			case GL_RGBA32F:
-			case GL_DEPTH_COMPONENT24:
-			case GL_DEPTH_COMPONENT32_OES:
-			case GL_DEPTH_COMPONENT32F:
-			case GL_DEPTH32F_STENCIL8:
-			case GL_DEPTH_COMPONENT16:
-			case GL_STENCIL_INDEX8:
-			case GL_DEPTH24_STENCIL8_OES:
-			case GL_RGBA8_SNORM:
-			case GL_SRGB8:
-			case GL_RGB8_SNORM:
-			case GL_RGB9_E5:
+				return GL_INVALID_VALUE;
+			}
+		}
+
+		if((GLenum)internalformat == format)
+		{
+			// Validate format, type, and unsized internalformat combinations [OpenGL ES 3.0 Table 3.3]
+			switch(format)
+			{
+			case GL_RGBA:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+				case GL_UNSIGNED_SHORT_4_4_4_4:
+				case GL_UNSIGNED_SHORT_5_5_5_1:
+				case GL_FLOAT:            // GL_OES_texture_float
+				case GL_HALF_FLOAT_OES:   // GL_OES_texture_half_float
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_RGB:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+				case GL_UNSIGNED_SHORT_5_6_5:
+				case GL_FLOAT:            // GL_OES_texture_float
+				case GL_HALF_FLOAT_OES:   // GL_OES_texture_half_float
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_LUMINANCE_ALPHA:
+			case GL_LUMINANCE:
+			case GL_ALPHA:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:
+				case GL_FLOAT:            // GL_OES_texture_float
+				case GL_HALF_FLOAT_OES:   // GL_OES_texture_half_float
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_DEPTH_COMPONENT:
+				switch(type)
+				{
+				case GL_UNSIGNED_SHORT:   // GL_OES_depth_texture
+				case GL_UNSIGNED_INT:     // GL_OES_depth_texture
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_DEPTH_STENCIL_OES:
+				switch(type)
+				{
+				case GL_UNSIGNED_INT_24_8_OES:   // GL_OES_packed_depth_stencil
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_RED_EXT:
+			case GL_RG_EXT:
+				switch(type)
+				{
+				case GL_UNSIGNED_BYTE:    // GL_EXT_texture_rg
+				case GL_FLOAT:            // GL_EXT_texture_rg + GL_OES_texture_float
+				case GL_HALF_FLOAT_OES:   // GL_EXT_texture_rg + GL_OES_texture_half_float
+					break;
+				default:
+					return GL_INVALID_OPERATION;
+				}
+				break;
+			case GL_BGRA_EXT:
+				if(type != GL_UNSIGNED_BYTE)   // GL_APPLE_texture_format_BGRA8888 / GL_EXT_texture_format_BGRA8888
+				{
+					return GL_INVALID_OPERATION;
+				}
 				break;
 			default:
-				return error(GL_INVALID_ENUM, false);
+				UNREACHABLE(format);
+				return GL_INVALID_ENUM;
 			}
+
+			return GL_NO_ERROR;
 		}
 
 		// Validate format, type, and sized internalformat combinations [OpenGL ES 3.0 Table 3.2]
@@ -895,13 +957,13 @@
 			{
 			case GL_UNSIGNED_BYTE:               VALIDATE_INTERNALFORMAT(GL_RGBA8, GL_RGB5_A1, GL_RGBA4, GL_SRGB8_ALPHA8)
 			case GL_BYTE:                        VALIDATE_INTERNALFORMAT(GL_RGBA8_SNORM)
-			case GL_HALF_FLOAT_OES:              break;
+			case GL_HALF_FLOAT_OES:              VALIDATE_INTERNALFORMAT(GL_RGBA16F)
 			case GL_UNSIGNED_SHORT_4_4_4_4:      VALIDATE_INTERNALFORMAT(GL_RGBA4)
 			case GL_UNSIGNED_SHORT_5_5_5_1:      VALIDATE_INTERNALFORMAT(GL_RGB5_A1)
 			case GL_UNSIGNED_INT_2_10_10_10_REV: VALIDATE_INTERNALFORMAT(GL_RGB10_A2, GL_RGB5_A1)
 			case GL_HALF_FLOAT:                  VALIDATE_INTERNALFORMAT(GL_RGBA16F)
 			case GL_FLOAT:                       VALIDATE_INTERNALFORMAT(GL_RGBA32F, GL_RGBA16F)
-			default:                             return error(GL_INVALID_OPERATION, false);
+			default:                             return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_RGBA_INTEGER:
@@ -914,7 +976,7 @@
 			case GL_UNSIGNED_INT:                VALIDATE_INTERNALFORMAT(GL_RGBA32UI)
 			case GL_INT:                         VALIDATE_INTERNALFORMAT(GL_RGBA32I)
 			case GL_UNSIGNED_INT_2_10_10_10_REV: VALIDATE_INTERNALFORMAT(GL_RGB10_A2UI)
-			default:                             return error(GL_INVALID_OPERATION, false);
+			default:                             return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_RGB:
@@ -922,25 +984,25 @@
 			{
 			case GL_UNSIGNED_BYTE:                VALIDATE_INTERNALFORMAT(GL_RGB8, GL_RGB565, GL_SRGB8)
 			case GL_BYTE:                         VALIDATE_INTERNALFORMAT(GL_RGB8_SNORM)
-			case GL_HALF_FLOAT_OES:               break;
+			case GL_HALF_FLOAT_OES:               VALIDATE_INTERNALFORMAT(GL_RGB16F)
 			case GL_UNSIGNED_SHORT_5_6_5:         VALIDATE_INTERNALFORMAT(GL_RGB565)
 			case GL_UNSIGNED_INT_10F_11F_11F_REV: VALIDATE_INTERNALFORMAT(GL_R11F_G11F_B10F)
 			case GL_UNSIGNED_INT_5_9_9_9_REV:     VALIDATE_INTERNALFORMAT(GL_RGB9_E5)
 			case GL_HALF_FLOAT:                   VALIDATE_INTERNALFORMAT(GL_RGB16F, GL_R11F_G11F_B10F, GL_RGB9_E5)
 			case GL_FLOAT:                        VALIDATE_INTERNALFORMAT(GL_RGB32F, GL_RGB16F, GL_R11F_G11F_B10F, GL_RGB9_E5)
-			default:                              return error(GL_INVALID_OPERATION, false);
+			default:                              return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_RGB_INTEGER:
 			switch(type)
 			{
-			case GL_UNSIGNED_BYTE:               VALIDATE_INTERNALFORMAT(GL_RGB8UI)
-			case GL_BYTE:                        VALIDATE_INTERNALFORMAT(GL_RGB8I)
-			case GL_UNSIGNED_SHORT:              VALIDATE_INTERNALFORMAT(GL_RGB16UI)
-			case GL_SHORT:                       VALIDATE_INTERNALFORMAT(GL_RGB16I)
-			case GL_UNSIGNED_INT:                VALIDATE_INTERNALFORMAT(GL_RGB32UI)
-			case GL_INT:                         VALIDATE_INTERNALFORMAT(GL_RGB32I)
-			default:                             return error(GL_INVALID_OPERATION, false);
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_RGB8UI)
+			case GL_BYTE:           VALIDATE_INTERNALFORMAT(GL_RGB8I)
+			case GL_UNSIGNED_SHORT: VALIDATE_INTERNALFORMAT(GL_RGB16UI)
+			case GL_SHORT:          VALIDATE_INTERNALFORMAT(GL_RGB16I)
+			case GL_UNSIGNED_INT:   VALIDATE_INTERNALFORMAT(GL_RGB32UI)
+			case GL_INT:            VALIDATE_INTERNALFORMAT(GL_RGB32I)
+			default:                return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_RG:
@@ -948,10 +1010,9 @@
 			{
 			case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_RG8)
 			case GL_BYTE:          VALIDATE_INTERNALFORMAT(GL_RG8_SNORM)
-			case GL_HALF_FLOAT_OES: break;
 			case GL_HALF_FLOAT:    VALIDATE_INTERNALFORMAT(GL_RG16F)
 			case GL_FLOAT:         VALIDATE_INTERNALFORMAT(GL_RG32F, GL_RG16F)
-			default:               return error(GL_INVALID_OPERATION, false);
+			default:               return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_RG_INTEGER:
@@ -963,7 +1024,7 @@
 			case GL_SHORT:          VALIDATE_INTERNALFORMAT(GL_RG16I)
 			case GL_UNSIGNED_INT:   VALIDATE_INTERNALFORMAT(GL_RG32UI)
 			case GL_INT:            VALIDATE_INTERNALFORMAT(GL_RG32I)
-			default:                return error(GL_INVALID_OPERATION, false);
+			default:                return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_RED:
@@ -971,10 +1032,9 @@
 			{
 			case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_R8)
 			case GL_BYTE:          VALIDATE_INTERNALFORMAT(GL_R8_SNORM)
-			case GL_HALF_FLOAT_OES: break;
 			case GL_HALF_FLOAT:    VALIDATE_INTERNALFORMAT(GL_R16F)
 			case GL_FLOAT:         VALIDATE_INTERNALFORMAT(GL_R32F, GL_R16F)
-			default:               return error(GL_INVALID_OPERATION, false);
+			default:               return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_RED_INTEGER:
@@ -986,7 +1046,7 @@
 			case GL_SHORT:          VALIDATE_INTERNALFORMAT(GL_R16I)
 			case GL_UNSIGNED_INT:   VALIDATE_INTERNALFORMAT(GL_R32UI)
 			case GL_INT:            VALIDATE_INTERNALFORMAT(GL_R32I)
-			default:                return error(GL_INVALID_OPERATION, false);
+			default:                return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_DEPTH_COMPONENT:
@@ -995,7 +1055,7 @@
 			case GL_UNSIGNED_SHORT: VALIDATE_INTERNALFORMAT(GL_DEPTH_COMPONENT16)
 			case GL_UNSIGNED_INT:   VALIDATE_INTERNALFORMAT(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16)
 			case GL_FLOAT:          VALIDATE_INTERNALFORMAT(GL_DEPTH_COMPONENT32F)
-			default:                return error(GL_INVALID_OPERATION, false);
+			default:                return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_DEPTH_STENCIL:
@@ -1003,59 +1063,112 @@
 			{
 			case GL_UNSIGNED_INT_24_8:              VALIDATE_INTERNALFORMAT(GL_DEPTH24_STENCIL8)
 			case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: VALIDATE_INTERNALFORMAT(GL_DEPTH32F_STENCIL8)
-			default:                                return error(GL_INVALID_OPERATION, false);
+			default:                                return GL_INVALID_OPERATION;
 			}
 			break;
 		case GL_LUMINANCE_ALPHA:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_LUMINANCE8_ALPHA8_EXT)
+			case GL_HALF_FLOAT_OES: VALIDATE_INTERNALFORMAT(GL_LUMINANCE_ALPHA16F_EXT)
+			case GL_HALF_FLOAT:     VALIDATE_INTERNALFORMAT(GL_LUMINANCE_ALPHA16F_EXT)
+			case GL_FLOAT:          VALIDATE_INTERNALFORMAT(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA16F_EXT)
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
 		case GL_LUMINANCE:
+			switch(type)
+			{
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_LUMINANCE8_EXT)
+			case GL_HALF_FLOAT_OES: VALIDATE_INTERNALFORMAT(GL_LUMINANCE16F_EXT)
+			case GL_HALF_FLOAT:     VALIDATE_INTERNALFORMAT(GL_LUMINANCE16F_EXT)
+			case GL_FLOAT:          VALIDATE_INTERNALFORMAT(GL_LUMINANCE32F_EXT, GL_LUMINANCE16F_EXT)
+			default:
+				return GL_INVALID_OPERATION;
+			}
+			break;
 		case GL_ALPHA:
 			switch(type)
 			{
-			case GL_UNSIGNED_BYTE:
-			case GL_HALF_FLOAT_OES:
-			case GL_FLOAT:
-				break;
+			case GL_UNSIGNED_BYTE:  VALIDATE_INTERNALFORMAT(GL_ALPHA8_EXT)
+			case GL_HALF_FLOAT_OES: VALIDATE_INTERNALFORMAT(GL_ALPHA16F_EXT)
+			case GL_HALF_FLOAT:     VALIDATE_INTERNALFORMAT(GL_ALPHA16F_EXT)
+			case GL_FLOAT:          VALIDATE_INTERNALFORMAT(GL_ALPHA32F_EXT, GL_ALPHA16F_EXT)
 			default:
-				return error(GL_INVALID_OPERATION, false);
+				return GL_INVALID_OPERATION;
 			}
 			break;
-		case GL_BGRA_EXT:
-			if(type != GL_UNSIGNED_BYTE)
+		case GL_BGRA_EXT:   // GL_APPLE_texture_format_BGRA8888
+			switch(type)
 			{
-				return error(GL_INVALID_OPERATION, false);
+			case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_BGRA8_EXT)
+			default:               return GL_INVALID_OPERATION;
 			}
 			break;
 		default:
 			UNREACHABLE(format);
-			return error(GL_INVALID_ENUM, false);
+			return GL_INVALID_ENUM;
 		}
 
 		#undef VALIDATE_INTERNALFORMAT
 
-		if((GLenum)internalformat != format && !validSizedInternalformat)
+		if(!validSizedInternalformat)
 		{
-			return error(GL_INVALID_OPERATION, false);
+			return GL_INVALID_OPERATION;
 		}
 
-		return true;
+		return GL_NO_ERROR;
 	}
 
-	bool IsColorRenderable(GLenum internalformat, GLint clientVersion, bool isTexture)
+	GLsizei GetTypeSize(GLenum type)
 	{
+		switch(type)
+		{
+		case GL_BYTE:
+		case GL_UNSIGNED_BYTE:
+			return 1;
+		case GL_UNSIGNED_SHORT_4_4_4_4:
+		case GL_UNSIGNED_SHORT_5_5_5_1:
+		case GL_UNSIGNED_SHORT_5_6_5:
+		case GL_HALF_FLOAT_OES:
+		case GL_UNSIGNED_SHORT:
+		case GL_SHORT:
+		case GL_HALF_FLOAT:
+			return 2;
+		case GL_FLOAT:
+		case GL_UNSIGNED_INT_24_8:
+		case GL_UNSIGNED_INT:
+		case GL_INT:
+		case GL_UNSIGNED_INT_2_10_10_10_REV:
+		case GL_UNSIGNED_INT_10F_11F_11F_REV:
+		case GL_UNSIGNED_INT_5_9_9_9_REV:
+		case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+			return 4;
+		default:
+			UNREACHABLE(type);
+			break;
+		}
+
+		return 1;
+	}
+
+	bool IsColorRenderable(GLint internalformat, GLint clientVersion)
+	{
+		if(IsCompressed(internalformat, clientVersion))
+		{
+			return false;
+		}
+
 		switch(internalformat)
 		{
-		case GL_RED_EXT:
-		case GL_RG_EXT:
-		case GL_RGB:
-		case GL_RGBA:
-			return isTexture;
 		case GL_RGBA4:
 		case GL_RGB5_A1:
 		case GL_RGB565:
-		case GL_R8_EXT:
-		case GL_RG8_EXT:
-		case GL_RGB8_OES:
-		case GL_RGBA8_OES:
+		case GL_R8:
+		case GL_RG8:
+		case GL_RGB8:
+		case GL_RGBA8:
 		case GL_R16F:
 		case GL_RG16F:
 		case GL_RGB16F:
@@ -1064,7 +1177,7 @@
 		case GL_RG32F:
 		case GL_RGB32F:
 		case GL_RGBA32F:
-		case GL_BGRA8_EXT:
+		case GL_BGRA8_EXT:   // GL_EXT_texture_format_BGRA8888
 			return true;
 		case GL_R8UI:
 		case GL_R8I:
@@ -1089,6 +1202,13 @@
 		case GL_RGBA32UI:
 		case GL_R11F_G11F_B10F:
 			return clientVersion >= 3;
+		case GL_R8_SNORM:
+		case GL_RG8_SNORM:
+		case GL_RGB8_SNORM:
+		case GL_RGBA8_SNORM:
+		case GL_ALPHA8_EXT:
+		case GL_LUMINANCE8_EXT:
+		case GL_LUMINANCE8_ALPHA8_EXT:
 		case GL_DEPTH_COMPONENT24:
 		case GL_DEPTH_COMPONENT32_OES:
 		case GL_DEPTH_COMPONENT32F:
@@ -1104,8 +1224,13 @@
 		return false;
 	}
 
-	bool IsDepthRenderable(GLenum internalformat, GLint clientVersion)
+	bool IsDepthRenderable(GLint internalformat, GLint clientVersion)
 	{
+		if(IsCompressed(internalformat, clientVersion))
+		{
+			return false;
+		}
+
 		switch(internalformat)
 		{
 		case GL_DEPTH_COMPONENT24:
@@ -1143,8 +1268,8 @@
 		case GL_RGBA4:
 		case GL_RGB5_A1:
 		case GL_RGB565:
-		case GL_RGB8_OES:
-		case GL_RGBA8_OES:
+		case GL_RGB8:
+		case GL_RGBA8:
 		case GL_RED:
 		case GL_RG:
 		case GL_RGB:
@@ -1158,6 +1283,10 @@
 		case GL_RG32F:
 		case GL_RGB32F:
 		case GL_RGBA32F:
+		case GL_R8_SNORM:
+		case GL_RG8_SNORM:
+		case GL_RGB8_SNORM:
+		case GL_RGBA8_SNORM:
 			return false;
 		default:
 			UNIMPLEMENTED();
@@ -1166,8 +1295,13 @@
 		return false;
 	}
 
-	bool IsStencilRenderable(GLenum internalformat, GLint clientVersion)
+	bool IsStencilRenderable(GLint internalformat, GLint clientVersion)
 	{
+		if(IsCompressed(internalformat, clientVersion))
+		{
+			return false;
+		}
+
 		switch(internalformat)
 		{
 		case GL_STENCIL_INDEX8:
@@ -1201,8 +1335,8 @@
 		case GL_RGBA4:
 		case GL_RGB5_A1:
 		case GL_RGB565:
-		case GL_RGB8_OES:
-		case GL_RGBA8_OES:
+		case GL_RGB8:
+		case GL_RGBA8:
 		case GL_RED:
 		case GL_RG:
 		case GL_RGB:
@@ -1220,6 +1354,10 @@
 		case GL_DEPTH_COMPONENT24:
 		case GL_DEPTH_COMPONENT32_OES:
 		case GL_DEPTH_COMPONENT32F:
+		case GL_R8_SNORM:
+		case GL_RG8_SNORM:
+		case GL_RGB8_SNORM:
+		case GL_RGBA8_SNORM:
 			return false;
 		default:
 			UNIMPLEMENTED();
@@ -1228,6 +1366,414 @@
 		return false;
 	}
 
+	bool IsMipmappable(GLint internalformat, GLint clientVersion)
+	{
+		if(IsNonNormalizedInteger(internalformat))
+		{
+			return false;
+		}
+
+		switch(internalformat)
+		{
+		case GL_ALPHA8_EXT:
+		case GL_LUMINANCE8_EXT:
+		case GL_LUMINANCE8_ALPHA8_EXT:
+			return true;
+		default:
+			return IsColorRenderable(internalformat, clientVersion);
+		}
+	}
+
+	GLuint GetAlphaSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE:           return 0;
+		case GL_RGBA4:          return 4;
+		case GL_RGB5_A1:        return 1;
+		case GL_RGB565:         return 0;
+		case GL_R8:             return 0;
+		case GL_RG8:            return 0;
+		case GL_RGB8:           return 0;
+		case GL_RGBA8:          return 8;
+		case GL_R16F:           return 0;
+		case GL_RG16F:          return 0;
+		case GL_RGB16F:         return 0;
+		case GL_RGBA16F:        return 16;
+		case GL_R32F:           return 0;
+		case GL_RG32F:          return 0;
+		case GL_RGB32F:         return 0;
+		case GL_RGBA32F:        return 32;
+		case GL_BGRA8_EXT:      return 8;
+		case GL_R8UI:           return 0;
+		case GL_R8I:            return 0;
+		case GL_R16UI:          return 0;
+		case GL_R16I:           return 0;
+		case GL_R32UI:          return 0;
+		case GL_R32I:           return 0;
+		case GL_RG8UI:          return 0;
+		case GL_RG8I:           return 0;
+		case GL_RG16UI:         return 0;
+		case GL_RG16I:          return 0;
+		case GL_RG32UI:         return 0;
+		case GL_RG32I:          return 0;
+		case GL_SRGB8_ALPHA8:   return 8;
+		case GL_RGB10_A2:       return 2;
+		case GL_RGBA8UI:        return 8;
+		case GL_RGBA8I:         return 8;
+		case GL_RGB10_A2UI:     return 2;
+		case GL_RGBA16UI:       return 16;
+		case GL_RGBA16I:        return 16;
+		case GL_RGBA32I:        return 32;
+		case GL_RGBA32UI:       return 32;
+		case GL_R11F_G11F_B10F: return 0;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetRedSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE:           return 0;
+		case GL_RGBA4:          return 4;
+		case GL_RGB5_A1:        return 5;
+		case GL_RGB565:         return 5;
+		case GL_R8:             return 8;
+		case GL_RG8:            return 8;
+		case GL_RGB8:           return 8;
+		case GL_RGBA8:          return 8;
+		case GL_R16F:           return 16;
+		case GL_RG16F:          return 16;
+		case GL_RGB16F:         return 16;
+		case GL_RGBA16F:        return 16;
+		case GL_R32F:           return 32;
+		case GL_RG32F:          return 32;
+		case GL_RGB32F:         return 32;
+		case GL_RGBA32F:        return 32;
+		case GL_BGRA8_EXT:      return 8;
+		case GL_R8UI:           return 8;
+		case GL_R8I:            return 8;
+		case GL_R16UI:          return 16;
+		case GL_R16I:           return 16;
+		case GL_R32UI:          return 32;
+		case GL_R32I:           return 32;
+		case GL_RG8UI:          return 8;
+		case GL_RG8I:           return 8;
+		case GL_RG16UI:         return 16;
+		case GL_RG16I:          return 16;
+		case GL_RG32UI:         return 32;
+		case GL_RG32I:          return 32;
+		case GL_SRGB8_ALPHA8:   return 8;
+		case GL_RGB10_A2:       return 10;
+		case GL_RGBA8UI:        return 8;
+		case GL_RGBA8I:         return 8;
+		case GL_RGB10_A2UI:     return 10;
+		case GL_RGBA16UI:       return 16;
+		case GL_RGBA16I:        return 16;
+		case GL_RGBA32I:        return 32;
+		case GL_RGBA32UI:       return 32;
+		case GL_R11F_G11F_B10F: return 11;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetGreenSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE:           return 0;
+		case GL_RGBA4:          return 4;
+		case GL_RGB5_A1:        return 5;
+		case GL_RGB565:         return 6;
+		case GL_R8:             return 0;
+		case GL_RG8:            return 8;
+		case GL_RGB8:           return 8;
+		case GL_RGBA8:          return 8;
+		case GL_R16F:           return 0;
+		case GL_RG16F:          return 16;
+		case GL_RGB16F:         return 16;
+		case GL_RGBA16F:        return 16;
+		case GL_R32F:           return 0;
+		case GL_RG32F:          return 32;
+		case GL_RGB32F:         return 32;
+		case GL_RGBA32F:        return 32;
+		case GL_BGRA8_EXT:      return 8;
+		case GL_R8UI:           return 0;
+		case GL_R8I:            return 0;
+		case GL_R16UI:          return 0;
+		case GL_R16I:           return 0;
+		case GL_R32UI:          return 0;
+		case GL_R32I:           return 0;
+		case GL_RG8UI:          return 8;
+		case GL_RG8I:           return 8;
+		case GL_RG16UI:         return 16;
+		case GL_RG16I:          return 16;
+		case GL_RG32UI:         return 32;
+		case GL_RG32I:          return 32;
+		case GL_SRGB8_ALPHA8:   return 8;
+		case GL_RGB10_A2:       return 10;
+		case GL_RGBA8UI:        return 8;
+		case GL_RGBA8I:         return 8;
+		case GL_RGB10_A2UI:     return 10;
+		case GL_RGBA16UI:       return 16;
+		case GL_RGBA16I:        return 16;
+		case GL_RGBA32I:        return 32;
+		case GL_RGBA32UI:       return 32;
+		case GL_R11F_G11F_B10F: return 11;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetBlueSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_NONE:           return 0;
+		case GL_RGBA4:          return 4;
+		case GL_RGB5_A1:        return 5;
+		case GL_RGB565:         return 5;
+		case GL_R8:             return 0;
+		case GL_RG8:            return 0;
+		case GL_RGB8:           return 8;
+		case GL_RGBA8:          return 8;
+		case GL_R16F:           return 0;
+		case GL_RG16F:          return 0;
+		case GL_RGB16F:         return 16;
+		case GL_RGBA16F:        return 16;
+		case GL_R32F:           return 0;
+		case GL_RG32F:          return 0;
+		case GL_RGB32F:         return 32;
+		case GL_RGBA32F:        return 32;
+		case GL_BGRA8_EXT:      return 8;
+		case GL_R8UI:           return 0;
+		case GL_R8I:            return 0;
+		case GL_R16UI:          return 0;
+		case GL_R16I:           return 0;
+		case GL_R32UI:          return 0;
+		case GL_R32I:           return 0;
+		case GL_RG8UI:          return 0;
+		case GL_RG8I:           return 0;
+		case GL_RG16UI:         return 0;
+		case GL_RG16I:          return 0;
+		case GL_RG32UI:         return 0;
+		case GL_RG32I:          return 0;
+		case GL_SRGB8_ALPHA8:   return 8;
+		case GL_RGB10_A2:       return 10;
+		case GL_RGBA8UI:        return 8;
+		case GL_RGBA8I:         return 8;
+		case GL_RGB10_A2UI:     return 10;
+		case GL_RGBA16UI:       return 16;
+		case GL_RGBA16I:        return 16;
+		case GL_RGBA32I:        return 32;
+		case GL_RGBA32UI:       return 32;
+		case GL_R11F_G11F_B10F: return 10;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetDepthSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_STENCIL_INDEX8:        return 0;
+		case GL_DEPTH_COMPONENT16:     return 16;
+		case GL_DEPTH_COMPONENT24:     return 24;
+		case GL_DEPTH_COMPONENT32_OES: return 32;
+		case GL_DEPTH_COMPONENT32F:    return 32;
+		case GL_DEPTH24_STENCIL8:      return 24;
+		case GL_DEPTH32F_STENCIL8:     return 32;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLuint GetStencilSize(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_STENCIL_INDEX8:        return 8;
+		case GL_DEPTH_COMPONENT16:     return 0;
+		case GL_DEPTH_COMPONENT24:     return 0;
+		case GL_DEPTH_COMPONENT32_OES: return 0;
+		case GL_DEPTH_COMPONENT32F:    return 0;
+		case GL_DEPTH24_STENCIL8:      return 8;
+		case GL_DEPTH32F_STENCIL8:     return 8;
+		default:
+		//	UNREACHABLE(internalformat);
+			return 0;
+		}
+	}
+
+	GLenum GetColorComponentType(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_ALPHA8_EXT:
+		case GL_LUMINANCE8_ALPHA8_EXT:
+		case GL_LUMINANCE8_EXT:
+		case GL_R8:
+		case GL_RG8:
+		case GL_SRGB8_ALPHA8:
+		case GL_RGB10_A2:
+		case GL_RGBA4:
+		case GL_RGB5_A1:
+		case GL_RGB565:
+		case GL_RGB8:
+		case GL_RGBA8:
+		case GL_SRGB8:
+		case GL_BGRA8_EXT:
+			return GL_UNSIGNED_NORMALIZED;
+		case GL_R8_SNORM:
+		case GL_RG8_SNORM:
+		case GL_RGB8_SNORM:
+		case GL_RGBA8_SNORM:
+			return GL_SIGNED_NORMALIZED;
+		case GL_R8UI:
+		case GL_R16UI:
+		case GL_R32UI:
+		case GL_RG8UI:
+		case GL_RG16UI:
+		case GL_RG32UI:
+		case GL_RGB8UI:
+		case GL_RGB16UI:
+		case GL_RGB32UI:
+		case GL_RGB10_A2UI:
+		case GL_RGBA16UI:
+		case GL_RGBA32UI:
+		case GL_RGBA8UI:
+			return GL_UNSIGNED_INT;
+		case GL_R8I:
+		case GL_R16I:
+		case GL_R32I:
+		case GL_RG8I:
+		case GL_RG16I:
+		case GL_RG32I:
+		case GL_RGB8I:
+		case GL_RGB16I:
+		case GL_RGB32I:
+		case GL_RGBA8I:
+		case GL_RGBA16I:
+		case GL_RGBA32I:
+			return GL_INT;
+		case GL_R16F:
+		case GL_RG16F:
+		case GL_R11F_G11F_B10F:
+		case GL_RGB16F:
+		case GL_RGBA16F:
+		case GL_R32F:
+		case GL_RG32F:
+		case GL_RGB32F:
+		case GL_RGBA32F:
+		case GL_RGB9_E5:
+			return GL_FLOAT;
+		default:
+		//	UNREACHABLE(internalformat);
+			return GL_NONE;
+		}
+	}
+
+	GLenum GetComponentType(GLint internalformat, GLenum attachment)
+	{
+		// Can be one of GL_FLOAT, GL_INT, GL_UNSIGNED_INT, GL_SIGNED_NORMALIZED, or GL_UNSIGNED_NORMALIZED
+		switch(attachment)
+		{
+		case GL_COLOR_ATTACHMENT0:
+		case GL_COLOR_ATTACHMENT1:
+		case GL_COLOR_ATTACHMENT2:
+		case GL_COLOR_ATTACHMENT3:
+		case GL_COLOR_ATTACHMENT4:
+		case GL_COLOR_ATTACHMENT5:
+		case GL_COLOR_ATTACHMENT6:
+		case GL_COLOR_ATTACHMENT7:
+		case GL_COLOR_ATTACHMENT8:
+		case GL_COLOR_ATTACHMENT9:
+		case GL_COLOR_ATTACHMENT10:
+		case GL_COLOR_ATTACHMENT11:
+		case GL_COLOR_ATTACHMENT12:
+		case GL_COLOR_ATTACHMENT13:
+		case GL_COLOR_ATTACHMENT14:
+		case GL_COLOR_ATTACHMENT15:
+		case GL_COLOR_ATTACHMENT16:
+		case GL_COLOR_ATTACHMENT17:
+		case GL_COLOR_ATTACHMENT18:
+		case GL_COLOR_ATTACHMENT19:
+		case GL_COLOR_ATTACHMENT20:
+		case GL_COLOR_ATTACHMENT21:
+		case GL_COLOR_ATTACHMENT22:
+		case GL_COLOR_ATTACHMENT23:
+		case GL_COLOR_ATTACHMENT24:
+		case GL_COLOR_ATTACHMENT25:
+		case GL_COLOR_ATTACHMENT26:
+		case GL_COLOR_ATTACHMENT27:
+		case GL_COLOR_ATTACHMENT28:
+		case GL_COLOR_ATTACHMENT29:
+		case GL_COLOR_ATTACHMENT30:
+		case GL_COLOR_ATTACHMENT31:
+			return GetColorComponentType(internalformat);
+		case GL_DEPTH_ATTACHMENT:
+		case GL_STENCIL_ATTACHMENT:
+			// Only color buffers may have integer components.
+			return GL_FLOAT;
+		default:
+			UNREACHABLE(attachment);
+			return GL_NONE;
+		}
+	}
+
+	bool IsNormalizedInteger(GLint internalformat)
+	{
+		GLenum type = GetColorComponentType(internalformat);
+
+		return type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED;
+	}
+
+	bool IsNonNormalizedInteger(GLint internalformat)
+	{
+		GLenum type = GetColorComponentType(internalformat);
+
+		return type == GL_UNSIGNED_INT || type == GL_INT;
+	}
+
+	bool IsFloatFormat(GLint internalformat)
+	{
+		return GetColorComponentType(internalformat) == GL_FLOAT;
+	}
+
+	bool IsSignedNonNormalizedInteger(GLint internalformat)
+	{
+		return GetColorComponentType(internalformat) == GL_INT;
+	}
+
+	bool IsUnsignedNonNormalizedInteger(GLint internalformat)
+	{
+		return GetColorComponentType(internalformat) == GL_UNSIGNED_INT;
+	}
+
+	GLenum GetColorEncoding(GLint internalformat)
+	{
+		switch(internalformat)
+		{
+		case GL_SRGB8:
+		case GL_SRGB8_ALPHA8:
+			return GL_SRGB;
+		default:
+			// [OpenGL ES 3.0.5] section 6.1.13 page 242:
+			// If attachment is not a color attachment, or no data storage or texture image
+			// has been specified for the attachment, params will contain the value LINEAR.
+			return GL_LINEAR;
+		}
+	}
+
 	std::string ParseUniformName(const std::string &name, unsigned int *outSubscript)
 	{
 		// Strip any trailing array operator and retrieve the subscript
@@ -1374,6 +1920,32 @@
 		return sw::ADDRESSING_WRAP;
 	}
 
+	sw::CompareFunc ConvertCompareFunc(GLenum compareFunc, GLenum compareMode)
+	{
+		if(compareMode == GL_COMPARE_REF_TO_TEXTURE)
+		{
+			switch(compareFunc)
+			{
+			case GL_LEQUAL:   return sw::COMPARE_LESSEQUAL;
+			case GL_GEQUAL:   return sw::COMPARE_GREATEREQUAL;
+			case GL_LESS:     return sw::COMPARE_LESS;
+			case GL_GREATER:  return sw::COMPARE_GREATER;
+			case GL_EQUAL:    return sw::COMPARE_EQUAL;
+			case GL_NOTEQUAL: return sw::COMPARE_NOTEQUAL;
+			case GL_ALWAYS:   return sw::COMPARE_ALWAYS;
+			case GL_NEVER:    return sw::COMPARE_NEVER;
+			default: UNREACHABLE(compareFunc);
+			}
+		}
+		else if(compareMode == GL_NONE)
+		{
+			return sw::COMPARE_BYPASS;
+		}
+		else UNREACHABLE(compareMode);
+
+		return sw::COMPARE_BYPASS;
+	};
+
 	sw::SwizzleType ConvertSwizzleType(GLenum swizzleType)
 	{
 		switch(swizzleType)
@@ -1421,15 +1993,12 @@
 		case GL_NEAREST:
 		case GL_LINEAR:
 			return sw::MIPMAP_NONE;
-			break;
 		case GL_NEAREST_MIPMAP_NEAREST:
 		case GL_LINEAR_MIPMAP_NEAREST:
 			return sw::MIPMAP_POINT;
-			break;
 		case GL_NEAREST_MIPMAP_LINEAR:
 		case GL_LINEAR_MIPMAP_LINEAR:
 			return sw::MIPMAP_LINEAR;
-			break;
 		default:
 			UNREACHABLE(minFilter);
 			return sw::MIPMAP_NONE;
@@ -1443,12 +2012,13 @@
 			return sw::FILTER_ANISOTROPIC;
 		}
 
-		sw::FilterType magFilterType = sw::FILTER_POINT;
 		switch(magFilter)
 		{
-		case GL_NEAREST: magFilterType = sw::FILTER_POINT;  break;
-		case GL_LINEAR:  magFilterType = sw::FILTER_LINEAR; break;
-		default: UNREACHABLE(magFilter);
+		case GL_NEAREST:
+		case GL_LINEAR:
+			break;
+		default:
+			UNREACHABLE(magFilter);
 		}
 
 		switch(minFilter)
@@ -1456,14 +2026,14 @@
 		case GL_NEAREST:
 		case GL_NEAREST_MIPMAP_NEAREST:
 		case GL_NEAREST_MIPMAP_LINEAR:
-			return (magFilterType == sw::FILTER_POINT) ? sw::FILTER_POINT : sw::FILTER_MIN_POINT_MAG_LINEAR;
+			return (magFilter == GL_NEAREST) ? sw::FILTER_POINT : sw::FILTER_MIN_POINT_MAG_LINEAR;
 		case GL_LINEAR:
 		case GL_LINEAR_MIPMAP_NEAREST:
 		case GL_LINEAR_MIPMAP_LINEAR:
-			return (magFilterType == sw::FILTER_POINT) ? sw::FILTER_MIN_LINEAR_MAG_POINT : sw::FILTER_LINEAR;
+			return (magFilter == GL_NEAREST) ? sw::FILTER_MIN_LINEAR_MAG_POINT : sw::FILTER_LINEAR;
 		default:
 			UNREACHABLE(minFilter);
-			return (magFilterType == sw::FILTER_POINT) ? sw::FILTER_POINT : sw::FILTER_MIN_POINT_MAG_LINEAR;
+			return sw::FILTER_POINT;
 		}
 	}
 
@@ -1524,433 +2094,23 @@
 
 		return true;
 	}
-
-	sw::Format ConvertRenderbufferFormat(GLenum format)
-	{
-		switch(format)
-		{
-		case GL_RGBA4:
-		case GL_RGB5_A1:
-		case GL_RGBA8_OES:            return sw::FORMAT_A8B8G8R8;
-		case GL_RGB565:               return sw::FORMAT_R5G6B5;
-		case GL_RGB8_OES:             return sw::FORMAT_X8B8G8R8;
-		case GL_DEPTH_COMPONENT16:
-		case GL_STENCIL_INDEX8:
-		case GL_DEPTH24_STENCIL8_OES: return sw::FORMAT_D24S8;
-		case GL_DEPTH_COMPONENT32_OES:return sw::FORMAT_D32;
-		case GL_R8:                   return sw::FORMAT_R8;
-		case GL_RG8:                  return sw::FORMAT_G8R8;
-		case GL_R8I:                  return sw::FORMAT_R8I;
-		case GL_RG8I:                 return sw::FORMAT_G8R8I;
-		case GL_RGB8I:                return sw::FORMAT_X8B8G8R8I;
-		case GL_RGBA8I:               return sw::FORMAT_A8B8G8R8I;
-		case GL_R8UI:                 return sw::FORMAT_R8UI;
-		case GL_RG8UI:                return sw::FORMAT_G8R8UI;
-		case GL_RGB8UI:               return sw::FORMAT_X8B8G8R8UI;
-		case GL_RGBA8UI:              return sw::FORMAT_A8B8G8R8UI;
-		case GL_R16I:                 return sw::FORMAT_R16I;
-		case GL_RG16I:                return sw::FORMAT_G16R16I;
-		case GL_RGB16I:               return sw::FORMAT_X16B16G16R16I;
-		case GL_RGBA16I:              return sw::FORMAT_A16B16G16R16I;
-		case GL_R16UI:                return sw::FORMAT_R16UI;
-		case GL_RG16UI:               return sw::FORMAT_G16R16UI;
-		case GL_RGB16UI:              return sw::FORMAT_X16B16G16R16UI;
-		case GL_RGB10_A2UI:
-		case GL_RGBA16UI:             return sw::FORMAT_A16B16G16R16UI;
-		case GL_R32I:                 return sw::FORMAT_R32I;
-		case GL_RG32I:                return sw::FORMAT_G32R32I;
-		case GL_RGB32I:               return sw::FORMAT_X32B32G32R32I;
-		case GL_RGBA32I:              return sw::FORMAT_A32B32G32R32I;
-		case GL_R32UI:                return sw::FORMAT_R32UI;
-		case GL_RG32UI:               return sw::FORMAT_G32R32UI;
-		case GL_RGB32UI:              return sw::FORMAT_X32B32G32R32UI;
-		case GL_RGBA32UI:             return sw::FORMAT_A32B32G32R32UI;
-		case GL_R16F:                 return sw::FORMAT_R16F;
-		case GL_RG16F:                return sw::FORMAT_G16R16F;
-		case GL_R11F_G11F_B10F:
-		case GL_RGB16F:               return sw::FORMAT_B16G16R16F;
-		case GL_RGBA16F:              return sw::FORMAT_A16B16G16R16F;
-		case GL_R32F:                 return sw::FORMAT_R32F;
-		case GL_RG32F:                return sw::FORMAT_G32R32F;
-		case GL_RGB32F:               return sw::FORMAT_B32G32R32F;
-		case GL_RGBA32F:              return sw::FORMAT_A32B32G32R32F;
-		case GL_RGB10_A2:             return sw::FORMAT_A2B10G10R10;
-		case GL_SRGB8:                return sw::FORMAT_SRGB8_X8;
-		case GL_SRGB8_ALPHA8:         return sw::FORMAT_SRGB8_A8;
-		default: UNREACHABLE(format); return sw::FORMAT_NULL;
-		}
-	}
 }
 
 namespace sw2es
 {
-	unsigned int GetStencilSize(sw::Format stencilFormat)
-	{
-		switch(stencilFormat)
-		{
-		case sw::FORMAT_D24FS8:
-		case sw::FORMAT_D24S8:
-		case sw::FORMAT_D32FS8_TEXTURE:
-		case sw::FORMAT_D32FS8_SHADOW:
-		case sw::FORMAT_S8:
-			return 8;
-	//	case sw::FORMAT_D24X4S4:
-	//		return 4;
-	//	case sw::FORMAT_D15S1:
-	//		return 1;
-	//	case sw::FORMAT_D16_LOCKABLE:
-		case sw::FORMAT_D32:
-		case sw::FORMAT_D24X8:
-		case sw::FORMAT_D32F_LOCKABLE:
-		case sw::FORMAT_D16:
-			return 0;
-	//	case sw::FORMAT_D32_LOCKABLE:  return 0;
-	//	case sw::FORMAT_S8_LOCKABLE:   return 8;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetAlphaSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_A16B16G16R16F:
-		case sw::FORMAT_A16B16G16R16I:
-		case sw::FORMAT_A16B16G16R16UI:
-			return 16;
-		case sw::FORMAT_A32B32G32R32F:
-		case sw::FORMAT_A32B32G32R32I:
-		case sw::FORMAT_A32B32G32R32UI:
-			return 32;
-		case sw::FORMAT_A2R10G10B10:
-			return 2;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_SRGB8_A8:
-		case sw::FORMAT_A8B8G8R8I:
-		case sw::FORMAT_A8B8G8R8UI:
-		case sw::FORMAT_A8B8G8R8I_SNORM:
-			return 8;
-		case sw::FORMAT_A2B10G10R10:
-			return 2;
-		case sw::FORMAT_A1R5G5B5:
-			return 1;
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-		case sw::FORMAT_SRGB8_X8:
-		case sw::FORMAT_R5G6B5:
-			return 0;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetRedSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_R16F:
-		case sw::FORMAT_G16R16F:
-		case sw::FORMAT_B16G16R16F:
-		case sw::FORMAT_A16B16G16R16F:
-		case sw::FORMAT_R16I:
-		case sw::FORMAT_G16R16I:
-		case sw::FORMAT_X16B16G16R16I:
-		case sw::FORMAT_A16B16G16R16I:
-		case sw::FORMAT_R16UI:
-		case sw::FORMAT_G16R16UI:
-		case sw::FORMAT_X16B16G16R16UI:
-		case sw::FORMAT_A16B16G16R16UI:
-			return 16;
-		case sw::FORMAT_R32F:
-		case sw::FORMAT_G32R32F:
-		case sw::FORMAT_B32G32R32F:
-		case sw::FORMAT_X32B32G32R32F:
-		case sw::FORMAT_A32B32G32R32F:
-		case sw::FORMAT_R32I:
-		case sw::FORMAT_G32R32I:
-		case sw::FORMAT_X32B32G32R32I:
-		case sw::FORMAT_A32B32G32R32I:
-		case sw::FORMAT_R32UI:
-		case sw::FORMAT_G32R32UI:
-		case sw::FORMAT_X32B32G32R32UI:
-		case sw::FORMAT_A32B32G32R32UI:
-			return 32;
-		case sw::FORMAT_A2B10G10R10:
-		case sw::FORMAT_A2R10G10B10:
-			return 10;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-		case sw::FORMAT_SRGB8_A8:
-		case sw::FORMAT_SRGB8_X8:
-		case sw::FORMAT_R8:
-		case sw::FORMAT_G8R8:
-		case sw::FORMAT_R8I:
-		case sw::FORMAT_G8R8I:
-		case sw::FORMAT_X8B8G8R8I:
-		case sw::FORMAT_A8B8G8R8I:
-		case sw::FORMAT_R8UI:
-		case sw::FORMAT_G8R8UI:
-		case sw::FORMAT_X8B8G8R8UI:
-		case sw::FORMAT_A8B8G8R8UI:
-		case sw::FORMAT_R8I_SNORM:
-		case sw::FORMAT_G8R8I_SNORM:
-		case sw::FORMAT_X8B8G8R8I_SNORM:
-		case sw::FORMAT_A8B8G8R8I_SNORM:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-		case sw::FORMAT_R5G6B5:
-			return 5;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetGreenSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_G16R16F:
-		case sw::FORMAT_B16G16R16F:
-		case sw::FORMAT_A16B16G16R16F:
-		case sw::FORMAT_G16R16I:
-		case sw::FORMAT_X16B16G16R16I:
-		case sw::FORMAT_A16B16G16R16I:
-		case sw::FORMAT_G16R16UI:
-		case sw::FORMAT_X16B16G16R16UI:
-		case sw::FORMAT_A16B16G16R16UI:
-			return 16;
-		case sw::FORMAT_G32R32F:
-		case sw::FORMAT_B32G32R32F:
-		case sw::FORMAT_X32B32G32R32F:
-		case sw::FORMAT_A32B32G32R32F:
-		case sw::FORMAT_G32R32I:
-		case sw::FORMAT_X32B32G32R32I:
-		case sw::FORMAT_A32B32G32R32I:
-		case sw::FORMAT_G32R32UI:
-		case sw::FORMAT_X32B32G32R32UI:
-		case sw::FORMAT_A32B32G32R32UI:
-			return 32;
-		case sw::FORMAT_A2B10G10R10:
-		case sw::FORMAT_A2R10G10B10:
-			return 10;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-		case sw::FORMAT_SRGB8_A8:
-		case sw::FORMAT_SRGB8_X8:
-		case sw::FORMAT_G8R8:
-		case sw::FORMAT_G8R8I:
-		case sw::FORMAT_X8B8G8R8I:
-		case sw::FORMAT_A8B8G8R8I:
-		case sw::FORMAT_G8R8UI:
-		case sw::FORMAT_X8B8G8R8UI:
-		case sw::FORMAT_A8B8G8R8UI:
-		case sw::FORMAT_G8R8I_SNORM:
-		case sw::FORMAT_X8B8G8R8I_SNORM:
-		case sw::FORMAT_A8B8G8R8I_SNORM:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-			return 5;
-		case sw::FORMAT_R5G6B5:
-			return 6;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetBlueSize(sw::Format colorFormat)
-	{
-		switch(colorFormat)
-		{
-		case sw::FORMAT_B16G16R16F:
-		case sw::FORMAT_A16B16G16R16F:
-		case sw::FORMAT_X16B16G16R16I:
-		case sw::FORMAT_A16B16G16R16I:
-		case sw::FORMAT_X16B16G16R16UI:
-		case sw::FORMAT_A16B16G16R16UI:
-			return 16;
-		case sw::FORMAT_B32G32R32F:
-		case sw::FORMAT_X32B32G32R32F:
-		case sw::FORMAT_A32B32G32R32F:
-		case sw::FORMAT_X32B32G32R32I:
-		case sw::FORMAT_A32B32G32R32I:
-		case sw::FORMAT_X32B32G32R32UI:
-		case sw::FORMAT_A32B32G32R32UI:
-			return 32;
-		case sw::FORMAT_A2B10G10R10:
-		case sw::FORMAT_A2R10G10B10:
-			return 10;
-		case sw::FORMAT_A8R8G8B8:
-		case sw::FORMAT_A8B8G8R8:
-		case sw::FORMAT_X8R8G8B8:
-		case sw::FORMAT_X8B8G8R8:
-		case sw::FORMAT_SRGB8_A8:
-		case sw::FORMAT_SRGB8_X8:
-		case sw::FORMAT_X8B8G8R8I:
-		case sw::FORMAT_A8B8G8R8I:
-		case sw::FORMAT_X8B8G8R8UI:
-		case sw::FORMAT_A8B8G8R8UI:
-		case sw::FORMAT_X8B8G8R8I_SNORM:
-		case sw::FORMAT_A8B8G8R8I_SNORM:
-			return 8;
-		case sw::FORMAT_A1R5G5B5:
-		case sw::FORMAT_R5G6B5:
-			return 5;
-		default:
-			return 0;
-		}
-	}
-
-	unsigned int GetDepthSize(sw::Format depthFormat)
-	{
-		switch(depthFormat)
-		{
-	//	case sw::FORMAT_D16_LOCKABLE:   return 16;
-		case sw::FORMAT_D32:            return 32;
-	//	case sw::FORMAT_D15S1:          return 15;
-		case sw::FORMAT_D24S8:          return 24;
-		case sw::FORMAT_D24X8:          return 24;
-	//	case sw::FORMAT_D24X4S4:        return 24;
-		case sw::FORMAT_DF16S8:
-		case sw::FORMAT_D16:            return 16;
-		case sw::FORMAT_D32F:
-		case sw::FORMAT_D32F_COMPLEMENTARY:
-		case sw::FORMAT_D32F_LOCKABLE:  return 32;
-		case sw::FORMAT_DF24S8:
-		case sw::FORMAT_D24FS8:         return 24;
-	//	case sw::FORMAT_D32_LOCKABLE:   return 32;
-	//	case sw::FORMAT_S8_LOCKABLE:    return 0;
-		case sw::FORMAT_D32FS8_SHADOW:
-		case sw::FORMAT_D32FS8_TEXTURE: return 32;
-		default:                        return 0;
-		}
-	}
-
-	GLenum GetComponentType(sw::Format format, GLenum attachment)
-	{
-		// Can be one of GL_FLOAT, GL_INT, GL_UNSIGNED_INT, GL_SIGNED_NORMALIZED, or GL_UNSIGNED_NORMALIZED
-		switch(attachment)
-		{
-		case GL_COLOR_ATTACHMENT0:
-		case GL_COLOR_ATTACHMENT1:
-		case GL_COLOR_ATTACHMENT2:
-		case GL_COLOR_ATTACHMENT3:
-		case GL_COLOR_ATTACHMENT4:
-		case GL_COLOR_ATTACHMENT5:
-		case GL_COLOR_ATTACHMENT6:
-		case GL_COLOR_ATTACHMENT7:
-		case GL_COLOR_ATTACHMENT8:
-		case GL_COLOR_ATTACHMENT9:
-		case GL_COLOR_ATTACHMENT10:
-		case GL_COLOR_ATTACHMENT11:
-		case GL_COLOR_ATTACHMENT12:
-		case GL_COLOR_ATTACHMENT13:
-		case GL_COLOR_ATTACHMENT14:
-		case GL_COLOR_ATTACHMENT15:
-		case GL_COLOR_ATTACHMENT16:
-		case GL_COLOR_ATTACHMENT17:
-		case GL_COLOR_ATTACHMENT18:
-		case GL_COLOR_ATTACHMENT19:
-		case GL_COLOR_ATTACHMENT20:
-		case GL_COLOR_ATTACHMENT21:
-		case GL_COLOR_ATTACHMENT22:
-		case GL_COLOR_ATTACHMENT23:
-		case GL_COLOR_ATTACHMENT24:
-		case GL_COLOR_ATTACHMENT25:
-		case GL_COLOR_ATTACHMENT26:
-		case GL_COLOR_ATTACHMENT27:
-		case GL_COLOR_ATTACHMENT28:
-		case GL_COLOR_ATTACHMENT29:
-		case GL_COLOR_ATTACHMENT30:
-		case GL_COLOR_ATTACHMENT31:
-			switch(format)
-			{
-			case sw::FORMAT_R8I:
-			case sw::FORMAT_G8R8I:
-			case sw::FORMAT_X8B8G8R8I:
-			case sw::FORMAT_A8B8G8R8I:
-			case sw::FORMAT_R16I:
-			case sw::FORMAT_G16R16I:
-			case sw::FORMAT_X16B16G16R16I:
-			case sw::FORMAT_A16B16G16R16I:
-			case sw::FORMAT_R32I:
-			case sw::FORMAT_G32R32I:
-			case sw::FORMAT_X32B32G32R32I:
-			case sw::FORMAT_A32B32G32R32I:
-				return GL_INT;
-			case sw::FORMAT_R8UI:
-			case sw::FORMAT_G8R8UI:
-			case sw::FORMAT_X8B8G8R8UI:
-			case sw::FORMAT_A8B8G8R8UI:
-			case sw::FORMAT_R16UI:
-			case sw::FORMAT_G16R16UI:
-			case sw::FORMAT_X16B16G16R16UI:
-			case sw::FORMAT_A16B16G16R16UI:
-			case sw::FORMAT_R32UI:
-			case sw::FORMAT_G32R32UI:
-			case sw::FORMAT_X32B32G32R32UI:
-			case sw::FORMAT_A32B32G32R32UI:
-				return GL_UNSIGNED_INT;
-			case sw::FORMAT_R16F:
-			case sw::FORMAT_G16R16F:
-			case sw::FORMAT_B16G16R16F:
-			case sw::FORMAT_A16B16G16R16F:
-			case sw::FORMAT_R32F:
-			case sw::FORMAT_G32R32F:
-			case sw::FORMAT_B32G32R32F:
-			case sw::FORMAT_X32B32G32R32F:
-			case sw::FORMAT_A32B32G32R32F:
-				return GL_FLOAT;
-			case sw::FORMAT_R8:
-			case sw::FORMAT_G8R8:
-			case sw::FORMAT_A2B10G10R10:
-			case sw::FORMAT_A2R10G10B10:
-			case sw::FORMAT_A8R8G8B8:
-			case sw::FORMAT_A8B8G8R8:
-			case sw::FORMAT_X8R8G8B8:
-			case sw::FORMAT_X8B8G8R8:
-			case sw::FORMAT_SRGB8_A8:
-			case sw::FORMAT_SRGB8_X8:
-			case sw::FORMAT_A1R5G5B5:
-			case sw::FORMAT_R5G6B5:
-				return GL_UNSIGNED_NORMALIZED;
-			case sw::FORMAT_R8I_SNORM:
-			case sw::FORMAT_X8B8G8R8I_SNORM:
-			case sw::FORMAT_A8B8G8R8I_SNORM:
-			case sw::FORMAT_G8R8I_SNORM:
-				return GL_SIGNED_NORMALIZED;
-			default:
-				UNREACHABLE(format);
-				return GL_NONE;
-			}
-		case GL_DEPTH_ATTACHMENT:
-		case GL_STENCIL_ATTACHMENT:
-			// Only color buffers may have integer components.
-			return GL_FLOAT;
-		default:
-			UNREACHABLE(attachment);
-			return GL_NONE;
-		}
-	}
-
 	GLenum ConvertBackBufferFormat(sw::Format format)
 	{
 		switch(format)
 		{
 		case sw::FORMAT_A4R4G4B4: return GL_RGBA4;
-		case sw::FORMAT_A8R8G8B8: return GL_RGBA8_OES;
-		case sw::FORMAT_A8B8G8R8: return GL_RGBA8_OES;
+		case sw::FORMAT_A8R8G8B8: return GL_RGBA8;
+		case sw::FORMAT_A8B8G8R8: return GL_RGBA8;
 		case sw::FORMAT_A1R5G5B5: return GL_RGB5_A1;
 		case sw::FORMAT_R5G6B5:   return GL_RGB565;
-		case sw::FORMAT_X8R8G8B8: return GL_RGB8_OES;
-		case sw::FORMAT_X8B8G8R8: return GL_RGB8_OES;
-		case sw::FORMAT_SRGB8_A8: return GL_RGBA8_OES;
-		case sw::FORMAT_SRGB8_X8: return GL_RGB8_OES;
+		case sw::FORMAT_X8R8G8B8: return GL_RGB8;
+		case sw::FORMAT_X8B8G8R8: return GL_RGB8;
+		case sw::FORMAT_SRGB8_A8: return GL_RGBA8;
+		case sw::FORMAT_SRGB8_X8: return GL_RGB8;
 		default:
 			UNREACHABLE(format);
 		}
@@ -1962,25 +2122,17 @@
 	{
 		switch(format)
 		{
-		case sw::FORMAT_D16:
-		case sw::FORMAT_D24X8:
-		case sw::FORMAT_D32:
-			return GL_DEPTH_COMPONENT16;
-		case sw::FORMAT_D24S8:
-			return GL_DEPTH24_STENCIL8_OES;
-		case sw::FORMAT_D32F:
-		case sw::FORMAT_D32F_COMPLEMENTARY:
-		case sw::FORMAT_D32F_LOCKABLE:
-			return GL_DEPTH_COMPONENT32F;
-		case sw::FORMAT_D32FS8_TEXTURE:
-		case sw::FORMAT_D32FS8_SHADOW:
-			return GL_DEPTH32F_STENCIL8;
-		case sw::FORMAT_S8:
-			return GL_STENCIL_INDEX8;
+		case sw::FORMAT_D16:    return GL_DEPTH_COMPONENT16;
+		case sw::FORMAT_D24X8:  return GL_DEPTH_COMPONENT24;
+		case sw::FORMAT_D32:    return GL_DEPTH_COMPONENT32_OES;
+		case sw::FORMAT_D24S8:  return GL_DEPTH24_STENCIL8_OES;
+		case sw::FORMAT_D32F:   return GL_DEPTH_COMPONENT32F;
+		case sw::FORMAT_D32FS8: return GL_DEPTH32F_STENCIL8;
+		case sw::FORMAT_S8:     return GL_STENCIL_INDEX8;
 		default:
 			UNREACHABLE(format);
 		}
 
 		return GL_DEPTH24_STENCIL8_OES;
 	}
-}
+}
\ No newline at end of file
diff --git a/src/OpenGL/libGLESv2/utilities.h b/src/OpenGL/libGLESv2/utilities.h
index 53deb98..d8e55aa 100644
--- a/src/OpenGL/libGLESv2/utilities.h
+++ b/src/OpenGL/libGLESv2/utilities.h
@@ -42,22 +42,42 @@
 
 	int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);
 
-	bool IsCompressed(GLenum format, GLint clientVersion);
-	GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type);
-	GLenum ValidateCompressedFormat(GLenum format, GLint clientVersion, bool expectCompressedFormats);
-	GLenum ValidateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum sizedInternalFormat, Texture *texture);
-	GLenum ValidateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLsizei depth, GLint xoffset, GLint yoffset, GLint zoffset, GLenum target, GLint level, GLenum sizedInternalFormat, Texture *texture);
+	bool IsCompressed(GLint intenalformat, GLint clientVersion);
+	bool IsSizedInternalFormat(GLint internalformat);   // Not compressed.
+	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	                              GLsizei width, GLsizei height, GLenum format, GLenum type, Texture *texture, GLint clientVersion);
+	GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+	                              GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, Texture *texture, GLint clientVersion);
+	bool ValidateCopyFormats(GLenum textureFormat, GLenum colorbufferFormat);
 	bool IsValidReadPixelsFormatType(const Framebuffer *framebuffer, GLenum format, GLenum type, GLint clientVersion);
 	bool IsDepthTexture(GLenum format);
 	bool IsStencilTexture(GLenum format);
 	bool IsCubemapTextureTarget(GLenum target);
 	int CubeFaceIndex(GLenum cubeTarget);
 	bool IsTextureTarget(GLenum target);
-	bool ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLint clientVersion);
+	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLenum target, GLint clientVersion);
+	GLsizei GetTypeSize(GLenum type);
 
-	bool IsColorRenderable(GLenum internalformat, GLint clientVersion, bool isTexture);
-	bool IsDepthRenderable(GLenum internalformat, GLint clientVersion);
-	bool IsStencilRenderable(GLenum internalformat, GLint clientVersion);
+	bool IsColorRenderable(GLint internalformat, GLint clientVersion);
+	bool IsDepthRenderable(GLint internalformat, GLint clientVersion);
+	bool IsStencilRenderable(GLint internalformat, GLint clientVersion);
+	bool IsMipmappable(GLint internalformat, GLint clientVersion);
+
+	GLuint GetAlphaSize(GLint internalformat);
+	GLuint GetRedSize(GLint internalformat);
+	GLuint GetGreenSize(GLint internalformat);
+	GLuint GetBlueSize(GLint internalformat);
+	GLuint GetDepthSize(GLint internalformat);
+	GLuint GetStencilSize(GLint internalformat);
+
+	GLenum GetColorComponentType(GLint internalformat);
+	GLenum GetComponentType(GLint internalformat, GLenum attachment);
+	bool IsNormalizedInteger(GLint internalformat);
+	bool IsNonNormalizedInteger(GLint internalformat);
+	bool IsFloatFormat(GLint internalformat);
+	bool IsSignedNonNormalizedInteger(GLint internalformat);
+	bool IsUnsignedNonNormalizedInteger(GLint internalformat);
+	GLenum GetColorEncoding(GLint internalformat);
 
 	// Parse the base uniform name and array index.  Returns the base name of the uniform. outSubscript is
 	// set to GL_INVALID_INDEX if the provided name is not an array or the array index is invalid.
@@ -74,25 +94,17 @@
 	sw::LogicalOperation ConvertLogicalOperation(GLenum logicalOperation);
 	sw::StencilOperation ConvertStencilOp(GLenum stencilOp);
 	sw::AddressingMode ConvertTextureWrap(GLenum wrap);
+	sw::CompareFunc ConvertCompareFunc(GLenum compareFunc, GLenum compareMode);
 	sw::SwizzleType ConvertSwizzleType(GLenum swizzleType);
 	sw::CullMode ConvertCullMode(GLenum cullFace, GLenum frontFace);
 	unsigned int ConvertColorMask(bool red, bool green, bool blue, bool alpha);
 	sw::MipmapType ConvertMipMapFilter(GLenum minFilter);
 	sw::FilterType ConvertTextureFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy);
 	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,  GLenum elementType, sw::DrawType &swPrimitiveType, int &primitiveCount, int &verticesPerPrimitive);
-	sw::Format ConvertRenderbufferFormat(GLenum format);
 }
 
 namespace sw2es
 {
-	GLuint GetAlphaSize(sw::Format colorFormat);
-	GLuint GetRedSize(sw::Format colorFormat);
-	GLuint GetGreenSize(sw::Format colorFormat);
-	GLuint GetBlueSize(sw::Format colorFormat);
-	GLuint GetDepthSize(sw::Format depthFormat);
-	GLuint GetStencilSize(sw::Format stencilFormat);
-	GLenum GetComponentType(sw::Format format, GLenum attachment);
-
 	GLenum ConvertBackBufferFormat(sw::Format format);
 	GLenum ConvertDepthStencilFormat(sw::Format format);
 }
diff --git a/src/Reactor/Android.mk b/src/Reactor/Android.mk
index 1a4c0ea..fa90a1a 100644
--- a/src/Reactor/Android.mk
+++ b/src/Reactor/Android.mk
@@ -108,7 +108,8 @@
 
 LOCAL_CPPFLAGS := -std=c++11
 
-LOCAL_CFLAGS += -DLOG_TAG=\"libsubzero\" \
+LOCAL_CFLAGS += \
+	-DLOG_TAG=\"libsubzero\" \
 	-Wall \
 	-Werror \
 	-Wno-error=undefined-var-template \
@@ -116,7 +117,8 @@
 	-Wno-unused-parameter \
 	-Wno-implicit-exception-spec-mismatch \
 	-Wno-overloaded-virtual \
-	-Wno-non-virtual-dtor
+	-Wno-non-virtual-dtor \
+	-Wno-unknown-warning-option
 
 ifneq (16,${PLATFORM_SDK_VERSION})
 LOCAL_CFLAGS += -Xclang -fuse-init-array
diff --git a/src/Reactor/BUILD.gn b/src/Reactor/BUILD.gn
index aac9de5..b92633d 100644
--- a/src/Reactor/BUILD.gn
+++ b/src/Reactor/BUILD.gn
@@ -17,7 +17,7 @@
 declare_args() {
   # Currently, Subzero is not used by default
   # LLVM is still the default backend
-  use_swiftshader_with_subzero = is_win || is_linux || is_chromeos
+  use_swiftshader_with_subzero = is_win || is_linux || is_mac || is_chromeos
 }
 
 # Need a separate config to ensure the warnings are added to the end.
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 8abb17a..4db16e0 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -32,10 +32,10 @@
 #include "LLVMRoutine.hpp"
 #include "LLVMRoutineManager.hpp"
 #include "x86.hpp"
-#include "CPUID.hpp"
-#include "Thread.hpp"
-#include "Memory.hpp"
-#include "MutexLock.hpp"
+#include "Common/CPUID.hpp"
+#include "Common/Thread.hpp"
+#include "Common/Memory.hpp"
+#include "Common/MutexLock.hpp"
 
 #include <fstream>
 
@@ -2791,7 +2791,7 @@
 	RValue<Short4> RoundShort4(RValue<Float4> cast)
 	{
 		RValue<Int4> int4 = RoundInt(cast);
-		return As<Short4>(Pack(int4, int4));
+		return As<Short4>(PackSigned(int4, int4));
 	}
 
 	RValue<Short4> Max(RValue<Short4> x, RValue<Short4> y)
@@ -2824,13 +2824,20 @@
 		return x86::pmaddwd(x, y);
 	}
 
-	RValue<SByte8> Pack(RValue<Short4> x, RValue<Short4> y)
+	RValue<SByte8> PackSigned(RValue<Short4> x, RValue<Short4> y)
 	{
 		auto result = x86::packsswb(x, y);
 
 		return As<SByte8>(Swizzle(As<Int4>(result), 0x88));
 	}
 
+	RValue<Byte8> PackUnsigned(RValue<Short4> x, RValue<Short4> y)
+	{
+		auto result = x86::packuswb(x, y);
+
+		return As<Byte8>(Swizzle(As<Int4>(result), 0x88));
+	}
+
 	RValue<Int2> UnpackLow(RValue<Short4> x, RValue<Short4> y)
 	{
 		int shuffle[8] = {0, 8, 1, 9, 2, 10, 3, 11};   // Real type is v8i16
@@ -2899,7 +2906,7 @@
 			if(CPUID::supportsSSE4_1())
 			{
 				Int4 int4(Min(cast, Float4(0xFFFF)));   // packusdw takes care of 0x0000 saturation
-				*this = As<Short4>(Pack(As<UInt4>(int4), As<UInt4>(int4)));
+				*this = As<Short4>(PackUnsigned(int4, int4));
 			}
 			else
 			{
@@ -3093,13 +3100,6 @@
 		return x86::pavgw(x, y);
 	}
 
-	RValue<Byte8> Pack(RValue<UShort4> x, RValue<UShort4> y)
-	{
-		auto result = x86::packuswb(x, y);
-
-		return As<Byte8>(Swizzle(As<Int4>(result), 0x88));
-	}
-
 	Type *UShort4::getType()
 	{
 		return T(Type_v4i16);
@@ -4786,7 +4786,10 @@
 
 	RValue<Int4> CmpLT(RValue<Int4> x, RValue<Int4> y)
 	{
-		return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSLT(x.value, y.value), Int4::getType()));
+		// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
+		//        Restore the following line when LLVM is updated to a version where this issue is fixed.
+		// return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSLT(x.value, y.value), Int4::getType()));
+		return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSGE(x.value, y.value), Int4::getType())) ^ Int4(0xFFFFFFFF);
 	}
 
 	RValue<Int4> CmpLE(RValue<Int4> x, RValue<Int4> y)
@@ -4799,7 +4802,10 @@
 
 	RValue<Int4> CmpNEQ(RValue<Int4> x, RValue<Int4> y)
 	{
-		return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpNE(x.value, y.value), Int4::getType()));
+		// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
+		//        Restore the following line when LLVM is updated to a version where this issue is fixed.
+		// return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpNE(x.value, y.value), Int4::getType()));
+		return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpEQ(x.value, y.value), Int4::getType())) ^ Int4(0xFFFFFFFF);
 	}
 
 	RValue<Int4> CmpNLT(RValue<Int4> x, RValue<Int4> y)
@@ -4812,7 +4818,10 @@
 
 	RValue<Int4> CmpNLE(RValue<Int4> x, RValue<Int4> y)
 	{
-		return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSGT(x.value, y.value), Int4::getType()));
+		// FIXME: An LLVM bug causes SExt(ICmpCC()) to produce 0 or 1 instead of 0 or ~0
+		//        Restore the following line when LLVM is updated to a version where this issue is fixed.
+		// return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSGT(x.value, y.value), Int4::getType()));
+		return RValue<Int4>(Nucleus::createSExt(Nucleus::createICmpSLE(x.value, y.value), Int4::getType())) ^ Int4(0xFFFFFFFF);
 	}
 
 	RValue<Int4> Max(RValue<Int4> x, RValue<Int4> y)
@@ -4846,11 +4855,16 @@
 		return x86::cvtps2dq(cast);
 	}
 
-	RValue<Short8> Pack(RValue<Int4> x, RValue<Int4> y)
+	RValue<Short8> PackSigned(RValue<Int4> x, RValue<Int4> y)
 	{
 		return x86::packssdw(x, y);
 	}
 
+	RValue<UShort8> PackUnsigned(RValue<Int4> x, RValue<Int4> y)
+	{
+		return x86::packusdw(x, y);
+	}
+
 	RValue<Int> Extract(RValue<Int4> x, int i)
 	{
 		return RValue<Int>(Nucleus::createExtractElement(x.value, Int::getType(), i));
@@ -5180,11 +5194,6 @@
 		}
 	}
 
-	RValue<UShort8> Pack(RValue<UInt4> x, RValue<UInt4> y)
-	{
-		return x86::packusdw(As<Int4>(x), As<Int4>(y));
-	}
-
 	Type *UInt4::getType()
 	{
 		return T(llvm::VectorType::get(T(UInt::getType()), 4));
@@ -5791,6 +5800,16 @@
 		return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpOGT(x.value, y.value), Int4::getType()));
 	}
 
+	RValue<Int4> IsInf(RValue<Float4> x)
+	{
+		return CmpEQ(As<Int4>(x) & Int4(0x7FFFFFFF), Int4(0x7F800000));
+	}
+
+	RValue<Int4> IsNan(RValue<Float4> x)
+	{
+		return ~CmpEQ(x, x);
+	}
+
 	RValue<Float4> Round(RValue<Float4> x)
 	{
 		if(CPUID::supportsSSE4_1())
@@ -6205,7 +6224,7 @@
 			return As<SByte8>(V(::builder->CreateCall2(packsswb, x.value, y.value)));
 		}
 
-		RValue<Byte8> packuswb(RValue<UShort4> x, RValue<UShort4> y)
+		RValue<Byte8> packuswb(RValue<Short4> x, RValue<Short4> y)
 		{
 			llvm::Function *packuswb = llvm::Intrinsic::getDeclaration(::module, llvm::Intrinsic::x86_sse2_packuswb_128);
 
diff --git a/src/Reactor/Main.cpp b/src/Reactor/Main.cpp
index 37a006a..81442b9 100644
--- a/src/Reactor/Main.cpp
+++ b/src/Reactor/Main.cpp
@@ -288,6 +288,18 @@
 			*Pointer<Short4>(out + 16 * (512 + 4)) = UnpackLow(Byte8(1, 2, 3, 4, 5, 6, 7, 8), Byte8(9, 10, 11, 12, 13, 14, 15, 16));
 			*Pointer<Short4>(out + 16 * (512 + 5)) = UnpackHigh(Byte8(1, 2, 3, 4, 5, 6, 7, 8), Byte8(9, 10, 11, 12, 13, 14, 15, 16));
 
+			for(int i = 0; i < 256; i++)
+			{
+				*Pointer<Short4>(out + 16 * (512 + 6) + (8 * i)) =
+                                    Swizzle(Short4(1, 2, 3, 4), i);
+			}
+
+			for(int i = 0; i < 256; i++)
+			{
+				*Pointer<Int4>(out + 16 * (512 + 6 + i) + (8 * 256)) =
+                                    Swizzle(Int4(1, 2, 3, 4), i);
+			}
+
 			Return(0);
 		}
 
@@ -298,7 +310,7 @@
 			struct
 			{
 				float f[256 + 256 + 2][4];
-				int i[4][4];
+				int i[388][4];
 			} out;
 
 			memset(&out, 0, sizeof(out));
@@ -351,6 +363,26 @@
 			EXPECT_EQ(out.i[3][1], 0x10080F07);
 			EXPECT_EQ(out.i[3][2], 0x00000000);
 			EXPECT_EQ(out.i[3][3], 0x00000000);
+
+			for(int i = 0; i < 256; i++)
+			{
+				EXPECT_EQ(out.i[4 + i/2][0 + (i%2) * 2] & 0xFFFF,
+                                          ((i >> 0) & 0x03) + 1);
+				EXPECT_EQ(out.i[4 + i/2][0 + (i%2) * 2] >> 16,
+                                          ((i >> 2) & 0x03) + 1);
+				EXPECT_EQ(out.i[4 + i/2][1 + (i%2) * 2] & 0xFFFF,
+                                          ((i >> 4) & 0x03) + 1);
+				EXPECT_EQ(out.i[4 + i/2][1 + (i%2) * 2] >> 16,
+                                          ((i >> 6) & 0x03) + 1);
+			}
+
+			for(int i = 0; i < 256; i++)
+			{
+				EXPECT_EQ(out.i[132 + i][0], ((i >> 0) & 0x03) + 1);
+				EXPECT_EQ(out.i[132 + i][1], ((i >> 2) & 0x03) + 1);
+				EXPECT_EQ(out.i[132 + i][2], ((i >> 4) & 0x03) + 1);
+				EXPECT_EQ(out.i[132 + i][3], ((i >> 6) & 0x03) + 1);
+			}
 		}
 	}
 
@@ -451,62 +483,62 @@
 
 		if(routine)
 		{
-			int out[10][4];
+			unsigned int out[10][4];
 
 			memset(&out, 0, sizeof(out));
 
 			int(*callable)(void*) = (int(*)(void*))routine->getEntry();
 			callable(&out);
 
-			EXPECT_EQ(out[0][0], 0x00000000);
-			EXPECT_EQ(out[0][1], 0x00000000);
-			EXPECT_EQ(out[0][2], 0x00000000);
-			EXPECT_EQ(out[0][3], 0x80000000);
+			EXPECT_EQ(out[0][0], 0x00000000u);
+			EXPECT_EQ(out[0][1], 0x00000000u);
+			EXPECT_EQ(out[0][2], 0x00000000u);
+			EXPECT_EQ(out[0][3], 0x80000000u);
 
-			EXPECT_EQ(out[1][0], 0x3F800000);
-			EXPECT_EQ(out[1][1], 0x3F800000);
-			EXPECT_EQ(out[1][2], 0x00000000);
-			EXPECT_EQ(out[1][3], 0x80000000);
+			EXPECT_EQ(out[1][0], 0x3F800000u);
+			EXPECT_EQ(out[1][1], 0x3F800000u);
+			EXPECT_EQ(out[1][2], 0x00000000u);
+			EXPECT_EQ(out[1][3], 0x80000000u);
 
-			EXPECT_EQ(out[2][0], 0x00000000);
-			EXPECT_EQ(out[2][1], 0x00000000);
-			EXPECT_EQ(out[2][2], 0xFFFFFFFF);
-			EXPECT_EQ(out[2][3], 0x00000000);
+			EXPECT_EQ(out[2][0], 0x00000000u);
+			EXPECT_EQ(out[2][1], 0x00000000u);
+			EXPECT_EQ(out[2][2], 0xFFFFFFFFu);
+			EXPECT_EQ(out[2][3], 0x00000000u);
 
-			EXPECT_EQ(out[3][0], 0x00000001);
-			EXPECT_EQ(out[3][1], 0x00000001);
-			EXPECT_EQ(out[3][2], 0x00000000);
-			EXPECT_EQ(out[3][3], 0x00000000);
+			EXPECT_EQ(out[3][0], 0x00000001u);
+			EXPECT_EQ(out[3][1], 0x00000001u);
+			EXPECT_EQ(out[3][2], 0x00000000u);
+			EXPECT_EQ(out[3][3], 0x00000000u);
 
-			EXPECT_EQ(out[4][0], 0x00000000);
-			EXPECT_EQ(out[4][1], 0x00000000);
-			EXPECT_EQ(out[4][2], 0x00000000);
-			EXPECT_EQ(out[4][3], 0x00000000);
+			EXPECT_EQ(out[4][0], 0x00000000u);
+			EXPECT_EQ(out[4][1], 0x00000000u);
+			EXPECT_EQ(out[4][2], 0x00000000u);
+			EXPECT_EQ(out[4][3], 0x00000000u);
 
-			EXPECT_EQ(out[5][0], 0x00000001);
-			EXPECT_EQ(out[5][1], 0x00000001);
-			EXPECT_EQ(out[5][2], 0xFFFFFFFF);
-			EXPECT_EQ(out[5][3], 0x00000000);
+			EXPECT_EQ(out[5][0], 0x00000001u);
+			EXPECT_EQ(out[5][1], 0x00000001u);
+			EXPECT_EQ(out[5][2], 0xFFFFFFFFu);
+			EXPECT_EQ(out[5][3], 0x00000000u);
 
-			EXPECT_EQ(out[6][0], 0x00000000);
-			EXPECT_EQ(out[6][1], 0x0000FFFF);
-			EXPECT_EQ(out[6][2], 0x00000000);
-			EXPECT_EQ(out[6][3], 0x00000000);
+			EXPECT_EQ(out[6][0], 0x00000000u);
+			EXPECT_EQ(out[6][1], 0x0000FFFFu);
+			EXPECT_EQ(out[6][2], 0x00000000u);
+			EXPECT_EQ(out[6][3], 0x00000000u);
 
-			EXPECT_EQ(out[7][0], 0x00010001);
-			EXPECT_EQ(out[7][1], 0x00000000);
-			EXPECT_EQ(out[7][2], 0x00000000);
-			EXPECT_EQ(out[7][3], 0x00000000);
+			EXPECT_EQ(out[7][0], 0x00010001u);
+			EXPECT_EQ(out[7][1], 0x00000000u);
+			EXPECT_EQ(out[7][2], 0x00000000u);
+			EXPECT_EQ(out[7][3], 0x00000000u);
 
-			EXPECT_EQ(out[8][0], 0x00000000);
-			EXPECT_EQ(out[8][1], 0x00000000);
-			EXPECT_EQ(out[8][2], 0x00000000);
-			EXPECT_EQ(out[8][3], 0x00000000);
+			EXPECT_EQ(out[8][0], 0x00000000u);
+			EXPECT_EQ(out[8][1], 0x00000000u);
+			EXPECT_EQ(out[8][2], 0x00000000u);
+			EXPECT_EQ(out[8][3], 0x00000000u);
 
-			EXPECT_EQ(out[9][0], 0x00010001);
-			EXPECT_EQ(out[9][1], 0x0000FFFF);
-			EXPECT_EQ(out[9][2], 0x00000000);
-			EXPECT_EQ(out[9][3], 0x00000000);
+			EXPECT_EQ(out[9][0], 0x00010001u);
+			EXPECT_EQ(out[9][1], 0x0000FFFFu);
+			EXPECT_EQ(out[9][2], 0x00000000u);
+			EXPECT_EQ(out[9][3], 0x00000000u);
 		}
 	}
 
@@ -541,57 +573,57 @@
 
 		if(routine)
 		{
-			int out[10][4];
+			unsigned int out[10][4];
 
 			memset(&out, 0, sizeof(out));
 
 			int(*callable)(void*) = (int(*)(void*))routine->getEntry();
 			callable(&out);
 
-			EXPECT_EQ(out[0][0], 0xAAAAAAAA);
-			EXPECT_EQ(out[0][1], 0x00000000);
-			EXPECT_EQ(out[0][2], 0x00000000);
-			EXPECT_EQ(out[0][3], 0x00000000);
+			EXPECT_EQ(out[0][0], 0xAAAAAAAAu);
+			EXPECT_EQ(out[0][1], 0x00000000u);
+			EXPECT_EQ(out[0][2], 0x00000000u);
+			EXPECT_EQ(out[0][3], 0x00000000u);
 
-			EXPECT_EQ(out[1][0], 0x0000AAAA);
-			EXPECT_EQ(out[1][1], 0x00000000);
-			EXPECT_EQ(out[1][2], 0x00000000);
-			EXPECT_EQ(out[1][3], 0x00000000);
+			EXPECT_EQ(out[1][0], 0x0000AAAAu);
+			EXPECT_EQ(out[1][1], 0x00000000u);
+			EXPECT_EQ(out[1][2], 0x00000000u);
+			EXPECT_EQ(out[1][3], 0x00000000u);
 
-			EXPECT_EQ(out[2][0], 0xAAAAAAAA);
-			EXPECT_EQ(out[2][1], 0x55555555);
-			EXPECT_EQ(out[2][2], 0xFFFFFFFF);
-			EXPECT_EQ(out[2][3], 0x00000000);
+			EXPECT_EQ(out[2][0], 0xAAAAAAAAu);
+			EXPECT_EQ(out[2][1], 0x55555555u);
+			EXPECT_EQ(out[2][2], 0xFFFFFFFFu);
+			EXPECT_EQ(out[2][3], 0x00000000u);
 
-			EXPECT_EQ(out[3][0], 0x5555AAAA);
-			EXPECT_EQ(out[3][1], 0x0000FFFF);
-			EXPECT_EQ(out[3][2], 0x00000000);
-			EXPECT_EQ(out[3][3], 0x00000000);
+			EXPECT_EQ(out[3][0], 0x5555AAAAu);
+			EXPECT_EQ(out[3][1], 0x0000FFFFu);
+			EXPECT_EQ(out[3][2], 0x00000000u);
+			EXPECT_EQ(out[3][3], 0x00000000u);
 
-			EXPECT_EQ(out[4][0], 0xAAAAAAAB);
-			EXPECT_EQ(out[4][1], 0x00000000);
-			EXPECT_EQ(out[4][2], 0x00000000);
-			EXPECT_EQ(out[4][3], 0x00000000);
+			EXPECT_EQ(out[4][0], 0xAAAAAAABu);
+			EXPECT_EQ(out[4][1], 0x00000000u);
+			EXPECT_EQ(out[4][2], 0x00000000u);
+			EXPECT_EQ(out[4][3], 0x00000000u);
 
-			EXPECT_EQ(out[5][0], 0x0000AAAB);
-			EXPECT_EQ(out[5][1], 0x00000000);
-			EXPECT_EQ(out[5][2], 0x00000000);
-			EXPECT_EQ(out[5][3], 0x00000000);
+			EXPECT_EQ(out[5][0], 0x0000AAABu);
+			EXPECT_EQ(out[5][1], 0x00000000u);
+			EXPECT_EQ(out[5][2], 0x00000000u);
+			EXPECT_EQ(out[5][3], 0x00000000u);
 
-			EXPECT_EQ(out[6][0], 0xAAAAAAAB);
-			EXPECT_EQ(out[6][1], 0x55555556);
-			EXPECT_EQ(out[6][2], 0x00000000);
-			EXPECT_EQ(out[6][3], 0x00000001);
+			EXPECT_EQ(out[6][0], 0xAAAAAAABu);
+			EXPECT_EQ(out[6][1], 0x55555556u);
+			EXPECT_EQ(out[6][2], 0x00000000u);
+			EXPECT_EQ(out[6][3], 0x00000001u);
 
-			EXPECT_EQ(out[7][0], 0x5556AAAB);
-			EXPECT_EQ(out[7][1], 0x00010000);
-			EXPECT_EQ(out[7][2], 0x00000000);
-			EXPECT_EQ(out[7][3], 0x00000000);
+			EXPECT_EQ(out[7][0], 0x5556AAABu);
+			EXPECT_EQ(out[7][1], 0x00010000u);
+			EXPECT_EQ(out[7][2], 0x00000000u);
+			EXPECT_EQ(out[7][3], 0x00000000u);
 
-			EXPECT_EQ(out[8][0], 0xBF800000);
-			EXPECT_EQ(out[8][1], 0x3F800000);
-			EXPECT_EQ(out[8][2], 0x80000000);
-			EXPECT_EQ(out[8][3], 0x00000000);
+			EXPECT_EQ(out[8][0], 0xBF800000u);
+			EXPECT_EQ(out[8][1], 0x3F800000u);
+			EXPECT_EQ(out[8][2], 0x80000000u);
+			EXPECT_EQ(out[8][3], 0x00000000u);
 		}
 	}
 
@@ -622,38 +654,338 @@
 
 		if(routine)
 		{
-			int out[6][4];
+			unsigned int out[6][4];
 
 			memset(&out, 0, sizeof(out));
 
 			int(*callable)(void*) = (int(*)(void*))routine->getEntry();
 			callable(&out);
 
-			EXPECT_EQ(out[0][0], 0x00000000);
-			EXPECT_EQ(out[0][1], 0xFFFFFFFF);
-			EXPECT_EQ(out[0][2], 0xFFFFFFFF);
-			EXPECT_EQ(out[0][3], 0xFFFFFFFF);
+			EXPECT_EQ(out[0][0], 0x00000000u);
+			EXPECT_EQ(out[0][1], 0xFFFFFFFFu);
+			EXPECT_EQ(out[0][2], 0xFFFFFFFFu);
+			EXPECT_EQ(out[0][3], 0xFFFFFFFFu);
 
-			EXPECT_EQ(out[1][0], 0x00000000);
-			EXPECT_EQ(out[1][1], 0x00000000);
-			EXPECT_EQ(out[1][2], 0x00000000);
-			EXPECT_EQ(out[1][3], 0xFFFFFFFF);
+			EXPECT_EQ(out[1][0], 0x00000000u);
+			EXPECT_EQ(out[1][1], 0x00000000u);
+			EXPECT_EQ(out[1][2], 0x00000000u);
+			EXPECT_EQ(out[1][3], 0xFFFFFFFFu);
 
-			EXPECT_EQ(out[2][0], 0xFF000000);
-			EXPECT_EQ(out[2][1], 0x00000000);
+			EXPECT_EQ(out[2][0], 0xFF000000u);
+			EXPECT_EQ(out[2][1], 0x00000000u);
 
-			EXPECT_EQ(out[3][0], 0xFFFFFFFF);
-			EXPECT_EQ(out[3][1], 0xFFFFFFFF);
-			EXPECT_EQ(out[3][2], 0xFFFFFFFF);
-			EXPECT_EQ(out[3][3], 0xFFFFFFFF);
+			EXPECT_EQ(out[3][0], 0xFFFFFFFFu);
+			EXPECT_EQ(out[3][1], 0xFFFFFFFFu);
+			EXPECT_EQ(out[3][2], 0xFFFFFFFFu);
+			EXPECT_EQ(out[3][3], 0xFFFFFFFFu);
 
-			EXPECT_EQ(out[4][0], 0xFFFFFFFF);
-			EXPECT_EQ(out[4][1], 0x00000000);
-			EXPECT_EQ(out[4][2], 0x00000000);
-			EXPECT_EQ(out[4][3], 0xFFFFFFFF);
+			EXPECT_EQ(out[4][0], 0xFFFFFFFFu);
+			EXPECT_EQ(out[4][1], 0x00000000u);
+			EXPECT_EQ(out[4][2], 0x00000000u);
+			EXPECT_EQ(out[4][3], 0xFFFFFFFFu);
 
-			EXPECT_EQ(out[5][0], 0x00000000);
-			EXPECT_EQ(out[5][1], 0xFFFFFFFF);
+			EXPECT_EQ(out[5][0], 0x00000000u);
+			EXPECT_EQ(out[5][1], 0xFFFFFFFFu);
+		}
+	}
+
+	delete routine;
+}
+
+TEST(SubzeroReactorTest, SaturatedAddAndSubtract)
+{
+	Routine *routine = nullptr;
+
+	{
+		Function<Int(Pointer<Byte>)> function;
+		{
+			Pointer<Byte> out = function.Arg<0>();
+
+			*Pointer<Byte8>(out + 8 * 0) =
+				AddSat(Byte8(1, 2, 3, 4, 5, 6, 7, 8),
+				       Byte8(7, 6, 5, 4, 3, 2, 1, 0));
+			*Pointer<Byte8>(out + 8 * 1) =
+				AddSat(Byte8(0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE),
+				       Byte8(7, 6, 5, 4, 3, 2, 1, 0));
+			*Pointer<Byte8>(out + 8 * 2) =
+				SubSat(Byte8(1, 2, 3, 4, 5, 6, 7, 8),
+				       Byte8(7, 6, 5, 4, 3, 2, 1, 0));
+
+			*Pointer<SByte8>(out + 8 * 3) =
+				AddSat(SByte8(1, 2, 3, 4, 5, 6, 7, 8),
+				       SByte8(7, 6, 5, 4, 3, 2, 1, 0));
+			*Pointer<SByte8>(out + 8 * 4) =
+				AddSat(SByte8(0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E),
+				       SByte8(7, 6, 5, 4, 3, 2, 1, 0));
+			*Pointer<SByte8>(out + 8 * 5) =
+				AddSat(SByte8(0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88),
+				       SByte8(-7, -6, -5, -4, -3, -2, -1, -0));
+			*Pointer<SByte8>(out + 8 * 6) =
+				SubSat(SByte8(0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88),
+				       SByte8(7, 6, 5, 4, 3, 2, 1, 0));
+
+			*Pointer<Short4>(out + 8 * 7) =
+				AddSat(Short4(1, 2, 3, 4), Short4(3, 2, 1, 0));
+			*Pointer<Short4>(out + 8 * 8) =
+				AddSat(Short4(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFE),
+				       Short4(3, 2, 1, 0));
+			*Pointer<Short4>(out + 8 * 9) =
+				AddSat(Short4(0x8001, 0x8002, 0x8003, 0x8004),
+				       Short4(-3, -2, -1, -0));
+			*Pointer<Short4>(out + 8 * 10) =
+				SubSat(Short4(0x8001, 0x8002, 0x8003, 0x8004),
+				       Short4(3, 2, 1, 0));
+
+			*Pointer<UShort4>(out + 8 * 11) =
+				AddSat(UShort4(1, 2, 3, 4), UShort4(3, 2, 1, 0));
+			*Pointer<UShort4>(out + 8 * 12) =
+				AddSat(UShort4(0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE),
+				       UShort4(3, 2, 1, 0));
+			*Pointer<UShort4>(out + 8 * 13) =
+				SubSat(UShort4(1, 2, 3, 4), UShort4(3, 2, 1, 0));
+
+			Return(0);
+		}
+
+		routine = function(L"one");
+
+		if(routine)
+		{
+			unsigned int out[14][2];
+
+			memset(&out, 0, sizeof(out));
+
+			int(*callable)(void*) = (int(*)(void*))routine->getEntry();
+			callable(&out);
+
+			EXPECT_EQ(out[0][0], 0x08080808u);
+			EXPECT_EQ(out[0][1], 0x08080808u);
+
+			EXPECT_EQ(out[1][0], 0xFFFFFFFFu);
+			EXPECT_EQ(out[1][1], 0xFEFFFFFFu);
+
+			EXPECT_EQ(out[2][0], 0x00000000u);
+			EXPECT_EQ(out[2][1], 0x08060402u);
+
+			EXPECT_EQ(out[3][0], 0x08080808u);
+			EXPECT_EQ(out[3][1], 0x08080808u);
+
+			EXPECT_EQ(out[4][0], 0x7F7F7F7Fu);
+			EXPECT_EQ(out[4][1], 0x7E7F7F7Fu);
+
+			EXPECT_EQ(out[5][0], 0x80808080u);
+			EXPECT_EQ(out[5][1], 0x88868482u);
+
+			EXPECT_EQ(out[6][0], 0x80808080u);
+			EXPECT_EQ(out[6][1], 0x88868482u);
+
+			EXPECT_EQ(out[7][0], 0x00040004u);
+			EXPECT_EQ(out[7][1], 0x00040004u);
+
+			EXPECT_EQ(out[8][0], 0x7FFF7FFFu);
+			EXPECT_EQ(out[8][1], 0x7FFE7FFFu);
+
+			EXPECT_EQ(out[9][0], 0x80008000u);
+			EXPECT_EQ(out[9][1], 0x80048002u);
+
+			EXPECT_EQ(out[10][0], 0x80008000u);
+			EXPECT_EQ(out[10][1], 0x80048002u);
+
+			EXPECT_EQ(out[11][0], 0x00040004u);
+			EXPECT_EQ(out[11][1], 0x00040004u);
+
+			EXPECT_EQ(out[12][0], 0xFFFFFFFFu);
+			EXPECT_EQ(out[12][1], 0xFFFEFFFFu);
+
+			EXPECT_EQ(out[13][0], 0x00000000u);
+			EXPECT_EQ(out[13][1], 0x00040002u);
+		}
+	}
+
+	delete routine;
+}
+
+TEST(SubzeroReactorTest, Unpack)
+{
+	Routine *routine = nullptr;
+
+	{
+		Function<Int(Pointer<Byte>,Pointer<Byte>)> function;
+		{
+			Pointer<Byte> in = function.Arg<0>();
+			Pointer<Byte> out = function.Arg<1>();
+
+			Byte4 test_byte_a = *Pointer<Byte4>(in + 4 * 0);
+			Byte4 test_byte_b = *Pointer<Byte4>(in + 4 * 1);
+
+			*Pointer<Short4>(out + 8 * 0) =
+				Unpack(test_byte_a, test_byte_b);
+
+			*Pointer<Short4>(out + 8 * 1) = Unpack(test_byte_a);
+
+			Return(0);
+		}
+
+		routine = function(L"one");
+
+		if(routine)
+		{
+			unsigned int in[1][2];
+			unsigned int out[2][2];
+
+			memset(&out, 0, sizeof(out));
+
+			in[0][0] = 0xABCDEF12u;
+			in[0][1] = 0x34567890u;
+
+			int(*callable)(void*,void*) = (int(*)(void*,void*))routine->getEntry();
+			callable(&in, &out);
+
+			EXPECT_EQ(out[0][0], 0x78EF9012u);
+			EXPECT_EQ(out[0][1], 0x34AB56CDu);
+
+			EXPECT_EQ(out[1][0], 0xEFEF1212u);
+			EXPECT_EQ(out[1][1], 0xABABCDCDu);
+		}
+	}
+
+	delete routine;
+}
+
+TEST(SubzeroReactorTest, Pack)
+{
+	Routine *routine = nullptr;
+
+	{
+		Function<Int(Pointer<Byte>)> function;
+		{
+			Pointer<Byte> out = function.Arg<0>();
+
+			*Pointer<SByte8>(out + 8 * 0) =
+				PackSigned(Short4(-1, -2, 1, 2),
+					   Short4(3, 4, -3, -4));
+
+			*Pointer<Byte8>(out + 8 * 1) =
+				PackUnsigned(Short4(-1, -2, 1, 2),
+					     Short4(3, 4, -3, -4));
+
+			*Pointer<Short8>(out + 8 * 2) =
+				PackSigned(Int4(-1, -2, 1, 2),
+					   Int4(3, 4, -3, -4));
+
+			*Pointer<UShort8>(out + 8 * 4) =
+				PackUnsigned(Int4(-1, -2, 1, 2),
+					     Int4(3, 4, -3, -4));
+
+			Return(0);
+		}
+
+		routine = function(L"one");
+
+		if(routine)
+		{
+			unsigned int out[6][2];
+
+			memset(&out, 0, sizeof(out));
+
+			int(*callable)(void*) = (int(*)(void*))routine->getEntry();
+			callable(&out);
+
+			EXPECT_EQ(out[0][0], 0x0201FEFFu);
+			EXPECT_EQ(out[0][1], 0xFCFD0403u);
+
+			EXPECT_EQ(out[1][0], 0x02010000u);
+			EXPECT_EQ(out[1][1], 0x00000403u);
+
+			EXPECT_EQ(out[2][0], 0xFFFEFFFFu);
+			EXPECT_EQ(out[2][1], 0x00020001u);
+
+			EXPECT_EQ(out[3][0], 0x00040003u);
+			EXPECT_EQ(out[3][1], 0xFFFCFFFDu);
+
+			EXPECT_EQ(out[4][0], 0x00000000u);
+			EXPECT_EQ(out[4][1], 0x00020001u);
+
+			EXPECT_EQ(out[5][0], 0x00040003u);
+			EXPECT_EQ(out[5][1], 0x00000000u);
+		}
+	}
+
+	delete routine;
+}
+
+TEST(SubzeroReactorTest, MulHigh)
+{
+	Routine *routine = nullptr;
+
+	{
+		Function<Int(Pointer<Byte>)> function;
+		{
+			Pointer<Byte> out = function.Arg<0>();
+
+			*Pointer<Short4>(out + 8 * 0) =
+				MulHigh(Short4(0x1aa, 0x2dd, 0x3ee, 0xF422),
+					Short4(0x1bb, 0x2cc, 0x3ff, 0xF411));
+			*Pointer<UShort4>(out + 8 * 1) =
+				MulHigh(UShort4(0x1aa, 0x2dd, 0x3ee, 0xF422),
+					UShort4(0x1bb, 0x2cc, 0x3ff, 0xF411));
+
+			// (U)Short8 variants are mentioned but unimplemented
+			Return(0);
+		}
+
+		routine = function(L"one");
+
+		if(routine)
+		{
+			unsigned int out[2][2];
+
+			memset(&out, 0, sizeof(out));
+
+			int(*callable)(void*) = (int(*)(void*))routine->getEntry();
+			callable(&out);
+
+			EXPECT_EQ(out[0][0], 0x00080002u);
+			EXPECT_EQ(out[0][1], 0x008D000fu);
+
+			EXPECT_EQ(out[1][0], 0x00080002u);
+			EXPECT_EQ(out[1][1], 0xe8C0000Fu);
+		}
+	}
+
+	delete routine;
+}
+
+TEST(SubzeroReactorTest, MulAdd)
+{
+	Routine *routine = nullptr;
+
+	{
+		Function<Int(Pointer<Byte>)> function;
+		{
+			Pointer<Byte> out = function.Arg<0>();
+
+			*Pointer<Int2>(out + 8 * 0) =
+				MulAdd(Short4(0x1aa, 0x2dd, 0x3ee, 0xF422),
+				       Short4(0x1bb, 0x2cc, 0x3ff, 0xF411));
+
+			// (U)Short8 variant is mentioned but unimplemented
+			Return(0);
+		}
+
+		routine = function(L"one");
+
+		if(routine)
+		{
+			unsigned int out[1][2];
+
+			memset(&out, 0, sizeof(out));
+
+			int(*callable)(void*) = (int(*)(void*))routine->getEntry();
+			callable(&out);
+
+			EXPECT_EQ(out[0][0], 0x000AE34Au);
+			EXPECT_EQ(out[0][1], 0x009D5254u);
 		}
 	}
 
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index 3f9fb3d4..a6d364f 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -797,7 +797,8 @@
 	RValue<Short4> SubSat(RValue<Short4> x, RValue<Short4> y);
 	RValue<Short4> MulHigh(RValue<Short4> x, RValue<Short4> y);
 	RValue<Int2> MulAdd(RValue<Short4> x, RValue<Short4> y);
-	RValue<SByte8> Pack(RValue<Short4> x, RValue<Short4> y);
+	RValue<SByte8> PackSigned(RValue<Short4> x, RValue<Short4> y);
+	RValue<Byte8> PackUnsigned(RValue<Short4> x, RValue<Short4> y);
 	RValue<Int2> UnpackLow(RValue<Short4> x, RValue<Short4> y);
 	RValue<Int2> UnpackHigh(RValue<Short4> x, RValue<Short4> y);
 	RValue<Short4> Swizzle(RValue<Short4> x, unsigned char select);
@@ -866,7 +867,6 @@
 	RValue<UShort4> SubSat(RValue<UShort4> x, RValue<UShort4> y);
 	RValue<UShort4> MulHigh(RValue<UShort4> x, RValue<UShort4> y);
 	RValue<UShort4> Average(RValue<UShort4> x, RValue<UShort4> y);
-	RValue<Byte8> Pack(RValue<UShort4> x, RValue<UShort4> y);
 
 	class Short8 : public LValue<Short8>
 	{
@@ -1831,7 +1831,8 @@
 	RValue<Int4> Max(RValue<Int4> x, RValue<Int4> y);
 	RValue<Int4> Min(RValue<Int4> x, RValue<Int4> y);
 	RValue<Int4> RoundInt(RValue<Float4> cast);
-	RValue<Short8> Pack(RValue<Int4> x, RValue<Int4> y);
+	RValue<Short8> PackSigned(RValue<Int4> x, RValue<Int4> y);
+	RValue<UShort8> PackUnsigned(RValue<Int4> x, RValue<Int4> y);
 	RValue<Int> Extract(RValue<Int4> val, int i);
 	RValue<Int4> Insert(RValue<Int4> val, RValue<Int> element, int i);
 	RValue<Int> SignMask(RValue<Int4> x);
@@ -1911,7 +1912,6 @@
 	RValue<UInt4> Max(RValue<UInt4> x, RValue<UInt4> y);
 	RValue<UInt4> Min(RValue<UInt4> x, RValue<UInt4> y);
 //	RValue<UInt4> RoundInt(RValue<Float4> cast);
-	RValue<UShort8> Pack(RValue<UInt4> x, RValue<UInt4> y);
 
 	class Float : public LValue<Float>
 	{
@@ -2110,6 +2110,8 @@
 	RValue<Int4> CmpNEQ(RValue<Float4> x, RValue<Float4> y);
 	RValue<Int4> CmpNLT(RValue<Float4> x, RValue<Float4> y);
 	RValue<Int4> CmpNLE(RValue<Float4> x, RValue<Float4> y);
+	RValue<Int4> IsInf(RValue<Float4> x);
+	RValue<Int4> IsNan(RValue<Float4> x);
 	RValue<Float4> Round(RValue<Float4> x);
 	RValue<Float4> Trunc(RValue<Float4> x);
 	RValue<Float4> Frac(RValue<Float4> x);
diff --git a/src/Reactor/Reactor.vcxproj b/src/Reactor/Reactor.vcxproj
index 744614c..6bd1813 100644
--- a/src/Reactor/Reactor.vcxproj
+++ b/src/Reactor/Reactor.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -30,43 +30,44 @@
     <ProjectGuid>{28FD076D-10B5-4BD8-A4CF-F44C7002A803}</ProjectGuid>

     <RootNamespace>Reactor</RootNamespace>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>false</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>false</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

@@ -109,7 +110,7 @@
     <ClCompile>

       <Optimization>Disabled</Optimization>

       <IntrinsicFunctions>true</IntrinsicFunctions>

-      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;..\Common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_HAS_EXCEPTIONS=0;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <MinimalRebuild>true</MinimalRebuild>

       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

@@ -122,6 +123,7 @@
       <TreatWarningAsError>true</TreatWarningAsError>

       <ExceptionHandling>false</ExceptionHandling>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <ProjectReference>

       <LinkLibraryDependencies>false</LinkLibraryDependencies>

@@ -133,7 +135,7 @@
     </Midl>

     <ClCompile>

       <Optimization>Disabled</Optimization>

-      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;..\Common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_HAS_EXCEPTIONS=0;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <MinimalRebuild>true</MinimalRebuild>

       <ExceptionHandling>false</ExceptionHandling>

@@ -147,6 +149,7 @@
       <OmitFramePointers>false</OmitFramePointers>

       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <ProjectReference>

       <LinkLibraryDependencies>false</LinkLibraryDependencies>

@@ -160,7 +163,7 @@
       <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

       <OmitFramePointers>true</OmitFramePointers>

       <WholeProgramOptimization>true</WholeProgramOptimization>

-      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;..\Common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_SECURE_SCL=0;_HAS_EXCEPTIONS=0;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <ExceptionHandling>false</ExceptionHandling>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

@@ -176,6 +179,7 @@
       <FloatingPointExceptions>false</FloatingPointExceptions>

       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <ProjectReference>

       <LinkLibraryDependencies>false</LinkLibraryDependencies>

@@ -189,7 +193,7 @@
       <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

       <OmitFramePointers>false</OmitFramePointers>

       <WholeProgramOptimization>false</WholeProgramOptimization>

-      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;..\Common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_SECURE_SCL=0;_HAS_EXCEPTIONS=0;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <ExceptionHandling>false</ExceptionHandling>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

@@ -203,6 +207,7 @@
       <StringPooling>true</StringPooling>

       <FloatingPointExceptions>false</FloatingPointExceptions>

       <TreatWarningAsError>true</TreatWarningAsError>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <ProjectReference>

       <LinkLibraryDependencies>false</LinkLibraryDependencies>

@@ -219,7 +224,7 @@
       <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

       <OmitFramePointers>true</OmitFramePointers>

       <WholeProgramOptimization>true</WholeProgramOptimization>

-      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;..\Common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_SECURE_SCL=0;_HAS_EXCEPTIONS=0;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <ExceptionHandling>false</ExceptionHandling>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

@@ -234,6 +239,7 @@
       <FloatingPointExceptions>false</FloatingPointExceptions>

       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <ProjectReference>

       <LinkLibraryDependencies>false</LinkLibraryDependencies>

@@ -250,7 +256,7 @@
       <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

       <OmitFramePointers>false</OmitFramePointers>

       <WholeProgramOptimization>false</WholeProgramOptimization>

-      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;..\Common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;..\..\third_party\LLVM\include;..\..\third_party\LLVM\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_SECURE_SCL=0;_HAS_EXCEPTIONS=0;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <ExceptionHandling>false</ExceptionHandling>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

@@ -264,6 +270,7 @@
       <StringPooling>true</StringPooling>

       <FloatingPointExceptions>false</FloatingPointExceptions>

       <TreatWarningAsError>true</TreatWarningAsError>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <ProjectReference>

       <LinkLibraryDependencies>false</LinkLibraryDependencies>

diff --git a/src/Reactor/Subzero.vcxproj b/src/Reactor/Subzero.vcxproj
index 34e87f6..1662e0f 100644
--- a/src/Reactor/Subzero.vcxproj
+++ b/src/Reactor/Subzero.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -22,32 +22,32 @@
     <ProjectGuid>{0EB31AEC-B020-46AB-BA05-730F6D01C29B}</ProjectGuid>

     <Keyword>Win32Proj</Keyword>

     <RootNamespace>Subzero</RootNamespace>

-    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>NotSet</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>NotSet</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>NotSet</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>NotSet</CharacterSet>

   </PropertyGroup>

@@ -91,6 +91,7 @@
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

       <ForcedIncludeFiles>src/IceTypes.h</ForcedIncludeFiles>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

@@ -109,6 +110,7 @@
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

       <ForcedIncludeFiles>src/IceTypes.h</ForcedIncludeFiles>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

@@ -129,6 +131,7 @@
       <ForcedIncludeFiles>src/IceTypes.h</ForcedIncludeFiles>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

@@ -155,6 +158,7 @@
       <ForcedIncludeFiles>src/IceTypes.h</ForcedIncludeFiles>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

diff --git a/src/Reactor/SubzeroLLVMDependencies.vcxproj b/src/Reactor/SubzeroLLVMDependencies.vcxproj
index c424b47..87502e9 100644
--- a/src/Reactor/SubzeroLLVMDependencies.vcxproj
+++ b/src/Reactor/SubzeroLLVMDependencies.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -21,32 +21,32 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{E3BBD7DA-45C1-43EF-9C87-3F411031BDE4}</ProjectGuid>

     <RootNamespace>SubzeroLLVMDependencies</RootNamespace>

-    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>NotSet</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>NotSet</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>NotSet</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>NotSet</CharacterSet>

   </PropertyGroup>

@@ -78,6 +78,7 @@
       <AdditionalIncludeDirectories>$(SolutionDir)third_party\llvm-subzero\include;$(SolutionDir)third_party\llvm-subzero\build\Windows\include</AdditionalIncludeDirectories>

       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

   </ItemDefinitionGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

@@ -89,6 +90,7 @@
       <AdditionalIncludeDirectories>$(SolutionDir)third_party\llvm-subzero\include;$(SolutionDir)third_party\llvm-subzero\build\Windows\include</AdditionalIncludeDirectories>

       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

   </ItemDefinitionGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

@@ -102,6 +104,7 @@
       <AdditionalIncludeDirectories>$(SolutionDir)third_party\llvm-subzero\include;$(SolutionDir)third_party\llvm-subzero\build\Windows\include</AdditionalIncludeDirectories>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <EnableCOMDATFolding>true</EnableCOMDATFolding>

@@ -119,6 +122,7 @@
       <AdditionalIncludeDirectories>$(SolutionDir)third_party\llvm-subzero\include;$(SolutionDir)third_party\llvm-subzero\build\Windows\include</AdditionalIncludeDirectories>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <EnableCOMDATFolding>true</EnableCOMDATFolding>

diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index a770981..66099ec 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -119,7 +119,7 @@
 
 	const bool CPUID::ARM = CPUID::detectARM();
 	const bool CPUID::SSE4_1 = CPUID::detectSSE4_1();
-	const bool emulateIntrinsics = CPUID::ARM;
+	const bool emulateIntrinsics = false;
 	const bool emulateMismatchedBitCast = CPUID::ARM;
 }
 
@@ -709,7 +709,7 @@
 
 	static Value *createArithmetic(Ice::InstArithmetic::OpKind op, Value *lhs, Value *rhs)
 	{
-		assert(lhs->getType() == rhs->getType() || (llvm::isa<Ice::Constant>(rhs) && (op == Ice::InstArithmetic::Shl || Ice::InstArithmetic::Lshr || Ice::InstArithmetic::Ashr)));
+		assert(lhs->getType() == rhs->getType() || llvm::isa<Ice::Constant>(rhs));
 
 		bool swapOperands = llvm::isa<Ice::Constant>(lhs) && isCommutative(op);
 
@@ -843,7 +843,7 @@
 		int valueType = (int)reinterpret_cast<intptr_t>(type);
 		Ice::Variable *result = ::function->makeVariable(T(type));
 
-		if(valueType & EmulatedBits)
+		if((valueType & EmulatedBits) && (align != 0))   // Narrow vector not stored on stack.
 		{
 			if(emulateIntrinsics)
 			{
@@ -896,7 +896,7 @@
 	{
 		int valueType = (int)reinterpret_cast<intptr_t>(type);
 
-		if(valueType & EmulatedBits)
+		if((valueType & EmulatedBits) && (align != 0))   // Narrow vector not stored on stack.
 		{
 			if(emulateIntrinsics)
 			{
@@ -941,7 +941,7 @@
 		}
 		else
 		{
-			assert(T(value->getType()) == type);
+			assert(value->getType() == T(type));
 
 			auto store = Ice::InstStore::create(::function, value, ptr, align);
 			::basicBlock->appendInst(store);
@@ -2716,9 +2716,9 @@
 		return RValue<Byte8>(Nucleus::createInsertElement(val.value, element.value, i));
 	}
 
-	RValue<Byte> Saturate(RValue<UShort> x)
+	RValue<Byte> SaturateUnsigned(RValue<Short> x)
 	{
-		return Byte(IfThenElse(Int(x) > 0xFF, Int(0xFF), Int(x)));
+		return Byte(IfThenElse(Int(x) > 0xFF, Int(0xFF), IfThenElse(Int(x) < 0, Int(0), Int(x))));
 	}
 
 	RValue<Byte8> AddSat(RValue<Byte8> x, RValue<Byte8> y)
@@ -2726,14 +2726,14 @@
 		if(emulateIntrinsics)
 		{
 			Byte8 result;
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 0))) + UShort(Int(Extract(y, 0)))), 0);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 1))) + UShort(Int(Extract(y, 1)))), 1);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 2))) + UShort(Int(Extract(y, 2)))), 2);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 3))) + UShort(Int(Extract(y, 3)))), 3);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 4))) + UShort(Int(Extract(y, 4)))), 4);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 5))) + UShort(Int(Extract(y, 5)))), 5);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 6))) + UShort(Int(Extract(y, 6)))), 6);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 7))) + UShort(Int(Extract(y, 7)))), 7);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 0)) + Int(Extract(y, 0)))), 0);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 1)) + Int(Extract(y, 1)))), 1);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 2)) + Int(Extract(y, 2)))), 2);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 3)) + Int(Extract(y, 3)))), 3);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 4)) + Int(Extract(y, 4)))), 4);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 5)) + Int(Extract(y, 5)))), 5);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 6)) + Int(Extract(y, 6)))), 6);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 7)) + Int(Extract(y, 7)))), 7);
 
 			return result;
 		}
@@ -2756,14 +2756,14 @@
 		if(emulateIntrinsics)
 		{
 			Byte8 result;
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 0))) - UShort(Int(Extract(y, 0)))), 0);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 1))) - UShort(Int(Extract(y, 1)))), 1);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 2))) - UShort(Int(Extract(y, 2)))), 2);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 3))) - UShort(Int(Extract(y, 3)))), 3);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 4))) - UShort(Int(Extract(y, 4)))), 4);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 5))) - UShort(Int(Extract(y, 5)))), 5);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 6))) - UShort(Int(Extract(y, 6)))), 6);
-			result = Insert(result, Saturate(UShort(Int(Extract(x, 7))) - UShort(Int(Extract(y, 7)))), 7);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 0)) - Int(Extract(y, 0)))), 0);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 1)) - Int(Extract(y, 1)))), 1);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 2)) - Int(Extract(y, 2)))), 2);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 3)) - Int(Extract(y, 3)))), 3);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 4)) - Int(Extract(y, 4)))), 4);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 5)) - Int(Extract(y, 5)))), 5);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 6)) - Int(Extract(y, 6)))), 6);
+			result = Insert(result, SaturateUnsigned(Short(Int(Extract(x, 7)) - Int(Extract(y, 7)))), 7);
 
 			return result;
 		}
@@ -2847,7 +2847,7 @@
 
 	RValue<Int> SignMask(RValue<Byte8> x)
 	{
-		if(emulateIntrinsics)
+		if(emulateIntrinsics || CPUID::ARM)
 		{
 			Byte8 xx = As<Byte8>(As<SByte8>(x) >> 7) & Byte8(0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80);
 			return Int(Extract(xx, 0)) | Int(Extract(xx, 1)) | Int(Extract(xx, 2)) | Int(Extract(xx, 3)) | Int(Extract(xx, 4)) | Int(Extract(xx, 5)) | Int(Extract(xx, 6)) | Int(Extract(xx, 7));
@@ -3043,7 +3043,7 @@
 		return RValue<SByte8>(Nucleus::createNot(val.value));
 	}
 
-	RValue<SByte> Saturate(RValue<Short> x)
+	RValue<SByte> SaturateSigned(RValue<Short> x)
 	{
 		return SByte(IfThenElse(Int(x) > 0x7F, Int(0x7F), IfThenElse(Int(x) < -0x80, Int(0x80), Int(x))));
 	}
@@ -3053,14 +3053,14 @@
 		if(emulateIntrinsics)
 		{
 			SByte8 result;
-			result = Insert(result, Saturate(Short(Int(Extract(x, 0))) + Short(Int(Extract(y, 0)))), 0);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 1))) + Short(Int(Extract(y, 1)))), 1);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 2))) + Short(Int(Extract(y, 2)))), 2);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 3))) + Short(Int(Extract(y, 3)))), 3);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 4))) + Short(Int(Extract(y, 4)))), 4);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 5))) + Short(Int(Extract(y, 5)))), 5);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 6))) + Short(Int(Extract(y, 6)))), 6);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 7))) + Short(Int(Extract(y, 7)))), 7);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 0)) + Int(Extract(y, 0)))), 0);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 1)) + Int(Extract(y, 1)))), 1);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 2)) + Int(Extract(y, 2)))), 2);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 3)) + Int(Extract(y, 3)))), 3);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 4)) + Int(Extract(y, 4)))), 4);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 5)) + Int(Extract(y, 5)))), 5);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 6)) + Int(Extract(y, 6)))), 6);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 7)) + Int(Extract(y, 7)))), 7);
 
 			return result;
 		}
@@ -3083,14 +3083,14 @@
 		if(emulateIntrinsics)
 		{
 			SByte8 result;
-			result = Insert(result, Saturate(Short(Int(Extract(x, 0))) - Short(Int(Extract(y, 0)))), 0);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 1))) - Short(Int(Extract(y, 1)))), 1);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 2))) - Short(Int(Extract(y, 2)))), 2);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 3))) - Short(Int(Extract(y, 3)))), 3);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 4))) - Short(Int(Extract(y, 4)))), 4);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 5))) - Short(Int(Extract(y, 5)))), 5);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 6))) - Short(Int(Extract(y, 6)))), 6);
-			result = Insert(result, Saturate(Short(Int(Extract(x, 7))) - Short(Int(Extract(y, 7)))), 7);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 0)) - Int(Extract(y, 0)))), 0);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 1)) - Int(Extract(y, 1)))), 1);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 2)) - Int(Extract(y, 2)))), 2);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 3)) - Int(Extract(y, 3)))), 3);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 4)) - Int(Extract(y, 4)))), 4);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 5)) - Int(Extract(y, 5)))), 5);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 6)) - Int(Extract(y, 6)))), 6);
+			result = Insert(result, SaturateSigned(Short(Int(Extract(x, 7)) - Int(Extract(y, 7)))), 7);
 
 			return result;
 		}
@@ -3123,7 +3123,7 @@
 
 	RValue<Int> SignMask(RValue<SByte8> x)
 	{
-		if(emulateIntrinsics)
+		if(emulateIntrinsics || CPUID::ARM)
 		{
 			SByte8 xx = (x >> 7) & SByte8(0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80);
 			return Int(Extract(xx, 0)) | Int(Extract(xx, 1)) | Int(Extract(xx, 2)) | Int(Extract(xx, 3)) | Int(Extract(xx, 4)) | Int(Extract(xx, 5)) | Int(Extract(xx, 6)) | Int(Extract(xx, 7));
@@ -3491,7 +3491,7 @@
 	RValue<Short4> RoundShort4(RValue<Float4> cast)
 	{
 		RValue<Int4> int4 = RoundInt(cast);
-		return As<Short4>(Pack(int4, int4));
+		return As<Short4>(PackSigned(int4, int4));
 	}
 
 	RValue<Short4> Max(RValue<Short4> x, RValue<Short4> y)
@@ -3520,7 +3520,7 @@
 		return RValue<Short4>(V(result));
 	}
 
-	RValue<Short> Saturate(RValue<Int> x)
+	RValue<Short> SaturateSigned(RValue<Int> x)
 	{
 		return Short(IfThenElse(x > 0x7FFF, Int(0x7FFF), IfThenElse(x < -0x8000, Int(0x8000), x)));
 	}
@@ -3530,10 +3530,10 @@
 		if(emulateIntrinsics)
 		{
 			Short4 result;
-			result = Insert(result, Saturate(Int(Extract(x, 0)) + Int(Extract(y, 0))), 0);
-			result = Insert(result, Saturate(Int(Extract(x, 1)) + Int(Extract(y, 1))), 1);
-			result = Insert(result, Saturate(Int(Extract(x, 2)) + Int(Extract(y, 2))), 2);
-			result = Insert(result, Saturate(Int(Extract(x, 3)) + Int(Extract(y, 3))), 3);
+			result = Insert(result, SaturateSigned(Int(Extract(x, 0)) + Int(Extract(y, 0))), 0);
+			result = Insert(result, SaturateSigned(Int(Extract(x, 1)) + Int(Extract(y, 1))), 1);
+			result = Insert(result, SaturateSigned(Int(Extract(x, 2)) + Int(Extract(y, 2))), 2);
+			result = Insert(result, SaturateSigned(Int(Extract(x, 3)) + Int(Extract(y, 3))), 3);
 
 			return result;
 		}
@@ -3556,10 +3556,10 @@
 		if(emulateIntrinsics)
 		{
 			Short4 result;
-			result = Insert(result, Saturate(Int(Extract(x, 0)) - Int(Extract(y, 0))), 0);
-			result = Insert(result, Saturate(Int(Extract(x, 1)) - Int(Extract(y, 1))), 1);
-			result = Insert(result, Saturate(Int(Extract(x, 2)) - Int(Extract(y, 2))), 2);
-			result = Insert(result, Saturate(Int(Extract(x, 3)) - Int(Extract(y, 3))), 3);
+			result = Insert(result, SaturateSigned(Int(Extract(x, 0)) - Int(Extract(y, 0))), 0);
+			result = Insert(result, SaturateSigned(Int(Extract(x, 1)) - Int(Extract(y, 1))), 1);
+			result = Insert(result, SaturateSigned(Int(Extract(x, 2)) - Int(Extract(y, 2))), 2);
+			result = Insert(result, SaturateSigned(Int(Extract(x, 3)) - Int(Extract(y, 3))), 3);
 
 			return result;
 		}
@@ -3627,19 +3627,19 @@
 		}
 	}
 
-	RValue<SByte8> Pack(RValue<Short4> x, RValue<Short4> y)
+	RValue<SByte8> PackSigned(RValue<Short4> x, RValue<Short4> y)
 	{
 		if(emulateIntrinsics)
 		{
 			SByte8 result;
-			result = Insert(result, Saturate(Extract(x, 0)), 0);
-			result = Insert(result, Saturate(Extract(x, 1)), 1);
-			result = Insert(result, Saturate(Extract(x, 2)), 2);
-			result = Insert(result, Saturate(Extract(x, 3)), 3);
-			result = Insert(result, Saturate(Extract(y, 0)), 4);
-			result = Insert(result, Saturate(Extract(y, 1)), 5);
-			result = Insert(result, Saturate(Extract(y, 2)), 6);
-			result = Insert(result, Saturate(Extract(y, 3)), 7);
+			result = Insert(result, SaturateSigned(Extract(x, 0)), 0);
+			result = Insert(result, SaturateSigned(Extract(x, 1)), 1);
+			result = Insert(result, SaturateSigned(Extract(x, 2)), 2);
+			result = Insert(result, SaturateSigned(Extract(x, 3)), 3);
+			result = Insert(result, SaturateSigned(Extract(y, 0)), 4);
+			result = Insert(result, SaturateSigned(Extract(y, 1)), 5);
+			result = Insert(result, SaturateSigned(Extract(y, 2)), 6);
+			result = Insert(result, SaturateSigned(Extract(y, 3)), 7);
 
 			return result;
 		}
@@ -3657,6 +3657,36 @@
 		}
 	}
 
+	RValue<Byte8> PackUnsigned(RValue<Short4> x, RValue<Short4> y)
+	{
+		if(emulateIntrinsics)
+		{
+			Byte8 result;
+			result = Insert(result, SaturateUnsigned(Extract(x, 0)), 0);
+			result = Insert(result, SaturateUnsigned(Extract(x, 1)), 1);
+			result = Insert(result, SaturateUnsigned(Extract(x, 2)), 2);
+			result = Insert(result, SaturateUnsigned(Extract(x, 3)), 3);
+			result = Insert(result, SaturateUnsigned(Extract(y, 0)), 4);
+			result = Insert(result, SaturateUnsigned(Extract(y, 1)), 5);
+			result = Insert(result, SaturateUnsigned(Extract(y, 2)), 6);
+			result = Insert(result, SaturateUnsigned(Extract(y, 3)), 7);
+
+			return result;
+		}
+		else
+		{
+			Ice::Variable *result = ::function->makeVariable(Ice::IceType_v16i8);
+			const Ice::Intrinsics::IntrinsicInfo intrinsic = {Ice::Intrinsics::VectorPackUnsigned, Ice::Intrinsics::SideEffects_F, Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_F};
+			auto target = ::context->getConstantUndef(Ice::IceType_i32);
+			auto pack = Ice::InstIntrinsicCall::create(::function, 2, result, target, intrinsic);
+			pack->addArg(x.value);
+			pack->addArg(y.value);
+			::basicBlock->appendInst(pack);
+
+			return As<Byte8>(Swizzle(As<Int4>(V(result)), 0x88));
+		}
+	}
+
 	RValue<Int2> UnpackLow(RValue<Short4> x, RValue<Short4> y)
 	{
 		int shuffle[8] = {0, 8, 1, 9, 2, 10, 3, 11};   // Real type is v8i16
@@ -3724,8 +3754,16 @@
 		{
 			if(CPUID::SSE4_1)
 			{
-				Int4 int4(Min(cast, Float4(0xFFFF)));   // packusdw takes care of 0x0000 saturation
-				*this = As<Short4>(Pack(As<UInt4>(int4), As<UInt4>(int4)));
+				// x86 produces 0x80000000 on 32-bit integer overflow/underflow.
+				// PackUnsigned takes care of 0x0000 saturation.
+				Int4 int4(Min(cast, Float4(0xFFFF)));
+				*this = As<UShort4>(PackUnsigned(int4, int4));
+			}
+			else if(CPUID::ARM)
+			{
+				// ARM saturates the 32-bit integer result on overflow/undeflow.
+				Int4 int4(cast);
+				*this = As<UShort4>(PackUnsigned(int4, int4));
 			}
 			else
 			{
@@ -3947,7 +3985,7 @@
 		return RValue<UShort4>(V(result));
 	}
 
-	RValue<UShort> SaturateUShort(RValue<Int> x)
+	RValue<UShort> SaturateUnsigned(RValue<Int> x)
 	{
 		return UShort(IfThenElse(x > 0xFFFF, Int(0xFFFF), IfThenElse(x < 0, Int(0), x)));
 	}
@@ -3957,10 +3995,10 @@
 		if(emulateIntrinsics)
 		{
 			UShort4 result;
-			result = Insert(result, SaturateUShort(Int(Extract(x, 0)) + Int(Extract(y, 0))), 0);
-			result = Insert(result, SaturateUShort(Int(Extract(x, 1)) + Int(Extract(y, 1))), 1);
-			result = Insert(result, SaturateUShort(Int(Extract(x, 2)) + Int(Extract(y, 2))), 2);
-			result = Insert(result, SaturateUShort(Int(Extract(x, 3)) + Int(Extract(y, 3))), 3);
+			result = Insert(result, SaturateUnsigned(Int(Extract(x, 0)) + Int(Extract(y, 0))), 0);
+			result = Insert(result, SaturateUnsigned(Int(Extract(x, 1)) + Int(Extract(y, 1))), 1);
+			result = Insert(result, SaturateUnsigned(Int(Extract(x, 2)) + Int(Extract(y, 2))), 2);
+			result = Insert(result, SaturateUnsigned(Int(Extract(x, 3)) + Int(Extract(y, 3))), 3);
 
 			return result;
 		}
@@ -3983,10 +4021,10 @@
 		if(emulateIntrinsics)
 		{
 			UShort4 result;
-			result = Insert(result, SaturateUShort(Int(Extract(x, 0)) - Int(Extract(y, 0))), 0);
-			result = Insert(result, SaturateUShort(Int(Extract(x, 1)) - Int(Extract(y, 1))), 1);
-			result = Insert(result, SaturateUShort(Int(Extract(x, 2)) - Int(Extract(y, 2))), 2);
-			result = Insert(result, SaturateUShort(Int(Extract(x, 3)) - Int(Extract(y, 3))), 3);
+			result = Insert(result, SaturateUnsigned(Int(Extract(x, 0)) - Int(Extract(y, 0))), 0);
+			result = Insert(result, SaturateUnsigned(Int(Extract(x, 1)) - Int(Extract(y, 1))), 1);
+			result = Insert(result, SaturateUnsigned(Int(Extract(x, 2)) - Int(Extract(y, 2))), 2);
+			result = Insert(result, SaturateUnsigned(Int(Extract(x, 3)) - Int(Extract(y, 3))), 3);
 
 			return result;
 		}
@@ -4035,36 +4073,6 @@
 		assert(false && "UNIMPLEMENTED"); return RValue<UShort4>(V(nullptr));
 	}
 
-	RValue<Byte8> Pack(RValue<UShort4> x, RValue<UShort4> y)
-	{
-		if(emulateIntrinsics)
-		{
-			Byte8 result;
-			result = Insert(result, Saturate(Extract(x, 0)), 0);
-			result = Insert(result, Saturate(Extract(x, 1)), 1);
-			result = Insert(result, Saturate(Extract(x, 2)), 2);
-			result = Insert(result, Saturate(Extract(x, 3)), 3);
-			result = Insert(result, Saturate(Extract(y, 0)), 4);
-			result = Insert(result, Saturate(Extract(y, 1)), 5);
-			result = Insert(result, Saturate(Extract(y, 2)), 6);
-			result = Insert(result, Saturate(Extract(y, 3)), 7);
-
-			return result;
-		}
-		else
-		{
-			Ice::Variable *result = ::function->makeVariable(Ice::IceType_v16i8);
-			const Ice::Intrinsics::IntrinsicInfo intrinsic = {Ice::Intrinsics::VectorPackUnsigned, Ice::Intrinsics::SideEffects_F, Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_F};
-			auto target = ::context->getConstantUndef(Ice::IceType_i32);
-			auto pack = Ice::InstIntrinsicCall::create(::function, 2, result, target, intrinsic);
-			pack->addArg(x.value);
-			pack->addArg(y.value);
-			::basicBlock->appendInst(pack);
-
-			return As<Byte8>(Swizzle(As<Int4>(V(result)), 0x88));
-		}
-	}
-
 	Type *UShort4::getType()
 	{
 		return T(Type_v4i16);
@@ -4670,7 +4678,7 @@
 
 	RValue<Int> RoundInt(RValue<Float> cast)
 	{
-		if(emulateIntrinsics)
+		if(emulateIntrinsics || CPUID::ARM)
 		{
 			// Push the fractional part off the mantissa. Accurate up to +/-2^22.
 			return Int((cast + Float(0x00C00000)) - Float(0x00C00000));
@@ -5913,7 +5921,7 @@
 
 	RValue<Int4> RoundInt(RValue<Float4> cast)
 	{
-		if(emulateIntrinsics)
+		if(emulateIntrinsics || CPUID::ARM)
 		{
 			// Push the fractional part off the mantissa. Accurate up to +/-2^22.
 			return Int4((cast + Float4(0x00C00000)) - Float4(0x00C00000));
@@ -5931,19 +5939,19 @@
 		}
 	}
 
-	RValue<Short8> Pack(RValue<Int4> x, RValue<Int4> y)
+	RValue<Short8> PackSigned(RValue<Int4> x, RValue<Int4> y)
 	{
 		if(emulateIntrinsics)
 		{
 			Short8 result;
-			result = Insert(result, Saturate(Extract(x, 0)), 0);
-			result = Insert(result, Saturate(Extract(x, 1)), 1);
-			result = Insert(result, Saturate(Extract(x, 2)), 2);
-			result = Insert(result, Saturate(Extract(x, 3)), 3);
-			result = Insert(result, Saturate(Extract(y, 0)), 4);
-			result = Insert(result, Saturate(Extract(y, 1)), 5);
-			result = Insert(result, Saturate(Extract(y, 2)), 6);
-			result = Insert(result, Saturate(Extract(y, 3)), 7);
+			result = Insert(result, SaturateSigned(Extract(x, 0)), 0);
+			result = Insert(result, SaturateSigned(Extract(x, 1)), 1);
+			result = Insert(result, SaturateSigned(Extract(x, 2)), 2);
+			result = Insert(result, SaturateSigned(Extract(x, 3)), 3);
+			result = Insert(result, SaturateSigned(Extract(y, 0)), 4);
+			result = Insert(result, SaturateSigned(Extract(y, 1)), 5);
+			result = Insert(result, SaturateSigned(Extract(y, 2)), 6);
+			result = Insert(result, SaturateSigned(Extract(y, 3)), 7);
 
 			return result;
 		}
@@ -5961,6 +5969,32 @@
 		}
 	}
 
+	RValue<UShort8> PackUnsigned(RValue<Int4> x, RValue<Int4> y)
+	{
+		if(emulateIntrinsics || !(CPUID::SSE4_1 || CPUID::ARM))
+		{
+			RValue<Int4> sx = As<Int4>(x);
+			RValue<Int4> bx = (sx & ~(sx >> 31)) - Int4(0x8000);
+
+			RValue<Int4> sy = As<Int4>(y);
+			RValue<Int4> by = (sy & ~(sy >> 31)) - Int4(0x8000);
+
+			return As<UShort8>(PackSigned(bx, by) + Short8(0x8000u));
+		}
+		else
+		{
+			Ice::Variable *result = ::function->makeVariable(Ice::IceType_v8i16);
+			const Ice::Intrinsics::IntrinsicInfo intrinsic = {Ice::Intrinsics::VectorPackUnsigned, Ice::Intrinsics::SideEffects_F, Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_F};
+			auto target = ::context->getConstantUndef(Ice::IceType_i32);
+			auto pack = Ice::InstIntrinsicCall::create(::function, 2, result, target, intrinsic);
+			pack->addArg(x.value);
+			pack->addArg(y.value);
+			::basicBlock->appendInst(pack);
+
+			return RValue<UShort8>(V(result));
+		}
+	}
+
 	RValue<Int> Extract(RValue<Int4> x, int i)
 	{
 		return RValue<Int>(Nucleus::createExtractElement(x.value, Int::getType(), i));
@@ -5973,7 +6007,7 @@
 
 	RValue<Int> SignMask(RValue<Int4> x)
 	{
-		if(emulateIntrinsics)
+		if(emulateIntrinsics || CPUID::ARM)
 		{
 			Int4 xx = (x >> 31) & Int4(0x00000001, 0x00000002, 0x00000004, 0x00000008);
 			return Extract(xx, 0) | Extract(xx, 1) | Extract(xx, 2) | Extract(xx, 3);
@@ -6329,32 +6363,6 @@
 		return RValue<UInt4>(V(result));
 	}
 
-	RValue<UShort8> Pack(RValue<UInt4> x, RValue<UInt4> y)
-	{
-		if(CPUID::SSE4_1)
-		{
-			Ice::Variable *result = ::function->makeVariable(Ice::IceType_v8i16);
-			const Ice::Intrinsics::IntrinsicInfo intrinsic = {Ice::Intrinsics::VectorPackUnsigned, Ice::Intrinsics::SideEffects_F, Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_F};
-			auto target = ::context->getConstantUndef(Ice::IceType_i32);
-			auto pack = Ice::InstIntrinsicCall::create(::function, 2, result, target, intrinsic);
-			pack->addArg(x.value);
-			pack->addArg(y.value);
-			::basicBlock->appendInst(pack);
-
-			return RValue<UShort8>(V(result));
-		}
-		else
-		{
-			RValue<Int4> sx = As<Int4>(x);
-			RValue<Int4> bx = (sx & ~(sx >> 31)) - Int4(0x8000);
-
-			RValue<Int4> sy = As<Int4>(y);
-			RValue<Int4> by = (sy & ~(sy >> 31)) - Int4(0x8000);
-
-			return As<UShort8>(Pack(bx, by) + Short8(0x8000u));
-		}
-	}
-
 	Type *UInt4::getType()
 	{
 		return T(Ice::IceType_v4i32);
@@ -6837,7 +6845,7 @@
 
 	RValue<Float4> Sqrt(RValue<Float4> x)
 	{
-		if(emulateIntrinsics)
+		if(emulateIntrinsics || CPUID::ARM)
 		{
 			Float4 result;
 			result.x = Sqrt(Float(Float4(x).x));
@@ -6911,7 +6919,7 @@
 
 	RValue<Int> SignMask(RValue<Float4> x)
 	{
-		if(emulateIntrinsics)
+		if(emulateIntrinsics || CPUID::ARM)
 		{
 			Int4 xx = (As<Int4>(x) >> 31) & Int4(0x00000001, 0x00000002, 0x00000004, 0x00000008);
 			return Extract(xx, 0) | Extract(xx, 1) | Extract(xx, 2) | Extract(xx, 3);
@@ -6959,9 +6967,19 @@
 		return RValue<Int4>(Nucleus::createFCmpOGT(x.value, y.value));
 	}
 
+	RValue<Int4> IsInf(RValue<Float4> x)
+	{
+		return CmpEQ(As<Int4>(x) & Int4(0x7FFFFFFF), Int4(0x7F800000));
+	}
+
+	RValue<Int4> IsNan(RValue<Float4> x)
+	{
+		return ~CmpEQ(x, x);
+	}
+
 	RValue<Float4> Round(RValue<Float4> x)
 	{
-		if(emulateIntrinsics)
+		if(emulateIntrinsics || CPUID::ARM)
 		{
 			// Push the fractional part off the mantissa. Accurate up to +/-2^22.
 			return (x + Float4(0x00C00000)) - Float4(0x00C00000);
diff --git a/src/Reactor/SubzeroTest.vcxproj b/src/Reactor/SubzeroTest.vcxproj
index 4428ece..febe352 100644
--- a/src/Reactor/SubzeroTest.vcxproj
+++ b/src/Reactor/SubzeroTest.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -22,32 +22,32 @@
     <ProjectGuid>{4EC107AB-89E8-4A0B-8366-B3E81085AE07}</ProjectGuid>

     <Keyword>Win32Proj</Keyword>

     <RootNamespace>SubzeroTest</RootNamespace>

-    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

@@ -95,6 +95,7 @@
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

       <AdditionalIncludeDirectories>$(SolutionDir)third_party\googletest\googletest\include\;$(SolutionDir)third_party\googletest\googletest\;$(SolutionDir)third_party\subzero\src\;$(SolutionDir)third_party\subzero\unittest\;$(SolutionDir)third_party\llvm-subzero\include\;$(SolutionDir)third_party\llvm-subzero\build\Windows\include;SubmoduleCheck;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <ForcedIncludeFiles>gtest/gtest.h</ForcedIncludeFiles>

+      <TreatSpecificWarningsAsErrors>5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

@@ -111,6 +112,7 @@
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

       <AdditionalIncludeDirectories>$(SolutionDir)third_party\googletest\googletest\include\;$(SolutionDir)third_party\googletest\googletest\;$(SolutionDir)third_party\subzero\src\;$(SolutionDir)third_party\subzero\unittest\;$(SolutionDir)third_party\llvm-subzero\include\;$(SolutionDir)third_party\llvm-subzero\build\Windows\include;SubmoduleCheck;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <ForcedIncludeFiles>gtest/gtest.h</ForcedIncludeFiles>

+      <TreatSpecificWarningsAsErrors>5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

@@ -129,6 +131,7 @@
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

       <AdditionalIncludeDirectories>$(SolutionDir)third_party\googletest\googletest\include\;$(SolutionDir)third_party\googletest\googletest\;$(SolutionDir)third_party\subzero\src\;$(SolutionDir)third_party\subzero\unittest\;$(SolutionDir)third_party\llvm-subzero\include\;$(SolutionDir)third_party\llvm-subzero\build\Windows\include;SubmoduleCheck;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <ForcedIncludeFiles>gtest/gtest.h</ForcedIncludeFiles>

+      <TreatSpecificWarningsAsErrors>5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

@@ -149,6 +152,7 @@
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

       <AdditionalIncludeDirectories>$(SolutionDir)third_party\googletest\googletest\include\;$(SolutionDir)third_party\googletest\googletest\;$(SolutionDir)third_party\subzero\src\;$(SolutionDir)third_party\subzero\unittest\;$(SolutionDir)third_party\llvm-subzero\include\;$(SolutionDir)third_party\llvm-subzero\build\Windows\include;SubmoduleCheck;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <ForcedIncludeFiles>gtest/gtest.h</ForcedIncludeFiles>

+      <TreatSpecificWarningsAsErrors>5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

diff --git a/src/Reactor/x86.hpp b/src/Reactor/x86.hpp
index 5e759b3..1b8786e 100644
--- a/src/Reactor/x86.hpp
+++ b/src/Reactor/x86.hpp
@@ -66,7 +66,7 @@
 		RValue<Short4> packssdw(RValue<Int2> x, RValue<Int2> y);
 		RValue<Short8> packssdw(RValue<Int4> x, RValue<Int4> y);
 		RValue<SByte8> packsswb(RValue<Short4> x, RValue<Short4> y);
-		RValue<Byte8> packuswb(RValue<UShort4> x, RValue<UShort4> y);
+		RValue<Byte8> packuswb(RValue<Short4> x, RValue<Short4> y);
 
 		RValue<UShort8> packusdw(RValue<Int4> x, RValue<Int4> y);
 
diff --git a/src/Renderer/BUILD.gn b/src/Renderer/BUILD.gn
index a8ad847..04ccd2e 100644
--- a/src/Renderer/BUILD.gn
+++ b/src/Renderer/BUILD.gn
@@ -60,8 +60,5 @@
   include_dirs = [
     ".",
     "..",
-    "../Common",
-    "../Main",
-    "../Shader",
   ]
 }
diff --git a/src/Renderer/Blitter.cpp b/src/Renderer/Blitter.cpp
index 0c4a160..3cb0fc9 100644
--- a/src/Renderer/Blitter.cpp
+++ b/src/Renderer/Blitter.cpp
@@ -14,6 +14,7 @@
 
 #include "Blitter.hpp"
 
+#include "Shader/ShaderCore.hpp"
 #include "Reactor/Reactor.hpp"
 #include "Common/Memory.hpp"
 #include "Common/Debug.hpp"
@@ -22,7 +23,7 @@
 {
 	Blitter::Blitter()
 	{
-		blitCache = new RoutineCache<BlitState>(1024);
+		blitCache = new RoutineCache<State>(1024);
 	}
 
 	Blitter::~Blitter()
@@ -30,7 +31,7 @@
 		delete blitCache;
 	}
 
-	void Blitter::clear(void* pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask)
+	void Blitter::clear(void *pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask)
 	{
 		if(fastClear(pixel, format, dest, dRect, rgbaMask))
 		{
@@ -38,14 +39,12 @@
 		}
 
 		sw::Surface *color = sw::Surface::create(1, 1, 1, format, pixel, sw::Surface::bytes(format), sw::Surface::bytes(format));
-		Blitter::Options clearOptions = static_cast<sw::Blitter::Options>((rgbaMask & 0xF) | CLEAR_OPERATION);
-		SliceRect sRect(dRect);
-		sRect.slice = 0;
-		blit(color, sRect, dest, dRect, clearOptions);
+		SliceRectF sRect((float)dRect.x0, (float)dRect.y0, (float)dRect.x1, (float)dRect.y1, 0);
+		blit(color, sRect, dest, dRect, {rgbaMask});
 		delete color;
 	}
 
-	bool Blitter::fastClear(void* pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask)
+	bool Blitter::fastClear(void *pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask)
 	{
 		if(format != FORMAT_A32B32G32R32F)
 		{
@@ -100,26 +99,33 @@
 			return false;
 		}
 
-		uint8_t *d = (uint8_t*)dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
+		uint8_t *slice = (uint8_t*)dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
 
-		switch(Surface::bytes(dest->getFormat()))
+		for(int j = 0; j < dest->getSamples(); j++)
 		{
-		case 2:
-			for(int i = dRect.y0; i < dRect.y1; i++)
+			uint8_t *d = slice;
+
+			switch(Surface::bytes(dest->getFormat()))
 			{
-				sw::clear((uint16_t*)d, packed, dRect.x1 - dRect.x0);
-				d += dest->getInternalPitchB();
+			case 2:
+				for(int i = dRect.y0; i < dRect.y1; i++)
+				{
+					sw::clear((uint16_t*)d, packed, dRect.x1 - dRect.x0);
+					d += dest->getInternalPitchB();
+				}
+				break;
+			case 4:
+				for(int i = dRect.y0; i < dRect.y1; i++)
+				{
+					sw::clear((uint32_t*)d, packed, dRect.x1 - dRect.x0);
+					d += dest->getInternalPitchB();
+				}
+				break;
+			default:
+				assert(false);
 			}
-			break;
-		case 4:
-			for(int i = dRect.y0; i < dRect.y1; i++)
-			{
-				sw::clear((uint32_t*)d, packed, dRect.x1 - dRect.x0);
-				d += dest->getInternalPitchB();
-			}
-			break;
-		default:
-			assert(false);
+
+			slice += dest->getInternalSliceB();
 		}
 
 		dest->unlockInternal();
@@ -127,21 +133,7 @@
 		return true;
 	}
 
-	void Blitter::blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil)
-	{
-		Blitter::Options options = WRITE_RGBA;
-		if(filter)
-		{
-			options = static_cast<Blitter::Options>(options | FILTER_LINEAR);
-		}
-		if(isStencil)
-		{
-			options = static_cast<Blitter::Options>(options | USE_STENCIL);
-		}
-		blit(source, sRect, dest, dRect, options);
-	}
-
-	void Blitter::blit(Surface *source, const SliceRect &sourceRect, Surface *dest, const SliceRect &destRect, const Blitter::Options& options)
+	void Blitter::blit(Surface *source, const SliceRectF &sourceRect, Surface *dest, const SliceRect &destRect, const Blitter::Options& options)
 	{
 		if(dest->getInternalFormat() == FORMAT_NULL)
 		{
@@ -153,7 +145,7 @@
 			return;
 		}
 
-		SliceRect sRect = sourceRect;
+		SliceRectF sRect = sourceRect;
 		SliceRect dRect = destRect;
 
 		bool flipX = destRect.x0 > destRect.x1;
@@ -170,14 +162,14 @@
 			swap(sRect.y0, sRect.y1);
 		}
 
-		source->lockInternal(sRect.x0, sRect.y0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
+		source->lockInternal((int)sRect.x0, (int)sRect.y0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
 		dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
 
-		float w = static_cast<float>(sRect.x1 - sRect.x0) / static_cast<float>(dRect.x1 - dRect.x0);
-		float h = static_cast<float>(sRect.y1 - sRect.y0) / static_cast<float>(dRect.y1 - dRect.y0);
+		float w = sRect.width() / dRect.width();
+		float h = sRect.height() / dRect.height();
 
-		const float xStart = (float)sRect.x0 + 0.5f * w;
-		float y = (float)sRect.y0 + 0.5f * h;
+		const float xStart = sRect.x0 + 0.5f * w;
+		float y = sRect.y0 + 0.5f * h;
 
 		for(int j = dRect.y0; j < dRect.y1; j++)
 		{
@@ -186,7 +178,7 @@
 			for(int i = dRect.x0; i < dRect.x1; i++)
 			{
 				// FIXME: Support RGBA mask
-				dest->copyInternal(source, i, j, x, y, (options & FILTER_LINEAR) == FILTER_LINEAR);
+				dest->copyInternal(source, i, j, x, y, options.filter);
 
 				x += w;
 			}
@@ -208,13 +200,13 @@
 		float d = static_cast<float>(source->getDepth())  / static_cast<float>(dest->getDepth());
 
 		float z = 0.5f * d;
-		for(int k = 0; k < dest->getDepth(); ++k)
+		for(int k = 0; k < dest->getDepth(); k++)
 		{
 			float y = 0.5f * h;
-			for(int j = 0; j < dest->getHeight(); ++j)
+			for(int j = 0; j < dest->getHeight(); j++)
 			{
 				float x = 0.5f * w;
-				for(int i = 0; i < dest->getWidth(); ++i)
+				for(int i = 0; i < dest->getWidth(); i++)
 				{
 					dest->copyInternal(source, i, j, k, x, y, z, true);
 					x += w;
@@ -228,11 +220,11 @@
 		dest->unlockInternal();
 	}
 
-	bool Blitter::read(Float4 &c, Pointer<Byte> element, Format format)
+	bool Blitter::read(Float4 &c, Pointer<Byte> element, const State &state)
 	{
 		c = Float4(0.0f, 0.0f, 0.0f, 1.0f);
 
-		switch(format)
+		switch(state.sourceFormat)
 		{
 		case FORMAT_L8:
 			c.xyz = Float(Int(*Pointer<Byte>(element)));
@@ -242,7 +234,7 @@
 			c.w = Float(Int(*Pointer<Byte>(element)));
 			break;
 		case FORMAT_R8I:
-		case FORMAT_R8I_SNORM:
+		case FORMAT_R8_SNORM:
 			c.x = Float(Int(*Pointer<SByte>(element)));
 			c.w = float(0x7F);
 			break;
@@ -271,7 +263,7 @@
 			c = Float4(*Pointer<Byte4>(element)).zyxw;
 			break;
 		case FORMAT_A8B8G8R8I:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 			c = Float4(*Pointer<SByte4>(element));
 			break;
 		case FORMAT_A8B8G8R8:
@@ -296,7 +288,7 @@
 			c.w = float(0xFF);
 			break;
 		case FORMAT_X8B8G8R8I:
-		case FORMAT_X8B8G8R8I_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
 			c = Float4(*Pointer<SByte4>(element));
 			c.w = float(0x7F);
 			break;
@@ -336,7 +328,7 @@
 			c.w = float(0xFFFFFFFF);
 			break;
 		case FORMAT_G8R8I:
-		case FORMAT_G8R8I_SNORM:
+		case FORMAT_G8R8_SNORM:
 			c.x = Float(Int(*Pointer<SByte>(element + 0)));
 			c.y = Float(Int(*Pointer<SByte>(element + 1)));
 			c.w = float(0x7F);
@@ -372,6 +364,7 @@
 			c = *Pointer<Float4>(element);
 			break;
 		case FORMAT_X32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_B32G32R32F:
 			c.z = *Pointer<Float>(element + 8);
 		case FORMAT_G32R32F:
@@ -387,6 +380,7 @@
 			c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
 			break;
 		case FORMAT_A2B10G10R10:
+		case FORMAT_A2B10G10R10UI:
 			c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
 			c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
 			c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
@@ -401,18 +395,15 @@
 		case FORMAT_D32:
 			c.x = Float(Int((*Pointer<UInt>(element))));
 			break;
-		case FORMAT_D32F:
-			c.x = *Pointer<Float>(element);
-			break;
 		case FORMAT_D32F_COMPLEMENTARY:
+		case FORMAT_D32FS8_COMPLEMENTARY:
 			c.x = 1.0f - *Pointer<Float>(element);
 			break;
+		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_LOCKABLE:
-			c.x = *Pointer<Float>(element);
-			break;
 		case FORMAT_D32FS8_TEXTURE:
-			c.x = *Pointer<Float>(element);
-			break;
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 			c.x = *Pointer<Float>(element);
 			break;
@@ -426,15 +417,15 @@
 		return true;
 	}
 
-	bool Blitter::write(Float4 &c, Pointer<Byte> element, Format format, const Blitter::Options& options)
+	bool Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
 	{
-		bool writeR = (options & WRITE_RED) == WRITE_RED;
-		bool writeG = (options & WRITE_GREEN) == WRITE_GREEN;
-		bool writeB = (options & WRITE_BLUE) == WRITE_BLUE;
-		bool writeA = (options & WRITE_ALPHA) == WRITE_ALPHA;
+		bool writeR = state.writeRed;
+		bool writeG = state.writeGreen;
+		bool writeB = state.writeBlue;
+		bool writeA = state.writeAlpha;
 		bool writeRGBA = writeR && writeG && writeB && writeA;
 
-		switch(format)
+		switch(state.destFormat)
 		{
 		case FORMAT_L8:
 			*Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
@@ -445,8 +436,8 @@
 		case FORMAT_A8R8G8B8:
 			if(writeRGBA)
 			{
-				UShort4 c0 = As<UShort4>(RoundShort4(c.zyxw));
-				*Pointer<Byte4>(element) = Byte4(Pack(c0, c0));
+				Short4 c0 = RoundShort4(c.zyxw);
+				*Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
 			}
 			else
 			{
@@ -460,8 +451,8 @@
 		case FORMAT_SRGB8_A8:
 			if(writeRGBA)
 			{
-				UShort4 c0 = As<UShort4>(RoundShort4(c));
-				*Pointer<Byte4>(element) = Byte4(Pack(c0, c0));
+				Short4 c0 = RoundShort4(c);
+				*Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
 			}
 			else
 			{
@@ -474,8 +465,8 @@
 		case FORMAT_X8R8G8B8:
 			if(writeRGBA)
 			{
-				UShort4 c0 = As<UShort4>(RoundShort4(c.zyxw)) | UShort4(0x0000, 0x0000, 0x0000, 0xFFFFu);
-				*Pointer<Byte4>(element) = Byte4(Pack(c0, c0));
+				Short4 c0 = RoundShort4(c.zyxw) | Short4(0x0000, 0x0000, 0x0000, 0x00FF);
+				*Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
 			}
 			else
 			{
@@ -489,8 +480,8 @@
 		case FORMAT_SRGB8_X8:
 			if(writeRGBA)
 			{
-				UShort4 c0 = As<UShort4>(RoundShort4(c)) | UShort4(0x0000, 0x0000, 0x0000, 0xFFFFu);
-				*Pointer<Byte4>(element) = Byte4(Pack(c0, c0));
+				Short4 c0 = RoundShort4(c) | Short4(0x0000, 0x0000, 0x0000, 0x00FF);
+				*Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
 			}
 			else
 			{
@@ -524,6 +515,7 @@
 			}
 			break;
 		case FORMAT_X32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 			if(writeA) { *Pointer<Float>(element + 12) = 1.0f; }
 		case FORMAT_B32G32R32F:
 			if(writeR) { *Pointer<Float>(element) = c.x; }
@@ -545,26 +537,26 @@
 			if(writeR) { *Pointer<Float>(element) = c.x; }
 			break;
 		case FORMAT_A8B8G8R8I:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 			if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
 		case FORMAT_X8B8G8R8I:
-		case FORMAT_X8B8G8R8I_SNORM:
-			if(writeA && (format == FORMAT_X8B8G8R8I || format == FORMAT_X8B8G8R8I_SNORM))
+		case FORMAT_X8B8G8R8_SNORM:
+			if(writeA && (state.destFormat == FORMAT_X8B8G8R8I || state.destFormat == FORMAT_X8B8G8R8_SNORM))
 			{
 				*Pointer<SByte>(element + 3) = SByte(0x7F);
 			}
 			if(writeB) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.z))); }
 		case FORMAT_G8R8I:
-		case FORMAT_G8R8I_SNORM:
+		case FORMAT_G8R8_SNORM:
 			if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
 		case FORMAT_R8I:
-		case FORMAT_R8I_SNORM:
+		case FORMAT_R8_SNORM:
 			if(writeR) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.x))); }
 			break;
 		case FORMAT_A8B8G8R8UI:
 			if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
 		case FORMAT_X8B8G8R8UI:
-			if(writeA && (format == FORMAT_X8B8G8R8UI))
+			if(writeA && (state.destFormat == FORMAT_X8B8G8R8UI))
 			{
 				*Pointer<Byte>(element + 3) = Byte(0xFF);
 			}
@@ -738,6 +730,7 @@
 			}
 			break;
 		case FORMAT_A2B10G10R10:
+		case FORMAT_A2B10G10R10UI:
 			if(writeRGBA)
 			{
 				*Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) |
@@ -768,18 +761,15 @@
 		case FORMAT_D32:
 			*Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)));
 			break;
-		case FORMAT_D32F:
-			*Pointer<Float>(element) = c.x;
-			break;
 		case FORMAT_D32F_COMPLEMENTARY:
+		case FORMAT_D32FS8_COMPLEMENTARY:
 			*Pointer<Float>(element) = 1.0f - c.x;
 			break;
+		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_LOCKABLE:
-			*Pointer<Float>(element) = c.x;
-			break;
 		case FORMAT_D32FS8_TEXTURE:
-			*Pointer<Float>(element) = c.x;
-			break;
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 			*Pointer<Float>(element) = c.x;
 			break;
@@ -792,11 +782,11 @@
 		return true;
 	}
 
-	bool Blitter::read(Int4 &c, Pointer<Byte> element, Format format)
+	bool Blitter::read(Int4 &c, Pointer<Byte> element, const State &state)
 	{
 		c = Int4(0, 0, 0, 1);
 
-		switch(format)
+		switch(state.sourceFormat)
 		{
 		case FORMAT_A8B8G8R8I:
 			c = Insert(c, Int(*Pointer<SByte>(element + 3)), 3);
@@ -855,20 +845,20 @@
 		return true;
 	}
 
-	bool Blitter::write(Int4 &c, Pointer<Byte> element, Format format, const Blitter::Options& options)
+	bool Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
 	{
-		bool writeR = (options & WRITE_RED) == WRITE_RED;
-		bool writeG = (options & WRITE_GREEN) == WRITE_GREEN;
-		bool writeB = (options & WRITE_BLUE) == WRITE_BLUE;
-		bool writeA = (options & WRITE_ALPHA) == WRITE_ALPHA;
+		bool writeR = state.writeRed;
+		bool writeG = state.writeGreen;
+		bool writeB = state.writeBlue;
+		bool writeA = state.writeAlpha;
 		bool writeRGBA = writeR && writeG && writeB && writeA;
 
-		switch(format)
+		switch(state.destFormat)
 		{
 		case FORMAT_A8B8G8R8I:
 			if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
 		case FORMAT_X8B8G8R8I:
-			if(writeA && (format != FORMAT_A8B8G8R8I))
+			if(writeA && (state.destFormat != FORMAT_A8B8G8R8I))
 			{
 				*Pointer<SByte>(element + 3) = SByte(0x7F);
 			}
@@ -881,7 +871,7 @@
 		case FORMAT_A8B8G8R8UI:
 			if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
 		case FORMAT_X8B8G8R8UI:
-			if(writeA && (format != FORMAT_A8B8G8R8UI))
+			if(writeA && (state.destFormat != FORMAT_A8B8G8R8UI))
 			{
 				*Pointer<Byte>(element + 3) = Byte(0xFF);
 			}
@@ -894,7 +884,7 @@
 		case FORMAT_A16B16G16R16I:
 			if(writeA) { *Pointer<Short>(element + 6) = Short(Extract(c, 3)); }
 		case FORMAT_X16B16G16R16I:
-			if(writeA && (format != FORMAT_A16B16G16R16I))
+			if(writeA && (state.destFormat != FORMAT_A16B16G16R16I))
 			{
 				*Pointer<Short>(element + 6) = Short(0x7FFF);
 			}
@@ -907,7 +897,7 @@
 		case FORMAT_A16B16G16R16UI:
 			if(writeA) { *Pointer<UShort>(element + 6) = UShort(Extract(c, 3)); }
 		case FORMAT_X16B16G16R16UI:
-			if(writeA && (format != FORMAT_A16B16G16R16UI))
+			if(writeA && (state.destFormat != FORMAT_A16B16G16R16UI))
 			{
 				*Pointer<UShort>(element + 6) = UShort(0xFFFF);
 			}
@@ -990,7 +980,7 @@
 		return true;
 	}
 
-	bool Blitter::GetScale(float4& scale, Format format)
+	bool Blitter::GetScale(float4 &scale, Format format)
 	{
 		switch(format)
 		{
@@ -1008,10 +998,10 @@
 		case FORMAT_SRGB8_A8:
 			scale = vector(0xFF, 0xFF, 0xFF, 0xFF);
 			break;
-		case FORMAT_R8I_SNORM:
-		case FORMAT_G8R8I_SNORM:
-		case FORMAT_X8B8G8R8I_SNORM:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_R8_SNORM:
+		case FORMAT_G8R8_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 			scale = vector(0x7F, 0x7F, 0x7F, 0x7F);
 			break;
 		case FORMAT_A16B16G16R16:
@@ -1044,9 +1034,11 @@
 		case FORMAT_A32B32G32R32UI:
 		case FORMAT_A32B32G32R32F:
 		case FORMAT_X32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_B32G32R32F:
 		case FORMAT_G32R32F:
 		case FORMAT_R32F:
+		case FORMAT_A2B10G10R10UI:
 			scale = vector(1.0f, 1.0f, 1.0f, 1.0f);
 			break;
 		case FORMAT_R5G6B5:
@@ -1065,9 +1057,12 @@
 			scale = vector(static_cast<float>(0xFFFFFFFF), 0.0f, 0.0f, 0.0f);
 			break;
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_COMPLEMENTARY:
+		case FORMAT_D32FS8_COMPLEMENTARY:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		case FORMAT_S8:
 			scale = vector(1.0f, 1.0f, 1.0f, 1.0f);
@@ -1079,12 +1074,12 @@
 		return true;
 	}
 
-	bool Blitter::ApplyScaleAndClamp(Float4& value, const BlitState& state)
+	bool Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
 	{
 		float4 scale, unscale;
-		if(Surface::isNonNormalizedInteger(state.sourceFormat) &&
-		   !Surface::isNonNormalizedInteger(state.destFormat) &&
-		   (state.options & CLEAR_OPERATION))
+		if(state.clearOperation &&
+		   Surface::isNonNormalizedInteger(state.sourceFormat) &&
+		   !Surface::isNonNormalizedInteger(state.destFormat))
 		{
 			// If we're clearing a buffer from an int or uint color into a normalized color,
 			// then the whole range of the int or uint color must be scaled between 0 and 1.
@@ -1110,12 +1105,26 @@
 			return false;
 		}
 
-		if(unscale != scale)
+		bool srcSRGB = Surface::isSRGBformat(state.sourceFormat);
+		bool dstSRGB = Surface::isSRGBformat(state.destFormat);
+
+		if(state.convertSRGB && ((srcSRGB && !preScaled) || dstSRGB))   // One of the formats is sRGB encoded.
+		{
+			value *= preScaled ? Float4(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z, 1.0f / scale.w) : // Unapply scale
+			                     Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w); // Apply unscale
+			value = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : LinearToSRGB(value);
+			value *= Float4(scale.x, scale.y, scale.z, scale.w); // Apply scale
+		}
+		else if(unscale != scale)
 		{
 			value *= Float4(scale.x / unscale.x, scale.y / unscale.y, scale.z / unscale.z, scale.w / unscale.w);
 		}
 
-		if(Surface::isFloatFormat(state.sourceFormat) && !Surface::isFloatFormat(state.destFormat))
+		if(state.destFormat == FORMAT_X32B32G32R32F_UNSIGNED)
+		{
+			value = Max(value, Float4(0.0f));  // TODO: Only necessary if source is signed.
+		}
+		else if(Surface::isFloatFormat(state.sourceFormat) && !Surface::isFloatFormat(state.destFormat))
 		{
 			value = Min(value, Float4(scale.x, scale.y, scale.z, scale.w));
 
@@ -1128,13 +1137,45 @@
 		return true;
 	}
 
-	Int Blitter::ComputeOffset(Int& x, Int& y, Int& pitchB, int bytes, bool quadLayout)
+	Int Blitter::ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout)
 	{
-		return (quadLayout ? (y & Int(~1)) : RValue<Int>(y)) * pitchB +
-		       (quadLayout ? ((y & Int(1)) << 1) + (x * 2) - (x & Int(1)) : RValue<Int>(x)) * bytes;
+		if(!quadLayout)
+		{
+			return y * pitchB + x * bytes;
+		}
+		else
+		{
+			// (x & ~1) * 2 + (x & 1) == (x - (x & 1)) * 2 + (x & 1) == x * 2 - (x & 1) * 2 + (x & 1) == x * 2 - (x & 1)
+			return (y & Int(~1)) * pitchB +
+			       ((y & Int(1)) * 2 + x * 2 - (x & Int(1))) * bytes;
+		}
 	}
 
-	Routine *Blitter::generate(BlitState &state)
+	Float4 Blitter::LinearToSRGB(Float4 &c)
+	{
+		Float4 lc = Min(c, Float4(0.0031308f)) * Float4(12.92f);
+		Float4 ec = Float4(1.055f) * power(c, Float4(1.0f / 2.4f)) - Float4(0.055f);
+
+		Float4 s = c;
+		s.xyz = Max(lc, ec);
+
+		return s;
+	}
+
+	Float4 Blitter::sRGBtoLinear(Float4 &c)
+	{
+		Float4 lc = c * Float4(1.0f / 12.92f);
+		Float4 ec = power((c + Float4(0.055f)) * Float4(1.0f / 1.055f), Float4(2.4f));
+
+		Int4 linear = CmpLT(c, Float4(0.04045f));
+
+		Float4 s = c;
+		s.xyz = As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec)));   // FIXME: IfThenElse()
+
+		return s;
+	}
+
+	Routine *Blitter::generate(const State &state)
 	{
 		Function<Void(Pointer<Byte>)> function;
 		{
@@ -1170,11 +1211,11 @@
 			Int4 constantColorI;
 			bool hasConstantColorF = false;
 			Float4 constantColorF;
-			if(state.options & CLEAR_OPERATION)
+			if(state.clearOperation)
 			{
 				if(intBoth) // Integer types
 				{
-					if(!read(constantColorI, source, state.sourceFormat))
+					if(!read(constantColorI, source, state))
 					{
 						return nullptr;
 					}
@@ -1182,7 +1223,7 @@
 				}
 				else
 				{
-					if(!read(constantColorF, source, state.sourceFormat))
+					if(!read(constantColorF, source, state))
 					{
 						return nullptr;
 					}
@@ -1205,16 +1246,17 @@
 				For(Int i = x0d, i < x1d, i++)
 				{
 					Pointer<Byte> d = destLine + (dstQuadLayout ? (((j & Int(1)) << 1) + (i * 2) - (i & Int(1))) : RValue<Int>(i)) * dstBytes;
+
 					if(hasConstantColorI)
 					{
-						if(!write(constantColorI, d, state.destFormat, state.options))
+						if(!write(constantColorI, d, state))
 						{
 							return nullptr;
 						}
 					}
 					else if(hasConstantColorF)
 					{
-						if(!write(constantColorF, d, state.destFormat, state.options))
+						if(!write(constantColorF, d, state))
 						{
 							return nullptr;
 						}
@@ -1225,14 +1267,20 @@
 						Int X = Int(x);
 						Int Y = Int(y);
 
+						if(state.clampToEdge)
+						{
+							X = Clamp(X, 0, sWidth - 1);
+							Y = Clamp(Y, 0, sHeight - 1);
+						}
+
 						Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
 
-						if(!read(color, s, state.sourceFormat))
+						if(!read(color, s, state))
 						{
 							return nullptr;
 						}
 
-						if(!write(color, d, state.destFormat, state.options))
+						if(!write(color, d, state))
 						{
 							return nullptr;
 						}
@@ -1241,70 +1289,107 @@
 					{
 						Float4 color;
 
-						if(!(state.options & FILTER_LINEAR) || intSrc)
+						bool preScaled = false;
+						if(!state.filter || intSrc)
 						{
 							Int X = Int(x);
 							Int Y = Int(y);
 
+							if(state.clampToEdge)
+							{
+								X = Clamp(X, 0, sWidth - 1);
+								Y = Clamp(Y, 0, sHeight - 1);
+							}
+
 							Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
 
-							if(!read(color, s, state.sourceFormat))
+							if(!read(color, s, state))
 							{
 								return nullptr;
 							}
 						}
 						else   // Bilinear filtering
 						{
-							Float x0 = x - 0.5f;
-							Float y0 = y - 0.5f;
+							Float X = x;
+							Float Y = y;
+
+							if(state.clampToEdge)
+							{
+								X = Min(Max(x, 0.5f), Float(sWidth) - 0.5f);
+								Y = Min(Max(y, 0.5f), Float(sHeight) - 0.5f);
+							}
+
+							Float x0 = X - 0.5f;
+							Float y0 = Y - 0.5f;
 
 							Int X0 = Max(Int(x0), 0);
 							Int Y0 = Max(Int(y0), 0);
 
-							Int X1 = IfThenElse(X0 + 1 >= sWidth, X0, X0 + 1);
-							Int Y1 = IfThenElse(Y0 + 1 >= sHeight, Y0, Y0 + 1);
+							Int X1 = X0 + 1;
+							Int Y1 = Y0 + 1;
+							X1 = IfThenElse(X1 >= sWidth, X0, X1);
+							Y1 = IfThenElse(Y1 >= sHeight, Y0, Y1);
 
 							Pointer<Byte> s00 = source + ComputeOffset(X0, Y0, sPitchB, srcBytes, srcQuadLayout);
 							Pointer<Byte> s01 = source + ComputeOffset(X1, Y0, sPitchB, srcBytes, srcQuadLayout);
 							Pointer<Byte> s10 = source + ComputeOffset(X0, Y1, sPitchB, srcBytes, srcQuadLayout);
 							Pointer<Byte> s11 = source + ComputeOffset(X1, Y1, sPitchB, srcBytes, srcQuadLayout);
 
-							Float4 c00; if(!read(c00, s00, state.sourceFormat)) return nullptr;
-							Float4 c01; if(!read(c01, s01, state.sourceFormat)) return nullptr;
-							Float4 c10; if(!read(c10, s10, state.sourceFormat)) return nullptr;
-							Float4 c11; if(!read(c11, s11, state.sourceFormat)) return nullptr;
+							Float4 c00; if(!read(c00, s00, state)) return nullptr;
+							Float4 c01; if(!read(c01, s01, state)) return nullptr;
+							Float4 c10; if(!read(c10, s10, state)) return nullptr;
+							Float4 c11; if(!read(c11, s11, state)) return nullptr;
+
+							if(state.convertSRGB && Surface::isSRGBformat(state.sourceFormat)) // sRGB -> RGB
+							{
+								if(!ApplyScaleAndClamp(c00, state)) return nullptr;
+								if(!ApplyScaleAndClamp(c01, state)) return nullptr;
+								if(!ApplyScaleAndClamp(c10, state)) return nullptr;
+								if(!ApplyScaleAndClamp(c11, state)) return nullptr;
+								preScaled = true;
+							}
 
 							Float4 fx = Float4(x0 - Float(X0));
 							Float4 fy = Float4(y0 - Float(Y0));
+							Float4 ix = Float4(1.0f) - fx;
+							Float4 iy = Float4(1.0f) - fy;
 
-							color = c00 * (Float4(1.0f) - fx) * (Float4(1.0f) - fy) +
-							        c01 * fx * (Float4(1.0f) - fy) +
-							        c10 * (Float4(1.0f) - fx) * fy +
-							        c11 * fx * fy;
+							color = (c00 * ix + c01 * fx) * iy +
+							        (c10 * ix + c11 * fx) * fy;
 						}
 
-						if(!ApplyScaleAndClamp(color, state) || !write(color, d, state.destFormat, state.options))
+						if(!ApplyScaleAndClamp(color, state, preScaled))
 						{
 							return nullptr;
 						}
+
+						for(int s = 0; s < state.destSamples; s++)
+						{
+							if(!write(color, d, state))
+							{
+								return nullptr;
+							}
+
+							d += *Pointer<Int>(blit + OFFSET(BlitData,dSliceB));
+						}
 					}
 
-					if(!hasConstantColorI && !hasConstantColorF) { x += w; }
+					if(!state.clearOperation) { x += w; }
 				}
 
-				if(!hasConstantColorI && !hasConstantColorF) { y += h; }
+				if(!state.clearOperation) { y += h; }
 			}
 		}
 
 		return function(L"BlitRoutine");
 	}
 
-	bool Blitter::blitReactor(Surface *source, const SliceRect &sourceRect, Surface *dest, const SliceRect &destRect, const Blitter::Options& options)
+	bool Blitter::blitReactor(Surface *source, const SliceRectF &sourceRect, Surface *dest, const SliceRect &destRect, const Blitter::Options &options)
 	{
-		ASSERT(!(options & CLEAR_OPERATION) || ((source->getWidth() == 1) && (source->getHeight() == 1) && (source->getDepth() == 1)));
+		ASSERT(!options.clearOperation || ((source->getWidth() == 1) && (source->getHeight() == 1) && (source->getDepth() == 1)));
 
 		Rect dRect = destRect;
-		Rect sRect = sourceRect;
+		RectF sRect = sourceRect;
 		if(destRect.x0 > destRect.x1)
 		{
 			swap(dRect.x0, dRect.x1);
@@ -1316,15 +1401,19 @@
 			swap(sRect.y0, sRect.y1);
 		}
 
-		BlitState state;
+		State state(options);
+		state.clampToEdge = (sourceRect.x0 < 0.0f) ||
+		                    (sourceRect.y0 < 0.0f) ||
+		                    (sourceRect.x1 > (float)source->getWidth()) ||
+		                    (sourceRect.y1 > (float)source->getHeight());
 
 		bool useSourceInternal = !source->isExternalDirty();
 		bool useDestInternal = !dest->isExternalDirty();
-		bool isStencil = ((options & USE_STENCIL) == USE_STENCIL);
+		bool isStencil = options.useStencil;
 
 		state.sourceFormat = isStencil ? source->getStencilFormat() : source->getFormat(useSourceInternal);
 		state.destFormat = isStencil ? dest->getStencilFormat() : dest->getFormat(useDestInternal);
-		state.options = options;
+		state.destSamples = dest->getSamples();
 
 		criticalSection.lock();
 		Routine *blitRoutine = blitCache->query(state);
@@ -1348,7 +1437,7 @@
 
 		BlitData data;
 
-		bool isRGBA = ((options & WRITE_RGBA) == WRITE_RGBA);
+		bool isRGBA = options.writeMask == 0xF;
 		bool isEntireDest = dest->isEntire(destRect);
 
 		data.source = isStencil ? source->lockStencil(0, 0, 0, sw::PUBLIC) :
@@ -1357,11 +1446,12 @@
 		                        dest->lock(0, 0, destRect.slice, isRGBA ? (isEntireDest ? sw::LOCK_DISCARD : sw::LOCK_WRITEONLY) : sw::LOCK_READWRITE, sw::PUBLIC, useDestInternal);
 		data.sPitchB = isStencil ? source->getStencilPitchB() : source->getPitchB(useSourceInternal);
 		data.dPitchB = isStencil ? dest->getStencilPitchB() : dest->getPitchB(useDestInternal);
+		data.dSliceB = isStencil ? dest->getStencilSliceB() : dest->getSliceB(useDestInternal);
 
-		data.w = 1.0f / (dRect.x1 - dRect.x0) * (sRect.x1 - sRect.x0);
-		data.h = 1.0f / (dRect.y1 - dRect.y0) * (sRect.y1 - sRect.y0);
-		data.x0 = (float)sRect.x0 + 0.5f * data.w;
-		data.y0 = (float)sRect.y0 + 0.5f * data.h;
+		data.w = sRect.width() / dRect.width();
+		data.h = sRect.height() / dRect.height();
+		data.x0 = sRect.x0 + 0.5f * data.w;
+		data.y0 = sRect.y0 + 0.5f * data.h;
 
 		data.x0d = dRect.x0;
 		data.x1d = dRect.x1;
diff --git a/src/Renderer/Blitter.hpp b/src/Renderer/Blitter.hpp
index f04dc24..e3db745 100644
--- a/src/Renderer/Blitter.hpp
+++ b/src/Renderer/Blitter.hpp
@@ -25,29 +25,47 @@
 {
 	class Blitter
 	{
-		enum Options : unsigned char
+		struct Options
 		{
-			FILTER_POINT = 0x00,
-			WRITE_RED = 0x01,
-			WRITE_GREEN = 0x02,
-			WRITE_BLUE = 0x04,
-			WRITE_ALPHA = 0x08,
-			WRITE_RGBA = WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA,
-			FILTER_LINEAR = 0x10,
-			CLEAR_OPERATION = 0x20,
-			USE_STENCIL = 0x40,
+			Options() = default;
+			Options(bool filter, bool useStencil, bool convertSRGB)
+				: writeMask(0xF), clearOperation(false), filter(filter), useStencil(useStencil), convertSRGB(convertSRGB), clampToEdge(false) {}
+			Options(unsigned int writeMask)
+				: writeMask(writeMask), clearOperation(true), filter(false), useStencil(false), convertSRGB(true), clampToEdge(false) {}
+
+			union
+			{
+				struct
+				{
+					bool writeRed : 1;
+					bool writeGreen : 1;
+					bool writeBlue : 1;
+					bool writeAlpha : 1;
+				};
+
+				unsigned char writeMask;
+			};
+
+			bool clearOperation : 1;
+			bool filter : 1;
+			bool useStencil : 1;
+			bool convertSRGB : 1;
+			bool clampToEdge : 1;
 		};
 
-		struct BlitState
+		struct State : Options
 		{
-			bool operator==(const BlitState &state) const
+			State() = default;
+			State(const Options &options) : Options(options) {}
+
+			bool operator==(const State &state) const
 			{
-				return memcmp(this, &state, sizeof(BlitState)) == 0;
+				return memcmp(this, &state, sizeof(State)) == 0;
 			}
 
 			Format sourceFormat;
 			Format destFormat;
-			Blitter::Options options;
+			int destSamples;
 		};
 
 		struct BlitData
@@ -56,6 +74,7 @@
 			void *dest;
 			int sPitchB;
 			int dPitchB;
+			int dSliceB;
 
 			float x0;
 			float y0;
@@ -75,25 +94,26 @@
 		Blitter();
 		virtual ~Blitter();
 
-		void clear(void* pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask);
-		void blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil = false);
+		void clear(void *pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask);
+		void blit(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, const Options &options);
 		void blit3D(Surface *source, Surface *dest);
 
 	private:
-		bool fastClear(void* pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask);
+		bool fastClear(void *pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask);
 
-		bool read(Float4 &color, Pointer<Byte> element, Format format);
-		bool write(Float4 &color, Pointer<Byte> element, Format format, const Blitter::Options& options);
-		bool read(Int4 &color, Pointer<Byte> element, Format format);
-		bool write(Int4 &color, Pointer<Byte> element, Format format, const Blitter::Options& options);
+		bool read(Float4 &color, Pointer<Byte> element, const State &state);
+		bool write(Float4 &color, Pointer<Byte> element, const State &state);
+		bool read(Int4 &color, Pointer<Byte> element, const State &state);
+		bool write(Int4 &color, Pointer<Byte> element, const State &state);
 		static bool GetScale(float4& scale, Format format);
-		static bool ApplyScaleAndClamp(Float4& value, const BlitState& state);
-		static Int ComputeOffset(Int& x, Int& y, Int& pitchB, int bytes, bool quadLayout);
-		void blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, const Blitter::Options& options);
-		bool blitReactor(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, const Blitter::Options& options);
-		Routine *generate(BlitState &state);
+		static bool ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled = false);
+		static Int ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout);
+		static Float4 LinearToSRGB(Float4 &color);
+		static Float4 sRGBtoLinear(Float4 &color);
+		bool blitReactor(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, const Options &options);
+		Routine *generate(const State &state);
 
-		RoutineCache<BlitState> *blitCache;
+		RoutineCache<State> *blitCache;
 		MutexLock criticalSection;
 	};
 }
diff --git a/src/Renderer/Clipper.cpp b/src/Renderer/Clipper.cpp
index cfd859f..a100f05 100644
--- a/src/Renderer/Clipper.cpp
+++ b/src/Renderer/Clipper.cpp
@@ -16,7 +16,7 @@
 
 #include "Polygon.hpp"
 #include "Renderer.hpp"
-#include "Debug.hpp"
+#include "Common/Debug.hpp"
 
 namespace sw
 {
@@ -60,20 +60,21 @@
 
 		if(clipFlagsOr & CLIP_USER)
 		{
+			int clipFlags = draw.clipFlags;
 			DrawData &data = *draw.data;
 
 			if(polygon.n >= 3) {
-			if(draw.clipFlags & CLIP_PLANE0) clipPlane(polygon, data.clipPlane[0]);
+			if(clipFlags & CLIP_PLANE0) clipPlane(polygon, data.clipPlane[0]);
 			if(polygon.n >= 3) {
-			if(draw.clipFlags & CLIP_PLANE1) clipPlane(polygon, data.clipPlane[1]);
+			if(clipFlags & CLIP_PLANE1) clipPlane(polygon, data.clipPlane[1]);
 			if(polygon.n >= 3) {
-			if(draw.clipFlags & CLIP_PLANE2) clipPlane(polygon, data.clipPlane[2]);
+			if(clipFlags & CLIP_PLANE2) clipPlane(polygon, data.clipPlane[2]);
 			if(polygon.n >= 3) {
-			if(draw.clipFlags & CLIP_PLANE3) clipPlane(polygon, data.clipPlane[3]);
+			if(clipFlags & CLIP_PLANE3) clipPlane(polygon, data.clipPlane[3]);
 			if(polygon.n >= 3) {
-			if(draw.clipFlags & CLIP_PLANE4) clipPlane(polygon, data.clipPlane[4]);
+			if(clipFlags & CLIP_PLANE4) clipPlane(polygon, data.clipPlane[4]);
 			if(polygon.n >= 3) {
-			if(draw.clipFlags & CLIP_PLANE5) clipPlane(polygon, data.clipPlane[5]);
+			if(clipFlags & CLIP_PLANE5) clipPlane(polygon, data.clipPlane[5]);
 			}}}}}}
 		}
 
diff --git a/src/Renderer/Context.cpp b/src/Renderer/Context.cpp
index e5ee4dc..f9d72a9 100644
--- a/src/Renderer/Context.cpp
+++ b/src/Renderer/Context.cpp
@@ -14,12 +14,12 @@
 
 #include "Context.hpp"
 
-#include "PixelShader.hpp"
-#include "VertexShader.hpp"
 #include "Primitive.hpp"
 #include "Surface.hpp"
-#include "Memory.hpp"
-#include "Debug.hpp"
+#include "Shader/PixelShader.hpp"
+#include "Shader/VertexShader.hpp"
+#include "Common/Memory.hpp"
+#include "Common/Debug.hpp"
 
 #include <string.h>
 
@@ -276,6 +276,9 @@
 		cullMode = CULL_CLOCKWISE;
 		alphaReference = 0.0f;
 
+		depthBias = 0.0f;
+		slopeDepthBias = 0.0f;
+
 		for(int i = 0; i < RENDERTARGETS; i++)
 		{
 			colorWriteMask[i] = 0x0000000F;
@@ -481,7 +484,7 @@
 	{
 		if(!colorUsed()) return false;
 
-		if(pixelShaderVersion() >= 0x0300) return false;
+		if(pixelShaderModel() >= 0x0300) return false;
 
 		return fogEnable;
 	}
@@ -613,7 +616,7 @@
 
 	bool Context::isProjectionComponent(unsigned int coordinate, int component)
 	{
-		if(pixelShaderVersion() <= 0x0103 && coordinate < 8 && textureTransformProject[coordinate])
+		if(pixelShaderModel() <= 0x0103 && coordinate < 8 && textureTransformProject[coordinate])
 		{
 			if(textureTransformCount[coordinate] == 2)
 			{
@@ -1379,7 +1382,7 @@
 			return false;
 		}
 
-		if(textureTransformProject[coordinate] && pixelShaderVersion() <= 0x0103)
+		if(textureTransformProject[coordinate] && pixelShaderModel() <= 0x0103)
 		{
 			if(textureTransformCount[coordinate] == 2)
 			{
@@ -1432,14 +1435,14 @@
 		return false;
 	}
 
-	unsigned short Context::pixelShaderVersion() const
+	unsigned short Context::pixelShaderModel() const
 	{
-		return pixelShader ? pixelShader->getVersion() : 0x0000;
+		return pixelShader ? pixelShader->getShaderModel() : 0x0000;
 	}
 
-	unsigned short Context::vertexShaderVersion() const
+	unsigned short Context::vertexShaderModel() const
 	{
-		return vertexShader ? vertexShader->getVersion() : 0x0000;
+		return vertexShader ? vertexShader->getShaderModel() : 0x0000;
 	}
 
 	int Context::getMultiSampleCount() const
diff --git a/src/Renderer/Context.hpp b/src/Renderer/Context.hpp
index 640ec4e..9274233 100644
--- a/src/Renderer/Context.hpp
+++ b/src/Renderer/Context.hpp
@@ -399,8 +399,8 @@
 		bool textureActive(int coordinate);
 		bool textureActive(int coordinate, int component);
 
-		unsigned short pixelShaderVersion() const;
-		unsigned short vertexShaderVersion() const;
+		unsigned short pixelShaderModel() const;
+		unsigned short vertexShaderModel() const;
 
 		int getMultiSampleCount() const;
 		int getSuperSampleCount() const;
@@ -434,6 +434,9 @@
 		CullMode cullMode;
 		float alphaReference;
 
+		float depthBias;
+		float slopeDepthBias;
+
 		TextureStage textureStage[8];
 		Sampler sampler[TOTAL_IMAGE_UNITS];
 
@@ -462,8 +465,11 @@
 		bool textureTransformProject[8];
 
 		Surface *renderTarget[RENDERTARGETS];
+		unsigned int renderTargetLayer[RENDERTARGETS];
 		Surface *depthBuffer;
+		unsigned int depthBufferLayer;
 		Surface *stencilBuffer;
+		unsigned int stencilBufferLayer;
 
 		// Fog
 		bool fogEnable;
diff --git a/src/Renderer/ETC_Decoder.cpp b/src/Renderer/ETC_Decoder.cpp
index 8e109f3..dbc6276 100644
--- a/src/Renderer/ETC_Decoder.cpp
+++ b/src/Renderer/ETC_Decoder.cpp
@@ -26,6 +26,13 @@
 		return (value < -128) ? -128 : ((value > 127) ? 127 : value);
 	}
 
+	inline int clampEAC(int value, bool isSigned)
+	{
+		int min = isSigned ? -1023 : 0;
+		int max = isSigned ? 1023 : 2047;
+		return (value < min) ? min : ((value > max) ? max : value);
+	}
+
 	struct bgra8
 	{
 		unsigned char b;
@@ -82,35 +89,53 @@
 	struct ETC2
 	{
 		// Decodes unsigned single or dual channel block to bytes
-		static void DecodeBlock(const ETC2** sources, unsigned char *dest, int nbChannels, int x, int y, int w, int h, int pitch, bool isSigned)
+		static void DecodeBlock(const ETC2** sources, unsigned char *dest, int nbChannels, int x, int y, int w, int h, int pitch, bool isSigned, bool isEAC)
 		{
-			if(isSigned)
+			if(isEAC)
 			{
-				signed char* sDst = reinterpret_cast<signed char*>(dest);
 				for(int j = 0; j < 4 && (y + j) < h; j++)
 				{
+					int* sDst = reinterpret_cast<int*>(dest);
 					for(int i = 0; i < 4 && (x + i) < w; i++)
 					{
 						for(int c = nbChannels - 1; c >= 0; c--)
 						{
-							sDst[i * nbChannels + c] = clampSByte(sources[c]->getSingleChannel(i, j, isSigned));
+							sDst[i * nbChannels + c] = clampEAC(sources[c]->getSingleChannel(i, j, isSigned, true), isSigned);
 						}
 					}
-					sDst += pitch;
+					dest += pitch;
 				}
 			}
 			else
 			{
-				for(int j = 0; j < 4 && (y + j) < h; j++)
+				if(isSigned)
 				{
-					for(int i = 0; i < 4 && (x + i) < w; i++)
+					signed char* sDst = reinterpret_cast<signed char*>(dest);
+					for(int j = 0; j < 4 && (y + j) < h; j++)
 					{
-						for(int c = nbChannels - 1; c >= 0; c--)
+						for(int i = 0; i < 4 && (x + i) < w; i++)
 						{
-							dest[i * nbChannels + c] = clampByte(sources[c]->getSingleChannel(i, j, isSigned));
+							for(int c = nbChannels - 1; c >= 0; c--)
+							{
+								sDst[i * nbChannels + c] = clampSByte(sources[c]->getSingleChannel(i, j, isSigned, false));
+							}
 						}
+						sDst += pitch;
 					}
-					dest += pitch;
+				}
+				else
+				{
+					for(int j = 0; j < 4 && (y + j) < h; j++)
+					{
+						for(int i = 0; i < 4 && (x + i) < w; i++)
+						{
+							for(int c = nbChannels - 1; c >= 0; c--)
+							{
+								dest[i * nbChannels + c] = clampByte(sources[c]->getSingleChannel(i, j, isSigned, false));
+							}
+						}
+						dest += pitch;
+					}
 				}
 			}
 		}
@@ -591,10 +616,14 @@
 		}
 
 		// Single channel utility functions
-		inline int getSingleChannel(int x, int y, bool isSigned) const
+		inline int getSingleChannel(int x, int y, bool isSigned, bool isEAC) const
 		{
 			int codeword = isSigned ? signed_base_codeword : base_codeword;
-			return codeword + getSingleChannelModifier(x, y) * multiplier;
+			return isEAC ?
+			       ((multiplier == 0) ?
+			        (codeword * 8 + 4 + getSingleChannelModifier(x, y)) :
+			        (codeword * 8 + 4 + getSingleChannelModifier(x, y) * multiplier * 8)) :
+			       codeword + getSingleChannelModifier(x, y) * multiplier;
 		}
 
 		inline int getSingleChannelIndex(int x, int y) const
@@ -661,7 +690,7 @@
 			unsigned char *dstRow = dst + (y * dstPitch);
 			for(int x = 0; x < w; x += 4, sources[0]++)
 			{
-				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 1, x, y, dstW, dstH, dstPitch, inputType == ETC_R_SIGNED);
+				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 1, x, y, dstW, dstH, dstPitch, inputType == ETC_R_SIGNED, true);
 			}
 		}
 		break;
@@ -673,7 +702,7 @@
 			unsigned char *dstRow = dst + (y * dstPitch);
 			for(int x = 0; x < w; x += 4, sources[0] += 2, sources[1] += 2)
 			{
-				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 2, x, y, dstW, dstH, dstPitch, inputType == ETC_RG_SIGNED);
+				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 2, x, y, dstW, dstH, dstPitch, inputType == ETC_RG_SIGNED, true);
 			}
 		}
 		break;
@@ -695,7 +724,7 @@
 			for(int x = 0; x < w; x += 4)
 			{
 				// Decode Alpha
-				ETC2::DecodeBlock(&sources[0], &(alphaValues[0][0]), 1, x, y, dstW, dstH, 4, false);
+				ETC2::DecodeBlock(&sources[0], &(alphaValues[0][0]), 1, x, y, dstW, dstH, 4, false, false);
 				sources[0]++; // RGBA packets are 128 bits, so move on to the next 64 bit packet to decode the RGB color
 
 				// Decode RGB
diff --git a/src/Renderer/Matrix.cpp b/src/Renderer/Matrix.cpp
index 1b27bf8..0da07e5 100644
--- a/src/Renderer/Matrix.cpp
+++ b/src/Renderer/Matrix.cpp
@@ -15,7 +15,7 @@
 #include "Matrix.hpp"
 
 #include "Point.hpp"
-#include "Math.hpp"
+#include "Common/Math.hpp"
 
 namespace sw
 {
diff --git a/src/Renderer/PixelProcessor.cpp b/src/Renderer/PixelProcessor.cpp
index db11aed..7ae45e9 100644
--- a/src/Renderer/PixelProcessor.cpp
+++ b/src/Renderer/PixelProcessor.cpp
@@ -14,13 +14,13 @@
 
 #include "PixelProcessor.hpp"
 
-#include "PixelPipeline.hpp"
-#include "PixelProgram.hpp"
-#include "PixelShader.hpp"
 #include "Surface.hpp"
 #include "Primitive.hpp"
-#include "Constants.hpp"
-#include "Debug.hpp"
+#include "Shader/PixelPipeline.hpp"
+#include "Shader/PixelProgram.hpp"
+#include "Shader/PixelShader.hpp"
+#include "Shader/Constants.hpp"
+#include "Common/Debug.hpp"
 
 #include <string.h>
 
@@ -159,19 +159,22 @@
 		}
 	}
 
-	void PixelProcessor::setRenderTarget(int index, Surface *renderTarget)
+	void PixelProcessor::setRenderTarget(int index, Surface *renderTarget, unsigned int layer)
 	{
 		context->renderTarget[index] = renderTarget;
+		context->renderTargetLayer[index] = layer;
 	}
 
-	void PixelProcessor::setDepthBuffer(Surface *depthBuffer)
+	void PixelProcessor::setDepthBuffer(Surface *depthBuffer, unsigned int layer)
 	{
 		context->depthBuffer = depthBuffer;
+		context->depthBufferLayer = layer;
 	}
 
-	void PixelProcessor::setStencilBuffer(Surface *stencilBuffer)
+	void PixelProcessor::setStencilBuffer(Surface *stencilBuffer, unsigned int layer)
 	{
 		context->stencilBuffer = stencilBuffer;
+		context->stencilBufferLayer = layer;
 	}
 
 	void PixelProcessor::setTexCoordIndex(unsigned int stage, int texCoordIndex)
@@ -489,6 +492,15 @@
 		else ASSERT(false);
 	}
 
+	void PixelProcessor::setCompareFunc(unsigned int sampler, CompareFunc compFunc)
+	{
+		if(sampler < TEXTURE_IMAGE_UNITS)
+		{
+			context->sampler[sampler].setCompareFunc(compFunc);
+		}
+		else ASSERT(false);
+	}
+
 	void PixelProcessor::setBaseLevel(unsigned int sampler, int baseLevel)
 	{
 		if(sampler < TEXTURE_IMAGE_UNITS)
@@ -990,6 +1002,7 @@
 		state.pixelFogMode = context->pixelFogActive();
 		state.wBasedFog = context->wBasedFog && context->pixelFogActive() != FOG_NONE;
 		state.perspective = context->perspectiveActive();
+		state.depthClamp = (context->depthBias != 0.0f) || (context->slopeDepthBias != 0.0f);
 
 		if(context->alphaBlendActive())
 		{
@@ -1052,7 +1065,7 @@
 		const bool sprite = context->pointSpriteActive();
 		const bool flatShading = (context->shadingMode == SHADING_FLAT) || point;
 
-		if(context->pixelShaderVersion() < 0x0300)
+		if(context->pixelShaderModel() < 0x0300)
 		{
 			for(int coordinate = 0; coordinate < 8; coordinate++)
 			{
@@ -1069,7 +1082,7 @@
 					}
 				}
 
-				if(context->textureTransformProject[coordinate] && context->pixelShaderVersion() <= 0x0103)
+				if(context->textureTransformProject[coordinate] && context->pixelShaderModel() <= 0x0103)
 				{
 					if(context->textureTransformCount[coordinate] == 2)
 					{
@@ -1163,7 +1176,7 @@
 
 		if(!routine)
 		{
-			const bool integerPipeline = (context->pixelShaderVersion() <= 0x0104);
+			const bool integerPipeline = (context->pixelShaderModel() <= 0x0104);
 			QuadRasterizer *generator = nullptr;
 
 			if(integerPipeline)
diff --git a/src/Renderer/PixelProcessor.hpp b/src/Renderer/PixelProcessor.hpp
index 65f6b92..1954610 100644
--- a/src/Renderer/PixelProcessor.hpp
+++ b/src/Renderer/PixelProcessor.hpp
@@ -34,8 +34,8 @@
 
 			int shaderID;
 
-			bool depthOverride                        : 1;
-			bool shaderContainsKill                   : 1;
+			bool depthOverride                        : 1;   // TODO: Eliminate by querying shader.
+			bool shaderContainsKill                   : 1;   // TODO: Eliminate by querying shader.
 
 			DepthCompareMode depthCompareMode         : BITS(DEPTH_LAST);
 			AlphaCompareMode alphaCompareMode         : BITS(ALPHA_LAST);
@@ -66,6 +66,7 @@
 			bool occlusionEnabled                     : 1;
 			bool wBasedFog                            : 1;
 			bool perspective                          : 1;
+			bool depthClamp                           : 1;
 
 			bool alphaBlendActive                     : 1;
 			BlendFactor sourceBlendFactor             : BITS(BLEND_LAST);
@@ -196,9 +197,9 @@
 		void setUniformBuffer(int index, sw::Resource* buffer, int offset);
 		void lockUniformBuffers(byte** u, sw::Resource* uniformBuffers[]);
 
-		void setRenderTarget(int index, Surface *renderTarget);
-		void setDepthBuffer(Surface *depthBuffer);
-		void setStencilBuffer(Surface *stencilBuffer);
+		void setRenderTarget(int index, Surface *renderTarget, unsigned int layer = 0);
+		void setDepthBuffer(Surface *depthBuffer, unsigned int layer = 0);
+		void setStencilBuffer(Surface *stencilBuffer, unsigned int layer = 0);
 
 		void setTexCoordIndex(unsigned int stage, int texCoordIndex);
 		void setStageOperation(unsigned int stage, TextureStage::StageOperation stageOperation);
@@ -236,6 +237,7 @@
 		void setSwizzleG(unsigned int sampler, SwizzleType swizzleG);
 		void setSwizzleB(unsigned int sampler, SwizzleType swizzleB);
 		void setSwizzleA(unsigned int sampler, SwizzleType swizzleA);
+		void setCompareFunc(unsigned int sampler, CompareFunc compare);
 		void setBaseLevel(unsigned int sampler, int baseLevel);
 		void setMaxLevel(unsigned int sampler, int maxLevel);
 		void setMinLod(unsigned int sampler, float minLod);
diff --git a/src/Renderer/Primitive.hpp b/src/Renderer/Primitive.hpp
index 9f19c4b..52daa18 100644
--- a/src/Renderer/Primitive.hpp
+++ b/src/Renderer/Primitive.hpp
@@ -16,7 +16,7 @@
 #define sw_Primitive_hpp
 
 #include "Vertex.hpp"
-#include "Config.hpp"
+#include "Main/Config.hpp"
 
 namespace sw
 {
diff --git a/src/Renderer/QuadRasterizer.cpp b/src/Renderer/QuadRasterizer.cpp
index f88c39e..6b319b4 100644
--- a/src/Renderer/QuadRasterizer.cpp
+++ b/src/Renderer/QuadRasterizer.cpp
@@ -14,11 +14,11 @@
 
 #include "QuadRasterizer.hpp"
 
-#include "Math.hpp"
 #include "Primitive.hpp"
 #include "Renderer.hpp"
-#include "Constants.hpp"
-#include "Debug.hpp"
+#include "Shader/Constants.hpp"
+#include "Common/Math.hpp"
+#include "Common/Debug.hpp"
 
 namespace sw
 {
@@ -49,6 +49,7 @@
 
 		constants = *Pointer<Pointer<Byte>>(data + OFFSET(DrawData,constants));
 		occlusion = 0;
+		int clusterCount = Renderer::getClusterCount();
 
 		Do
 		{
@@ -158,7 +159,7 @@
 				}
 			}
 
-			if(veryEarlyDepthTest && state.multiSample == 1)
+			if(veryEarlyDepthTest && state.multiSample == 1 && !state.depthOverride)
 			{
 				if(!state.stencilActive && state.depthTestActive && (state.depthCompareMode == DEPTH_LESSEQUAL || state.depthCompareMode == DEPTH_LESS))   // FIXME: Both modes ok?
 				{
@@ -179,7 +180,7 @@
 
 					For(Int x = x0, x < x1, x += 2)
 					{
-						Float4 z = interpolate(xxxx, Dz[0], z, primitive + OFFSET(Primitive,z), false, false);
+						Float4 z = interpolate(xxxx, Dz[0], z, primitive + OFFSET(Primitive,z), false, false, state.depthClamp);
 
 						Float4 zValue;
 
@@ -283,13 +284,15 @@
 					for(unsigned int q = 0; q < state.multiSample; q++)
 					{
 						Short4 mask = CmpGT(xxxx, xLeft[q]) & CmpGT(xRight[q], xxxx);
-						cMask[q] = SignMask(Pack(mask, mask)) & 0x0000000F;
+						cMask[q] = SignMask(PackSigned(mask, mask)) & 0x0000000F;
 					}
 
 					quad(cBuffer, zBuffer, sBuffer, cMask, x, y);
 				}
 			}
 
+			int clusterCount = Renderer::getClusterCount();
+
 			for(int index = 0; index < RENDERTARGETS; index++)
 			{
 				if(state.colorWriteActive(index))
@@ -313,7 +316,7 @@
 		Until(y >= yMax)
 	}
 
-	Float4 QuadRasterizer::interpolate(Float4 &x, Float4 &D, Float4 &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective)
+	Float4 QuadRasterizer::interpolate(Float4 &x, Float4 &D, Float4 &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective, bool clamp)
 	{
 		Float4 interpolant = D;
 
@@ -327,6 +330,11 @@
 			}
 		}
 
+		if(clamp)
+		{
+			interpolant = Min(Max(interpolant, Float4(0.0f)), Float4(1.0f));
+		}
+
 		return interpolant;
 	}
 
diff --git a/src/Renderer/QuadRasterizer.hpp b/src/Renderer/QuadRasterizer.hpp
index 5616112..1d7681d 100644
--- a/src/Renderer/QuadRasterizer.hpp
+++ b/src/Renderer/QuadRasterizer.hpp
@@ -16,10 +16,9 @@
 #define sw_QuadRasterizer_hpp
 
 #include "Rasterizer.hpp"
-#include "ShaderCore.hpp"
-#include "PixelShader.hpp"
-
-#include "Types.hpp"
+#include "Shader/ShaderCore.hpp"
+#include "Shader/PixelShader.hpp"
+#include "Common/Types.hpp"
 
 namespace sw
 {
@@ -49,7 +48,7 @@
 
 		bool interpolateZ() const;
 		bool interpolateW() const;
-		Float4 interpolate(Float4 &x, Float4 &D, Float4 &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective);
+		Float4 interpolate(Float4 &x, Float4 &D, Float4 &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective, bool clamp);
 
 		const PixelProcessor::State &state;
 		const PixelShader *const shader;
diff --git a/src/Renderer/Rasterizer.hpp b/src/Renderer/Rasterizer.hpp
index 8d0b4fb..3811a25 100644
--- a/src/Renderer/Rasterizer.hpp
+++ b/src/Renderer/Rasterizer.hpp
@@ -16,9 +16,8 @@
 #define sw_Rasterizer_hpp
 
 #include "Context.hpp"
-
 #include "PixelProcessor.hpp"
-#include "Config.hpp"
+#include "Main/Config.hpp"
 
 namespace sw
 {
diff --git a/src/Renderer/Renderer.cpp b/src/Renderer/Renderer.cpp
index 32e2027..2bb699a 100644
--- a/src/Renderer/Renderer.cpp
+++ b/src/Renderer/Renderer.cpp
@@ -15,21 +15,21 @@
 #include "Renderer.hpp"
 
 #include "Clipper.hpp"
-#include "Math.hpp"
-#include "FrameBuffer.hpp"
-#include "Timer.hpp"
 #include "Surface.hpp"
-#include "Half.hpp"
 #include "Primitive.hpp"
 #include "Polygon.hpp"
-#include "SwiftConfig.hpp"
-#include "MutexLock.hpp"
-#include "CPUID.hpp"
-#include "Memory.hpp"
-#include "Resource.hpp"
-#include "Constants.hpp"
-#include "Debug.hpp"
+#include "Main/FrameBuffer.hpp"
+#include "Main/SwiftConfig.hpp"
 #include "Reactor/Reactor.hpp"
+#include "Shader/Constants.hpp"
+#include "Common/MutexLock.hpp"
+#include "Common/CPUID.hpp"
+#include "Common/Memory.hpp"
+#include "Common/Resource.hpp"
+#include "Common/Half.hpp"
+#include "Common/Math.hpp"
+#include "Common/Timer.hpp"
+#include "Common/Debug.hpp"
 
 #undef max
 
@@ -61,10 +61,10 @@
 	extern bool precacheSetup;
 	extern bool precachePixel;
 
-	int batchSize = 128;
-	int threadCount = 1;
-	int unitCount = 1;
-	int clusterCount = 1;
+	static const int batchSize = 128;
+	AtomicInt threadCount(1);
+	AtomicInt Renderer::unitCount(1);
+	AtomicInt Renderer::clusterCount(1);
 
 	TranscendentalPrecision logPrecision = ACCURATE;
 	TranscendentalPrecision expPrecision = ACCURATE;
@@ -281,7 +281,7 @@
 				setupPrimitives = &Renderer::setupPoints;
 			}
 
-			DrawCall *draw = 0;
+			DrawCall *draw = nullptr;
 
 			do
 			{
@@ -290,7 +290,7 @@
 					if(drawCall[i]->references == -1)
 					{
 						draw = drawCall[i];
-						drawList[nextDraw % DRAW_COUNT] = draw;
+						drawList[nextDraw & DRAW_COUNT_BITS] = draw;
 
 						break;
 					}
@@ -309,13 +309,12 @@
 			{
 				draw->queries = new std::list<Query*>();
 				bool includePrimitivesWrittenQueries = vertexState.transformFeedbackQueryEnabled && vertexState.transformFeedbackEnabled;
-				for(std::list<Query*>::iterator query = queries.begin(); query != queries.end(); query++)
+				for(auto &query : queries)
 				{
-					Query* q = *query;
-					if(includePrimitivesWrittenQueries || (q->type != Query::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN))
+					if(includePrimitivesWrittenQueries || (query->type != Query::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN))
 					{
-						atomicIncrement(&(q->reference));
-						draw->queries->push_back(q);
+						++query->reference; // Atomic
+						draw->queries->push_back(query);
 					}
 				}
 			}
@@ -402,7 +401,7 @@
 				}
 			}
 
-			if(context->pixelShaderVersion() <= 0x0104)
+			if(context->pixelShaderModel() <= 0x0104)
 			{
 				for(int stage = 0; stage < 8; stage++)
 				{
@@ -416,11 +415,11 @@
 
 			if(context->vertexShader)
 			{
-				if(context->vertexShader->getVersion() >= 0x0300)
+				if(context->vertexShader->getShaderModel() >= 0x0300)
 				{
 					for(int sampler = 0; sampler < VERTEX_TEXTURE_IMAGE_UNITS; sampler++)
 					{
-						if(vertexState.samplerState[sampler].textureType != TEXTURE_NULL)
+						if(vertexState.sampler[sampler].textureType != TEXTURE_NULL)
 						{
 							draw->texture[TEXTURE_IMAGE_UNITS + sampler] = context->texture[TEXTURE_IMAGE_UNITS + sampler];
 							draw->texture[TEXTURE_IMAGE_UNITS + sampler]->lock(PUBLIC, PRIVATE);
@@ -545,7 +544,7 @@
 
 				if(context->isDrawTriangle(false))
 				{
-					N += depthBias;
+					N += context->depthBias;
 				}
 
 				if(complementaryDepthBuffer)
@@ -583,7 +582,7 @@
 				data->halfPixelX = replicate(0.5f / W);
 				data->halfPixelY = replicate(0.5f / H);
 				data->viewportHeight = abs(viewport.height);
-				data->slopeDepthBias = slopeDepthBias;
+				data->slopeDepthBias = context->slopeDepthBias;
 				data->depthRange = Z;
 				data->depthNear = N;
 				draw->clipFlags = clipFlags;
@@ -607,7 +606,9 @@
 
 					if(draw->renderTarget[index])
 					{
-						data->colorBuffer[index] = (unsigned int*)context->renderTarget[index]->lockInternal(0, 0, q * ms, LOCK_READWRITE, MANAGED);
+						unsigned int layer = context->renderTargetLayer[index];
+						data->colorBuffer[index] = (unsigned int*)context->renderTarget[index]->lockInternal(0, 0, layer, LOCK_READWRITE, MANAGED);
+						data->colorBuffer[index] += q * ms * context->renderTarget[index]->getSliceB(true);
 						data->colorPitchB[index] = context->renderTarget[index]->getInternalPitchB();
 						data->colorSliceB[index] = context->renderTarget[index]->getInternalSliceB();
 					}
@@ -618,14 +619,18 @@
 
 				if(draw->depthBuffer)
 				{
-					data->depthBuffer = (float*)context->depthBuffer->lockInternal(0, 0, q * ms, LOCK_READWRITE, MANAGED);
+					unsigned int layer = context->depthBufferLayer;
+					data->depthBuffer = (float*)context->depthBuffer->lockInternal(0, 0, layer, LOCK_READWRITE, MANAGED);
+					data->depthBuffer += q * ms * context->depthBuffer->getSliceB(true);
 					data->depthPitchB = context->depthBuffer->getInternalPitchB();
 					data->depthSliceB = context->depthBuffer->getInternalSliceB();
 				}
 
 				if(draw->stencilBuffer)
 				{
-					data->stencilBuffer = (unsigned char*)context->stencilBuffer->lockStencil(0, 0, q * ms, MANAGED);
+					unsigned int layer = context->stencilBufferLayer;
+					data->stencilBuffer = (unsigned char*)context->stencilBuffer->lockStencil(0, 0, layer, MANAGED);
+					data->stencilBuffer += q * ms * context->stencilBuffer->getSliceB(true);
 					data->stencilPitchB = context->stencilBuffer->getStencilPitchB();
 					data->stencilSliceB = context->stencilBuffer->getStencilSliceB();
 				}
@@ -645,7 +650,7 @@
 			draw->references = (count + batch - 1) / batch;
 
 			schedulerMutex.lock();
-			nextDraw++;
+			++nextDraw; // Atomic
 			schedulerMutex.unlock();
 
 			#ifndef NDEBUG
@@ -674,18 +679,12 @@
 
 	void Renderer::clear(void *value, Format format, Surface *dest, const Rect &clearRect, unsigned int rgbaMask)
 	{
-		SliceRect rect = clearRect;
-		int samples = dest->getDepth();
-
-		for(rect.slice = 0; rect.slice < samples; rect.slice++)
-		{
-			blitter->clear(value, format, dest, rect, rgbaMask);
-		}
+		blitter->clear(value, format, dest, clearRect, rgbaMask);
 	}
 
-	void Renderer::blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil)
+	void Renderer::blit(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil, bool sRGBconversion)
 	{
-		blitter->blit(source, sRect, dest, dRect, filter, isStencil);
+		blitter->blit(source, sRect, dest, dRect, {filter, isStencil, sRGBconversion});
 	}
 
 	void Renderer::blit3D(Surface *source, Surface *dest)
@@ -750,7 +749,7 @@
 								pixelProgress[cluster].executing = true;
 
 								// Commit to the task queue
-								qHead = (qHead + 1) % 32;
+								qHead = (qHead + 1) & TASK_COUNT_BITS;
 								qSize++;
 
 								break;
@@ -769,24 +768,27 @@
 
 		for(int unit = 0; unit < unitCount; unit++)
 		{
-			DrawCall *draw = drawList[currentDraw % DRAW_COUNT];
+			DrawCall *draw = drawList[currentDraw & DRAW_COUNT_BITS];
 
-			if(draw->primitive >= draw->count)
+			int primitive = draw->primitive;
+			int count = draw->count;
+
+			if(primitive >= count)
 			{
-				currentDraw++;
+				++currentDraw; // Atomic
 
 				if(currentDraw == nextDraw)
 				{
 					return;   // No more primitives to process
 				}
 
-				draw = drawList[currentDraw % DRAW_COUNT];
+				draw = drawList[currentDraw & DRAW_COUNT_BITS];
 			}
 
 			if(!primitiveProgress[unit].references)   // Task not already being executed and not still in use by a pixel unit
 			{
-				int primitive = draw->primitive;
-				int count = draw->count;
+				primitive = draw->primitive;
+				count = draw->count;
 				int batch = draw->batchSize;
 
 				primitiveProgress[unit].drawCall = currentDraw;
@@ -802,7 +804,7 @@
 				primitiveProgress[unit].references = -1;
 
 				// Commit to the task queue
-				qHead = (qHead + 1) % 32;
+				qHead = (qHead + 1) & TASK_COUNT_BITS;
 				qSize++;
 			}
 		}
@@ -812,19 +814,21 @@
 	{
 		schedulerMutex.lock();
 
-		if((int)qSize < threadCount - threadsAwake + 1)
+		int curThreadsAwake = threadsAwake;
+
+		if((int)qSize < threadCount - curThreadsAwake + 1)
 		{
 			findAvailableTasks();
 		}
 
 		if(qSize != 0)
 		{
-			task[threadIndex] = taskQueue[(qHead - qSize) % 32];
+			task[threadIndex] = taskQueue[(qHead - qSize) & TASK_COUNT_BITS];
 			qSize--;
 
-			if(threadsAwake != threadCount)
+			if(curThreadsAwake != threadCount)
 			{
-				int wakeup = qSize - threadsAwake + 1;
+				int wakeup = qSize - curThreadsAwake + 1;
 
 				for(int i = 0; i < threadCount && wakeup > 0; i++)
 				{
@@ -834,7 +838,7 @@
 						task[i].type = Task::RESUME;
 						resume[i]->signal();
 
-						threadsAwake++;
+						++threadsAwake; // Atomic
 						wakeup--;
 					}
 				}
@@ -844,7 +848,7 @@
 		{
 			task[threadIndex].type = Task::SUSPEND;
 
-			threadsAwake--;
+			--threadsAwake; // Atomic
 		}
 
 		schedulerMutex.unlock();
@@ -864,7 +868,7 @@
 
 				int input = primitiveProgress[unit].firstPrimitive;
 				int count = primitiveProgress[unit].primitiveCount;
-				DrawCall *draw = drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
+				DrawCall *draw = drawList[primitiveProgress[unit].drawCall & DRAW_COUNT_BITS];
 				int (Renderer::*setupPrimitives)(int batch, int count) = draw->setupPrimitives;
 
 				processPrimitiveVertices(unit, input, count, draw->count, threadIndex);
@@ -899,7 +903,7 @@
 				{
 					int cluster = task[threadIndex].pixelCluster;
 					Primitive *primitive = primitiveBatch[unit];
-					DrawCall *draw = drawList[pixelProgress[cluster].drawCall % DRAW_COUNT];
+					DrawCall *draw = drawList[pixelProgress[cluster].drawCall & DRAW_COUNT_BITS];
 					DrawData *data = draw->data;
 					PixelProcessor::RoutinePointer pixelRoutine = draw->pixelPointer;
 
@@ -933,7 +937,7 @@
 		int unit = pixelTask.primitiveUnit;
 		int cluster = pixelTask.pixelCluster;
 
-		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
+		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall & DRAW_COUNT_BITS];
 		DrawData &data = *draw.data;
 		int primitive = primitiveProgress[unit].firstPrimitive;
 		int count = primitiveProgress[unit].primitiveCount;
@@ -943,15 +947,15 @@
 
 		if(pixelProgress[cluster].processedPrimitives >= draw.count)
 		{
-			pixelProgress[cluster].drawCall++;
+			++pixelProgress[cluster].drawCall; // Atomic
 			pixelProgress[cluster].processedPrimitives = 0;
 		}
 
-		int ref = atomicDecrement(&primitiveProgress[unit].references);
+		int ref = primitiveProgress[unit].references--; // Atomic
 
 		if(ref == 0)
 		{
-			ref = atomicDecrement(&draw.references);
+			ref = draw.references--; // Atomic
 
 			if(ref == 0)
 			{
@@ -967,26 +971,24 @@
 
 				if(draw.queries)
 				{
-					for(std::list<Query*>::iterator q = draw.queries->begin(); q != draw.queries->end(); q++)
+					for(auto &query : *(draw.queries))
 					{
-						Query *query = *q;
-
 						switch(query->type)
 						{
 						case Query::FRAGMENTS_PASSED:
 							for(int cluster = 0; cluster < clusterCount; cluster++)
 							{
-								atomicAdd((volatile int*)&query->data, data.occlusion[cluster]);
+								query->data += data.occlusion[cluster];
 							}
 							break;
 						case Query::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
-							atomicAdd((volatile int*)&query->data, processedPrimitives);
+							query->data += processedPrimitives;
 							break;
 						default:
 							break;
 						}
 
-						atomicDecrement(&query->reference);
+						--query->reference; // Atomic
 					}
 
 					delete draw.queries;
@@ -1069,17 +1071,18 @@
 	void Renderer::processPrimitiveVertices(int unit, unsigned int start, unsigned int triangleCount, unsigned int loop, int thread)
 	{
 		Triangle *triangle = triangleBatch[unit];
-		DrawCall *draw = drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
+		int primitiveDrawCall = primitiveProgress[unit].drawCall;
+		DrawCall *draw = drawList[primitiveDrawCall & DRAW_COUNT_BITS];
 		DrawData *data = draw->data;
 		VertexTask *task = vertexTask[thread];
 
 		const void *indices = data->indices;
 		VertexProcessor::RoutinePointer vertexRoutine = draw->vertexPointer;
 
-		if(task->vertexCache.drawCall != primitiveProgress[unit].drawCall)
+		if(task->vertexCache.drawCall != primitiveDrawCall)
 		{
 			task->vertexCache.clear();
-			task->vertexCache.drawCall = primitiveProgress[unit].drawCall;
+			task->vertexCache.drawCall = primitiveDrawCall;
 		}
 
 		unsigned int batch[128][3];   // FIXME: Adjust to dynamic batch size
@@ -1162,9 +1165,18 @@
 
 				for(unsigned int i = 0; i < triangleCount; i++)
 				{
-					batch[i][0] = index + 0;
-					batch[i][1] = index + (index & 1) + 1;
-					batch[i][2] = index + (~index & 1) + 1;
+					if(leadingVertexFirst)
+					{
+						batch[i][0] = index + 0;
+						batch[i][1] = index + (index & 1) + 1;
+						batch[i][2] = index + (~index & 1) + 1;
+					}
+					else
+					{
+						batch[i][0] = index + (index & 1);
+						batch[i][1] = index + (~index & 1);
+						batch[i][2] = index + 2;
+					}
 
 					index += 1;
 				}
@@ -1176,9 +1188,18 @@
 
 				for(unsigned int i = 0; i < triangleCount; i++)
 				{
-					batch[i][0] = index + 1;
-					batch[i][1] = index + 2;
-					batch[i][2] = 0;
+					if(leadingVertexFirst)
+					{
+						batch[i][0] = index + 1;
+						batch[i][1] = index + 2;
+						batch[i][2] = 0;
+					}
+					else
+					{
+						batch[i][0] = 0;
+						batch[i][1] = index + 1;
+						batch[i][2] = index + 2;
+					}
 
 					index += 1;
 				}
@@ -1499,7 +1520,7 @@
 		Triangle *triangle = triangleBatch[unit];
 		Primitive *primitive = primitiveBatch[unit];
 
-		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
+		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall & DRAW_COUNT_BITS];
 		SetupProcessor::State &state = draw.setupState;
 		const SetupProcessor::RoutinePointer &setupRoutine = draw.setupPointer;
 
@@ -1545,7 +1566,7 @@
 		Primitive *primitive = primitiveBatch[unit];
 		int visible = 0;
 
-		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
+		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall & DRAW_COUNT_BITS];
 		SetupProcessor::State &state = draw.setupState;
 
 		const Vertex &v0 = triangle[0].v0;
@@ -1602,7 +1623,7 @@
 		Primitive *primitive = primitiveBatch[unit];
 		int visible = 0;
 
-		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
+		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall & DRAW_COUNT_BITS];
 		SetupProcessor::State &state = draw.setupState;
 
 		const Vertex &v0 = triangle[0].v0;
@@ -1646,7 +1667,7 @@
 		Primitive *primitive = primitiveBatch[unit];
 		int visible = 0;
 
-		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
+		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall & DRAW_COUNT_BITS];
 		SetupProcessor::State &state = draw.setupState;
 
 		int ms = state.multiSample;
@@ -1671,7 +1692,7 @@
 		Primitive *primitive = primitiveBatch[unit];
 		int visible = 0;
 
-		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
+		DrawCall &draw = *drawList[primitiveProgress[unit].drawCall & DRAW_COUNT_BITS];
 		SetupProcessor::State &state = draw.setupState;
 
 		int ms = state.multiSample;
@@ -1722,7 +1743,7 @@
 			return false;
 		}
 
-		if(false)   // Rectangle
+		if(state.multiSample > 1)   // Rectangle
 		{
 			float4 P[4];
 			int C[4];
@@ -2382,6 +2403,18 @@
 		}
 	}
 
+	void Renderer::setCompareFunc(SamplerType type, int sampler, CompareFunc compFunc)
+	{
+		if(type == SAMPLER_PIXEL)
+		{
+			PixelProcessor::setCompareFunc(sampler, compFunc);
+		}
+		else
+		{
+			VertexProcessor::setCompareFunc(sampler, compFunc);
+		}
+	}
+
 	void Renderer::setBaseLevel(SamplerType type, int sampler, int baseLevel)
 	{
 		if(type == SAMPLER_PIXEL)
@@ -2447,12 +2480,12 @@
 
 	void Renderer::setDepthBias(float bias)
 	{
-		depthBias = bias;
+		context->depthBias = bias;
 	}
 
 	void Renderer::setSlopeDepthBias(float slopeBias)
 	{
-		slopeDepthBias = slopeBias;
+		context->slopeDepthBias = slopeBias;
 	}
 
 	void Renderer::setRasterizerDiscard(bool rasterizerDiscard)
diff --git a/src/Renderer/Renderer.hpp b/src/Renderer/Renderer.hpp
index e33f828..8893fb58 100644
--- a/src/Renderer/Renderer.hpp
+++ b/src/Renderer/Renderer.hpp
@@ -37,11 +37,6 @@
 	class Renderer;
 	struct Constants;
 
-	extern int batchSize;
-	extern int threadCount;
-	extern int unitCount;
-	extern int clusterCount;
-
 	enum TranscendentalPrecision
 	{
 		APPROXIMATE,
@@ -110,8 +105,8 @@
 		}
 
 		bool building;
-		volatile int reference;
-		volatile unsigned int data;
+		AtomicInt reference;
+		AtomicInt data;
 
 		const Type type;
 	};
@@ -213,8 +208,8 @@
 
 		~DrawCall();
 
-		DrawType drawType;
-		int batchSize;
+		AtomicInt drawType;
+		AtomicInt batchSize;
 
 		Routine *vertexRoutine;
 		Routine *setupRoutine;
@@ -247,11 +242,11 @@
 
 		std::list<Query*> *queries;
 
-		int clipFlags;
+		AtomicInt clipFlags;
 
-		volatile int primitive;    // Current primitive to enter pipeline
-		volatile int count;        // Number of primitives to render
-		volatile int references;   // Remaining references to this draw call, 0 when done drawing, -1 when resources unlocked and slot is free
+		AtomicInt primitive;    // Current primitive to enter pipeline
+		AtomicInt count;        // Number of primitives to render
+		AtomicInt references;   // Remaining references to this draw call, 0 when done drawing, -1 when resources unlocked and slot is free
 
 		DrawData *data;
 	};
@@ -279,9 +274,9 @@
 				SUSPEND
 			};
 
-			volatile Type type;
-			volatile int primitiveUnit;
-			volatile int pixelCluster;
+			AtomicInt type;
+			AtomicInt primitiveUnit;
+			AtomicInt pixelCluster;
 		};
 
 		struct PrimitiveProgress
@@ -295,11 +290,11 @@
 				references = 0;
 			}
 
-			volatile int drawCall;
-			volatile int firstPrimitive;
-			volatile int primitiveCount;
-			volatile int visible;
-			volatile int references;
+			AtomicInt drawCall;
+			AtomicInt firstPrimitive;
+			AtomicInt primitiveCount;
+			AtomicInt visible;
+			AtomicInt references;
 		};
 
 		struct PixelProgress
@@ -311,9 +306,9 @@
 				executing = false;
 			}
 
-			volatile int drawCall;
-			volatile int processedPrimitives;
-			volatile bool executing;
+			AtomicInt drawCall;
+			AtomicInt processedPrimitives;
+			AtomicInt executing;
 		};
 
 	public:
@@ -327,7 +322,7 @@
 		void draw(DrawType drawType, unsigned int indexOffset, unsigned int count, bool update = true);
 
 		void clear(void *value, Format format, Surface *dest, const Rect &rect, unsigned int rgbaMask);
-		void blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil = false);
+		void blit(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, bool filter, bool isStencil = false, bool sRGBconversion = true);
 		void blit3D(Surface *source, Surface *dest);
 
 		void setIndexBuffer(Resource *indexBuffer);
@@ -353,6 +348,7 @@
 		void setSwizzleG(SamplerType type, int sampler, SwizzleType swizzleG);
 		void setSwizzleB(SamplerType type, int sampler, SwizzleType swizzleB);
 		void setSwizzleA(SamplerType type, int sampler, SwizzleType swizzleA);
+		void setCompareFunc(SamplerType type, int sampler, CompareFunc compare);
 		void setBaseLevel(SamplerType type, int sampler, int baseLevel);
 		void setMaxLevel(SamplerType type, int sampler, int maxLevel);
 		void setMinLod(SamplerType type, int sampler, float minLod);
@@ -405,6 +401,8 @@
 			void resetTimers();
 		#endif
 
+		static int getClusterCount() { return clusterCount; }
+
 	private:
 		static void threadFunction(void *parameters);
 		void threadLoop(int threadIndex);
@@ -449,8 +447,8 @@
 		Plane clipPlane[MAX_CLIP_PLANES];   // Tranformed to clip space
 		bool updateClipPlanes;
 
-		volatile bool exitThreads;
-		volatile int threadsAwake;
+		AtomicInt exitThreads;
+		AtomicInt threadsAwake;
 		Thread *worker[16];
 		Event *resume[16];         // Events for resuming threads
 		Event *suspend[16];        // Events for suspending threads
@@ -460,16 +458,26 @@
 		PixelProgress pixelProgress[16];
 		Task task[16];   // Current tasks for threads
 
-		enum {DRAW_COUNT = 16};   // Number of draw calls buffered
+		enum {
+			DRAW_COUNT = 16,   // Number of draw calls buffered (must be power of 2)
+			DRAW_COUNT_BITS = DRAW_COUNT - 1,
+		};
 		DrawCall *drawCall[DRAW_COUNT];
 		DrawCall *drawList[DRAW_COUNT];
 
-		volatile int currentDraw;
-		volatile int nextDraw;
+		AtomicInt currentDraw;
+		AtomicInt nextDraw;
 
-		Task taskQueue[32];
-		unsigned int qHead;
-		unsigned int qSize;
+		enum {
+			TASK_COUNT = 32,   // Size of the task queue (must be power of 2)
+			TASK_COUNT_BITS = TASK_COUNT - 1,
+		};
+		Task taskQueue[TASK_COUNT];
+		AtomicInt qHead;
+		AtomicInt qSize;
+
+		static AtomicInt unitCount;
+		static AtomicInt clusterCount;
 
 		MutexLock schedulerMutex;
 
diff --git a/src/Renderer/Sampler.cpp b/src/Renderer/Sampler.cpp
index 60f5e35..85448b9 100644
--- a/src/Renderer/Sampler.cpp
+++ b/src/Renderer/Sampler.cpp
@@ -16,8 +16,8 @@
 
 #include "Context.hpp"
 #include "Surface.hpp"
-#include "PixelRoutine.hpp"
-#include "Debug.hpp"
+#include "Shader/PixelRoutine.hpp"
+#include "Common/Debug.hpp"
 
 #include <memory.h>
 #include <string.h>
@@ -61,12 +61,15 @@
 		sRGB = false;
 		gather = false;
 		highPrecisionFiltering = false;
+		border = 0;
 
 		swizzleR = SWIZZLE_RED;
 		swizzleG = SWIZZLE_GREEN;
 		swizzleB = SWIZZLE_BLUE;
 		swizzleA = SWIZZLE_ALPHA;
 
+		compare = COMPARE_BYPASS;
+
 		texture.LOD = 0.0f;
 		exp2LOD = 1.0f;
 
@@ -93,12 +96,13 @@
 			state.addressingModeV = getAddressingModeV();
 			state.addressingModeW = getAddressingModeW();
 			state.mipmapFilter = mipmapFilter();
-			state.sRGB = sRGB && Surface::isSRGBreadable(externalTextureFormat);
+			state.sRGB = (sRGB && Surface::isSRGBreadable(externalTextureFormat)) || Surface::isSRGBformat(internalTextureFormat);
 			state.swizzleR = swizzleR;
 			state.swizzleG = swizzleG;
 			state.swizzleB = swizzleB;
 			state.swizzleA = swizzleA;
 			state.highPrecisionFiltering = highPrecisionFiltering;
+			state.compare = getCompareFunc();
 
 			#if PERF_PROFILE
 				state.compressedFormat = Surface::isCompressed(externalTextureFormat);
@@ -114,7 +118,8 @@
 		{
 			Mipmap &mipmap = texture.mipmap[level];
 
-			mipmap.buffer[face] = surface->lockInternal(0, 0, 0, LOCK_UNLOCKED, PRIVATE);
+			border = surface->getBorder();
+			mipmap.buffer[face] = surface->lockInternal(-border, -border, 0, LOCK_UNLOCKED, PRIVATE);
 
 			if(face == 0)
 			{
@@ -332,6 +337,11 @@
 		this->swizzleA = swizzleA;
 	}
 
+	void Sampler::setCompareFunc(CompareFunc compare)
+	{
+		this->compare = compare;
+	}
+
 	void Sampler::setBaseLevel(int baseLevel)
 	{
 		texture.baseLevel = baseLevel;
@@ -446,9 +456,9 @@
 
 	AddressingMode Sampler::getAddressingModeU() const
 	{
-		if(hasCubeTexture())
+		if(textureType == TEXTURE_CUBE)
 		{
-			return ADDRESSING_CLAMP;
+			return border ? ADDRESSING_SEAMLESS : ADDRESSING_CLAMP;
 		}
 
 		return addressingModeU;
@@ -456,9 +466,9 @@
 
 	AddressingMode Sampler::getAddressingModeV() const
 	{
-		if(hasCubeTexture())
+		if(textureType == TEXTURE_CUBE)
 		{
-			return ADDRESSING_CLAMP;
+			return border ? ADDRESSING_SEAMLESS : ADDRESSING_CLAMP;
 		}
 
 		return addressingModeV;
@@ -466,16 +476,28 @@
 
 	AddressingMode Sampler::getAddressingModeW() const
 	{
-		if(hasCubeTexture())
-		{
-			return ADDRESSING_CLAMP;
-		}
-
-		if(textureType == TEXTURE_2D_ARRAY || textureType == TEXTURE_2D)
+		if(textureType == TEXTURE_2D_ARRAY ||
+		   textureType == TEXTURE_2D ||
+		   textureType == TEXTURE_CUBE)
 		{
 			return ADDRESSING_LAYER;
 		}
 
 		return addressingModeW;
 	}
+
+	CompareFunc Sampler::getCompareFunc() const
+	{
+		if(getTextureFilter() == FILTER_GATHER)
+		{
+			return COMPARE_BYPASS;
+		}
+
+		if(internalTextureFormat == FORMAT_D32FS8_SHADOW)
+		{
+			return COMPARE_LESSEQUAL;
+		}
+
+		return compare;
+	}
 }
diff --git a/src/Renderer/Sampler.hpp b/src/Renderer/Sampler.hpp
index 6fae602..c73721d 100644
--- a/src/Renderer/Sampler.hpp
+++ b/src/Renderer/Sampler.hpp
@@ -69,6 +69,7 @@
 	{
 		TEXTURE_NULL,
 		TEXTURE_2D,
+		TEXTURE_RECTANGLE,
 		TEXTURE_CUBE,
 		TEXTURE_3D,
 		TEXTURE_2D_ARRAY,
@@ -103,13 +104,29 @@
 		ADDRESSING_CLAMP,
 		ADDRESSING_MIRROR,
 		ADDRESSING_MIRRORONCE,
-		ADDRESSING_BORDER,
+		ADDRESSING_BORDER,     // Single color
+		ADDRESSING_SEAMLESS,   // Border of pixels
 		ADDRESSING_LAYER,
 		ADDRESSING_TEXELFETCH,
 
 		ADDRESSING_LAST = ADDRESSING_TEXELFETCH
 	};
 
+	enum CompareFunc ENUM_UNDERLYING_TYPE_UNSIGNED_INT
+	{
+		COMPARE_BYPASS,
+		COMPARE_LESSEQUAL,
+		COMPARE_GREATEREQUAL,
+		COMPARE_LESS,
+		COMPARE_GREATER,
+		COMPARE_EQUAL,
+		COMPARE_NOTEQUAL,
+		COMPARE_ALWAYS,
+		COMPARE_NEVER,
+
+		COMPARE_LAST = COMPARE_NEVER
+	};
+
 	enum SwizzleType ENUM_UNDERLYING_TYPE_UNSIGNED_INT
 	{
 		SWIZZLE_RED,
@@ -142,6 +159,7 @@
 			SwizzleType swizzleB           : BITS(SWIZZLE_LAST);
 			SwizzleType swizzleA           : BITS(SWIZZLE_LAST);
 			bool highPrecisionFiltering    : 1;
+			CompareFunc compare            : BITS(COMPARE_LAST);
 
 			#if PERF_PROFILE
 			bool compressedFormat          : 1;
@@ -170,6 +188,7 @@
 		void setSwizzleG(SwizzleType swizzleG);
 		void setSwizzleB(SwizzleType swizzleB);
 		void setSwizzleA(SwizzleType swizzleA);
+		void setCompareFunc(CompareFunc compare);
 		void setBaseLevel(int baseLevel);
 		void setMaxLevel(int maxLevel);
 		void setMinLod(float minLod);
@@ -193,6 +212,7 @@
 		AddressingMode getAddressingModeU() const;
 		AddressingMode getAddressingModeV() const;
 		AddressingMode getAddressingModeW() const;
+		CompareFunc getCompareFunc() const;
 
 		Format externalTextureFormat;
 		Format internalTextureFormat;
@@ -206,11 +226,14 @@
 		bool sRGB;
 		bool gather;
 		bool highPrecisionFiltering;
+		int border;
 
 		SwizzleType swizzleR;
 		SwizzleType swizzleG;
 		SwizzleType swizzleB;
 		SwizzleType swizzleA;
+		CompareFunc compare;
+
 		Texture texture;
 		float exp2LOD;
 
diff --git a/src/Renderer/SetupProcessor.cpp b/src/Renderer/SetupProcessor.cpp
index 772327f..c5c2a16 100644
--- a/src/Renderer/SetupProcessor.cpp
+++ b/src/Renderer/SetupProcessor.cpp
@@ -14,13 +14,13 @@
 
 #include "SetupProcessor.hpp"
 
-#include "SetupRoutine.hpp"
 #include "Primitive.hpp"
 #include "Polygon.hpp"
 #include "Context.hpp"
 #include "Renderer.hpp"
-#include "Constants.hpp"
-#include "Debug.hpp"
+#include "Shader/SetupRoutine.hpp"
+#include "Shader/Constants.hpp"
+#include "Common/Debug.hpp"
 
 namespace sw
 {
@@ -85,7 +85,7 @@
 		state.pointSprite = context->pointSpriteActive();
 		state.cullMode = context->cullMode;
 		state.twoSidedStencil = context->stencilActive() && context->twoSidedStencil;
-		state.slopeDepthBias = slopeDepthBias != 0.0f;
+		state.slopeDepthBias = context->slopeDepthBias != 0.0f;
 		state.vFace = context->pixelShader && context->pixelShader->isVFaceDeclared();
 
 		state.positionRegister = Pos;
@@ -183,7 +183,7 @@
 				}
 			}
 		}
-		else if(context->pixelShaderVersion() < 0x0300)
+		else if(context->pixelShaderModel() < 0x0300)
 		{
 			for(int coordinate = 0; coordinate < 8; coordinate++)
 			{
diff --git a/src/Renderer/SetupProcessor.hpp b/src/Renderer/SetupProcessor.hpp
index 2750d4c..be0adc7 100644
--- a/src/Renderer/SetupProcessor.hpp
+++ b/src/Renderer/SetupProcessor.hpp
@@ -95,9 +95,6 @@
 
 		void setRoutineCacheSize(int cacheSize);
 
-		float depthBias;
-		float slopeDepthBias;
-
 	private:
 		Context *const context;
 
diff --git a/src/Renderer/Stream.hpp b/src/Renderer/Stream.hpp
index 88c0840..969d8b2 100644
--- a/src/Renderer/Stream.hpp
+++ b/src/Renderer/Stream.hpp
@@ -39,7 +39,7 @@
 		STREAMTYPE_2_10_10_10_INT,
 		STREAMTYPE_2_10_10_10_UINT,
 
-		STREAMTYPE_LAST = STREAMTYPE_HALF
+		STREAMTYPE_LAST = STREAMTYPE_2_10_10_10_UINT
 	};
 
 	struct StreamResource
diff --git a/src/Renderer/Surface.cpp b/src/Renderer/Surface.cpp
index 6bcc657..8bb80ec 100644
--- a/src/Renderer/Surface.cpp
+++ b/src/Renderer/Surface.cpp
@@ -42,326 +42,352 @@
 	unsigned int *Surface::palette = 0;
 	unsigned int Surface::paletteID = 0;
 
-	void Rect::clip(int minX, int minY, int maxX, int maxY)
-	{
-		x0 = clamp(x0, minX, maxX);
-		y0 = clamp(y0, minY, maxY);
-		x1 = clamp(x1, minX, maxX);
-		y1 = clamp(y1, minY, maxY);
-	}
-
 	void Surface::Buffer::write(int x, int y, int z, const Color<float> &color)
 	{
-		void *element = (unsigned char*)buffer + x * bytes + y * pitchB + z * sliceB;
+		byte *element = (byte*)buffer + (x + border) * bytes + (y + border) * pitchB + z * samples * sliceB;
 
-		write(element, color);
+		for(int i = 0; i < samples; i++)
+		{
+			write(element, color);
+			element += sliceB;
+		}
 	}
 
 	void Surface::Buffer::write(int x, int y, const Color<float> &color)
 	{
-		void *element = (unsigned char*)buffer + x * bytes + y * pitchB;
+		byte *element = (byte*)buffer + (x + border) * bytes + (y + border) * pitchB;
 
-		write(element, color);
+		for(int i = 0; i < samples; i++)
+		{
+			write(element, color);
+			element += sliceB;
+		}
 	}
 
 	inline void Surface::Buffer::write(void *element, const Color<float> &color)
 	{
+		float r = color.r;
+		float g = color.g;
+		float b = color.b;
+		float a = color.a;
+
+		if(isSRGBformat(format))
+		{
+			r = linearToSRGB(r);
+			g = linearToSRGB(g);
+			b = linearToSRGB(b);
+		}
+
 		switch(format)
 		{
 		case FORMAT_A8:
-			*(unsigned char*)element = unorm<8>(color.a);
+			*(unsigned char*)element = unorm<8>(a);
 			break;
-		case FORMAT_R8I_SNORM:
-			*(char*)element = snorm<8>(color.r);
+		case FORMAT_R8_SNORM:
+			*(char*)element = snorm<8>(r);
 			break;
 		case FORMAT_R8:
-			*(unsigned char*)element = unorm<8>(color.r);
+			*(unsigned char*)element = unorm<8>(r);
 			break;
 		case FORMAT_R8I:
-			*(char*)element = scast<8>(color.r);
+			*(char*)element = scast<8>(r);
 			break;
 		case FORMAT_R8UI:
-			*(unsigned char*)element = ucast<8>(color.r);
+			*(unsigned char*)element = ucast<8>(r);
 			break;
 		case FORMAT_R16I:
-			*(short*)element = scast<16>(color.r);
+			*(short*)element = scast<16>(r);
 			break;
 		case FORMAT_R16UI:
-			*(unsigned short*)element = ucast<16>(color.r);
+			*(unsigned short*)element = ucast<16>(r);
 			break;
 		case FORMAT_R32I:
-			*(int*)element = static_cast<int>(color.r);
+			*(int*)element = static_cast<int>(r);
 			break;
 		case FORMAT_R32UI:
-			*(unsigned int*)element = static_cast<unsigned int>(color.r);
+			*(unsigned int*)element = static_cast<unsigned int>(r);
 			break;
 		case FORMAT_R3G3B2:
-			*(unsigned char*)element = (unorm<3>(color.r) << 5) | (unorm<3>(color.g) << 2) | (unorm<2>(color.b) << 0);
+			*(unsigned char*)element = (unorm<3>(r) << 5) | (unorm<3>(g) << 2) | (unorm<2>(b) << 0);
 			break;
 		case FORMAT_A8R3G3B2:
-			*(unsigned short*)element = (unorm<8>(color.a) << 8) | (unorm<3>(color.r) << 5) | (unorm<3>(color.g) << 2) | (unorm<2>(color.b) << 0);
+			*(unsigned short*)element = (unorm<8>(a) << 8) | (unorm<3>(r) << 5) | (unorm<3>(g) << 2) | (unorm<2>(b) << 0);
 			break;
 		case FORMAT_X4R4G4B4:
-			*(unsigned short*)element = 0xF000 | (unorm<4>(color.r) << 8) | (unorm<4>(color.g) << 4) | (unorm<4>(color.b) << 0);
+			*(unsigned short*)element = 0xF000 | (unorm<4>(r) << 8) | (unorm<4>(g) << 4) | (unorm<4>(b) << 0);
 			break;
 		case FORMAT_A4R4G4B4:
-			*(unsigned short*)element = (unorm<4>(color.a) << 12) | (unorm<4>(color.r) << 8) | (unorm<4>(color.g) << 4) | (unorm<4>(color.b) << 0);
+			*(unsigned short*)element = (unorm<4>(a) << 12) | (unorm<4>(r) << 8) | (unorm<4>(g) << 4) | (unorm<4>(b) << 0);
 			break;
 		case FORMAT_R4G4B4A4:
-			*(unsigned short*)element = (unorm<4>(color.r) << 12) | (unorm<4>(color.g) << 8) | (unorm<4>(color.b) << 4) | (unorm<4>(color.a) << 0);
+			*(unsigned short*)element = (unorm<4>(r) << 12) | (unorm<4>(g) << 8) | (unorm<4>(b) << 4) | (unorm<4>(a) << 0);
 			break;
 		case FORMAT_R5G6B5:
-			*(unsigned short*)element = (unorm<5>(color.r) << 11) | (unorm<6>(color.g) << 5) | (unorm<5>(color.b) << 0);
+			*(unsigned short*)element = (unorm<5>(r) << 11) | (unorm<6>(g) << 5) | (unorm<5>(b) << 0);
 			break;
 		case FORMAT_A1R5G5B5:
-			*(unsigned short*)element = (unorm<1>(color.a) << 15) | (unorm<5>(color.r) << 10) | (unorm<5>(color.g) << 5) | (unorm<5>(color.b) << 0);
+			*(unsigned short*)element = (unorm<1>(a) << 15) | (unorm<5>(r) << 10) | (unorm<5>(g) << 5) | (unorm<5>(b) << 0);
 			break;
 		case FORMAT_R5G5B5A1:
-			*(unsigned short*)element = (unorm<5>(color.r) << 11) | (unorm<5>(color.g) << 6) | (unorm<5>(color.b) << 1) | (unorm<5>(color.a) << 0);
+			*(unsigned short*)element = (unorm<5>(r) << 11) | (unorm<5>(g) << 6) | (unorm<5>(b) << 1) | (unorm<5>(a) << 0);
 			break;
 		case FORMAT_X1R5G5B5:
-			*(unsigned short*)element = 0x8000 | (unorm<5>(color.r) << 10) | (unorm<5>(color.g) << 5) | (unorm<5>(color.b) << 0);
+			*(unsigned short*)element = 0x8000 | (unorm<5>(r) << 10) | (unorm<5>(g) << 5) | (unorm<5>(b) << 0);
 			break;
 		case FORMAT_A8R8G8B8:
-			*(unsigned int*)element = (unorm<8>(color.a) << 24) | (unorm<8>(color.r) << 16) | (unorm<8>(color.g) << 8) | (unorm<8>(color.b) << 0);
+			*(unsigned int*)element = (unorm<8>(a) << 24) | (unorm<8>(r) << 16) | (unorm<8>(g) << 8) | (unorm<8>(b) << 0);
 			break;
 		case FORMAT_X8R8G8B8:
-			*(unsigned int*)element = 0xFF000000 | (unorm<8>(color.r) << 16) | (unorm<8>(color.g) << 8) | (unorm<8>(color.b) << 0);
+			*(unsigned int*)element = 0xFF000000 | (unorm<8>(r) << 16) | (unorm<8>(g) << 8) | (unorm<8>(b) << 0);
 			break;
-		case FORMAT_A8B8G8R8I_SNORM:
-			*(unsigned int*)element = (static_cast<unsigned int>(snorm<8>(color.a)) << 24) |
-			                          (static_cast<unsigned int>(snorm<8>(color.b)) << 16) |
-			                          (static_cast<unsigned int>(snorm<8>(color.g)) << 8) |
-			                          (static_cast<unsigned int>(snorm<8>(color.r)) << 0);
+		case FORMAT_A8B8G8R8_SNORM:
+			*(unsigned int*)element = (static_cast<unsigned int>(snorm<8>(a)) << 24) |
+			                          (static_cast<unsigned int>(snorm<8>(b)) << 16) |
+			                          (static_cast<unsigned int>(snorm<8>(g)) << 8) |
+			                          (static_cast<unsigned int>(snorm<8>(r)) << 0);
 			break;
 		case FORMAT_A8B8G8R8:
 		case FORMAT_SRGB8_A8:
-			*(unsigned int*)element = (unorm<8>(color.a) << 24) | (unorm<8>(color.b) << 16) | (unorm<8>(color.g) << 8) | (unorm<8>(color.r) << 0);
+			*(unsigned int*)element = (unorm<8>(a) << 24) | (unorm<8>(b) << 16) | (unorm<8>(g) << 8) | (unorm<8>(r) << 0);
 			break;
 		case FORMAT_A8B8G8R8I:
-			*(unsigned int*)element = (static_cast<unsigned int>(scast<8>(color.a)) << 24) |
-			                          (static_cast<unsigned int>(scast<8>(color.b)) << 16) |
-			                          (static_cast<unsigned int>(scast<8>(color.g)) << 8) |
-			                          (static_cast<unsigned int>(scast<8>(color.r)) << 0);
+			*(unsigned int*)element = (static_cast<unsigned int>(scast<8>(a)) << 24) |
+			                          (static_cast<unsigned int>(scast<8>(b)) << 16) |
+			                          (static_cast<unsigned int>(scast<8>(g)) << 8) |
+			                          (static_cast<unsigned int>(scast<8>(r)) << 0);
 			break;
 		case FORMAT_A8B8G8R8UI:
-			*(unsigned int*)element = (ucast<8>(color.a) << 24) | (ucast<8>(color.b) << 16) | (ucast<8>(color.g) << 8) | (ucast<8>(color.r) << 0);
+			*(unsigned int*)element = (ucast<8>(a) << 24) | (ucast<8>(b) << 16) | (ucast<8>(g) << 8) | (ucast<8>(r) << 0);
 			break;
-		case FORMAT_X8B8G8R8I_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
 			*(unsigned int*)element = 0x7F000000 |
-			                          (static_cast<unsigned int>(snorm<8>(color.b)) << 16) |
-			                          (static_cast<unsigned int>(snorm<8>(color.g)) << 8) |
-			                          (static_cast<unsigned int>(snorm<8>(color.r)) << 0);
+			                          (static_cast<unsigned int>(snorm<8>(b)) << 16) |
+			                          (static_cast<unsigned int>(snorm<8>(g)) << 8) |
+			                          (static_cast<unsigned int>(snorm<8>(r)) << 0);
 			break;
 		case FORMAT_X8B8G8R8:
 		case FORMAT_SRGB8_X8:
-			*(unsigned int*)element = 0xFF000000 | (unorm<8>(color.b) << 16) | (unorm<8>(color.g) << 8) | (unorm<8>(color.r) << 0);
+			*(unsigned int*)element = 0xFF000000 | (unorm<8>(b) << 16) | (unorm<8>(g) << 8) | (unorm<8>(r) << 0);
 			break;
 		case FORMAT_X8B8G8R8I:
 			*(unsigned int*)element = 0x7F000000 |
-			                          (static_cast<unsigned int>(scast<8>(color.b)) << 16) |
-			                          (static_cast<unsigned int>(scast<8>(color.g)) << 8) |
-			                          (static_cast<unsigned int>(scast<8>(color.r)) << 0);
+			                          (static_cast<unsigned int>(scast<8>(b)) << 16) |
+			                          (static_cast<unsigned int>(scast<8>(g)) << 8) |
+			                          (static_cast<unsigned int>(scast<8>(r)) << 0);
 		case FORMAT_X8B8G8R8UI:
-			*(unsigned int*)element = 0xFF000000 | (ucast<8>(color.b) << 16) | (ucast<8>(color.g) << 8) | (ucast<8>(color.r) << 0);
+			*(unsigned int*)element = 0xFF000000 | (ucast<8>(b) << 16) | (ucast<8>(g) << 8) | (ucast<8>(r) << 0);
 			break;
 		case FORMAT_A2R10G10B10:
-			*(unsigned int*)element = (unorm<2>(color.a) << 30) | (unorm<10>(color.r) << 20) | (unorm<10>(color.g) << 10) | (unorm<10>(color.b) << 0);
+			*(unsigned int*)element = (unorm<2>(a) << 30) | (unorm<10>(r) << 20) | (unorm<10>(g) << 10) | (unorm<10>(b) << 0);
 			break;
 		case FORMAT_A2B10G10R10:
-			*(unsigned int*)element = (unorm<2>(color.a) << 30) | (unorm<10>(color.b) << 20) | (unorm<10>(color.g) << 10) | (unorm<10>(color.r) << 0);
+		case FORMAT_A2B10G10R10UI:
+			*(unsigned int*)element = (unorm<2>(a) << 30) | (unorm<10>(b) << 20) | (unorm<10>(g) << 10) | (unorm<10>(r) << 0);
 			break;
-		case FORMAT_G8R8I_SNORM:
-			*(unsigned short*)element = (static_cast<unsigned short>(snorm<8>(color.g)) << 8) |
-			                            (static_cast<unsigned short>(snorm<8>(color.r)) << 0);
+		case FORMAT_G8R8_SNORM:
+			*(unsigned short*)element = (static_cast<unsigned short>(snorm<8>(g)) << 8) |
+			                            (static_cast<unsigned short>(snorm<8>(r)) << 0);
 			break;
 		case FORMAT_G8R8:
-			*(unsigned short*)element = (unorm<8>(color.g) << 8) | (unorm<8>(color.r) << 0);
+			*(unsigned short*)element = (unorm<8>(g) << 8) | (unorm<8>(r) << 0);
 			break;
 		case FORMAT_G8R8I:
-			*(unsigned short*)element = (static_cast<unsigned short>(scast<8>(color.g)) << 8) |
-			                            (static_cast<unsigned short>(scast<8>(color.r)) << 0);
+			*(unsigned short*)element = (static_cast<unsigned short>(scast<8>(g)) << 8) |
+			                            (static_cast<unsigned short>(scast<8>(r)) << 0);
 			break;
 		case FORMAT_G8R8UI:
-			*(unsigned short*)element = (ucast<8>(color.g) << 8) | (ucast<8>(color.r) << 0);
+			*(unsigned short*)element = (ucast<8>(g) << 8) | (ucast<8>(r) << 0);
 			break;
 		case FORMAT_G16R16:
-			*(unsigned int*)element = (unorm<16>(color.g) << 16) | (unorm<16>(color.r) << 0);
+			*(unsigned int*)element = (unorm<16>(g) << 16) | (unorm<16>(r) << 0);
 			break;
 		case FORMAT_G16R16I:
-			*(unsigned int*)element = (static_cast<unsigned int>(scast<16>(color.g)) << 16) |
-			                          (static_cast<unsigned int>(scast<16>(color.r)) << 0);
+			*(unsigned int*)element = (static_cast<unsigned int>(scast<16>(g)) << 16) |
+			                          (static_cast<unsigned int>(scast<16>(r)) << 0);
 			break;
 		case FORMAT_G16R16UI:
-			*(unsigned int*)element = (ucast<16>(color.g) << 16) | (ucast<16>(color.r) << 0);
+			*(unsigned int*)element = (ucast<16>(g) << 16) | (ucast<16>(r) << 0);
 			break;
 		case FORMAT_G32R32I:
 		case FORMAT_G32R32UI:
-			((unsigned int*)element)[0] = static_cast<unsigned int>(color.r);
-			((unsigned int*)element)[1] = static_cast<unsigned int>(color.g);
+			((unsigned int*)element)[0] = static_cast<unsigned int>(r);
+			((unsigned int*)element)[1] = static_cast<unsigned int>(g);
 			break;
 		case FORMAT_A16B16G16R16:
-			((unsigned short*)element)[0] = unorm<16>(color.r);
-			((unsigned short*)element)[1] = unorm<16>(color.g);
-			((unsigned short*)element)[2] = unorm<16>(color.b);
-			((unsigned short*)element)[3] = unorm<16>(color.a);
+			((unsigned short*)element)[0] = unorm<16>(r);
+			((unsigned short*)element)[1] = unorm<16>(g);
+			((unsigned short*)element)[2] = unorm<16>(b);
+			((unsigned short*)element)[3] = unorm<16>(a);
 			break;
 		case FORMAT_A16B16G16R16I:
-			((unsigned short*)element)[0] = static_cast<unsigned short>(scast<16>(color.r));
-			((unsigned short*)element)[1] = static_cast<unsigned short>(scast<16>(color.g));
-			((unsigned short*)element)[2] = static_cast<unsigned short>(scast<16>(color.b));
-			((unsigned short*)element)[3] = static_cast<unsigned short>(scast<16>(color.a));
+			((unsigned short*)element)[0] = static_cast<unsigned short>(scast<16>(r));
+			((unsigned short*)element)[1] = static_cast<unsigned short>(scast<16>(g));
+			((unsigned short*)element)[2] = static_cast<unsigned short>(scast<16>(b));
+			((unsigned short*)element)[3] = static_cast<unsigned short>(scast<16>(a));
 			break;
 		case FORMAT_A16B16G16R16UI:
-			((unsigned short*)element)[0] = static_cast<unsigned short>(ucast<16>(color.r));
-			((unsigned short*)element)[1] = static_cast<unsigned short>(ucast<16>(color.g));
-			((unsigned short*)element)[2] = static_cast<unsigned short>(ucast<16>(color.b));
-			((unsigned short*)element)[3] = static_cast<unsigned short>(ucast<16>(color.a));
+			((unsigned short*)element)[0] = static_cast<unsigned short>(ucast<16>(r));
+			((unsigned short*)element)[1] = static_cast<unsigned short>(ucast<16>(g));
+			((unsigned short*)element)[2] = static_cast<unsigned short>(ucast<16>(b));
+			((unsigned short*)element)[3] = static_cast<unsigned short>(ucast<16>(a));
 			break;
 		case FORMAT_X16B16G16R16I:
-			((unsigned short*)element)[0] = static_cast<unsigned short>(scast<16>(color.r));
-			((unsigned short*)element)[1] = static_cast<unsigned short>(scast<16>(color.g));
-			((unsigned short*)element)[2] = static_cast<unsigned short>(scast<16>(color.b));
+			((unsigned short*)element)[0] = static_cast<unsigned short>(scast<16>(r));
+			((unsigned short*)element)[1] = static_cast<unsigned short>(scast<16>(g));
+			((unsigned short*)element)[2] = static_cast<unsigned short>(scast<16>(b));
 			break;
 		case FORMAT_X16B16G16R16UI:
-			((unsigned short*)element)[0] = static_cast<unsigned short>(ucast<16>(color.r));
-			((unsigned short*)element)[1] = static_cast<unsigned short>(ucast<16>(color.g));
-			((unsigned short*)element)[2] = static_cast<unsigned short>(ucast<16>(color.b));
+			((unsigned short*)element)[0] = static_cast<unsigned short>(ucast<16>(r));
+			((unsigned short*)element)[1] = static_cast<unsigned short>(ucast<16>(g));
+			((unsigned short*)element)[2] = static_cast<unsigned short>(ucast<16>(b));
 			break;
 		case FORMAT_A32B32G32R32I:
 		case FORMAT_A32B32G32R32UI:
-			((unsigned int*)element)[0] = static_cast<unsigned int>(color.r);
-			((unsigned int*)element)[1] = static_cast<unsigned int>(color.g);
-			((unsigned int*)element)[2] = static_cast<unsigned int>(color.b);
-			((unsigned int*)element)[3] = static_cast<unsigned int>(color.a);
+			((unsigned int*)element)[0] = static_cast<unsigned int>(r);
+			((unsigned int*)element)[1] = static_cast<unsigned int>(g);
+			((unsigned int*)element)[2] = static_cast<unsigned int>(b);
+			((unsigned int*)element)[3] = static_cast<unsigned int>(a);
 			break;
 		case FORMAT_X32B32G32R32I:
 		case FORMAT_X32B32G32R32UI:
-			((unsigned int*)element)[0] = static_cast<unsigned int>(color.r);
-			((unsigned int*)element)[1] = static_cast<unsigned int>(color.g);
-			((unsigned int*)element)[2] = static_cast<unsigned int>(color.b);
+			((unsigned int*)element)[0] = static_cast<unsigned int>(r);
+			((unsigned int*)element)[1] = static_cast<unsigned int>(g);
+			((unsigned int*)element)[2] = static_cast<unsigned int>(b);
 			break;
 		case FORMAT_V8U8:
-			*(unsigned short*)element = (snorm<8>(color.g) << 8) | (snorm<8>(color.r) << 0);
+			*(unsigned short*)element = (snorm<8>(g) << 8) | (snorm<8>(r) << 0);
 			break;
 		case FORMAT_L6V5U5:
-			*(unsigned short*)element = (unorm<6>(color.b) << 10) | (snorm<5>(color.g) << 5) | (snorm<5>(color.r) << 0);
+			*(unsigned short*)element = (unorm<6>(b) << 10) | (snorm<5>(g) << 5) | (snorm<5>(r) << 0);
 			break;
 		case FORMAT_Q8W8V8U8:
-			*(unsigned int*)element = (snorm<8>(color.a) << 24) | (snorm<8>(color.b) << 16) | (snorm<8>(color.g) << 8) | (snorm<8>(color.r) << 0);
+			*(unsigned int*)element = (snorm<8>(a) << 24) | (snorm<8>(b) << 16) | (snorm<8>(g) << 8) | (snorm<8>(r) << 0);
 			break;
 		case FORMAT_X8L8V8U8:
-			*(unsigned int*)element = 0xFF000000 | (unorm<8>(color.b) << 16) | (snorm<8>(color.g) << 8) | (snorm<8>(color.r) << 0);
+			*(unsigned int*)element = 0xFF000000 | (unorm<8>(b) << 16) | (snorm<8>(g) << 8) | (snorm<8>(r) << 0);
 			break;
 		case FORMAT_V16U16:
-			*(unsigned int*)element = (snorm<16>(color.g) << 16) | (snorm<16>(color.r) << 0);
+			*(unsigned int*)element = (snorm<16>(g) << 16) | (snorm<16>(r) << 0);
 			break;
 		case FORMAT_A2W10V10U10:
-			*(unsigned int*)element = (unorm<2>(color.a) << 30) | (snorm<10>(color.b) << 20) | (snorm<10>(color.g) << 10) | (snorm<10>(color.r) << 0);
+			*(unsigned int*)element = (unorm<2>(a) << 30) | (snorm<10>(b) << 20) | (snorm<10>(g) << 10) | (snorm<10>(r) << 0);
 			break;
 		case FORMAT_A16W16V16U16:
-			((unsigned short*)element)[0] = snorm<16>(color.r);
-			((unsigned short*)element)[1] = snorm<16>(color.g);
-			((unsigned short*)element)[2] = snorm<16>(color.b);
-			((unsigned short*)element)[3] = unorm<16>(color.a);
+			((unsigned short*)element)[0] = snorm<16>(r);
+			((unsigned short*)element)[1] = snorm<16>(g);
+			((unsigned short*)element)[2] = snorm<16>(b);
+			((unsigned short*)element)[3] = unorm<16>(a);
 			break;
 		case FORMAT_Q16W16V16U16:
-			((unsigned short*)element)[0] = snorm<16>(color.r);
-			((unsigned short*)element)[1] = snorm<16>(color.g);
-			((unsigned short*)element)[2] = snorm<16>(color.b);
-			((unsigned short*)element)[3] = snorm<16>(color.a);
+			((unsigned short*)element)[0] = snorm<16>(r);
+			((unsigned short*)element)[1] = snorm<16>(g);
+			((unsigned short*)element)[2] = snorm<16>(b);
+			((unsigned short*)element)[3] = snorm<16>(a);
 			break;
 		case FORMAT_R8G8B8:
-			((unsigned char*)element)[0] = unorm<8>(color.b);
-			((unsigned char*)element)[1] = unorm<8>(color.g);
-			((unsigned char*)element)[2] = unorm<8>(color.r);
+			((unsigned char*)element)[0] = unorm<8>(b);
+			((unsigned char*)element)[1] = unorm<8>(g);
+			((unsigned char*)element)[2] = unorm<8>(r);
 			break;
 		case FORMAT_B8G8R8:
-			((unsigned char*)element)[0] = unorm<8>(color.r);
-			((unsigned char*)element)[1] = unorm<8>(color.g);
-			((unsigned char*)element)[2] = unorm<8>(color.b);
+			((unsigned char*)element)[0] = unorm<8>(r);
+			((unsigned char*)element)[1] = unorm<8>(g);
+			((unsigned char*)element)[2] = unorm<8>(b);
 			break;
 		case FORMAT_R16F:
-			*(half*)element = (half)color.r;
+			*(half*)element = (half)r;
 			break;
 		case FORMAT_A16F:
-			*(half*)element = (half)color.a;
+			*(half*)element = (half)a;
 			break;
 		case FORMAT_G16R16F:
-			((half*)element)[0] = (half)color.r;
-			((half*)element)[1] = (half)color.g;
+			((half*)element)[0] = (half)r;
+			((half*)element)[1] = (half)g;
 			break;
+		case FORMAT_X16B16G16R16F_UNSIGNED:
+			r = max(r, 0.0f); g = max(g, 0.0f); b = max(b, 0.0f);
+			// Fall through to FORMAT_X16B16G16R16F.
+		case FORMAT_X16B16G16R16F:
+			((half*)element)[3] = 1.0f;
+			// Fall through to FORMAT_B16G16R16F.
 		case FORMAT_B16G16R16F:
-			((half*)element)[0] = (half)color.r;
-			((half*)element)[1] = (half)color.g;
-			((half*)element)[2] = (half)color.b;
+			((half*)element)[0] = (half)r;
+			((half*)element)[1] = (half)g;
+			((half*)element)[2] = (half)b;
 			break;
 		case FORMAT_A16B16G16R16F:
-			((half*)element)[0] = (half)color.r;
-			((half*)element)[1] = (half)color.g;
-			((half*)element)[2] = (half)color.b;
-			((half*)element)[3] = (half)color.a;
+			((half*)element)[0] = (half)r;
+			((half*)element)[1] = (half)g;
+			((half*)element)[2] = (half)b;
+			((half*)element)[3] = (half)a;
 			break;
 		case FORMAT_A32F:
-			*(float*)element = color.a;
+			*(float*)element = a;
 			break;
 		case FORMAT_R32F:
-			*(float*)element = color.r;
+			*(float*)element = r;
 			break;
 		case FORMAT_G32R32F:
-			((float*)element)[0] = color.r;
-			((float*)element)[1] = color.g;
+			((float*)element)[0] = r;
+			((float*)element)[1] = g;
 			break;
+		case FORMAT_X32B32G32R32F_UNSIGNED:
+			r = max(r, 0.0f); g = max(g, 0.0f); b = max(b, 0.0f);
+			// Fall through to FORMAT_X32B32G32R32F.
 		case FORMAT_X32B32G32R32F:
 			((float*)element)[3] = 1.0f;
+			// Fall through to FORMAT_B32G32R32F.
 		case FORMAT_B32G32R32F:
-			((float*)element)[0] = color.r;
-			((float*)element)[1] = color.g;
-			((float*)element)[2] = color.b;
+			((float*)element)[0] = r;
+			((float*)element)[1] = g;
+			((float*)element)[2] = b;
 			break;
 		case FORMAT_A32B32G32R32F:
-			((float*)element)[0] = color.r;
-			((float*)element)[1] = color.g;
-			((float*)element)[2] = color.b;
-			((float*)element)[3] = color.a;
+			((float*)element)[0] = r;
+			((float*)element)[1] = g;
+			((float*)element)[2] = b;
+			((float*)element)[3] = a;
 			break;
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
-			*((float*)element) = color.r;
+			*((float*)element) = r;
 			break;
 		case FORMAT_D32F_COMPLEMENTARY:
-			*((float*)element) = 1 - color.r;
+		case FORMAT_D32FS8_COMPLEMENTARY:
+			*((float*)element) = 1 - r;
 			break;
 		case FORMAT_S8:
-			*((unsigned char*)element) = unorm<8>(color.r);
+			*((unsigned char*)element) = unorm<8>(r);
 			break;
 		case FORMAT_L8:
-			*(unsigned char*)element = unorm<8>(color.r);
+			*(unsigned char*)element = unorm<8>(r);
 			break;
 		case FORMAT_A4L4:
-			*(unsigned char*)element = (unorm<4>(color.a) << 4) | (unorm<4>(color.r) << 0);
+			*(unsigned char*)element = (unorm<4>(a) << 4) | (unorm<4>(r) << 0);
 			break;
 		case FORMAT_L16:
-			*(unsigned short*)element = unorm<16>(color.r);
+			*(unsigned short*)element = unorm<16>(r);
 			break;
 		case FORMAT_A8L8:
-			*(unsigned short*)element = (unorm<8>(color.a) << 8) | (unorm<8>(color.r) << 0);
+			*(unsigned short*)element = (unorm<8>(a) << 8) | (unorm<8>(r) << 0);
 			break;
 		case FORMAT_L16F:
-			*(half*)element = (half)color.r;
+			*(half*)element = (half)r;
 			break;
 		case FORMAT_A16L16F:
-			((half*)element)[0] = (half)color.r;
-			((half*)element)[1] = (half)color.a;
+			((half*)element)[0] = (half)r;
+			((half*)element)[1] = (half)a;
 			break;
 		case FORMAT_L32F:
-			*(float*)element = color.r;
+			*(float*)element = r;
 			break;
 		case FORMAT_A32L32F:
-			((float*)element)[0] = color.r;
-			((float*)element)[1] = color.a;
+			((float*)element)[0] = r;
+			((float*)element)[1] = a;
 			break;
 		default:
 			ASSERT(false);
@@ -370,14 +396,14 @@
 
 	Color<float> Surface::Buffer::read(int x, int y, int z) const
 	{
-		void *element = (unsigned char*)buffer + x * bytes + y * pitchB + z * sliceB;
+		void *element = (unsigned char*)buffer + (x + border) * bytes + (y + border) * pitchB + z * samples * sliceB;
 
 		return read(element);
 	}
 
 	Color<float> Surface::Buffer::read(int x, int y) const
 	{
-		void *element = (unsigned char*)buffer + x * bytes + y * pitchB;
+		void *element = (unsigned char*)buffer + (x + border) * bytes + (y + border) * pitchB;
 
 		return read(element);
 	}
@@ -421,7 +447,7 @@
 			b = 0;
 			a = *(unsigned char*)element * (1.0f / 0xFF);
 			break;
-		case FORMAT_R8I_SNORM:
+		case FORMAT_R8_SNORM:
 			r = max((*(signed char*)element) * (1.0f / 0x7F), -1.0f);
 			break;
 		case FORMAT_R8:
@@ -538,7 +564,7 @@
 				b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF);
 			}
 			break;
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 			{
 				signed char* abgr = (signed char*)element;
 
@@ -579,7 +605,7 @@
 				a = abgr[3];
 			}
 			break;
-		case FORMAT_X8B8G8R8I_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
 			{
 				signed char* bgr = (signed char*)element;
 
@@ -616,7 +642,7 @@
 				b = bgr[2];
 			}
 			break;
-		case FORMAT_G8R8I_SNORM:
+		case FORMAT_G8R8_SNORM:
 			{
 				signed char* gr = (signed char*)element;
 
@@ -698,6 +724,16 @@
 				r = (abgr & 0x000003FF) * (1.0f / 0x000003FF);
 			}
 			break;
+		case FORMAT_A2B10G10R10UI:
+			{
+				unsigned int abgr = *(unsigned int*)element;
+
+				a = static_cast<float>((abgr & 0xC0000000) >> 30);
+				b = static_cast<float>((abgr & 0x3FF00000) >> 20);
+				g = static_cast<float>((abgr & 0x000FFC00) >> 10);
+				r = static_cast<float>(abgr & 0x000003FF);
+			}
+			break;
 		case FORMAT_A16B16G16R16I:
 			{
 				short* abgr = (short*)element;
@@ -936,6 +972,8 @@
 			r = ((half*)element)[0];
 			g = ((half*)element)[1];
 			break;
+		case FORMAT_X16B16G16R16F:
+		case FORMAT_X16B16G16R16F_UNSIGNED:
 		case FORMAT_B16G16R16F:
 			r = ((half*)element)[0];
 			g = ((half*)element)[1];
@@ -958,6 +996,7 @@
 			g = ((float*)element)[1];
 			break;
 		case FORMAT_X32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_B32G32R32F:
 			r = ((float*)element)[0];
 			g = ((float*)element)[1];
@@ -970,8 +1009,10 @@
 			a = ((float*)element)[3];
 			break;
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 			r = *(float*)element;
 			g = r;
@@ -979,6 +1020,7 @@
 			a = r;
 			break;
 		case FORMAT_D32F_COMPLEMENTARY:
+		case FORMAT_D32FS8_COMPLEMENTARY:
 			r = 1.0f - *(float*)element;
 			g = r;
 			b = r;
@@ -991,12 +1033,12 @@
 			ASSERT(false);
 		}
 
-	//	if(sRGB)
-	//	{
-	//		r = sRGBtoLinear(r);
-	//		g = sRGBtoLinear(g);
-	//		b = sRGBtoLinear(b);
-	//	}
+		if(isSRGBformat(format))
+		{
+			r = sRGBtoLinear(r);
+			g = sRGBtoLinear(g);
+			b = sRGBtoLinear(b);
+		}
 
 		return Color<float>(r, g, b, a);
 	}
@@ -1041,7 +1083,7 @@
 		return c000 + c100 + c010 + c110 + c001 + c101 + c011 + c111;
 	}
 
-	Color<float> Surface::Buffer::sample(float x, float y) const
+	Color<float> Surface::Buffer::sample(float x, float y, int layer) const
 	{
 		x -= 0.5f;
 		y -= 0.5f;
@@ -1052,10 +1094,10 @@
 		int y0 = clamp((int)y, 0, height - 1);
 		int y1 = (y0 + 1 >= height) ? y0 : y0 + 1;
 
-		Color<float> c00 = read(x0, y0);
-		Color<float> c10 = read(x1, y0);
-		Color<float> c01 = read(x0, y1);
-		Color<float> c11 = read(x1, y1);
+		Color<float> c00 = read(x0, y0, layer);
+		Color<float> c10 = read(x1, y0, layer);
+		Color<float> c01 = read(x0, y1, layer);
+		Color<float> c11 = read(x1, y1, layer);
 
 		float fx = x - x0;
 		float fy = y - y0;
@@ -1076,6 +1118,7 @@
 		{
 		case LOCK_UNLOCKED:
 		case LOCK_READONLY:
+		case LOCK_UPDATE:
 			break;
 		case LOCK_WRITEONLY:
 		case LOCK_READWRITE:
@@ -1088,11 +1131,12 @@
 
 		if(buffer)
 		{
+			x += border;
+			y += border;
+
 			switch(format)
 			{
-			#if S3TC_SUPPORT
 			case FORMAT_DXT1:
-			#endif
 			case FORMAT_ATI1:
 			case FORMAT_ETC1:
 			case FORMAT_R11_EAC:
@@ -1148,18 +1192,16 @@
 			case FORMAT_RGBA_ASTC_12x12_KHR:
 			case FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR:
 				return (unsigned char*)buffer + 16 * (x / 12) + (y / 12) * pitchB + z * sliceB;
-			#if S3TC_SUPPORT
 			case FORMAT_DXT3:
 			case FORMAT_DXT5:
-			#endif
 			case FORMAT_ATI2:
 				return (unsigned char*)buffer + 16 * (x / 4) + (y / 4) * pitchB + z * sliceB;
 			default:
-				return (unsigned char*)buffer + x * bytes + y * pitchB + z * sliceB;
+				return (unsigned char*)buffer + x * bytes + y * pitchB + z * samples * sliceB;
 			}
 		}
 
-		return 0;
+		return nullptr;
 	}
 
 	void Surface::Buffer::unlockRect()
@@ -1172,8 +1214,8 @@
 	public:
 		SurfaceImplementation(int width, int height, int depth, Format format, void *pixels, int pitch, int slice)
 			: Surface(width, height, depth, format, pixels, pitch, slice) {}
-		SurfaceImplementation(Resource *texture, int width, int height, int depth, Format format, bool lockable, bool renderTarget, int pitchP = 0)
-			: Surface(texture, width, height, depth, format, lockable, renderTarget, pitchP) {}
+		SurfaceImplementation(Resource *texture, int width, int height, int depth, int border, int samples, Format format, bool lockable, bool renderTarget, int pitchP = 0)
+			: Surface(texture, width, height, depth, border, samples, format, lockable, renderTarget, pitchP) {}
 		~SurfaceImplementation() override {};
 
 		void *lockInternal(int x, int y, int z, Lock lock, Accessor client) override
@@ -1192,9 +1234,9 @@
 		return new SurfaceImplementation(width, height, depth, format, pixels, pitch, slice);
 	}
 
-	Surface *Surface::create(Resource *texture, int width, int height, int depth, Format format, bool lockable, bool renderTarget, int pitchPprovided)
+	Surface *Surface::create(Resource *texture, int width, int height, int depth, int border, int samples, Format format, bool lockable, bool renderTarget, int pitchPprovided)
 	{
-		return new SurfaceImplementation(texture, width, height, depth, format, lockable, renderTarget, pitchPprovided);
+		return new SurfaceImplementation(texture, width, height, depth, border, samples, format, lockable, renderTarget, pitchPprovided);
 	}
 
 	Surface::Surface(int width, int height, int depth, Format format, void *pixels, int pitch, int slice) : lockable(true), renderTarget(false)
@@ -1208,92 +1250,105 @@
 		external.width = width;
 		external.height = height;
 		external.depth = depth;
+		external.samples = 1;
 		external.format = format;
 		external.bytes = bytes(external.format);
 		external.pitchB = pitch;
 		external.pitchP = external.bytes ? pitch / external.bytes : 0;
 		external.sliceB = slice;
 		external.sliceP = external.bytes ? slice / external.bytes : 0;
+		external.border = 0;
 		external.lock = LOCK_UNLOCKED;
 		external.dirty = true;
 
-		internal.buffer = 0;
+		internal.buffer = nullptr;
 		internal.width = width;
 		internal.height = height;
 		internal.depth = depth;
+		internal.samples = 1;
 		internal.format = selectInternalFormat(format);
 		internal.bytes = bytes(internal.format);
-		internal.pitchB = pitchB(internal.width, internal.format, false);
-		internal.pitchP = pitchP(internal.width, internal.format, false);
-		internal.sliceB = sliceB(internal.width, internal.height, internal.format, false);
-		internal.sliceP = sliceP(internal.width, internal.height, internal.format, false);
+		internal.pitchB = pitchB(internal.width, 0, internal.format, false);
+		internal.pitchP = pitchP(internal.width, 0, internal.format, false);
+		internal.sliceB = sliceB(internal.width, internal.height, 0, internal.format, false);
+		internal.sliceP = sliceP(internal.width, internal.height, 0, internal.format, false);
+		internal.border = 0;
 		internal.lock = LOCK_UNLOCKED;
 		internal.dirty = false;
 
-		stencil.buffer = 0;
+		stencil.buffer = nullptr;
 		stencil.width = width;
 		stencil.height = height;
 		stencil.depth = depth;
-		stencil.format = FORMAT_S8;
+		stencil.samples = 1;
+		stencil.format = isStencil(format) ? FORMAT_S8 : FORMAT_NULL;
 		stencil.bytes = bytes(stencil.format);
-		stencil.pitchB = pitchB(stencil.width, stencil.format, false);
-		stencil.pitchP = pitchP(stencil.width, stencil.format, false);
-		stencil.sliceB = sliceB(stencil.width, stencil.height, stencil.format, false);
-		stencil.sliceP = sliceP(stencil.width, stencil.height, stencil.format, false);
+		stencil.pitchB = pitchB(stencil.width, 0, stencil.format, false);
+		stencil.pitchP = pitchP(stencil.width, 0, stencil.format, false);
+		stencil.sliceB = sliceB(stencil.width, stencil.height, 0, stencil.format, false);
+		stencil.sliceP = sliceP(stencil.width, stencil.height, 0, stencil.format, false);
+		stencil.border = 0;
 		stencil.lock = LOCK_UNLOCKED;
 		stencil.dirty = false;
 
-		dirtyMipmaps = true;
+		dirtyContents = true;
 		paletteUsed = 0;
 	}
 
-	Surface::Surface(Resource *texture, int width, int height, int depth, Format format, bool lockable, bool renderTarget, int pitchPprovided) : lockable(lockable), renderTarget(renderTarget)
+	Surface::Surface(Resource *texture, int width, int height, int depth, int border, int samples, Format format, bool lockable, bool renderTarget, int pitchPprovided) : lockable(lockable), renderTarget(renderTarget)
 	{
 		resource = texture ? texture : new Resource(0);
-		hasParent = texture != 0;
+		hasParent = texture != nullptr;
 		ownExternal = true;
 		depth = max(1, depth);
+		samples = max(1, samples);
 
-		external.buffer = 0;
+		external.buffer = nullptr;
 		external.width = width;
 		external.height = height;
 		external.depth = depth;
+		external.samples = (short)samples;
 		external.format = format;
 		external.bytes = bytes(external.format);
-		external.pitchB = pitchB(external.width, external.format, renderTarget && !texture);
-		external.pitchP = pitchP(external.width, external.format, renderTarget && !texture);
-		external.sliceB = sliceB(external.width, external.height, external.format, renderTarget && !texture);
-		external.sliceP = sliceP(external.width, external.height, external.format, renderTarget && !texture);
+		external.pitchB = pitchB(external.width, 0, external.format, renderTarget && !texture);
+		external.pitchP = pitchP(external.width, 0, external.format, renderTarget && !texture);
+		external.sliceB = sliceB(external.width, external.height, 0, external.format, renderTarget && !texture);
+		external.sliceP = sliceP(external.width, external.height, 0, external.format, renderTarget && !texture);
+		external.border = 0;
 		external.lock = LOCK_UNLOCKED;
 		external.dirty = false;
 
-		internal.buffer = 0;
+		internal.buffer = nullptr;
 		internal.width = width;
 		internal.height = height;
 		internal.depth = depth;
+		internal.samples = (short)samples;
 		internal.format = selectInternalFormat(format);
 		internal.bytes = bytes(internal.format);
-		internal.pitchB = !pitchPprovided ? pitchB(internal.width, internal.format, renderTarget) : pitchPprovided * internal.bytes;
-		internal.pitchP = !pitchPprovided ? pitchP(internal.width, internal.format, renderTarget) : pitchPprovided;
-		internal.sliceB = sliceB(internal.width, internal.height, internal.format, renderTarget);
-		internal.sliceP = sliceP(internal.width, internal.height, internal.format, renderTarget);
+		internal.pitchB = !pitchPprovided ? pitchB(internal.width, border, internal.format, renderTarget) : pitchPprovided * internal.bytes;
+		internal.pitchP = !pitchPprovided ? pitchP(internal.width, border, internal.format, renderTarget) : pitchPprovided;
+		internal.sliceB = sliceB(internal.width, internal.height, border, internal.format, renderTarget);
+		internal.sliceP = sliceP(internal.width, internal.height, border, internal.format, renderTarget);
+		internal.border = (short)border;
 		internal.lock = LOCK_UNLOCKED;
 		internal.dirty = false;
 
-		stencil.buffer = 0;
+		stencil.buffer = nullptr;
 		stencil.width = width;
 		stencil.height = height;
 		stencil.depth = depth;
-		stencil.format = FORMAT_S8;
+		stencil.samples = (short)samples;
+		stencil.format = isStencil(format) ? FORMAT_S8 : FORMAT_NULL;
 		stencil.bytes = bytes(stencil.format);
-		stencil.pitchB = pitchB(stencil.width, stencil.format, renderTarget);
-		stencil.pitchP = pitchP(stencil.width, stencil.format, renderTarget);
-		stencil.sliceB = sliceB(stencil.width, stencil.height, stencil.format, renderTarget);
-		stencil.sliceP = sliceP(stencil.width, stencil.height, stencil.format, renderTarget);
+		stencil.pitchB = pitchB(stencil.width, 0, stencil.format, renderTarget);
+		stencil.pitchP = pitchP(stencil.width, 0, stencil.format, renderTarget);
+		stencil.sliceB = sliceB(stencil.width, stencil.height, 0, stencil.format, renderTarget);
+		stencil.sliceP = sliceP(stencil.width, stencil.height, 0, stencil.format, renderTarget);
+		stencil.border = 0;
 		stencil.lock = LOCK_UNLOCKED;
 		stencil.dirty = false;
 
-		dirtyMipmaps = true;
+		dirtyContents = true;
 		paletteUsed = 0;
 	}
 
@@ -1337,7 +1392,7 @@
 			}
 			else
 			{
-				external.buffer = allocateBuffer(external.width, external.height, external.depth, external.format);
+				external.buffer = allocateBuffer(external.width, external.height, external.depth, external.border, external.samples, external.format);
 			}
 		}
 
@@ -1358,7 +1413,7 @@
 		case LOCK_WRITEONLY:
 		case LOCK_READWRITE:
 		case LOCK_DISCARD:
-			dirtyMipmaps = true;
+			dirtyContents = true;
 			break;
 		default:
 			ASSERT(false);
@@ -1389,7 +1444,7 @@
 			}
 			else
 			{
-				internal.buffer = allocateBuffer(internal.width, internal.height, internal.depth, internal.format);
+				internal.buffer = allocateBuffer(internal.width, internal.height, internal.depth, internal.border, internal.samples, internal.format);
 			}
 		}
 
@@ -1437,7 +1492,7 @@
 		case LOCK_WRITEONLY:
 		case LOCK_READWRITE:
 		case LOCK_DISCARD:
-			dirtyMipmaps = true;
+			dirtyContents = true;
 			break;
 		default:
 			ASSERT(false);
@@ -1460,11 +1515,16 @@
 
 	void *Surface::lockStencil(int x, int y, int front, Accessor client)
 	{
+		if(stencil.format == FORMAT_NULL)
+		{
+			return nullptr;
+		}
+
 		resource->lock(client);
 
 		if(!stencil.buffer)
 		{
-			stencil.buffer = allocateBuffer(stencil.width, stencil.height, stencil.depth, stencil.format);
+			stencil.buffer = allocateBuffer(stencil.width, stencil.height, stencil.depth, stencil.border, stencil.samples, stencil.format);
 		}
 
 		return stencil.lockRect(x, y, front, LOCK_READWRITE);   // FIXME
@@ -1516,12 +1576,13 @@
 		case FORMAT_X8B8G8R8UI:			return 4;
 		case FORMAT_A8B8G8R8UI:			return 4;
 		case FORMAT_A8B8G8R8:			return 4;
-		case FORMAT_R8I_SNORM:			return 1;
-		case FORMAT_G8R8I_SNORM:		return 2;
-		case FORMAT_X8B8G8R8I_SNORM:	return 4;
-		case FORMAT_A8B8G8R8I_SNORM:	return 4;
+		case FORMAT_R8_SNORM:			return 1;
+		case FORMAT_G8R8_SNORM:		return 2;
+		case FORMAT_X8B8G8R8_SNORM:	return 4;
+		case FORMAT_A8B8G8R8_SNORM:	return 4;
 		case FORMAT_A2R10G10B10:		return 4;
 		case FORMAT_A2B10G10R10:		return 4;
+		case FORMAT_A2B10G10R10UI:		return 4;
 		case FORMAT_G8R8I:				return 2;
 		case FORMAT_G8R8:				return 2;
 		case FORMAT_G16R16I:			return 4;
@@ -1539,11 +1600,9 @@
 		case FORMAT_A32B32G32R32I:		return 16;
 		case FORMAT_A32B32G32R32UI:		return 16;
 		// Compressed formats
-		#if S3TC_SUPPORT
 		case FORMAT_DXT1:				return 2;   // Column of four pixels
 		case FORMAT_DXT3:				return 4;   // Column of four pixels
 		case FORMAT_DXT5:				return 4;   // Column of four pixels
-		#endif
 		case FORMAT_ATI1:				return 2;   // Column of four pixels
 		case FORMAT_ATI2:				return 4;   // Column of four pixels
 		case FORMAT_ETC1:				return 2;   // Column of four pixels
@@ -1608,13 +1667,16 @@
 		case FORMAT_R16F:				return 2;
 		case FORMAT_G16R16F:			return 4;
 		case FORMAT_B16G16R16F:			return 6;
+		case FORMAT_X16B16G16R16F:		return 8;
 		case FORMAT_A16B16G16R16F:		return 8;
+		case FORMAT_X16B16G16R16F_UNSIGNED: return 8;
 		case FORMAT_A32F:				return 4;
 		case FORMAT_R32F:				return 4;
 		case FORMAT_G32R32F:			return 8;
 		case FORMAT_B32G32R32F:			return 12;
 		case FORMAT_X32B32G32R32F:		return 16;
 		case FORMAT_A32B32G32R32F:		return 16;
+		case FORMAT_X32B32G32R32F_UNSIGNED: return 16;
 		// Depth/stencil formats
 		case FORMAT_D16:				return 2;
 		case FORMAT_D32:				return 4;
@@ -1622,9 +1684,12 @@
 		case FORMAT_D24S8:				return 4;
 		case FORMAT_D24FS8:				return 4;
 		case FORMAT_D32F:				return 4;
+		case FORMAT_D32FS8:				return 4;
 		case FORMAT_D32F_COMPLEMENTARY:	return 4;
+		case FORMAT_D32FS8_COMPLEMENTARY: return 4;
 		case FORMAT_D32F_LOCKABLE:		return 4;
 		case FORMAT_D32FS8_TEXTURE:		return 4;
+		case FORMAT_D32F_SHADOW:		return 4;
 		case FORMAT_D32FS8_SHADOW:		return 4;
 		case FORMAT_DF24S8:				return 4;
 		case FORMAT_DF16S8:				return 2;
@@ -1640,8 +1705,10 @@
 		return 0;
 	}
 
-	int Surface::pitchB(int width, Format format, bool target)
+	int Surface::pitchB(int width, int border, Format format, bool target)
 	{
+		width += 2 * border;
+
 		if(target || isDepth(format) || isStencil(format))
 		{
 			width = align(width, 2);
@@ -1649,9 +1716,7 @@
 
 		switch(format)
 		{
-		#if S3TC_SUPPORT
 		case FORMAT_DXT1:
-		#endif
 		case FORMAT_ETC1:
 		case FORMAT_R11_EAC:
 		case FORMAT_SIGNED_R11_EAC:
@@ -1698,11 +1763,9 @@
 		case FORMAT_RGBA_ASTC_12x12_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR:
 			return 16 * ((width + 11) / 12);
-		#if S3TC_SUPPORT
 		case FORMAT_DXT3:
 		case FORMAT_DXT5:
 			return 16 * ((width + 3) / 4);   // 128 bit per 4x4 block, computed per 4 rows
-		#endif
 		case FORMAT_ATI1:
 			return 2 * ((width + 3) / 4);    // 64 bit per 4x4 block, computed per row
 		case FORMAT_ATI2:
@@ -1716,15 +1779,17 @@
 		}
 	}
 
-	int Surface::pitchP(int width, Format format, bool target)
+	int Surface::pitchP(int width, int border, Format format, bool target)
 	{
 		int B = bytes(format);
 
-		return B > 0 ? pitchB(width, format, target) / B : 0;
+		return B > 0 ? pitchB(width, border, format, target) / B : 0;
 	}
 
-	int Surface::sliceB(int width, int height, Format format, bool target)
+	int Surface::sliceB(int width, int height, int border, Format format, bool target)
 	{
+		height += 2 * border;
+
 		if(target || isDepth(format) || isStencil(format))
 		{
 			height = ((height + 1) & ~1);
@@ -1732,11 +1797,9 @@
 
 		switch(format)
 		{
-		#if S3TC_SUPPORT
 		case FORMAT_DXT1:
 		case FORMAT_DXT3:
 		case FORMAT_DXT5:
-		#endif
 		case FORMAT_ETC1:
 		case FORMAT_R11_EAC:
 		case FORMAT_SIGNED_R11_EAC:
@@ -1752,7 +1815,7 @@
 		case FORMAT_SRGB8_ALPHA8_ASTC_4x4_KHR:
 		case FORMAT_RGBA_ASTC_5x4_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_5x4_KHR:
-			return pitchB(width, format, target) * ((height + 3) / 4);   // Pitch computed per 4 rows
+			return pitchB(width, border, format, target) * ((height + 3) / 4);   // Pitch computed per 4 rows
 		case FORMAT_RGBA_ASTC_5x5_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_5x5_KHR:
 		case FORMAT_RGBA_ASTC_6x5_KHR:
@@ -1761,39 +1824,39 @@
 		case FORMAT_SRGB8_ALPHA8_ASTC_8x5_KHR:
 		case FORMAT_RGBA_ASTC_10x5_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_10x5_KHR:
-			return pitchB(width, format, target) * ((height + 4) / 5);   // Pitch computed per 5 rows
+			return pitchB(width, border, format, target) * ((height + 4) / 5);   // Pitch computed per 5 rows
 		case FORMAT_RGBA_ASTC_6x6_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_6x6_KHR:
 		case FORMAT_RGBA_ASTC_8x6_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_8x6_KHR:
 		case FORMAT_RGBA_ASTC_10x6_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_10x6_KHR:
-			return pitchB(width, format, target) * ((height + 5) / 6);   // Pitch computed per 6 rows
+			return pitchB(width, border, format, target) * ((height + 5) / 6);   // Pitch computed per 6 rows
 		case FORMAT_RGBA_ASTC_8x8_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_8x8_KHR:
 		case FORMAT_RGBA_ASTC_10x8_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_10x8_KHR:
-			return pitchB(width, format, target) * ((height + 7) / 8);   // Pitch computed per 8 rows
+			return pitchB(width, border, format, target) * ((height + 7) / 8);   // Pitch computed per 8 rows
 		case FORMAT_RGBA_ASTC_10x10_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_10x10_KHR:
 		case FORMAT_RGBA_ASTC_12x10_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_12x10_KHR:
-			return pitchB(width, format, target) * ((height + 9) / 10);   // Pitch computed per 10 rows
+			return pitchB(width, border, format, target) * ((height + 9) / 10);   // Pitch computed per 10 rows
 		case FORMAT_RGBA_ASTC_12x12_KHR:
 		case FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR:
-			return pitchB(width, format, target) * ((height + 11) / 12);   // Pitch computed per 12 rows
+			return pitchB(width, border, format, target) * ((height + 11) / 12);   // Pitch computed per 12 rows
 		case FORMAT_ATI1:
 		case FORMAT_ATI2:
 		default:
-			return pitchB(width, format, target) * height;   // Pitch computed per row
+			return pitchB(width, border, format, target) * height;   // Pitch computed per row
 		}
 	}
 
-	int Surface::sliceP(int width, int height, Format format, bool target)
+	int Surface::sliceP(int width, int height, int border, Format format, bool target)
 	{
 		int B = bytes(format);
 
-		return B > 0 ? sliceB(width, height, format, target) / B : 0;
+		return B > 0 ? sliceB(width, height, border, format, target) / B : 0;
 	}
 
 	void Surface::update(Buffer &destination, Buffer &source)
@@ -1813,11 +1876,9 @@
 			case FORMAT_X4R4G4B4:	decodeX4R4G4B4(destination, source);	break;   // FIXME: Check destination format
 			case FORMAT_A4R4G4B4:	decodeA4R4G4B4(destination, source);	break;   // FIXME: Check destination format
 			case FORMAT_P8:			decodeP8(destination, source);			break;   // FIXME: Check destination format
-			#if S3TC_SUPPORT
 			case FORMAT_DXT1:		decodeDXT1(destination, source);		break;   // FIXME: Check destination format
 			case FORMAT_DXT3:		decodeDXT3(destination, source);		break;   // FIXME: Check destination format
 			case FORMAT_DXT5:		decodeDXT5(destination, source);		break;   // FIXME: Check destination format
-			#endif
 			case FORMAT_ATI1:		decodeATI1(destination, source);		break;   // FIXME: Check destination format
 			case FORMAT_ATI2:		decodeATI2(destination, source);		break;   // FIXME: Check destination format
 			case FORMAT_R11_EAC:         decodeEAC(destination, source, 1, false); break; // FIXME: Check destination format
@@ -1866,8 +1927,8 @@
 
 	void Surface::genericUpdate(Buffer &destination, Buffer &source)
 	{
-		unsigned char *sourceSlice = (unsigned char*)source.buffer;
-		unsigned char *destinationSlice = (unsigned char*)destination.buffer;
+		unsigned char *sourceSlice = (unsigned char*)source.lockRect(0, 0, 0, sw::LOCK_READONLY);
+		unsigned char *destinationSlice = (unsigned char*)destination.lockRect(0, 0, 0, sw::LOCK_UPDATE);
 
 		int depth = min(destination.depth, source.depth);
 		int height = min(destination.height, source.height);
@@ -1907,24 +1968,31 @@
 			sourceSlice += source.sliceB;
 			destinationSlice += destination.sliceB;
 		}
+
+		source.unlockRect();
+		destination.unlockRect();
 	}
 
-	void Surface::decodeR8G8B8(Buffer &destination, const Buffer &source)
+	void Surface::decodeR8G8B8(Buffer &destination, Buffer &source)
 	{
-		unsigned char *sourceSlice = (unsigned char*)source.buffer;
-		unsigned char *destinationSlice = (unsigned char*)destination.buffer;
+		unsigned char *sourceSlice = (unsigned char*)source.lockRect(0, 0, 0, sw::LOCK_READONLY);
+		unsigned char *destinationSlice = (unsigned char*)destination.lockRect(0, 0, 0, sw::LOCK_UPDATE);
 
-		for(int z = 0; z < destination.depth && z < source.depth; z++)
+		int depth = min(destination.depth, source.depth);
+		int height = min(destination.height, source.height);
+		int width = min(destination.width, source.width);
+
+		for(int z = 0; z < depth; z++)
 		{
 			unsigned char *sourceRow = sourceSlice;
 			unsigned char *destinationRow = destinationSlice;
 
-			for(int y = 0; y < destination.height && y < source.height; y++)
+			for(int y = 0; y < height; y++)
 			{
 				unsigned char *sourceElement = sourceRow;
 				unsigned char *destinationElement = destinationRow;
 
-				for(int x = 0; x < destination.width && x < source.width; x++)
+				for(int x = 0; x < width; x++)
 				{
 					unsigned int b = sourceElement[0];
 					unsigned int g = sourceElement[1];
@@ -1943,24 +2011,31 @@
 			sourceSlice += source.sliceB;
 			destinationSlice += destination.sliceB;
 		}
+
+		source.unlockRect();
+		destination.unlockRect();
 	}
 
-	void Surface::decodeX1R5G5B5(Buffer &destination, const Buffer &source)
+	void Surface::decodeX1R5G5B5(Buffer &destination, Buffer &source)
 	{
-		unsigned char *sourceSlice = (unsigned char*)source.buffer;
-		unsigned char *destinationSlice = (unsigned char*)destination.buffer;
+		unsigned char *sourceSlice = (unsigned char*)source.lockRect(0, 0, 0, sw::LOCK_READONLY);
+		unsigned char *destinationSlice = (unsigned char*)destination.lockRect(0, 0, 0, sw::LOCK_UPDATE);
 
-		for(int z = 0; z < destination.depth && z < source.depth; z++)
+		int depth = min(destination.depth, source.depth);
+		int height = min(destination.height, source.height);
+		int width = min(destination.width, source.width);
+
+		for(int z = 0; z < depth; z++)
 		{
 			unsigned char *sourceRow = sourceSlice;
 			unsigned char *destinationRow = destinationSlice;
 
-			for(int y = 0; y < destination.height && y < source.height; y++)
+			for(int y = 0; y < height; y++)
 			{
 				unsigned char *sourceElement = sourceRow;
 				unsigned char *destinationElement = destinationRow;
 
-				for(int x = 0; x < destination.width && x < source.width; x++)
+				for(int x = 0; x < width; x++)
 				{
 					unsigned int xrgb = *(unsigned short*)sourceElement;
 
@@ -1981,24 +2056,31 @@
 			sourceSlice += source.sliceB;
 			destinationSlice += destination.sliceB;
 		}
+
+		source.unlockRect();
+		destination.unlockRect();
 	}
 
-	void Surface::decodeA1R5G5B5(Buffer &destination, const Buffer &source)
+	void Surface::decodeA1R5G5B5(Buffer &destination, Buffer &source)
 	{
-		unsigned char *sourceSlice = (unsigned char*)source.buffer;
-		unsigned char *destinationSlice = (unsigned char*)destination.buffer;
+		unsigned char *sourceSlice = (unsigned char*)source.lockRect(0, 0, 0, sw::LOCK_READONLY);
+		unsigned char *destinationSlice = (unsigned char*)destination.lockRect(0, 0, 0, sw::LOCK_UPDATE);
 
-		for(int z = 0; z < destination.depth && z < source.depth; z++)
+		int depth = min(destination.depth, source.depth);
+		int height = min(destination.height, source.height);
+		int width = min(destination.width, source.width);
+
+		for(int z = 0; z < depth; z++)
 		{
 			unsigned char *sourceRow = sourceSlice;
 			unsigned char *destinationRow = destinationSlice;
 
-			for(int y = 0; y < destination.height && y < source.height; y++)
+			for(int y = 0; y < height; y++)
 			{
 				unsigned char *sourceElement = sourceRow;
 				unsigned char *destinationElement = destinationRow;
 
-				for(int x = 0; x < destination.width && x < source.width; x++)
+				for(int x = 0; x < width; x++)
 				{
 					unsigned int argb = *(unsigned short*)sourceElement;
 
@@ -2020,24 +2102,31 @@
 			sourceSlice += source.sliceB;
 			destinationSlice += destination.sliceB;
 		}
+
+		source.unlockRect();
+		destination.unlockRect();
 	}
 
-	void Surface::decodeX4R4G4B4(Buffer &destination, const Buffer &source)
+	void Surface::decodeX4R4G4B4(Buffer &destination, Buffer &source)
 	{
-		unsigned char *sourceSlice = (unsigned char*)source.buffer;
-		unsigned char *destinationSlice = (unsigned char*)destination.buffer;
+		unsigned char *sourceSlice = (unsigned char*)source.lockRect(0, 0, 0, sw::LOCK_READONLY);
+		unsigned char *destinationSlice = (unsigned char*)destination.lockRect(0, 0, 0, sw::LOCK_UPDATE);
 
-		for(int z = 0; z < destination.depth && z < source.depth; z++)
+		int depth = min(destination.depth, source.depth);
+		int height = min(destination.height, source.height);
+		int width = min(destination.width, source.width);
+
+		for(int z = 0; z < depth; z++)
 		{
 			unsigned char *sourceRow = sourceSlice;
 			unsigned char *destinationRow = destinationSlice;
 
-			for(int y = 0; y < destination.height && y < source.height; y++)
+			for(int y = 0; y < height; y++)
 			{
 				unsigned char *sourceElement = sourceRow;
 				unsigned char *destinationElement = destinationRow;
 
-				for(int x = 0; x < destination.width && x < source.width; x++)
+				for(int x = 0; x < width; x++)
 				{
 					unsigned int xrgb = *(unsigned short*)sourceElement;
 
@@ -2058,24 +2147,31 @@
 			sourceSlice += source.sliceB;
 			destinationSlice += destination.sliceB;
 		}
+
+		source.unlockRect();
+		destination.unlockRect();
 	}
 
-	void Surface::decodeA4R4G4B4(Buffer &destination, const Buffer &source)
+	void Surface::decodeA4R4G4B4(Buffer &destination, Buffer &source)
 	{
-		unsigned char *sourceSlice = (unsigned char*)source.buffer;
-		unsigned char *destinationSlice = (unsigned char*)destination.buffer;
+		unsigned char *sourceSlice = (unsigned char*)source.lockRect(0, 0, 0, sw::LOCK_READONLY);
+		unsigned char *destinationSlice = (unsigned char*)destination.lockRect(0, 0, 0, sw::LOCK_UPDATE);
 
-		for(int z = 0; z < destination.depth && z < source.depth; z++)
+		int depth = min(destination.depth, source.depth);
+		int height = min(destination.height, source.height);
+		int width = min(destination.width, source.width);
+
+		for(int z = 0; z < depth; z++)
 		{
 			unsigned char *sourceRow = sourceSlice;
 			unsigned char *destinationRow = destinationSlice;
 
-			for(int y = 0; y < destination.height && y < source.height; y++)
+			for(int y = 0; y < height; y++)
 			{
 				unsigned char *sourceElement = sourceRow;
 				unsigned char *destinationElement = destinationRow;
 
-				for(int x = 0; x < destination.width && x < source.width; x++)
+				for(int x = 0; x < width; x++)
 				{
 					unsigned int argb = *(unsigned short*)sourceElement;
 
@@ -2097,24 +2193,31 @@
 			sourceSlice += source.sliceB;
 			destinationSlice += destination.sliceB;
 		}
+
+		source.unlockRect();
+		destination.unlockRect();
 	}
 
-	void Surface::decodeP8(Buffer &destination, const Buffer &source)
+	void Surface::decodeP8(Buffer &destination, Buffer &source)
 	{
-		unsigned char *sourceSlice = (unsigned char*)source.buffer;
-		unsigned char *destinationSlice = (unsigned char*)destination.buffer;
+		unsigned char *sourceSlice = (unsigned char*)source.lockRect(0, 0, 0, sw::LOCK_READONLY);
+		unsigned char *destinationSlice = (unsigned char*)destination.lockRect(0, 0, 0, sw::LOCK_UPDATE);
 
-		for(int z = 0; z < destination.depth && z < source.depth; z++)
+		int depth = min(destination.depth, source.depth);
+		int height = min(destination.height, source.height);
+		int width = min(destination.width, source.width);
+
+		for(int z = 0; z < depth; z++)
 		{
 			unsigned char *sourceRow = sourceSlice;
 			unsigned char *destinationRow = destinationSlice;
 
-			for(int y = 0; y < destination.height && y < source.height; y++)
+			for(int y = 0; y < height; y++)
 			{
 				unsigned char *sourceElement = sourceRow;
 				unsigned char *destinationElement = destinationRow;
 
-				for(int x = 0; x < destination.width && x < source.width; x++)
+				for(int x = 0; x < width; x++)
 				{
 					unsigned int abgr = palette[*(unsigned char*)sourceElement];
 
@@ -2136,13 +2239,15 @@
 			sourceSlice += source.sliceB;
 			destinationSlice += destination.sliceB;
 		}
+
+		source.unlockRect();
+		destination.unlockRect();
 	}
 
-#if S3TC_SUPPORT
-	void Surface::decodeDXT1(Buffer &internal, const Buffer &external)
+	void Surface::decodeDXT1(Buffer &internal, Buffer &external)
 	{
-		unsigned int *destSlice = (unsigned int*)internal.buffer;
-		const DXT1 *source = (const DXT1*)external.buffer;
+		unsigned int *destSlice = (unsigned int*)internal.lockRect(0, 0, 0, LOCK_UPDATE);
+		const DXT1 *source = (const DXT1*)external.lockRect(0, 0, 0, LOCK_READONLY);
 
 		for(int z = 0; z < external.depth; z++)
 		{
@@ -2199,12 +2304,15 @@
 
 			(byte*&)destSlice += internal.sliceB;
 		}
+
+		external.unlockRect();
+		internal.unlockRect();
 	}
 
-	void Surface::decodeDXT3(Buffer &internal, const Buffer &external)
+	void Surface::decodeDXT3(Buffer &internal, Buffer &external)
 	{
-		unsigned int *destSlice = (unsigned int*)internal.buffer;
-		const DXT3 *source = (const DXT3*)external.buffer;
+		unsigned int *destSlice = (unsigned int*)internal.lockRect(0, 0, 0, LOCK_UPDATE);
+		const DXT3 *source = (const DXT3*)external.lockRect(0, 0, 0, LOCK_READONLY);
 
 		for(int z = 0; z < external.depth; z++)
 		{
@@ -2246,12 +2354,15 @@
 
 			(byte*&)destSlice += internal.sliceB;
 		}
+
+		external.unlockRect();
+		internal.unlockRect();
 	}
 
-	void Surface::decodeDXT5(Buffer &internal, const Buffer &external)
+	void Surface::decodeDXT5(Buffer &internal, Buffer &external)
 	{
-		unsigned int *destSlice = (unsigned int*)internal.buffer;
-		const DXT5 *source = (const DXT5*)external.buffer;
+		unsigned int *destSlice = (unsigned int*)internal.lockRect(0, 0, 0, LOCK_UPDATE);
+		const DXT5 *source = (const DXT5*)external.lockRect(0, 0, 0, LOCK_READONLY);
 
 		for(int z = 0; z < external.depth; z++)
 		{
@@ -2317,13 +2428,15 @@
 
 			(byte*&)destSlice += internal.sliceB;
 		}
-	}
-#endif
 
-	void Surface::decodeATI1(Buffer &internal, const Buffer &external)
+		external.unlockRect();
+		internal.unlockRect();
+	}
+
+	void Surface::decodeATI1(Buffer &internal, Buffer &external)
 	{
-		byte *destSlice = (byte*)internal.buffer;
-		const ATI1 *source = (const ATI1*)external.buffer;
+		byte *destSlice = (byte*)internal.lockRect(0, 0, 0, LOCK_UPDATE);
+		const ATI1 *source = (const ATI1*)external.lockRect(0, 0, 0, LOCK_READONLY);
 
 		for(int z = 0; z < external.depth; z++)
 		{
@@ -2371,12 +2484,15 @@
 
 			destSlice += internal.sliceB;
 		}
+
+		external.unlockRect();
+		internal.unlockRect();
 	}
 
-	void Surface::decodeATI2(Buffer &internal, const Buffer &external)
+	void Surface::decodeATI2(Buffer &internal, Buffer &external)
 	{
-		word *destSlice = (word*)internal.buffer;
-		const ATI2 *source = (const ATI2*)external.buffer;
+		word *destSlice = (word*)internal.lockRect(0, 0, 0, LOCK_UPDATE);
+		const ATI2 *source = (const ATI2*)external.lockRect(0, 0, 0, LOCK_READONLY);
 
 		for(int z = 0; z < external.depth; z++)
 		{
@@ -2451,12 +2567,17 @@
 
 			(byte*&)destSlice += internal.sliceB;
 		}
+
+		external.unlockRect();
+		internal.unlockRect();
 	}
 
-	void Surface::decodeETC2(Buffer &internal, const Buffer &external, int nbAlphaBits, bool isSRGB)
+	void Surface::decodeETC2(Buffer &internal, Buffer &external, int nbAlphaBits, bool isSRGB)
 	{
-		ETC_Decoder::Decode((const byte*)external.buffer, (byte*)internal.buffer, external.width, external.height, internal.width, internal.height, internal.pitchB, internal.bytes,
+		ETC_Decoder::Decode((const byte*)external.lockRect(0, 0, 0, LOCK_READONLY), (byte*)internal.lockRect(0, 0, 0, LOCK_UPDATE), external.width, external.height, internal.width, internal.height, internal.pitchB, internal.bytes,
 		                    (nbAlphaBits == 8) ? ETC_Decoder::ETC_RGBA : ((nbAlphaBits == 1) ? ETC_Decoder::ETC_RGB_PUNCHTHROUGH_ALPHA : ETC_Decoder::ETC_RGB));
+		external.unlockRect();
+		internal.unlockRect();
 
 		if(isSRGB)
 		{
@@ -2472,69 +2593,68 @@
 			}
 
 			// Perform sRGB conversion in place after decoding
-			byte* src = (byte*)internal.buffer;
+			byte *src = (byte*)internal.lockRect(0, 0, 0, LOCK_READWRITE);
 			for(int y = 0; y < internal.height; y++)
 			{
-				byte* srcRow = src + y * internal.pitchB;
+				byte *srcRow = src + y * internal.pitchB;
 				for(int x = 0; x <  internal.width; x++)
 				{
-					byte* srcPix = srcRow + x * internal.bytes;
+					byte *srcPix = srcRow + x * internal.bytes;
 					for(int i = 0; i < 3; i++)
 					{
 						srcPix[i] = sRGBtoLinearTable[srcPix[i]];
 					}
 				}
 			}
+			internal.unlockRect();
 		}
 	}
 
-	void Surface::decodeEAC(Buffer &internal, const Buffer &external, int nbChannels, bool isSigned)
+	void Surface::decodeEAC(Buffer &internal, Buffer &external, int nbChannels, bool isSigned)
 	{
 		ASSERT(nbChannels == 1 || nbChannels == 2);
 
-		ETC_Decoder::Decode((const byte*)external.buffer, (byte*)internal.buffer, external.width, external.height, internal.width, internal.height, internal.pitchB, internal.bytes,
+		byte *src = (byte*)internal.lockRect(0, 0, 0, LOCK_READWRITE);
+		ETC_Decoder::Decode((const byte*)external.lockRect(0, 0, 0, LOCK_READONLY), src, external.width, external.height, internal.width, internal.height, internal.pitchB, internal.bytes,
 		                    (nbChannels == 1) ? (isSigned ? ETC_Decoder::ETC_R_SIGNED : ETC_Decoder::ETC_R_UNSIGNED) : (isSigned ? ETC_Decoder::ETC_RG_SIGNED : ETC_Decoder::ETC_RG_UNSIGNED));
+		external.unlockRect();
 
-		// FIXME: We convert signed data to float, until signed integer internal formats are supported
-		//        This code can be removed if signed ETC2 images are decoded to internal 8 bit signed R/RG formats
-		if(isSigned)
+		// FIXME: We convert EAC data to float, until signed short internal formats are supported
+		//        This code can be removed if ETC2 images are decoded to internal 16 bit signed R/RG formats
+		const float normalization = isSigned ? (1.0f / (8.0f * 127.875f)) : (1.0f / (8.0f * 255.875f));
+		for(int y = 0; y < internal.height; y++)
 		{
-			sbyte* src = (sbyte*)internal.buffer;
-
-			for(int y = 0; y < internal.height; y++)
+			byte* srcRow = src + y * internal.pitchB;
+			for(int x = internal.width - 1; x >= 0; x--)
 			{
-				sbyte* srcRow = src + y * internal.pitchB;
-				for(int x = internal.width - 1; x >= 0; x--)
+				int* srcPix = reinterpret_cast<int*>(srcRow + x * internal.bytes);
+				float* dstPix = reinterpret_cast<float*>(srcPix);
+				for(int c = nbChannels - 1; c >= 0; c--)
 				{
-					int dx = x & 0xFFFFFFFC;
-					int mx = x - dx;
-					sbyte* srcPix = srcRow + dx * internal.bytes + mx * nbChannels;
-					float* dstPix = (float*)(srcRow + x * internal.bytes);
-					for(int c = nbChannels - 1; c >= 0; c--)
-					{
-						static const float normalization = 1.0f / 127.875f;
-						dstPix[c] = clamp(static_cast<float>(srcPix[c]) * normalization, -1.0f, 1.0f);
-					}
+					dstPix[c] = clamp(static_cast<float>(srcPix[c]) * normalization, -1.0f, 1.0f);
 				}
 			}
 		}
+
+		internal.unlockRect();
 	}
 
-	void Surface::decodeASTC(Buffer &internal, const Buffer &external, int xBlockSize, int yBlockSize, int zBlockSize, bool isSRGB)
+	void Surface::decodeASTC(Buffer &internal, Buffer &external, int xBlockSize, int yBlockSize, int zBlockSize, bool isSRGB)
 	{
 	}
 
-	unsigned int Surface::size(int width, int height, int depth, Format format)
+	unsigned int Surface::size(int width, int height, int depth, int border, int samples, Format format)
 	{
+		width += 2 * border;
+		height += 2 * border;
+
 		// Dimensions rounded up to multiples of 4, used for compressed formats
 		int width4 = align(width, 4);
 		int height4 = align(height, 4);
 
 		switch(format)
 		{
-		#if S3TC_SUPPORT
 		case FORMAT_DXT1:
-		#endif
 		case FORMAT_ATI1:
 		case FORMAT_ETC1:
 		case FORMAT_R11_EAC:
@@ -2544,10 +2664,8 @@
 		case FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
 		case FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
 			return width4 * height4 * depth / 2;
-		#if S3TC_SUPPORT
 		case FORMAT_DXT3:
 		case FORMAT_DXT5:
-		#endif
 		case FORMAT_ATI2:
 		case FORMAT_RG11_EAC:
 		case FORMAT_SIGNED_RG11_EAC:
@@ -2607,7 +2725,7 @@
 				return YSize + 2 * CSize;
 			}
 		default:
-			return bytes(format) * width * height * depth;
+			return bytes(format) * width * height * depth * samples;
 		}
 	}
 
@@ -2621,6 +2739,7 @@
 		case FORMAT_D32F:
 		case FORMAT_D32F_COMPLEMENTARY:
 		case FORMAT_D32F_LOCKABLE:
+		case FORMAT_D32F_SHADOW:
 			return false;
 		case FORMAT_D24S8:
 		case FORMAT_D24FS8:
@@ -2629,6 +2748,8 @@
 		case FORMAT_DF16S8:
 		case FORMAT_D32FS8_TEXTURE:
 		case FORMAT_D32FS8_SHADOW:
+		case FORMAT_D32FS8:
+		case FORMAT_D32FS8_COMPLEMENTARY:
 		case FORMAT_INTZ:
 			return true;
 		default:
@@ -2646,11 +2767,14 @@
 		case FORMAT_D24S8:
 		case FORMAT_D24FS8:
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_COMPLEMENTARY:
+		case FORMAT_D32FS8_COMPLEMENTARY:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_DF24S8:
 		case FORMAT_DF16S8:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		case FORMAT_INTZ:
 			return true;
@@ -2671,7 +2795,9 @@
 		case FORMAT_D24S8:
 		case FORMAT_D24FS8:
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_COMPLEMENTARY:
+		case FORMAT_D32FS8_COMPLEMENTARY:
 		case FORMAT_DF24S8:
 		case FORMAT_DF16S8:
 		case FORMAT_INTZ:
@@ -2681,6 +2807,7 @@
 			return true;
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		default:
 			break;
@@ -2723,10 +2850,11 @@
 		case FORMAT_G8R8I:
 		case FORMAT_G8R8:
 		case FORMAT_A2B10G10R10:
-		case FORMAT_R8I_SNORM:
-		case FORMAT_G8R8I_SNORM:
-		case FORMAT_X8B8G8R8I_SNORM:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_A2B10G10R10UI:
+		case FORMAT_R8_SNORM:
+		case FORMAT_G8R8_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 		case FORMAT_R16I:
 		case FORMAT_R16UI:
 		case FORMAT_G16R16I:
@@ -2765,16 +2893,22 @@
 		case FORMAT_R16F:
 		case FORMAT_G16R16F:
 		case FORMAT_B16G16R16F:
+		case FORMAT_X16B16G16R16F:
 		case FORMAT_A16B16G16R16F:
+		case FORMAT_X16B16G16R16F_UNSIGNED:
 		case FORMAT_R32F:
 		case FORMAT_G32R32F:
 		case FORMAT_B32G32R32F:
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_COMPLEMENTARY:
+		case FORMAT_D32FS8_COMPLEMENTARY:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		case FORMAT_L16F:
 		case FORMAT_A16L16F:
@@ -2804,6 +2938,7 @@
 		case FORMAT_SRGB8_A8:
 		case FORMAT_G8R8:
 		case FORMAT_A2B10G10R10:
+		case FORMAT_A2B10G10R10UI:
 		case FORMAT_R16UI:
 		case FORMAT_G16R16:
 		case FORMAT_G16R16UI:
@@ -2814,14 +2949,18 @@
 		case FORMAT_G32R32UI:
 		case FORMAT_X32B32G32R32UI:
 		case FORMAT_A32B32G32R32UI:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_R8UI:
 		case FORMAT_G8R8UI:
 		case FORMAT_X8B8G8R8UI:
 		case FORMAT_A8B8G8R8UI:
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_COMPLEMENTARY:
+		case FORMAT_D32FS8_COMPLEMENTARY:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		case FORMAT_A8:
 		case FORMAT_R8:
@@ -2835,7 +2974,7 @@
 		case FORMAT_A8B8G8R8I:
 		case FORMAT_A16B16G16R16I:
 		case FORMAT_A32B32G32R32I:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 		case FORMAT_Q8W8V8U8:
 		case FORMAT_Q16W16V16U16:
 		case FORMAT_A32B32G32R32F:
@@ -2844,7 +2983,7 @@
 		case FORMAT_R8I:
 		case FORMAT_R16I:
 		case FORMAT_R32I:
-		case FORMAT_R8I_SNORM:
+		case FORMAT_R8_SNORM:
 			return component >= 1;
 		case FORMAT_V8U8:
 		case FORMAT_X8L8V8U8:
@@ -2853,7 +2992,7 @@
 		case FORMAT_G8R8I:
 		case FORMAT_G16R16I:
 		case FORMAT_G32R32I:
-		case FORMAT_G8R8I_SNORM:
+		case FORMAT_G8R8_SNORM:
 			return component >= 2;
 		case FORMAT_A16W16V16U16:
 		case FORMAT_B32G32R32F:
@@ -2861,7 +3000,7 @@
 		case FORMAT_X8B8G8R8I:
 		case FORMAT_X16B16G16R16I:
 		case FORMAT_X32B32G32R32I:
-		case FORMAT_X8B8G8R8I_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
 			return component >= 3;
 		default:
 			ASSERT(false);
@@ -2888,11 +3027,9 @@
 		case FORMAT_X1R5G5B5:
 		case FORMAT_A1R5G5B5:
 		case FORMAT_A4R4G4B4:
-		#if S3TC_SUPPORT
 		case FORMAT_DXT1:
 		case FORMAT_DXT3:
 		case FORMAT_DXT5:
-		#endif
 		case FORMAT_ATI1:
 		case FORMAT_ATI2:
 			return true;
@@ -2920,15 +3057,25 @@
 		}
 	}
 
+	bool Surface::isSRGBformat(Format format)
+	{
+		switch(format)
+		{
+		case FORMAT_SRGB8_X8:
+		case FORMAT_SRGB8_A8:
+			return true;
+		default:
+			return false;
+		}
+	}
+
 	bool Surface::isCompressed(Format format)
 	{
 		switch(format)
 		{
-		#if S3TC_SUPPORT
 		case FORMAT_DXT1:
 		case FORMAT_DXT3:
 		case FORMAT_DXT5:
-		#endif
 		case FORMAT_ATI1:
 		case FORMAT_ATI2:
 		case FORMAT_ETC1:
@@ -3050,15 +3197,16 @@
 		case FORMAT_A8B8G8R8:       return 4;
 		case FORMAT_G8R8I:          return 2;
 		case FORMAT_G8R8:           return 2;
-		case FORMAT_R8I_SNORM:      return 1;
-		case FORMAT_G8R8I_SNORM:    return 2;
-		case FORMAT_X8B8G8R8I_SNORM:return 3;
-		case FORMAT_A8B8G8R8I_SNORM:return 4;
+		case FORMAT_R8_SNORM:      return 1;
+		case FORMAT_G8R8_SNORM:    return 2;
+		case FORMAT_X8B8G8R8_SNORM:return 3;
+		case FORMAT_A8B8G8R8_SNORM:return 4;
 		case FORMAT_R8UI:           return 1;
 		case FORMAT_G8R8UI:         return 2;
 		case FORMAT_X8B8G8R8UI:     return 3;
 		case FORMAT_A8B8G8R8UI:     return 4;
 		case FORMAT_A2B10G10R10:    return 4;
+		case FORMAT_A2B10G10R10UI:  return 4;
 		case FORMAT_G16R16I:        return 2;
 		case FORMAT_G16R16UI:       return 2;
 		case FORMAT_G16R16:         return 2;
@@ -3083,9 +3231,12 @@
 		case FORMAT_G32R32F:        return 2;
 		case FORMAT_X32B32G32R32F:  return 3;
 		case FORMAT_A32B32G32R32F:  return 4;
+		case FORMAT_X32B32G32R32F_UNSIGNED: return 3;
 		case FORMAT_D32F:           return 1;
+		case FORMAT_D32FS8:         return 1;
 		case FORMAT_D32F_LOCKABLE:  return 1;
 		case FORMAT_D32FS8_TEXTURE: return 1;
+		case FORMAT_D32F_SHADOW:    return 1;
 		case FORMAT_D32FS8_SHADOW:  return 1;
 		case FORMAT_A8:             return 1;
 		case FORMAT_R8I:            return 1;
@@ -3107,7 +3258,7 @@
 		return 1;
 	}
 
-	void *Surface::allocateBuffer(int width, int height, int depth, Format format)
+	void *Surface::allocateBuffer(int width, int height, int depth, int border, int samples, Format format)
 	{
 		// Render targets require 2x2 quads
 		int width2 = (width + 1) & ~1;
@@ -3116,7 +3267,7 @@
 		// FIXME: Unpacking byte4 to short4 in the sampler currently involves reading 8 bytes,
 		// and stencil operations also read 8 bytes per four 8-bit stencil values,
 		// so we have to allocate 4 extra bytes to avoid buffer overruns.
-		return allocate(size(width2, height2, depth, format) + 4);
+		return allocate(size(width2, height2, depth, border, samples, format) + 4);
 	}
 
 	void Surface::memfill4(void *buffer, int pattern, int bytes)
@@ -3222,24 +3373,22 @@
 		const bool entire = x0 == 0 && y0 == 0 && width == internal.width && height == internal.height;
 		const Lock lock = entire ? LOCK_DISCARD : LOCK_WRITEONLY;
 
-		int width2 = (internal.width + 1) & ~1;
-
 		int x1 = x0 + width;
 		int y1 = y0 + height;
 
-		if(internal.format == FORMAT_D32F_LOCKABLE ||
-		   internal.format == FORMAT_D32FS8_TEXTURE ||
-		   internal.format == FORMAT_D32FS8_SHADOW)
+		if(!hasQuadLayout(internal.format))
 		{
-			float *target = (float*)lockInternal(0, 0, 0, lock, PUBLIC) + x0 + width2 * y0;
+			float *target = (float*)lockInternal(x0, y0, 0, lock, PUBLIC);
 
-			for(int z = 0; z < internal.depth; z++)
+			for(int z = 0; z < internal.samples; z++)
 			{
+				float *row = target;
 				for(int y = y0; y < y1; y++)
 				{
-					memfill4(target, (int&)depth, 4 * width);
-					target += width2;
+					memfill4(row, (int&)depth, width * sizeof(float));
+					row += internal.pitchP;
 				}
+				target += internal.sliceP;
 			}
 
 			unlockInternal();
@@ -3258,11 +3407,11 @@
 			int evenX0 = ((x0 + 1) & ~1) * 2;
 			int evenBytes = (oddX1 - evenX0) * sizeof(float);
 
-			for(int z = 0; z < internal.depth; z++)
+			for(int z = 0; z < internal.samples; z++)
 			{
 				for(int y = y0; y < y1; y++)
 				{
-					float *target = buffer + (y & ~1) * width2 + (y & 1) * 2;
+					float *target = buffer + (y & ~1) * internal.pitchP + (y & 1) * 2;
 
 					if((y & 1) == 0 && y + 1 < y1)   // Fill quad line at once
 					{
@@ -3344,8 +3493,6 @@
 		if(y0 < 0) {height += y0; y0 = 0;}
 		if(y0 + height > internal.height) height = internal.height - y0;
 
-		int width2 = (internal.width + 1) & ~1;
-
 		int x1 = x0 + width;
 		int y1 = y0 + height;
 
@@ -3362,11 +3509,11 @@
 		char *buffer = (char*)lockStencil(0, 0, 0, PUBLIC);
 
 		// Stencil buffers are assumed to use quad layout
-		for(int z = 0; z < stencil.depth; z++)
+		for(int z = 0; z < stencil.samples; z++)
 		{
 			for(int y = y0; y < y1; y++)
 			{
-				char *target = buffer + (y & ~1) * width2 + (y & 1) * 2;
+				char *target = buffer + (y & ~1) * stencil.pitchP + (y & 1) * 2;
 
 				if((y & 1) == 0 && y + 1 < y1 && mask == 0xFF)   // Fill quad line at once
 				{
@@ -3388,8 +3535,9 @@
 				}
 				else
 				{
-					for(int x = x0, i = oddX0; x < x1; x++, i = (x & ~1) * 2 + (x & 1))
+					for(int x = x0; x < x1; x++)
 					{
+						int i = (x & ~1) * 2 + (x & 1);
 						target[i] = maskedS | (target[i] & invMask);
 					}
 				}
@@ -3459,7 +3607,7 @@
 		}
 	}
 
-	void Surface::copyInternal(const Surface* source, int x, int y, float srcX, float srcY, bool filter)
+	void Surface::copyInternal(const Surface *source, int x, int y, float srcX, float srcY, bool filter)
 	{
 		ASSERT(internal.lock != LOCK_UNLOCKED && source && source->internal.lock != LOCK_UNLOCKED);
 
@@ -3467,17 +3615,17 @@
 
 		if(!filter)
 		{
-			color = source->internal.read((int)srcX, (int)srcY);
+			color = source->internal.read((int)srcX, (int)srcY, 0);
 		}
 		else   // Bilinear filtering
 		{
-			color = source->internal.sample(srcX, srcY);
+			color = source->internal.sample(srcX, srcY, 0);
 		}
 
 		internal.write(x, y, color);
 	}
 
-	void Surface::copyInternal(const Surface* source, int x, int y, int z, float srcX, float srcY, float srcZ, bool filter)
+	void Surface::copyInternal(const Surface *source, int x, int y, int z, float srcX, float srcY, float srcZ, bool filter)
 	{
 		ASSERT(internal.lock != LOCK_UNLOCKED && source && source->internal.lock != LOCK_UNLOCKED);
 
@@ -3495,6 +3643,81 @@
 		internal.write(x, y, z, color);
 	}
 
+	void Surface::copyCubeEdge(Edge dstEdge, Surface *src, Edge srcEdge)
+	{
+		Surface *dst = this;
+
+		// Figure out if the edges to be copied in reverse order respectively from one another
+		// The copy should be reversed whenever the same edges are contiguous or if we're
+		// copying top <-> right or bottom <-> left. This is explained by the layout, which is:
+		//
+		//      | +y |
+		// | -x | +z | +x | -z |
+		//      | -y |
+
+		bool reverse = (srcEdge == dstEdge) ||
+		               ((srcEdge == TOP) && (dstEdge == RIGHT)) ||
+		               ((srcEdge == RIGHT) && (dstEdge == TOP)) ||
+		               ((srcEdge == BOTTOM) && (dstEdge == LEFT)) ||
+		               ((srcEdge == LEFT) && (dstEdge == BOTTOM));
+
+		int srcBytes = src->bytes(src->Surface::getInternalFormat());
+		int srcPitch = src->getInternalPitchB();
+		int dstBytes = dst->bytes(dst->Surface::getInternalFormat());
+		int dstPitch = dst->getInternalPitchB();
+
+		int srcW = src->getWidth();
+		int srcH = src->getHeight();
+		int dstW = dst->getWidth();
+		int dstH = dst->getHeight();
+
+		ASSERT(srcW == srcH && dstW == dstH && srcW == dstW && srcBytes == dstBytes);
+
+		// Src is expressed in the regular [0, width-1], [0, height-1] space
+		int srcDelta = ((srcEdge == TOP) || (srcEdge == BOTTOM)) ? srcBytes : srcPitch;
+		int srcStart = ((srcEdge == BOTTOM) ? srcPitch * (srcH - 1) : ((srcEdge == RIGHT) ? srcBytes * (srcW - 1) : 0));
+
+		// Dst contains borders, so it is expressed in the [-1, width+1], [-1, height+1] space
+		int dstDelta = (((dstEdge == TOP) || (dstEdge == BOTTOM)) ? dstBytes : dstPitch) * (reverse ? -1 : 1);
+		int dstStart = ((dstEdge == BOTTOM) ? dstPitch * (dstH + 1) : ((dstEdge == RIGHT) ? dstBytes * (dstW + 1) : 0)) + (reverse ? dstW * -dstDelta : dstDelta);
+
+		char *srcBuf = (char*)src->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PRIVATE) + srcStart;
+		char *dstBuf = (char*)dst->lockInternal(-1, -1, 0, sw::LOCK_READWRITE, sw::PRIVATE) + dstStart;
+
+		for(int i = 0; i < srcW; ++i, dstBuf += dstDelta, srcBuf += srcDelta)
+		{
+			memcpy(dstBuf, srcBuf, srcBytes);
+		}
+
+		if(dstEdge == LEFT || dstEdge == RIGHT)
+		{
+			// TOP and BOTTOM are already set, let's average out the corners
+			int x0 = (dstEdge == RIGHT) ? dstW : -1;
+			int y0 = -1;
+			int x1 = (dstEdge == RIGHT) ? dstW - 1 : 0;
+			int y1 = 0;
+			dst->computeCubeCorner(x0, y0, x1, y1);
+			y0 = dstH;
+			y1 = dstH - 1;
+			dst->computeCubeCorner(x0, y0, x1, y1);
+		}
+
+		src->unlockInternal();
+		dst->unlockInternal();
+	}
+
+	void Surface::computeCubeCorner(int x0, int y0, int x1, int y1)
+	{
+		ASSERT(internal.lock != LOCK_UNLOCKED);
+
+		sw::Color<float> color = internal.read(x0, y1);
+		color += internal.read(x1, y0);
+		color += internal.read(x1, y1);
+		color *= (1.0f / 3.0f);
+
+		internal.write(x0, y0, color);
+	}
+
 	bool Surface::hasStencil() const
 	{
 		return isStencil(external.format);
@@ -3515,14 +3738,14 @@
 		return renderTarget;
 	}
 
-	bool Surface::hasDirtyMipmaps() const
+	bool Surface::hasDirtyContents() const
 	{
-		return dirtyMipmaps;
+		return dirtyContents;
 	}
 
-	void Surface::cleanMipmaps()
+	void Surface::markContentsClean()
 	{
-		dirtyMipmaps = false;
+		dirtyContents = false;
 	}
 
 	Resource *Surface::getResource()
@@ -3537,7 +3760,9 @@
 		       external.height == internal.height &&
 		       external.depth  == internal.depth &&
 		       external.pitchB == internal.pitchB &&
-		       external.sliceB == internal.sliceB;
+		       external.sliceB == internal.sliceB &&
+		       external.border == internal.border &&
+		       external.samples == internal.samples;
 	}
 
 	Format Surface::selectInternalFormat(Format format) const
@@ -3558,8 +3783,8 @@
 			return FORMAT_R8I;
 		case FORMAT_R8UI:
 			return FORMAT_R8UI;
-		case FORMAT_R8I_SNORM:
-			return FORMAT_R8I_SNORM;
+		case FORMAT_R8_SNORM:
+			return FORMAT_R8_SNORM;
 		case FORMAT_R8:
 			return FORMAT_R8;
 		case FORMAT_R16I:
@@ -3571,27 +3796,33 @@
 		case FORMAT_R32UI:
 			return FORMAT_R32UI;
 		case FORMAT_X16B16G16R16I:
+			return FORMAT_X16B16G16R16I;
 		case FORMAT_A16B16G16R16I:
 			return FORMAT_A16B16G16R16I;
 		case FORMAT_X16B16G16R16UI:
+			return FORMAT_X16B16G16R16UI;
 		case FORMAT_A16B16G16R16UI:
 			return FORMAT_A16B16G16R16UI;
 		case FORMAT_A2R10G10B10:
 		case FORMAT_A2B10G10R10:
 		case FORMAT_A16B16G16R16:
 			return FORMAT_A16B16G16R16;
+		case FORMAT_A2B10G10R10UI:
+			return FORMAT_A16B16G16R16UI;
 		case FORMAT_X32B32G32R32I:
+			return FORMAT_X32B32G32R32I;
 		case FORMAT_A32B32G32R32I:
 			return FORMAT_A32B32G32R32I;
 		case FORMAT_X32B32G32R32UI:
+			return FORMAT_X32B32G32R32UI;
 		case FORMAT_A32B32G32R32UI:
 			return FORMAT_A32B32G32R32UI;
 		case FORMAT_G8R8I:
 			return FORMAT_G8R8I;
 		case FORMAT_G8R8UI:
 			return FORMAT_G8R8UI;
-		case FORMAT_G8R8I_SNORM:
-			return FORMAT_G8R8I_SNORM;
+		case FORMAT_G8R8_SNORM:
+			return FORMAT_G8R8_SNORM;
 		case FORMAT_G8R8:
 			return FORMAT_G8R8;
 		case FORMAT_G16R16I:
@@ -3617,8 +3848,8 @@
 			return FORMAT_A8B8G8R8I;
 		case FORMAT_A8B8G8R8UI:
 			return FORMAT_A8B8G8R8UI;
-		case FORMAT_A8B8G8R8I_SNORM:
-			return FORMAT_A8B8G8R8I_SNORM;
+		case FORMAT_A8B8G8R8_SNORM:
+			return FORMAT_A8B8G8R8_SNORM;
 		case FORMAT_R5G5B5A1:
 		case FORMAT_R4G4B4A4:
 		case FORMAT_A8B8G8R8:
@@ -3642,8 +3873,8 @@
 			return FORMAT_X8B8G8R8I;
 		case FORMAT_X8B8G8R8UI:
 			return FORMAT_X8B8G8R8UI;
-		case FORMAT_X8B8G8R8I_SNORM:
-			return FORMAT_X8B8G8R8I_SNORM;
+		case FORMAT_X8B8G8R8_SNORM:
+			return FORMAT_X8B8G8R8_SNORM;
 		case FORMAT_B8G8R8:
 		case FORMAT_X8B8G8R8:
 			return FORMAT_X8B8G8R8;
@@ -3652,11 +3883,9 @@
 		case FORMAT_SRGB8_A8:
 			return FORMAT_SRGB8_A8;
 		// Compressed formats
-		#if S3TC_SUPPORT
 		case FORMAT_DXT1:
 		case FORMAT_DXT3:
 		case FORMAT_DXT5:
-		#endif
 		case FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
 		case FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
 		case FORMAT_RGBA8_ETC2_EAC:
@@ -3693,13 +3922,13 @@
 			// ASTC supports HDR, so a floating point format is required to represent it properly
 			return FORMAT_A32B32G32R32F; // FIXME: 16FP is probably sufficient, but it's currently unsupported
 		case FORMAT_ATI1:
-		case FORMAT_R11_EAC:
 			return FORMAT_R8;
+		case FORMAT_R11_EAC:
 		case FORMAT_SIGNED_R11_EAC:
 			return FORMAT_R32F; // FIXME: Signed 8bit format would be sufficient
 		case FORMAT_ATI2:
-		case FORMAT_RG11_EAC:
 			return FORMAT_G8R8;
+		case FORMAT_RG11_EAC:
 		case FORMAT_SIGNED_RG11_EAC:
 			return FORMAT_G32R32F; // FIXME: Signed 8bit format would be sufficient
 		case FORMAT_ETC1:
@@ -3719,13 +3948,16 @@
 		case FORMAT_R16F:			return FORMAT_R32F;
 		case FORMAT_G16R16F:		return FORMAT_G32R32F;
 		case FORMAT_B16G16R16F:     return FORMAT_X32B32G32R32F;
+		case FORMAT_X16B16G16R16F:	return FORMAT_X32B32G32R32F;
 		case FORMAT_A16B16G16R16F:	return FORMAT_A32B32G32R32F;
+		case FORMAT_X16B16G16R16F_UNSIGNED: return FORMAT_X32B32G32R32F_UNSIGNED;
 		case FORMAT_A32F:			return FORMAT_A32B32G32R32F;
 		case FORMAT_R32F:			return FORMAT_R32F;
 		case FORMAT_G32R32F:		return FORMAT_G32R32F;
 		case FORMAT_B32G32R32F:     return FORMAT_X32B32G32R32F;
 		case FORMAT_X32B32G32R32F:  return FORMAT_X32B32G32R32F;
 		case FORMAT_A32B32G32R32F:	return FORMAT_A32B32G32R32F;
+		case FORMAT_X32B32G32R32F_UNSIGNED: return FORMAT_X32B32G32R32F_UNSIGNED;
 		// Luminance formats
 		case FORMAT_L8:				return FORMAT_L8;
 		case FORMAT_A4L4:			return FORMAT_A8L8;
@@ -3739,11 +3971,9 @@
 		case FORMAT_D16:
 		case FORMAT_D32:
 		case FORMAT_D24X8:
-		case FORMAT_D24S8:
-		case FORMAT_D24FS8:
 			if(hasParent)   // Texture
 			{
-				return FORMAT_D32FS8_SHADOW;
+				return FORMAT_D32F_SHADOW;
 			}
 			else if(complementaryDepthBuffer)
 			{
@@ -3753,12 +3983,29 @@
 			{
 				return FORMAT_D32F;
 			}
+		case FORMAT_D24S8:
+		case FORMAT_D24FS8:
+			if(hasParent)   // Texture
+			{
+				return FORMAT_D32FS8_SHADOW;
+			}
+			else if(complementaryDepthBuffer)
+			{
+				return FORMAT_D32FS8_COMPLEMENTARY;
+			}
+			else
+			{
+				return FORMAT_D32FS8;
+			}
 		case FORMAT_D32F:           return FORMAT_D32F;
+		case FORMAT_D32FS8:         return FORMAT_D32FS8;
 		case FORMAT_D32F_LOCKABLE:  return FORMAT_D32F_LOCKABLE;
 		case FORMAT_D32FS8_TEXTURE: return FORMAT_D32FS8_TEXTURE;
 		case FORMAT_INTZ:           return FORMAT_D32FS8_TEXTURE;
 		case FORMAT_DF24S8:         return FORMAT_D32FS8_SHADOW;
 		case FORMAT_DF16S8:         return FORMAT_D32FS8_SHADOW;
+		case FORMAT_S8:             return FORMAT_S8;
+		// YUV formats
 		case FORMAT_YV12_BT601:     return FORMAT_YV12_BT601;
 		case FORMAT_YV12_BT709:     return FORMAT_YV12_BT709;
 		case FORMAT_YV12_JFIF:      return FORMAT_YV12_JFIF;
@@ -3777,11 +4024,13 @@
 
 	void Surface::resolve()
 	{
-		if(internal.depth <= 1 || !internal.dirty || !renderTarget || internal.format == FORMAT_NULL)
+		if(internal.samples <= 1 || !internal.dirty || !renderTarget || internal.format == FORMAT_NULL)
 		{
 			return;
 		}
 
+		ASSERT(internal.depth == 1);  // Unimplemented
+
 		void *source = internal.lockRect(0, 0, 0, LOCK_READWRITE);
 
 		int width = internal.width;
@@ -3813,7 +4062,7 @@
 			#if defined(__i386__) || defined(__x86_64__)
 				if(CPUID::supportsSSE2() && (width % 4) == 0)
 				{
-					if(internal.depth == 2)
+					if(internal.samples == 2)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -3831,7 +4080,7 @@
 							source1 += pitch;
 						}
 					}
-					else if(internal.depth == 4)
+					else if(internal.samples == 4)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -3855,7 +4104,7 @@
 							source3 += pitch;
 						}
 					}
-					else if(internal.depth == 8)
+					else if(internal.samples == 8)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -3891,7 +4140,7 @@
 							source7 += pitch;
 						}
 					}
-					else if(internal.depth == 16)
+					else if(internal.samples == 16)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -3958,7 +4207,7 @@
 			{
 				#define AVERAGE(x, y) (((x) & (y)) + ((((x) ^ (y)) >> 1) & 0x7F7F7F7F) + (((x) ^ (y)) & 0x01010101))
 
-				if(internal.depth == 2)
+				if(internal.samples == 2)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -3976,7 +4225,7 @@
 						source1 += pitch;
 					}
 				}
-				else if(internal.depth == 4)
+				else if(internal.samples == 4)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4000,7 +4249,7 @@
 						source3 += pitch;
 					}
 				}
-				else if(internal.depth == 8)
+				else if(internal.samples == 8)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4036,7 +4285,7 @@
 						source7 += pitch;
 					}
 				}
-				else if(internal.depth == 16)
+				else if(internal.samples == 16)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4107,7 +4356,7 @@
 			#if defined(__i386__) || defined(__x86_64__)
 				if(CPUID::supportsSSE2() && (width % 4) == 0)
 				{
-					if(internal.depth == 2)
+					if(internal.samples == 2)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4125,7 +4374,7 @@
 							source1 += pitch;
 						}
 					}
-					else if(internal.depth == 4)
+					else if(internal.samples == 4)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4149,7 +4398,7 @@
 							source3 += pitch;
 						}
 					}
-					else if(internal.depth == 8)
+					else if(internal.samples == 8)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4185,7 +4434,7 @@
 							source7 += pitch;
 						}
 					}
-					else if(internal.depth == 16)
+					else if(internal.samples == 16)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4252,7 +4501,7 @@
 			{
 				#define AVERAGE(x, y) (((x) & (y)) + ((((x) ^ (y)) >> 1) & 0x7FFF7FFF) + (((x) ^ (y)) & 0x00010001))
 
-				if(internal.depth == 2)
+				if(internal.samples == 2)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4270,7 +4519,7 @@
 						source1 += pitch;
 					}
 				}
-				else if(internal.depth == 4)
+				else if(internal.samples == 4)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4294,7 +4543,7 @@
 						source3 += pitch;
 					}
 				}
-				else if(internal.depth == 8)
+				else if(internal.samples == 8)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4330,7 +4579,7 @@
 						source7 += pitch;
 					}
 				}
-				else if(internal.depth == 16)
+				else if(internal.samples == 16)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4400,7 +4649,7 @@
 			#if defined(__i386__) || defined(__x86_64__)
 				if(CPUID::supportsSSE2() && (width % 2) == 0)
 				{
-					if(internal.depth == 2)
+					if(internal.samples == 2)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4418,7 +4667,7 @@
 							source1 += pitch;
 						}
 					}
-					else if(internal.depth == 4)
+					else if(internal.samples == 4)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4442,7 +4691,7 @@
 							source3 += pitch;
 						}
 					}
-					else if(internal.depth == 8)
+					else if(internal.samples == 8)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4478,7 +4727,7 @@
 							source7 += pitch;
 						}
 					}
-					else if(internal.depth == 16)
+					else if(internal.samples == 16)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4545,7 +4794,7 @@
 			{
 				#define AVERAGE(x, y) (((x) & (y)) + ((((x) ^ (y)) >> 1) & 0x7FFF7FFF) + (((x) ^ (y)) & 0x00010001))
 
-				if(internal.depth == 2)
+				if(internal.samples == 2)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4563,7 +4812,7 @@
 						source1 += pitch;
 					}
 				}
-				else if(internal.depth == 4)
+				else if(internal.samples == 4)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4587,7 +4836,7 @@
 						source3 += pitch;
 					}
 				}
-				else if(internal.depth == 8)
+				else if(internal.samples == 8)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4623,7 +4872,7 @@
 						source7 += pitch;
 					}
 				}
-				else if(internal.depth == 16)
+				else if(internal.samples == 16)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4693,7 +4942,7 @@
 			#if defined(__i386__) || defined(__x86_64__)
 				if(CPUID::supportsSSE() && (width % 4) == 0)
 				{
-					if(internal.depth == 2)
+					if(internal.samples == 2)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4712,7 +4961,7 @@
 							source1 += pitch;
 						}
 					}
-					else if(internal.depth == 4)
+					else if(internal.samples == 4)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4737,7 +4986,7 @@
 							source3 += pitch;
 						}
 					}
-					else if(internal.depth == 8)
+					else if(internal.samples == 8)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4774,7 +5023,7 @@
 							source7 += pitch;
 						}
 					}
-					else if(internal.depth == 16)
+					else if(internal.samples == 16)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -4840,7 +5089,7 @@
 				else
 			#endif
 			{
-				if(internal.depth == 2)
+				if(internal.samples == 2)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4859,7 +5108,7 @@
 						source1 += pitch;
 					}
 				}
-				else if(internal.depth == 4)
+				else if(internal.samples == 4)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4884,7 +5133,7 @@
 						source3 += pitch;
 					}
 				}
-				else if(internal.depth == 8)
+				else if(internal.samples == 8)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4921,7 +5170,7 @@
 						source7 += pitch;
 					}
 				}
-				else if(internal.depth == 16)
+				else if(internal.samples == 16)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -4990,7 +5239,7 @@
 			#if defined(__i386__) || defined(__x86_64__)
 				if(CPUID::supportsSSE() && (width % 2) == 0)
 				{
-					if(internal.depth == 2)
+					if(internal.samples == 2)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5009,7 +5258,7 @@
 							source1 += pitch;
 						}
 					}
-					else if(internal.depth == 4)
+					else if(internal.samples == 4)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5034,7 +5283,7 @@
 							source3 += pitch;
 						}
 					}
-					else if(internal.depth == 8)
+					else if(internal.samples == 8)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5071,7 +5320,7 @@
 							source7 += pitch;
 						}
 					}
-					else if(internal.depth == 16)
+					else if(internal.samples == 16)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5137,7 +5386,7 @@
 				else
 			#endif
 			{
-				if(internal.depth == 2)
+				if(internal.samples == 2)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5156,7 +5405,7 @@
 						source1 += pitch;
 					}
 				}
-				else if(internal.depth == 4)
+				else if(internal.samples == 4)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5181,7 +5430,7 @@
 						source3 += pitch;
 					}
 				}
-				else if(internal.depth == 8)
+				else if(internal.samples == 8)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5218,7 +5467,7 @@
 						source7 += pitch;
 					}
 				}
-				else if(internal.depth == 16)
+				else if(internal.samples == 16)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5282,12 +5531,14 @@
 				else ASSERT(false);
 			}
 		}
-		else if(internal.format == FORMAT_A32B32G32R32F || internal.format == FORMAT_X32B32G32R32F)
+		else if(internal.format == FORMAT_A32B32G32R32F ||
+		        internal.format == FORMAT_X32B32G32R32F ||
+		        internal.format == FORMAT_X32B32G32R32F_UNSIGNED)
 		{
 			#if defined(__i386__) || defined(__x86_64__)
 				if(CPUID::supportsSSE())
 				{
-					if(internal.depth == 2)
+					if(internal.samples == 2)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5306,7 +5557,7 @@
 							source1 += pitch;
 						}
 					}
-					else if(internal.depth == 4)
+					else if(internal.samples == 4)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5331,7 +5582,7 @@
 							source3 += pitch;
 						}
 					}
-					else if(internal.depth == 8)
+					else if(internal.samples == 8)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5368,7 +5619,7 @@
 							source7 += pitch;
 						}
 					}
-					else if(internal.depth == 16)
+					else if(internal.samples == 16)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5434,7 +5685,7 @@
 				else
 			#endif
 			{
-				if(internal.depth == 2)
+				if(internal.samples == 2)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5453,7 +5704,7 @@
 						source1 += pitch;
 					}
 				}
-				else if(internal.depth == 4)
+				else if(internal.samples == 4)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5478,7 +5729,7 @@
 						source3 += pitch;
 					}
 				}
-				else if(internal.depth == 8)
+				else if(internal.samples == 8)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5515,7 +5766,7 @@
 						source7 += pitch;
 					}
 				}
-				else if(internal.depth == 16)
+				else if(internal.samples == 16)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5584,7 +5835,7 @@
 			#if defined(__i386__) || defined(__x86_64__)
 				if(CPUID::supportsSSE2() && (width % 8) == 0)
 				{
-					if(internal.depth == 2)
+					if(internal.samples == 2)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5613,7 +5864,7 @@
 							source1 += pitch;
 						}
 					}
-					else if(internal.depth == 4)
+					else if(internal.samples == 4)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5654,7 +5905,7 @@
 							source3 += pitch;
 						}
 					}
-					else if(internal.depth == 8)
+					else if(internal.samples == 8)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5719,7 +5970,7 @@
 							source7 += pitch;
 						}
 					}
-					else if(internal.depth == 16)
+					else if(internal.samples == 16)
 					{
 						for(int y = 0; y < height; y++)
 						{
@@ -5839,7 +6090,7 @@
 			{
 				#define AVERAGE(x, y) (((x) & (y)) + ((((x) ^ (y)) >> 1) & 0x7BEF) + (((x) ^ (y)) & 0x0821))
 
-				if(internal.depth == 2)
+				if(internal.samples == 2)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5857,7 +6108,7 @@
 						source1 += pitch;
 					}
 				}
-				else if(internal.depth == 4)
+				else if(internal.samples == 4)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5881,7 +6132,7 @@
 						source3 += pitch;
 					}
 				}
-				else if(internal.depth == 8)
+				else if(internal.samples == 8)
 				{
 					for(int y = 0; y < height; y++)
 					{
@@ -5917,7 +6168,7 @@
 						source7 += pitch;
 					}
 				}
-				else if(internal.depth == 16)
+				else if(internal.samples == 16)
 				{
 					for(int y = 0; y < height; y++)
 					{
diff --git a/src/Renderer/Surface.hpp b/src/Renderer/Surface.hpp
index 6418c08..bff1b7d 100644
--- a/src/Renderer/Surface.hpp
+++ b/src/Renderer/Surface.hpp
@@ -23,31 +23,43 @@
 {
 	class Resource;
 
-	struct Rect
+	template <typename T> struct RectT
 	{
-		Rect() {}
-		Rect(int x0i, int y0i, int x1i, int y1i) : x0(x0i), y0(y0i), x1(x1i), y1(y1i) {}
+		RectT() {}
+		RectT(T x0i, T y0i, T x1i, T y1i) : x0(x0i), y0(y0i), x1(x1i), y1(y1i) {}
 
-		void clip(int minX, int minY, int maxX, int maxY);
+		void clip(T minX, T minY, T maxX, T maxY)
+		{
+			x0 = clamp(x0, minX, maxX);
+			y0 = clamp(y0, minY, maxY);
+			x1 = clamp(x1, minX, maxX);
+			y1 = clamp(y1, minY, maxY);
+		}
 
-		int width() const  { return x1 - x0; }
-		int height() const { return y1 - y0; }
+		T width() const  { return x1 - x0; }
+		T height() const { return y1 - y0; }
 
-		int x0;   // Inclusive
-		int y0;   // Inclusive
-		int x1;   // Exclusive
-		int y1;   // Exclusive
+		T x0;   // Inclusive
+		T y0;   // Inclusive
+		T x1;   // Exclusive
+		T y1;   // Exclusive
 	};
 
-	struct SliceRect : public Rect
+	typedef RectT<int> Rect;
+	typedef RectT<float> RectF;
+
+	template<typename T> struct SliceRectT : public RectT<T>
 	{
-		SliceRect() : slice(0) {}
-		SliceRect(const Rect& rect) : Rect(rect), slice(0) {}
-		SliceRect(const Rect& rect, int s) : Rect(rect), slice(s) {}
-		SliceRect(int x0, int y0, int x1, int y1, int s) : Rect(x0, y0, x1, y1), slice(s) {}
+		SliceRectT() : slice(0) {}
+		SliceRectT(const RectT<T>& rect) : RectT<T>(rect), slice(0) {}
+		SliceRectT(const RectT<T>& rect, int s) : RectT<T>(rect), slice(s) {}
+		SliceRectT(T x0, T y0, T x1, T y1, int s) : RectT<T>(x0, y0, x1, y1), slice(s) {}
 		int slice;
 	};
 
+	typedef SliceRectT<int> SliceRect;
+	typedef SliceRectT<float> SliceRectF;
+
 	enum Format : unsigned char
 	{
 		FORMAT_NULL,
@@ -55,8 +67,8 @@
 		FORMAT_A8,
 		FORMAT_R8I,
 		FORMAT_R8UI,
-		FORMAT_R8I_SNORM,
-		FORMAT_R8, // UI_SNORM
+		FORMAT_R8_SNORM,
+		FORMAT_R8,
 		FORMAT_R16I,
 		FORMAT_R16UI,
 		FORMAT_R32I,
@@ -73,12 +85,12 @@
 		FORMAT_A8R8G8B8,
 		FORMAT_X8B8G8R8I,
 		FORMAT_X8B8G8R8UI,
-		FORMAT_X8B8G8R8I_SNORM,
-		FORMAT_X8B8G8R8, // UI_SNORM
+		FORMAT_X8B8G8R8_SNORM,
+		FORMAT_X8B8G8R8,
 		FORMAT_A8B8G8R8I,
 		FORMAT_A8B8G8R8UI,
-		FORMAT_A8B8G8R8I_SNORM,
-		FORMAT_A8B8G8R8, // UI_SNORM
+		FORMAT_A8B8G8R8_SNORM,
+		FORMAT_A8B8G8R8,
 		FORMAT_SRGB8_X8,
 		FORMAT_SRGB8_A8,
 		FORMAT_X1R5G5B5,
@@ -86,16 +98,17 @@
 		FORMAT_R5G5B5A1,
 		FORMAT_G8R8I,
 		FORMAT_G8R8UI,
-		FORMAT_G8R8I_SNORM,
-		FORMAT_G8R8, // UI_SNORM
-		FORMAT_G16R16, // D3D format
+		FORMAT_G8R8_SNORM,
+		FORMAT_G8R8,
+		FORMAT_G16R16,
 		FORMAT_G16R16I,
 		FORMAT_G16R16UI,
 		FORMAT_G32R32I,
 		FORMAT_G32R32UI,
 		FORMAT_A2R10G10B10,
 		FORMAT_A2B10G10R10,
-		FORMAT_A16B16G16R16, // D3D format
+		FORMAT_A2B10G10R10UI,
+		FORMAT_A16B16G16R16,
 		FORMAT_X16B16G16R16I,
 		FORMAT_X16B16G16R16UI,
 		FORMAT_A16B16G16R16I,
@@ -157,13 +170,16 @@
 		FORMAT_R16F,
 		FORMAT_G16R16F,
 		FORMAT_B16G16R16F,
+		FORMAT_X16B16G16R16F,
 		FORMAT_A16B16G16R16F,
+		FORMAT_X16B16G16R16F_UNSIGNED,
 		FORMAT_A32F,
 		FORMAT_R32F,
 		FORMAT_G32R32F,
 		FORMAT_B32G32R32F,
 		FORMAT_X32B32G32R32F,
 		FORMAT_A32B32G32R32F,
+		FORMAT_X32B32G32R32F_UNSIGNED,
 		// Bump map formats
 		FORMAT_V8U8,
 		FORMAT_L6V5U5,
@@ -189,9 +205,12 @@
 		FORMAT_D24S8,
 		FORMAT_D24FS8,
 		FORMAT_D32F,                 // Quad layout
+		FORMAT_D32FS8,               // Quad layout
 		FORMAT_D32F_COMPLEMENTARY,   // Quad layout, 1 - z
+		FORMAT_D32FS8_COMPLEMENTARY, // Quad layout, 1 - z
 		FORMAT_D32F_LOCKABLE,        // Linear layout
 		FORMAT_D32FS8_TEXTURE,       // Linear layout, no PCF
+		FORMAT_D32F_SHADOW,          // Linear layout, PCF
 		FORMAT_D32FS8_SHADOW,        // Linear layout, PCF
 		FORMAT_DF24S8,
 		FORMAT_DF16S8,
@@ -214,7 +233,8 @@
 		LOCK_READONLY,
 		LOCK_WRITEONLY,
 		LOCK_READWRITE,
-		LOCK_DISCARD
+		LOCK_DISCARD,
+		LOCK_UPDATE   // Write access which doesn't dirty the buffer, because it's being updated with the sibling's data.
 	};
 
 	class [[clang::lto_visibility_public]] Surface
@@ -222,7 +242,9 @@
 	private:
 		struct Buffer
 		{
-		public:
+			friend Surface;
+
+		private:
 			void write(int x, int y, int z, const Color<float> &color);
 			void write(int x, int y, const Color<float> &color);
 			void write(void *element, const Color<float> &color);
@@ -230,7 +252,7 @@
 			Color<float> read(int x, int y) const;
 			Color<float> read(void *element) const;
 			Color<float> sample(float x, float y, float z) const;
-			Color<float> sample(float x, float y) const;
+			Color<float> sample(float x, float y, int layer) const;
 
 			void *lockRect(int x, int y, int z, Lock lock);
 			void unlockRect();
@@ -239,24 +261,28 @@
 			int width;
 			int height;
 			int depth;
+			short border;
+			short samples;
+
 			int bytes;
 			int pitchB;
 			int pitchP;
 			int sliceB;
 			int sliceP;
-			Format format;
-			Lock lock;
 
-			bool dirty;
+			Format format;
+			AtomicInt lock;
+
+			bool dirty;   // Sibling internal/external buffer doesn't match.
 		};
 
 	protected:
 		Surface(int width, int height, int depth, Format format, void *pixels, int pitch, int slice);
-		Surface(Resource *texture, int width, int height, int depth, Format format, bool lockable, bool renderTarget, int pitchP = 0);
+		Surface(Resource *texture, int width, int height, int depth, int border, int samples, Format format, bool lockable, bool renderTarget, int pitchP = 0);
 
 	public:
 		static Surface *create(int width, int height, int depth, Format format, void *pixels, int pitch, int slice);
-		static Surface *create(Resource *texture, int width, int height, int depth, Format format, bool lockable, bool renderTarget, int pitchP = 0);
+		static Surface *create(Resource *texture, int width, int height, int depth, int border, int samples, Format format, bool lockable, bool renderTarget, int pitchP = 0);
 
 		virtual ~Surface() = 0;
 
@@ -265,6 +291,7 @@
 		inline int getWidth() const;
 		inline int getHeight() const;
 		inline int getDepth() const;
+		inline int getBorder() const;
 		inline Format getFormat(bool internal = false) const;
 		inline int getPitchB(bool internal = false) const;
 		inline int getPitchP(bool internal = false) const;
@@ -296,6 +323,7 @@
 		void sync();                      // Wait for lock(s) to be released.
 		inline bool isUnlocked() const;   // Only reliable after sync().
 
+		inline int getSamples() const;
 		inline int getMultiSampleCount() const;
 		inline int getSuperSampleCount() const;
 
@@ -315,22 +343,26 @@
 		void copyInternal(const Surface* src, int x, int y, float srcX, float srcY, bool filter);
 		void copyInternal(const Surface* src, int x, int y, int z, float srcX, float srcY, float srcZ, bool filter);
 
+		enum Edge { TOP, BOTTOM, RIGHT, LEFT };
+		void copyCubeEdge(Edge dstEdge, Surface *src, Edge srcEdge);
+		void computeCubeCorner(int x0, int y0, int x1, int y1);
+
 		bool hasStencil() const;
 		bool hasDepth() const;
 		bool hasPalette() const;
 		bool isRenderTarget() const;
 
-		bool hasDirtyMipmaps() const;
-		void cleanMipmaps();
+		bool hasDirtyContents() const;
+		void markContentsClean();
 		inline bool isExternalDirty() const;
 		Resource *getResource();
 
 		static int bytes(Format format);
-		static int pitchB(int width, Format format, bool target);
-		static int pitchP(int width, Format format, bool target);
-		static int sliceB(int width, int height, Format format, bool target);
-		static int sliceP(int width, int height, Format format, bool target);
-		static unsigned int size(int width, int height, int depth, Format format);   // FIXME: slice * depth
+		static int pitchB(int width, int border, Format format, bool target);
+		static int pitchP(int width, int border, Format format, bool target);
+		static int sliceB(int width, int height, int border, Format format, bool target);
+		static int sliceP(int width, int height, int border, Format format, bool target);
+		static unsigned int size(int width, int height, int depth, int border, int samples, Format format);   // FIXME: slice * depth
 
 		static bool isStencil(Format format);
 		static bool isDepth(Format format);
@@ -341,6 +373,7 @@
 		static bool isUnsignedComponent(Format format, int component);
 		static bool isSRGBreadable(Format format);
 		static bool isSRGBwritable(Format format);
+		static bool isSRGBformat(Format format);
 		static bool isCompressed(Format format);
 		static bool isSignedNonNormalizedInteger(Format format);
 		static bool isUnsignedNonNormalizedInteger(Format format);
@@ -358,7 +391,6 @@
 		typedef unsigned int dword;
 		typedef uint64_t qword;
 
-		#if S3TC_SUPPORT
 		struct DXT1
 		{
 			word c0;
@@ -392,7 +424,6 @@
 			word c1;
 			dword clut;
 		};
-		#endif
 
 		struct ATI2
 		{
@@ -433,27 +464,25 @@
 			};
 		};
 
-		static void decodeR8G8B8(Buffer &destination, const Buffer &source);
-		static void decodeX1R5G5B5(Buffer &destination, const Buffer &source);
-		static void decodeA1R5G5B5(Buffer &destination, const Buffer &source);
-		static void decodeX4R4G4B4(Buffer &destination, const Buffer &source);
-		static void decodeA4R4G4B4(Buffer &destination, const Buffer &source);
-		static void decodeP8(Buffer &destination, const Buffer &source);
+		static void decodeR8G8B8(Buffer &destination, Buffer &source);
+		static void decodeX1R5G5B5(Buffer &destination, Buffer &source);
+		static void decodeA1R5G5B5(Buffer &destination, Buffer &source);
+		static void decodeX4R4G4B4(Buffer &destination, Buffer &source);
+		static void decodeA4R4G4B4(Buffer &destination, Buffer &source);
+		static void decodeP8(Buffer &destination, Buffer &source);
 
-		#if S3TC_SUPPORT
-		static void decodeDXT1(Buffer &internal, const Buffer &external);
-		static void decodeDXT3(Buffer &internal, const Buffer &external);
-		static void decodeDXT5(Buffer &internal, const Buffer &external);
-		#endif
-		static void decodeATI1(Buffer &internal, const Buffer &external);
-		static void decodeATI2(Buffer &internal, const Buffer &external);
-		static void decodeEAC(Buffer &internal, const Buffer &external, int nbChannels, bool isSigned);
-		static void decodeETC2(Buffer &internal, const Buffer &external, int nbAlphaBits, bool isSRGB);
-		static void decodeASTC(Buffer &internal, const Buffer &external, int xSize, int ySize, int zSize, bool isSRGB);
+		static void decodeDXT1(Buffer &internal, Buffer &external);
+		static void decodeDXT3(Buffer &internal, Buffer &external);
+		static void decodeDXT5(Buffer &internal, Buffer &external);
+		static void decodeATI1(Buffer &internal, Buffer &external);
+		static void decodeATI2(Buffer &internal, Buffer &external);
+		static void decodeEAC(Buffer &internal, Buffer &external, int nbChannels, bool isSigned);
+		static void decodeETC2(Buffer &internal, Buffer &external, int nbAlphaBits, bool isSRGB);
+		static void decodeASTC(Buffer &internal, Buffer &external, int xSize, int ySize, int zSize, bool isSRGB);
 
 		static void update(Buffer &destination, Buffer &source);
 		static void genericUpdate(Buffer &destination, Buffer &source);
-		static void *allocateBuffer(int width, int height, int depth, Format format);
+		static void *allocateBuffer(int width, int height, int depth, int border, int samples, Format format);
 		static void memfill4(void *buffer, int pattern, int bytes);
 
 		bool identicalFormats() const;
@@ -468,7 +497,7 @@
 		const bool lockable;
 		const bool renderTarget;
 
-		bool dirtyMipmaps;
+		bool dirtyContents;   // Sibling surfaces need updating (mipmaps / cube borders).
 		unsigned int paletteUsed;
 
 		static unsigned int *palette;   // FIXME: Not multi-device safe
@@ -509,6 +538,11 @@
 		return external.depth;
 	}
 
+	int Surface::getBorder() const
+	{
+		return internal.border;
+	}
+
 	Format Surface::getFormat(bool internal) const
 	{
 		return internal ? getInternalFormat() : getExternalFormat();
@@ -599,14 +633,19 @@
 		return stencil.sliceB;
 	}
 
+	int Surface::getSamples() const
+	{
+		return internal.samples;
+	}
+
 	int Surface::getMultiSampleCount() const
 	{
-		return sw::min(internal.depth, 4);
+		return sw::min((int)internal.samples, 4);
 	}
 
 	int Surface::getSuperSampleCount() const
 	{
-		return internal.depth > 4 ? internal.depth / 4 : 1;
+		return internal.samples > 4 ? internal.samples / 4 : 1;
 	}
 
 	bool Surface::isUnlocked() const
diff --git a/src/Renderer/TextureStage.cpp b/src/Renderer/TextureStage.cpp
index 583f82e..0327478 100644
--- a/src/Renderer/TextureStage.cpp
+++ b/src/Renderer/TextureStage.cpp
@@ -15,7 +15,7 @@
 #include "TextureStage.hpp"
 
 #include "Sampler.hpp"
-#include "Debug.hpp"
+#include "Common/Debug.hpp"
 
 #include <string.h>
 
diff --git a/src/Renderer/Vector.cpp b/src/Renderer/Vector.cpp
index a212f3d..4a02534 100644
--- a/src/Renderer/Vector.cpp
+++ b/src/Renderer/Vector.cpp
@@ -14,8 +14,8 @@
 
 #include "Vector.hpp"
 
-#include "Math.hpp"
 #include "Matrix.hpp"
+#include "Common/Math.hpp"
 
 namespace sw
 {
diff --git a/src/Renderer/VertexProcessor.cpp b/src/Renderer/VertexProcessor.cpp
index 6972d94..cc9bd25 100644
--- a/src/Renderer/VertexProcessor.cpp
+++ b/src/Renderer/VertexProcessor.cpp
@@ -14,13 +14,13 @@
 
 #include "VertexProcessor.hpp"
 
-#include "Math.hpp"
-#include "VertexPipeline.hpp"
-#include "VertexProgram.hpp"
-#include "VertexShader.hpp"
-#include "PixelShader.hpp"
-#include "Constants.hpp"
-#include "Debug.hpp"
+#include "Shader/VertexPipeline.hpp"
+#include "Shader/VertexProgram.hpp"
+#include "Shader/VertexShader.hpp"
+#include "Shader/PixelShader.hpp"
+#include "Shader/Constants.hpp"
+#include "Common/Math.hpp"
+#include "Common/Debug.hpp"
 
 #include <string.h>
 
@@ -647,6 +647,15 @@
 		else ASSERT(false);
 	}
 
+	void VertexProcessor::setCompareFunc(unsigned int sampler, CompareFunc compFunc)
+	{
+		if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
+		{
+			context->sampler[TEXTURE_IMAGE_UNITS + sampler].setCompareFunc(compFunc);
+		}
+		else ASSERT(false);
+	}
+
 	void VertexProcessor::setBaseLevel(unsigned int sampler, int baseLevel)
 	{
 		if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
@@ -916,7 +925,7 @@
 			state.shaderID = 0;
 		}
 
-		state.fixedFunction = !context->vertexShader && context->pixelShaderVersion() < 0x0300;
+		state.fixedFunction = !context->vertexShader && context->pixelShaderModel() < 0x0300;
 		state.textureSampling = context->vertexShader ? context->vertexShader->containsTextureSampling() : false;
 		state.positionRegister = context->vertexShader ? context->vertexShader->getPositionRegister() : Pos;
 		state.pointSizeRegister = context->vertexShader ? context->vertexShader->getPointSizeRegister() : Pts;
@@ -986,7 +995,7 @@
 			{
 				if(context->vertexShader->usesSampler(i))
 				{
-					state.samplerState[i] = context->sampler[TEXTURE_IMAGE_UNITS + i].samplerState();
+					state.sampler[i] = context->sampler[TEXTURE_IMAGE_UNITS + i].samplerState();
 				}
 			}
 		}
@@ -1001,7 +1010,7 @@
 				state.output[i].wWrite = context->vertexShader->getOutput(i, 3).active();
 			}
 		}
-		else if(!context->preTransformed || context->pixelShaderVersion() < 0x0300)
+		else if(!context->preTransformed || context->pixelShaderModel() < 0x0300)
 		{
 			state.output[Pos].write = 0xF;
 
@@ -1059,7 +1068,7 @@
 			}
 		}
 
-		if(context->vertexShaderVersion() < 0x0300)
+		if(context->vertexShaderModel() < 0x0300)
 		{
 			state.output[C0].clamp = 0xF;
 			state.output[C1].clamp = 0xF;
diff --git a/src/Renderer/VertexProcessor.hpp b/src/Renderer/VertexProcessor.hpp
index 3552f84..cd3849a 100644
--- a/src/Renderer/VertexProcessor.hpp
+++ b/src/Renderer/VertexProcessor.hpp
@@ -50,10 +50,10 @@
 
 			uint64_t shaderID;
 
-			bool fixedFunction             : 1;
-			bool textureSampling           : 1;
-			unsigned int positionRegister  : BITS(MAX_VERTEX_OUTPUTS);
-			unsigned int pointSizeRegister : BITS(MAX_VERTEX_OUTPUTS);
+			bool fixedFunction             : 1;   // TODO: Eliminate by querying shader.
+			bool textureSampling           : 1;   // TODO: Eliminate by querying shader.
+			unsigned int positionRegister  : BITS(MAX_VERTEX_OUTPUTS);   // TODO: Eliminate by querying shader.
+			unsigned int pointSizeRegister : BITS(MAX_VERTEX_OUTPUTS);   // TODO: Eliminate by querying shader.
 
 			unsigned int vertexBlendMatrixCount               : 3;
 			bool indexedVertexBlendEnable                     : 1;
@@ -91,7 +91,7 @@
 
 			TextureState textureState[8];
 
-			Sampler::State samplerState[VERTEX_TEXTURE_IMAGE_UNITS];
+			Sampler::State sampler[VERTEX_TEXTURE_IMAGE_UNITS];
 
 			struct Input
 			{
@@ -263,6 +263,7 @@
 		void setSwizzleG(unsigned int sampler, SwizzleType swizzleG);
 		void setSwizzleB(unsigned int sampler, SwizzleType swizzleB);
 		void setSwizzleA(unsigned int sampler, SwizzleType swizzleA);
+		void setCompareFunc(unsigned int sampler, CompareFunc compare);
 		void setBaseLevel(unsigned int sampler, int baseLevel);
 		void setMaxLevel(unsigned int sampler, int maxLevel);
 		void setMinLod(unsigned int sampler, float minLod);
diff --git a/src/Shader/BUILD.gn b/src/Shader/BUILD.gn
index 3b19766..baf1233 100644
--- a/src/Shader/BUILD.gn
+++ b/src/Shader/BUILD.gn
@@ -55,8 +55,5 @@
   include_dirs = [
     ".",
     "..",
-    "../Common",
-    "../Main",
-    "../Renderer",
   ]
 }
diff --git a/src/Shader/Constants.cpp b/src/Shader/Constants.cpp
index e02ba03..06dda32 100644
--- a/src/Shader/Constants.cpp
+++ b/src/Shader/Constants.cpp
@@ -264,17 +264,17 @@
 
 		for(int i = 0; i < 256; i++)
 		{
-			sRGBtoLinear8_12[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0xFF) * 0x1000 + 0.5f);
+			sRGBtoLinear8_16[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0xFF) * 0xFFFF + 0.5f);
 		}
 
 		for(int i = 0; i < 64; i++)
 		{
-			sRGBtoLinear6_12[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0x3F) * 0x1000 + 0.5f);
+			sRGBtoLinear6_16[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0x3F) * 0xFFFF + 0.5f);
 		}
 
 		for(int i = 0; i < 32; i++)
 		{
-			sRGBtoLinear5_12[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0x1F) * 0x1000 + 0.5f);
+			sRGBtoLinear5_16[i] = (unsigned short)(sw::sRGBtoLinear((float)i / 0x1F) * 0xFFFF + 0.5f);
 		}
 
 		for(int i = 0; i < 0x1000; i++)
diff --git a/src/Shader/Constants.hpp b/src/Shader/Constants.hpp
index 5210643..6b70e04 100644
--- a/src/Shader/Constants.hpp
+++ b/src/Shader/Constants.hpp
@@ -22,7 +22,7 @@
 	struct Constants
 	{
 		Constants();
-	
+
 		unsigned int transposeBit0[16];
 		unsigned int transposeBit1[16];
 		unsigned int transposeBit2[16];
@@ -67,9 +67,9 @@
 		dword4 maskD01X[4];
 		word4 mask565Q[8];
 
-		unsigned short sRGBtoLinear8_12[256];
-		unsigned short sRGBtoLinear6_12[64];
-		unsigned short sRGBtoLinear5_12[32];
+		unsigned short sRGBtoLinear8_16[256];
+		unsigned short sRGBtoLinear6_16[64];
+		unsigned short sRGBtoLinear5_16[32];
 
 		unsigned short linearToSRGB12_16[4096];
 		unsigned short sRGBtoLinear12_16[4096];
diff --git a/src/Shader/PixelPipeline.cpp b/src/Shader/PixelPipeline.cpp
index 66d6a09..d4faebd 100644
--- a/src/Shader/PixelPipeline.cpp
+++ b/src/Shader/PixelPipeline.cpp
@@ -13,8 +13,8 @@
 // limitations under the License.
 
 #include "PixelPipeline.hpp"
-#include "Renderer.hpp"
 #include "SamplerCore.hpp"
+#include "Renderer/Renderer.hpp"
 
 namespace sw
 {
@@ -49,7 +49,7 @@
 
 			if(state.textureStage[stage].usesTexture)
 			{
-				sampleTexture(texture, stage, stage);
+				texture = sampleTexture(stage, stage);
 			}
 
 			blendTexture(temp, texture, stage);
@@ -88,7 +88,7 @@
 			const Src &src1 = instruction->src[1];
 			const Src &src2 = instruction->src[2];
 
-			unsigned short version = shader->getVersion();
+			unsigned short shaderModel = shader->getShaderModel();
 			bool pairing = i + 1 < shader->getLength() && shader->getInstruction(i + 1)->coissue;   // First instruction of pair
 			bool coissue = instruction->coissue;                                                              // Second instruction of pair
 
@@ -101,10 +101,10 @@
 			if(src1.type != Shader::PARAMETER_VOID) s1 = fetchRegister(src1);
 			if(src2.type != Shader::PARAMETER_VOID) s2 = fetchRegister(src2);
 
-			Float4 x = version < 0x0104 ? v[2 + dst.index].x : v[2 + src0.index].x;
-			Float4 y = version < 0x0104 ? v[2 + dst.index].y : v[2 + src0.index].y;
-			Float4 z = version < 0x0104 ? v[2 + dst.index].z : v[2 + src0.index].z;
-			Float4 w = version < 0x0104 ? v[2 + dst.index].w : v[2 + src0.index].w;
+			Float4 x = shaderModel < 0x0104 ? v[2 + dst.index].x : v[2 + src0.index].x;
+			Float4 y = shaderModel < 0x0104 ? v[2 + dst.index].y : v[2 + src0.index].y;
+			Float4 z = shaderModel < 0x0104 ? v[2 + dst.index].z : v[2 + src0.index].z;
+			Float4 w = shaderModel < 0x0104 ? v[2 + dst.index].w : v[2 + src0.index].w;
 
 			switch(opcode)
 			{
@@ -126,7 +126,7 @@
 			case Shader::OPCODE_DP4: DP4(d, s0, s1);     break;
 			case Shader::OPCODE_LRP: LRP(d, s0, s1, s2); break;
 			case Shader::OPCODE_TEXCOORD:
-				if(version < 0x0104)
+				if(shaderModel < 0x0104)
 				{
 					TEXCOORD(d, x, y, z, dst.index);
 			}
@@ -143,11 +143,11 @@
 				}
 				break;
 			case Shader::OPCODE_TEXKILL:
-				if(version < 0x0104)
+				if(shaderModel < 0x0104)
 				{
 					TEXKILL(cMask, x, y, z);
 				}
-				else if(version == 0x0104)
+				else if(shaderModel == 0x0104)
 				{
 					if(dst.type == Shader::PARAMETER_TEXTURE)
 					{
@@ -161,11 +161,11 @@
 				else ASSERT(false);
 				break;
 			case Shader::OPCODE_TEX:
-				if(version < 0x0104)
+				if(shaderModel < 0x0104)
 				{
 					TEX(d, x, y, z, dst.index, false);
 				}
-				else if(version == 0x0104)
+				else if(shaderModel == 0x0104)
 				{
 					if(src0.type == Shader::PARAMETER_TEXTURE)
 					{
@@ -256,15 +256,15 @@
 				}
 			}
 		}
-	}
 
-	Bool PixelPipeline::alphaTest(Int cMask[4])
-	{
 		current.x = Min(current.x, Short4(0x0FFF)); current.x = Max(current.x, Short4(0x0000));
 		current.y = Min(current.y, Short4(0x0FFF)); current.y = Max(current.y, Short4(0x0000));
 		current.z = Min(current.z, Short4(0x0FFF)); current.z = Max(current.z, Short4(0x0000));
 		current.w = Min(current.w, Short4(0x0FFF)); current.w = Max(current.w, Short4(0x0000));
+	}
 
+	Bool PixelPipeline::alphaTest(Int cMask[4])
+	{
 		if(!state.alphaTestActive())
 		{
 			return true;
@@ -356,6 +356,7 @@
 		case FORMAT_G32R32F:
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+	//	case FORMAT_X32B32G32R32F_UNSIGNED:   // Not renderable in any fixed-function API.
 			convertSigned12(oC, current);
 			PixelRoutine::fogBlend(oC, fog);
 
@@ -1207,7 +1208,7 @@
 		current.z = AddSat(current.z, specular.z);
 	}
 
-	void PixelPipeline::sampleTexture(Vector4s &c, int coordinates, int stage, bool project)
+	Vector4s PixelPipeline::sampleTexture(int coordinates, int stage, bool project)
 	{
 		Float4 x = v[2 + coordinates].x;
 		Float4 y = v[2 + coordinates].y;
@@ -1222,11 +1223,13 @@
 			perturbate = false;
 		}
 
-		sampleTexture(c, stage, x, y, z, w, project);
+		return sampleTexture(stage, x, y, z, w, project);
 	}
 
-	void PixelPipeline::sampleTexture(Vector4s &c, int stage, Float4 &u, Float4 &v, Float4 &w, Float4 &q, bool project)
+	Vector4s PixelPipeline::sampleTexture(int stage, Float4 &u, Float4 &v, Float4 &w, Float4 &q, bool project)
 	{
+		Vector4s c;
+
 		#if PERF_PROFILE
 			Long texTime = Ticks();
 		#endif
@@ -1238,7 +1241,7 @@
 
 		if(!project)
 		{
-			sampler[stage]->sampleTexture(texture, c, u, v, w, q, dsx, dsy);
+			c = SamplerCore(constants, state.sampler[stage]).sampleTexture(texture, u, v, w, q, q, dsx, dsy);
 		}
 		else
 		{
@@ -1248,12 +1251,14 @@
 			Float4 v_q = v * rq;
 			Float4 w_q = w * rq;
 
-			sampler[stage]->sampleTexture(texture, c, u_q, v_q, w_q, q, dsx, dsy);
+			c = SamplerCore(constants, state.sampler[stage]).sampleTexture(texture, u_q, v_q, w_q, q, q, dsx, dsy);
 		}
 
 		#if PERF_PROFILE
 			cycles[PERF_TEX] += Ticks() - texTime;
 		#endif
+
+		return c;
 	}
 
 	Short4 PixelPipeline::convertFixed12(RValue<Float4> cf)
@@ -1470,22 +1475,18 @@
 	{
 		// FIXME: Long fixed-point multiply fixup
 		{ dst.x = MulHigh(src0.x, src1.x); dst.x = AddSat(dst.x, dst.x); dst.x = AddSat(dst.x, dst.x); dst.x = AddSat(dst.x, dst.x); dst.x = AddSat(dst.x, dst.x); dst.x = AddSat(dst.x, src2.x); }
-		{
-		dst.y = MulHigh(src0.y, src1.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, src2.y);
-	}
-		{dst.z = MulHigh(src0.z, src1.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, src2.z); }
-		{dst.w = MulHigh(src0.w, src1.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, src2.w); }
+		{ dst.y = MulHigh(src0.y, src1.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, src2.y); }
+		{ dst.z = MulHigh(src0.z, src1.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, src2.z); }
+		{ dst.w = MulHigh(src0.w, src1.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, src2.w); }
 	}
 
 	void PixelPipeline::MUL(Vector4s &dst, Vector4s &src0, Vector4s &src1)
 	{
 		// FIXME: Long fixed-point multiply fixup
 		{ dst.x = MulHigh(src0.x, src1.x); dst.x = AddSat(dst.x, dst.x); dst.x = AddSat(dst.x, dst.x); dst.x = AddSat(dst.x, dst.x); dst.x = AddSat(dst.x, dst.x); }
-		{
-		dst.y = MulHigh(src0.y, src1.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y);
-	}
-		{dst.z = MulHigh(src0.z, src1.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); }
-		{dst.w = MulHigh(src0.w, src1.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); }
+		{ dst.y = MulHigh(src0.y, src1.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); dst.y = AddSat(dst.y, dst.y); }
+		{ dst.z = MulHigh(src0.z, src1.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); dst.z = AddSat(dst.z, dst.z); }
+		{ dst.w = MulHigh(src0.w, src1.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); dst.w = AddSat(dst.w, dst.w); }
 	}
 
 	void PixelPipeline::DP3(Vector4s &dst, Vector4s &src0, Vector4s &src1)
@@ -1647,7 +1648,7 @@
 		v_ = Float4(0.0f);
 		w_ = Float4(0.0f);
 
-		sampleTexture(dst, stage, u_, v_, w_, w_);
+		dst = sampleTexture(stage, u_, v_, w_, w_);
 	}
 
 	void PixelPipeline::TEXKILL(Int cMask[4], Float4 &u, Float4 &v, Float4 &s)
@@ -1665,7 +1666,7 @@
 	void PixelPipeline::TEXKILL(Int cMask[4], Vector4s &src)
 	{
 		Short4 test = src.x | src.y | src.z;
-		Int kill = SignMask(Pack(test, test)) ^ 0x0000000F;
+		Int kill = SignMask(PackSigned(test, test)) ^ 0x0000000F;
 
 		for(unsigned int q = 0; q < state.multiSample; q++)
 		{
@@ -1675,7 +1676,7 @@
 
 	void PixelPipeline::TEX(Vector4s &dst, Float4 &u, Float4 &v, Float4 &s, int sampler, bool project)
 	{
-		sampleTexture(dst, sampler, u, v, s, s, project);
+		dst = sampleTexture(sampler, u, v, s, s, project);
 	}
 
 	void PixelPipeline::TEXLD(Vector4s &dst, Vector4s &src, int sampler, bool project)
@@ -1684,7 +1685,7 @@
 		Float4 v = Float4(src.y) * Float4(1.0f / 0x0FFE);
 		Float4 s = Float4(src.z) * Float4(1.0f / 0x0FFE);
 
-		sampleTexture(dst, sampler, u, v, s, s, project);
+		dst = sampleTexture(sampler, u, v, s, s, project);
 	}
 
 	void PixelPipeline::TEXBEM(Vector4s &dst, Vector4s &src, Float4 &u, Float4 &v, Float4 &s, int stage)
@@ -1705,7 +1706,7 @@
 		Float4 u_ = u + du;
 		Float4 v_ = v + dv;
 
-		sampleTexture(dst, stage, u_, v_, s, s);
+		dst = sampleTexture(stage, u_, v_, s, s);
 	}
 
 	void PixelPipeline::TEXBEML(Vector4s &dst, Vector4s &src, Float4 &u, Float4 &v, Float4 &s, int stage)
@@ -1726,7 +1727,7 @@
 		Float4 u_ = u + du;
 		Float4 v_ = v + dv;
 
-		sampleTexture(dst, stage, u_, v_, s, s);
+		dst = sampleTexture(stage, u_, v_, s, s);
 
 		Short4 L;
 
@@ -1748,7 +1749,7 @@
 		Float4 v = Float4(src0.x) * Float4(1.0f / 0x0FFE);
 		Float4 s = Float4(src0.z) * Float4(1.0f / 0x0FFE);
 
-		sampleTexture(dst, stage, u, v, s, s);
+		dst = sampleTexture(stage, u, v, s, s);
 	}
 
 	void PixelPipeline::TEXREG2GB(Vector4s &dst, Vector4s &src0, int stage)
@@ -1757,7 +1758,7 @@
 		Float4 v = Float4(src0.z) * Float4(1.0f / 0x0FFE);
 		Float4 s = v;
 
-		sampleTexture(dst, stage, u, v, s, s);
+		dst = sampleTexture(stage, u, v, s, s);
 	}
 
 	void PixelPipeline::TEXREG2RGB(Vector4s &dst, Vector4s &src0, int stage)
@@ -1766,7 +1767,7 @@
 		Float4 v = Float4(src0.y) * Float4(1.0f / 0x0FFE);
 		Float4 s = Float4(src0.z) * Float4(1.0f / 0x0FFE);
 
-		sampleTexture(dst, stage, u, v, s, s);
+		dst = sampleTexture(stage, u, v, s, s);
 	}
 
 	void PixelPipeline::TEXM3X2DEPTH(Vector4s &dst, Float4 &u, Float4 &v, Float4 &s, Vector4s &src, bool signedScaling)
@@ -1790,7 +1791,7 @@
 
 		w_ = Float4(0.0f);
 
-		sampleTexture(dst, stage, u_, v_, w_, w_);
+		dst = sampleTexture(stage, u_, v_, w_, w_);
 	}
 
 	void PixelPipeline::TEXM3X3(Vector4s &dst, Float4 &u, Float4 &v, Float4 &s, Vector4s &src0, bool signedScaling)
@@ -1861,14 +1862,14 @@
 		v__ -= E[1] * u_;
 		w__ -= E[2] * u_;
 
-		sampleTexture(dst, stage, u__, v__, w__, w__);
+		dst = sampleTexture(stage, u__, v__, w__, w__);
 	}
 
 	void PixelPipeline::TEXM3X3TEX(Vector4s &dst, Float4 &u, Float4 &v, Float4 &s, int stage, Vector4s &src0, bool signedScaling)
 	{
 		TEXM3X3PAD(u, v, s, src0, 2, signedScaling);
 
-		sampleTexture(dst, stage, u_, v_, w_, w_);
+		dst = sampleTexture(stage, u_, v_, w_, w_);
 	}
 
 	void PixelPipeline::TEXM3X3VSPEC(Vector4s &dst, Float4 &x, Float4 &y, Float4 &z, int stage, Vector4s &src0)
@@ -1905,7 +1906,7 @@
 		v__ -= E[1] * u_;
 		w__ -= E[2] * u_;
 
-		sampleTexture(dst, stage, u__, v__, w__, w__);
+		dst = sampleTexture(stage, u__, v__, w__, w__);
 	}
 
 	void PixelPipeline::TEXDEPTH()
diff --git a/src/Shader/PixelPipeline.hpp b/src/Shader/PixelPipeline.hpp
index d8d2a03..66f0ec7 100644
--- a/src/Shader/PixelPipeline.hpp
+++ b/src/Shader/PixelPipeline.hpp
@@ -59,8 +59,8 @@
 		void fogBlend(Vector4s &current, Float4 &fog);
 		void specularPixel(Vector4s &current, Vector4s &specular);
 
-		void sampleTexture(Vector4s &c, int coordinates, int sampler, bool project = false);
-		void sampleTexture(Vector4s &c, int sampler, Float4 &u, Float4 &v, Float4 &w, Float4 &q, bool project = false);
+		Vector4s sampleTexture(int coordinates, int sampler, bool project = false);
+		Vector4s sampleTexture(int sampler, Float4 &u, Float4 &v, Float4 &w, Float4 &q, bool project = false);
 
 		Short4 convertFixed12(RValue<Float4> cf);
 		void convertFixed12(Vector4s &cs, Vector4f &cf);
diff --git a/src/Shader/PixelProgram.cpp b/src/Shader/PixelProgram.cpp
index 948f103..0f0f6bd 100644
--- a/src/Shader/PixelProgram.cpp
+++ b/src/Shader/PixelProgram.cpp
@@ -13,9 +13,10 @@
 // limitations under the License.
 
 #include "PixelProgram.hpp"
-#include "Primitive.hpp"
-#include "Renderer.hpp"
+
 #include "SamplerCore.hpp"
+#include "Renderer/Primitive.hpp"
+#include "Renderer/Renderer.hpp"
 
 namespace sw
 {
@@ -26,7 +27,7 @@
 
 	void PixelProgram::setBuiltins(Int &x, Int &y, Float4(&z)[4], Float4 &w)
 	{
-		if(shader->getVersion() >= 0x0300)
+		if(shader->getShaderModel() >= 0x0300)
 		{
 			if(shader->isVPosDeclared())
 			{
@@ -229,6 +230,8 @@
 			case Shader::OPCODE_LRP:        lrp(d, s0, s1, s2);                            break;
 			case Shader::OPCODE_STEP:       step(d, s0, s1);                               break;
 			case Shader::OPCODE_SMOOTH:     smooth(d, s0, s1, s2);                         break;
+			case Shader::OPCODE_ISINF:      isinf(d, s0);                                  break;
+			case Shader::OPCODE_ISNAN:      isnan(d, s0);                                  break;
 			case Shader::OPCODE_FLOATBITSTOINT:
 			case Shader::OPCODE_FLOATBITSTOUINT:
 			case Shader::OPCODE_INTBITSTOFLOAT:
@@ -280,17 +283,20 @@
 			case Shader::OPCODE_M3X4:       M3X4(d, s0, src1);                             break;
 			case Shader::OPCODE_M3X3:       M3X3(d, s0, src1);                             break;
 			case Shader::OPCODE_M3X2:       M3X2(d, s0, src1);                             break;
-			case Shader::OPCODE_TEX:        TEXLD(d, s0, src1, project, bias);             break;
-			case Shader::OPCODE_TEXLDD:     TEXLDD(d, s0, src1, s2, s3);                   break;
-			case Shader::OPCODE_TEXLDL:     TEXLDL(d, s0, src1);                           break;
+			case Shader::OPCODE_TEX:        TEX(d, s0, src1, project, bias);               break;
+			case Shader::OPCODE_TEXLDD:     TEXGRAD(d, s0, src1, s2, s3);                  break;
+			case Shader::OPCODE_TEXLDL:     TEXLOD(d, s0, src1, s0.w);                     break;
+			case Shader::OPCODE_TEXLOD:     TEXLOD(d, s0, src1, s2.x);                     break;
 			case Shader::OPCODE_TEXSIZE:    TEXSIZE(d, s0.x, src1);                        break;
 			case Shader::OPCODE_TEXKILL:    TEXKILL(cMask, d, dst.mask);                   break;
-			case Shader::OPCODE_TEXOFFSET:  TEXOFFSET(d, s0, src1, s2, bias);              break;
-			case Shader::OPCODE_TEXLDLOFFSET: TEXLDL(d, s0, src1, s2, bias);               break;
-			case Shader::OPCODE_TEXELFETCH: TEXELFETCH(d, s0, src1);                       break;
-			case Shader::OPCODE_TEXELFETCHOFFSET: TEXELFETCH(d, s0, src1, s2);             break;
+			case Shader::OPCODE_TEXOFFSET:  TEXOFFSET(d, s0, src1, s2);                    break;
+			case Shader::OPCODE_TEXLODOFFSET: TEXLODOFFSET(d, s0, src1, s2, s3.x);         break;
+			case Shader::OPCODE_TEXELFETCH: TEXELFETCH(d, s0, src1, s2.x);                 break;
+			case Shader::OPCODE_TEXELFETCHOFFSET: TEXELFETCHOFFSET(d, s0, src1, s2, s3.x); break;
 			case Shader::OPCODE_TEXGRAD:    TEXGRAD(d, s0, src1, s2, s3);                  break;
-			case Shader::OPCODE_TEXGRADOFFSET: TEXGRAD(d, s0, src1, s2, s3, s4);           break;
+			case Shader::OPCODE_TEXGRADOFFSET: TEXGRADOFFSET(d, s0, src1, s2, s3, s4);     break;
+			case Shader::OPCODE_TEXBIAS:    TEXBIAS(d, s0, src1, s2.x);                    break;
+			case Shader::OPCODE_TEXOFFSETBIAS: TEXOFFSETBIAS(d, s0, src1, s2, s3.x);       break;
 			case Shader::OPCODE_DISCARD:    DISCARD(cMask, instruction);                   break;
 			case Shader::OPCODE_DFDX:       DFDX(d, s0);                                   break;
 			case Shader::OPCODE_DFDY:       DFDY(d, s0);                                   break;
@@ -333,21 +339,6 @@
 
 			if(dst.type != Shader::PARAMETER_VOID && dst.type != Shader::PARAMETER_LABEL && opcode != Shader::OPCODE_TEXKILL && opcode != Shader::OPCODE_NOP)
 			{
-				if(dst.integer)
-				{
-					switch(opcode)
-					{
-					case Shader::OPCODE_DIV:
-						if(dst.x) d.x = Trunc(d.x);
-						if(dst.y) d.y = Trunc(d.y);
-						if(dst.z) d.z = Trunc(d.z);
-						if(dst.w) d.w = Trunc(d.w);
-						break;
-					default:
-						break;   // No truncation to integer required when arguments are integer
-					}
-				}
-
 				if(dst.saturate)
 				{
 					if(dst.x) d.x = Max(d.x, Float4(0.0f));
@@ -534,12 +525,17 @@
 				c[i] = oC[i];
 			}
 		}
+
+		clampColor(c);
+
+		if(state.depthOverride)
+		{
+			oDepth = Min(Max(oDepth, Float4(0.0f)), Float4(1.0f));
+		}
 	}
 
 	Bool PixelProgram::alphaTest(Int cMask[4])
 	{
-		clampColor(c);
-
 		if(!state.alphaTestActive())
 		{
 			return true;
@@ -641,6 +637,7 @@
 			case FORMAT_G32R32F:
 			case FORMAT_X32B32G32R32F:
 			case FORMAT_A32B32G32R32F:
+			case FORMAT_X32B32G32R32F_UNSIGNED:
 			case FORMAT_R32I:
 			case FORMAT_G32R32I:
 			case FORMAT_A32B32G32R32I:
@@ -677,13 +674,13 @@
 		}
 	}
 
-	void PixelProgram::sampleTexture(Vector4f &c, const Src &sampler, Vector4f &uvwq, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
+	Vector4f PixelProgram::sampleTexture(const Src &sampler, Vector4f &uvwq, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
 	{
 		Vector4f tmp;
 
 		if(sampler.type == Shader::PARAMETER_SAMPLER && sampler.rel.type == Shader::PARAMETER_VOID)
 		{
-			sampleTexture(tmp, sampler.index, uvwq, dsx, dsy, offset, function);
+			tmp = sampleTexture(sampler.index, uvwq, bias, dsx, dsy, offset, function);
 		}
 		else
 		{
@@ -695,31 +692,36 @@
 				{
 					If(index == i)
 					{
-						sampleTexture(tmp, i, uvwq, dsx, dsy, offset, function);
+						tmp = sampleTexture(i, uvwq, bias, dsx, dsy, offset, function);
 						// FIXME: When the sampler states are the same, we could use one sampler and just index the texture
 					}
 				}
 			}
 		}
 
+		Vector4f c;
 		c.x = tmp[(sampler.swizzle >> 0) & 0x3];
 		c.y = tmp[(sampler.swizzle >> 2) & 0x3];
 		c.z = tmp[(sampler.swizzle >> 4) & 0x3];
 		c.w = tmp[(sampler.swizzle >> 6) & 0x3];
+
+		return c;
 	}
 
-	void PixelProgram::sampleTexture(Vector4f &c, int samplerIndex, Vector4f &uvwq, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
+	Vector4f PixelProgram::sampleTexture(int samplerIndex, Vector4f &uvwq, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
 	{
 		#if PERF_PROFILE
 			Long texTime = Ticks();
 		#endif
 
 		Pointer<Byte> texture = data + OFFSET(DrawData, mipmap) + samplerIndex * sizeof(Texture);
-		sampler[samplerIndex]->sampleTexture(texture, c, uvwq.x, uvwq.y, uvwq.z, uvwq.w, dsx, dsy, offset, function);
+		Vector4f c = SamplerCore(constants, state.sampler[samplerIndex]).sampleTexture(texture, uvwq.x, uvwq.y, uvwq.z, uvwq.w, bias, dsx, dsy, offset, function);
 
 		#if PERF_PROFILE
 			cycles[PERF_TEX] += Ticks() - texTime;
 		#endif
+
+		return c;
 	}
 
 	void PixelProgram::clampColor(Vector4f oC[RENDERTARGETS])
@@ -775,6 +777,12 @@
 			case FORMAT_G8R8UI:
 			case FORMAT_A8B8G8R8UI:
 				break;
+			case FORMAT_X32B32G32R32F_UNSIGNED:
+				oC[index].x = Max(oC[index].x, Float4(0.0f));
+				oC[index].y = Max(oC[index].y, Float4(0.0f));
+				oC[index].z = Max(oC[index].z, Float4(0.0f));
+				oC[index].w = Max(oC[index].w, Float4(0.0f));
+				break;
 			default:
 				ASSERT(false);
 			}
@@ -1107,7 +1115,7 @@
 		dst.w = dot4(src0, row3);
 	}
 
-	void PixelProgram::TEXLD(Vector4f &dst, Vector4f &src0, const Src &src1, bool project, bool bias)
+	void PixelProgram::TEX(Vector4f &dst, Vector4f &src0, const Src &src1, bool project, bool bias)
 	{
 		if(project)
 		{
@@ -1117,58 +1125,63 @@
 			proj.y = src0.y * rw;
 			proj.z = src0.z * rw;
 
-			sampleTexture(dst, src1, proj, src0, src0, src0, Implicit);
+			dst = sampleTexture(src1, proj, src0.x, (src0), (src0), (src0), Implicit);
 		}
 		else
 		{
-			sampleTexture(dst, src1, src0, src0, src0, src0, bias ? Bias : Implicit);
+			dst = sampleTexture(src1, src0, src0.x, (src0), (src0), (src0), bias ? Bias : Implicit);
 		}
 	}
 
-	void PixelProgram::TEXOFFSET(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &src2, bool bias)
+	void PixelProgram::TEXOFFSET(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &offset)
 	{
-		sampleTexture(dst, src1, src0, src0, src0, src2, {bias ? Bias : Implicit, Offset});
+		dst = sampleTexture(src1, src0, (src0.x), (src0), (src0), offset, {Implicit, Offset});
 	}
 
-	void PixelProgram::TEXLDL(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &offset, bool bias)
+	void PixelProgram::TEXLODOFFSET(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &offset, Float4 &lod)
 	{
-		sampleTexture(dst, src1, src0, src0, src0, offset, {Lod, Offset});
+		dst = sampleTexture(src1, src0, lod, (src0), (src0), offset, {Lod, Offset});
 	}
 
-	void PixelProgram::TEXELFETCH(Vector4f &dst, Vector4f &src0, const Src& src1)
+	void PixelProgram::TEXBIAS(Vector4f &dst, Vector4f &src0, const Src &src1, Float4 &bias)
 	{
-		sampleTexture(dst, src1, src0, src0, src0, src0, Fetch);
+		dst = sampleTexture(src1, src0, bias, (src0), (src0), (src0), Bias);
 	}
 
-	void PixelProgram::TEXELFETCH(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &offset)
+	void PixelProgram::TEXOFFSETBIAS(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &offset, Float4 &bias)
 	{
-		sampleTexture(dst, src1, src0, src0, src0, offset, {Fetch, Offset});
+		dst = sampleTexture(src1, src0, bias, (src0), (src0), offset, {Bias, Offset});
 	}
 
-	void PixelProgram::TEXGRAD(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &src2, Vector4f &src3)
+	void PixelProgram::TEXELFETCH(Vector4f &dst, Vector4f &src0, const Src& src1, Float4 &lod)
 	{
-		sampleTexture(dst, src1, src0, src2, src3, src0, Grad);
+		dst = sampleTexture(src1, src0, lod, (src0), (src0), (src0), Fetch);
 	}
 
-	void PixelProgram::TEXGRAD(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &src2, Vector4f &src3, Vector4f &offset)
+	void PixelProgram::TEXELFETCHOFFSET(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &offset, Float4 &lod)
 	{
-		sampleTexture(dst, src1, src0, src2, src3, offset, {Grad, Offset});
+		dst = sampleTexture(src1, src0, lod, (src0), (src0), offset, {Fetch, Offset});
 	}
 
-	void PixelProgram::TEXLDD(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &src2, Vector4f &src3)
+	void PixelProgram::TEXGRAD(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &dsx, Vector4f &dsy)
 	{
-		sampleTexture(dst, src1, src0, src2, src3, src0, Grad);
+		dst = sampleTexture(src1, src0, (src0.x), dsx, dsy, (src0), Grad);
 	}
 
-	void PixelProgram::TEXLDL(Vector4f &dst, Vector4f &src0, const Src &src1)
+	void PixelProgram::TEXGRADOFFSET(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &dsx, Vector4f &dsy, Vector4f &offset)
 	{
-		sampleTexture(dst, src1, src0, src0, src0, src0, Lod);
+		dst = sampleTexture(src1, src0, (src0.x), dsx, dsy, offset, {Grad, Offset});
+	}
+
+	void PixelProgram::TEXLOD(Vector4f &dst, Vector4f &src0, const Src &src1, Float4 &lod)
+	{
+		dst = sampleTexture(src1, src0, lod, (src0), (src0), (src0), Lod);
 	}
 
 	void PixelProgram::TEXSIZE(Vector4f &dst, Float4 &lod, const Src &src1)
 	{
 		Pointer<Byte> texture = data + OFFSET(DrawData, mipmap) + src1.index * sizeof(Texture);
-		sampler[src1.index]->textureSize(texture, dst, lod);
+		dst = SamplerCore::textureSize(texture, lod);
 	}
 
 	void PixelProgram::TEXKILL(Int cMask[4], Vector4f &src, unsigned char mask)
@@ -1238,25 +1251,7 @@
 
 	void PixelProgram::BREAK()
 	{
-		BasicBlock *deadBlock = Nucleus::createBasicBlock();
-		BasicBlock *endBlock = loopRepEndBlock[loopRepDepth - 1];
-
-		if(breakDepth == 0)
-		{
-			enableIndex = enableIndex - breakDepth;
-			Nucleus::createBr(endBlock);
-		}
-		else
-		{
-			enableBreak = enableBreak & ~enableStack[enableIndex];
-			Bool allBreak = SignMask(enableBreak) == 0x0;
-
-			enableIndex = enableIndex - breakDepth;
-			branch(allBreak, endBlock, deadBlock);
-		}
-
-		Nucleus::setInsertBlock(deadBlock);
-		enableIndex = enableIndex + breakDepth;
+		enableBreak = enableBreak & ~enableStack[enableIndex];
 	}
 
 	void PixelProgram::BREAKC(Vector4f &src0, Vector4f &src1, Control control)
@@ -1294,17 +1289,7 @@
 	{
 		condition &= enableStack[enableIndex];
 
-		BasicBlock *continueBlock = Nucleus::createBasicBlock();
-		BasicBlock *endBlock = loopRepEndBlock[loopRepDepth - 1];
-
 		enableBreak = enableBreak & ~condition;
-		Bool allBreak = SignMask(enableBreak) == 0x0;
-
-		enableIndex = enableIndex - breakDepth;
-		branch(allBreak, endBlock, continueBlock);
-
-		Nucleus::setInsertBlock(continueBlock);
-		enableIndex = enableIndex + breakDepth;
 	}
 
 	void PixelProgram::CONTINUE()
@@ -1448,7 +1433,6 @@
 
 		if(isConditionalIf[ifDepth])
 		{
-			breakDepth--;
 			enableIndex--;
 		}
 	}
@@ -1494,7 +1478,6 @@
 		Nucleus::setInsertBlock(endBlock);
 
 		enableIndex--;
-		enableBreak = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 		whileTest = false;
 	}
 
@@ -1504,11 +1487,8 @@
 
 		BasicBlock *endBlock = loopRepEndBlock[loopRepDepth];
 
-		Nucleus::createBr(loopRepEndBlock[loopRepDepth]);
+		Nucleus::createBr(endBlock);
 		Nucleus::setInsertBlock(endBlock);
-
-		enableIndex--;
-		enableBreak = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 	}
 
 	void PixelProgram::IF(const Src &src)
@@ -1599,7 +1579,6 @@
 		ifFalseBlock[ifDepth] = falseBlock;
 
 		ifDepth++;
-		breakDepth++;
 	}
 
 	void PixelProgram::LABEL(int labelIndex)
@@ -1643,7 +1622,6 @@
 		iteration[loopDepth] = iteration[loopDepth] - 1;   // FIXME: --
 
 		loopRepDepth++;
-		breakDepth = 0;
 	}
 
 	void PixelProgram::REP(const Src &integerRegister)
@@ -1670,7 +1648,6 @@
 		iteration[loopDepth] = iteration[loopDepth] - 1;   // FIXME: --
 
 		loopRepDepth++;
-		breakDepth = 0;
 	}
 
 	void PixelProgram::WHILE(const Src &temporaryRegister)
@@ -1687,7 +1664,7 @@
 		Int4 restoreBreak = enableBreak;
 		Int4 restoreContinue = enableContinue;
 
-		// FIXME: jump(testBlock)
+		// TODO: jump(testBlock)
 		Nucleus::createBr(testBlock);
 		Nucleus::setInsertBlock(testBlock);
 		enableContinue = restoreContinue;
@@ -1696,6 +1673,7 @@
 		Int4 condition = As<Int4>(src.x);
 		condition &= enableStack[enableIndex - 1];
 		if(shader->containsLeaveInstruction()) condition &= enableLeave;
+		if(shader->containsBreakInstruction()) condition &= enableBreak;
 		enableStack[enableIndex] = condition;
 
 		Bool notAllFalse = SignMask(condition) != 0;
@@ -1707,21 +1685,25 @@
 		Nucleus::setInsertBlock(loopBlock);
 
 		loopRepDepth++;
-		breakDepth = 0;
 	}
 
 	void PixelProgram::SWITCH()
 	{
-		enableIndex++;
-		enableStack[enableIndex] = Int4(0xFFFFFFFF);
-
 		BasicBlock *endBlock = Nucleus::createBasicBlock();
 
 		loopRepTestBlock[loopRepDepth] = nullptr;
 		loopRepEndBlock[loopRepDepth] = endBlock;
 
+		Int4 restoreBreak = enableBreak;
+
+		BasicBlock *currentBlock = Nucleus::getInsertBlock();
+
+		Nucleus::setInsertBlock(endBlock);
+		enableBreak = restoreBreak;
+
+		Nucleus::setInsertBlock(currentBlock);
+
 		loopRepDepth++;
-		breakDepth = 0;
 	}
 
 	void PixelProgram::RET()
diff --git a/src/Shader/PixelProgram.hpp b/src/Shader/PixelProgram.hpp
index b15177a..951e147 100644
--- a/src/Shader/PixelProgram.hpp
+++ b/src/Shader/PixelProgram.hpp
@@ -24,8 +24,8 @@
 	{
 	public:
 		PixelProgram(const PixelProcessor::State &state, const PixelShader *shader) :
-			PixelRoutine(state, shader), r(shader && shader->dynamicallyIndexedTemporaries),
-			loopDepth(-1), ifDepth(0), loopRepDepth(0), breakDepth(0), currentLabel(-1), whileTest(false)
+			PixelRoutine(state, shader), r(shader->dynamicallyIndexedTemporaries),
+			loopDepth(-1), ifDepth(0), loopRepDepth(0), currentLabel(-1), whileTest(false)
 		{
 			for(int i = 0; i < 2048; ++i)
 			{
@@ -34,12 +34,12 @@
 
 			enableStack[0] = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 
-			if(shader && shader->containsBreakInstruction())
+			if(shader->containsBreakInstruction())
 			{
 				enableBreak = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 			}
 
-			if(shader && shader->containsContinueInstruction())
+			if(shader->containsContinueInstruction())
 			{
 				enableContinue = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 			}
@@ -82,8 +82,8 @@
 		Int4 enableContinue;
 		Int4 enableLeave;
 
-		void sampleTexture(Vector4f &c, const Src &sampler, Vector4f &uvwq, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
-		void sampleTexture(Vector4f &c, int samplerIndex, Vector4f &uvwq, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
+		Vector4f sampleTexture(const Src &sampler, Vector4f &uvwq, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
+		Vector4f sampleTexture(int samplerIndex, Vector4f &uvwq, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
 
 		// Raster operations
 		void clampColor(Vector4f oC[RENDERTARGETS]);
@@ -106,17 +106,18 @@
 		void M3X4(Vector4f &dst, Vector4f &src0, const Src &src1);
 		void M4X3(Vector4f &dst, Vector4f &src0, const Src &src1);
 		void M4X4(Vector4f &dst, Vector4f &src0, const Src &src1);
-		void TEXLD(Vector4f &dst, Vector4f &src0, const Src &src1, bool project, bool bias);
-		void TEXLDD(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &src2, Vector4f &src3);
-		void TEXLDL(Vector4f &dst, Vector4f &src0, const Src &src1);
+		void TEX(Vector4f &dst, Vector4f &src0, const Src &src1, bool project, bool bias);
+		void TEXLOD(Vector4f &dst, Vector4f &src0, const Src &src1, Float4 &lod);
+		void TEXBIAS(Vector4f &dst, Vector4f &src0, const Src &src1, Float4 &bias);
 		void TEXSIZE(Vector4f &dst, Float4 &lod, const Src &src1);
 		void TEXKILL(Int cMask[4], Vector4f &src, unsigned char mask);
-		void TEXOFFSET(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &src2, bool bias);
-		void TEXLDL(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &src2, bool bias);
-		void TEXELFETCH(Vector4f &dst, Vector4f &src, const Src&);
-		void TEXELFETCH(Vector4f &dst, Vector4f &src, const Src&, Vector4f &src2);
-		void TEXGRAD(Vector4f &dst, Vector4f &src, const Src&, Vector4f &src2, Vector4f &src3);
-		void TEXGRAD(Vector4f &dst, Vector4f &src, const Src&, Vector4f &src2, Vector4f &src3, Vector4f &src4);
+		void TEXOFFSET(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &offset);
+		void TEXOFFSETBIAS(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &offset, Float4 &bias);
+		void TEXLODOFFSET(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &offset, Float4 &lod);
+		void TEXELFETCH(Vector4f &dst, Vector4f &src, const Src &, Float4 &lod);
+		void TEXELFETCHOFFSET(Vector4f &dst, Vector4f &src, const Src &, Vector4f &offset, Float4 &lod);
+		void TEXGRAD(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &dsx, Vector4f &dsy);
+		void TEXGRADOFFSET(Vector4f &dst, Vector4f &src, const Src &, Vector4f &dsx, Vector4f &dsy, Vector4f &offset);
 		void DISCARD(Int cMask[4], const Shader::Instruction *instruction);
 		void DFDX(Vector4f &dst, Vector4f &src);
 		void DFDY(Vector4f &dst, Vector4f &src);
@@ -152,7 +153,6 @@
 
 		int ifDepth;
 		int loopRepDepth;
-		int breakDepth;
 		int currentLabel;
 		bool whileTest;
 
diff --git a/src/Shader/PixelRoutine.cpp b/src/Shader/PixelRoutine.cpp
index 44fafd3..1c300b0 100644
--- a/src/Shader/PixelRoutine.cpp
+++ b/src/Shader/PixelRoutine.cpp
@@ -14,13 +14,13 @@
 
 #include "PixelRoutine.hpp"
 
-#include "Renderer.hpp"
-#include "QuadRasterizer.hpp"
-#include "Surface.hpp"
-#include "Primitive.hpp"
 #include "SamplerCore.hpp"
 #include "Constants.hpp"
-#include "Debug.hpp"
+#include "Renderer/Renderer.hpp"
+#include "Renderer/QuadRasterizer.hpp"
+#include "Renderer/Surface.hpp"
+#include "Renderer/Primitive.hpp"
+#include "Common/Debug.hpp"
 
 namespace sw
 {
@@ -31,7 +31,7 @@
 
 	PixelRoutine::PixelRoutine(const PixelProcessor::State &state, const PixelShader *shader) : QuadRasterizer(state, shader), v(shader && shader->dynamicallyIndexedInput)
 	{
-		if(!shader || shader->getVersion() < 0x0200 || forceClearRegisters)
+		if(!shader || shader->getShaderModel() < 0x0200 || forceClearRegisters)
 		{
 			for(int i = 0; i < MAX_FRAGMENT_INPUTS; i++)
 			{
@@ -45,10 +45,6 @@
 
 	PixelRoutine::~PixelRoutine()
 	{
-		for(int i = 0; i < TEXTURE_IMAGE_UNITS; i++)
-		{
-			delete sampler[i];
-		}
 	}
 
 	void PixelRoutine::quad(Pointer<Byte> cBuffer[RENDERTARGETS], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x, Int &y)
@@ -57,11 +53,6 @@
 			Long pipeTime = Ticks();
 		#endif
 
-		for(int i = 0; i < TEXTURE_IMAGE_UNITS; i++)
-		{
-			sampler[i] = new SamplerCore(constants, state.sampler[i]);
-		}
-
 		const bool earlyDepthTest = !state.depthOverride && !state.alphaTestActive();
 
 		Int zMask[4];   // Depth mask
@@ -94,7 +85,7 @@
 					x -= *Pointer<Float4>(constants + OFFSET(Constants,X) + q * sizeof(float4));
 				}
 
-				z[q] = interpolate(x, Dz[q], z[q], primitive + OFFSET(Primitive,z), false, false);
+				z[q] = interpolate(x, Dz[q], z[q], primitive + OFFSET(Primitive,z), false, false, state.depthClamp);
 			}
 		}
 
@@ -141,7 +132,7 @@
 
 			if(interpolateW())
 			{
-				w = interpolate(xxxx, Dw, rhw, primitive + OFFSET(Primitive,w), false, false);
+				w = interpolate(xxxx, Dw, rhw, primitive + OFFSET(Primitive,w), false, false, false);
 				rhw = reciprocal(w, false, false, true);
 
 				if(state.centroid)
@@ -158,7 +149,7 @@
 					{
 						if(!state.interpolant[interpolant].centroid)
 						{
-							v[interpolant][component] = interpolate(xxxx, Dv[interpolant][component], rhw, primitive + OFFSET(Primitive, V[interpolant][component]), (state.interpolant[interpolant].flat & (1 << component)) != 0, state.perspective);
+							v[interpolant][component] = interpolate(xxxx, Dv[interpolant][component], rhw, primitive + OFFSET(Primitive, V[interpolant][component]), (state.interpolant[interpolant].flat & (1 << component)) != 0, state.perspective, false);
 						}
 						else
 						{
@@ -193,7 +184,7 @@
 
 			if(state.fog.component)
 			{
-				f = interpolate(xxxx, Df, rhw, primitive + OFFSET(Primitive,f), state.fog.flat & 0x01, state.perspective);
+				f = interpolate(xxxx, Df, rhw, primitive + OFFSET(Primitive,f), state.fog.flat & 0x01, state.perspective, false);
 			}
 
 			setBuiltins(x, y, z, w);
@@ -544,29 +535,29 @@
 			break;
 		case ALPHA_EQUAL:
 			cmp = CmpEQ(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)));
-			aMask = SignMask(Pack(cmp, Short4(0x0000)));
+			aMask = SignMask(PackSigned(cmp, Short4(0x0000)));
 			break;
 		case ALPHA_NOTEQUAL:       // a != b ~ !(a == b)
 			cmp = CmpEQ(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4))) ^ Short4(0xFFFFu);   // FIXME
-			aMask = SignMask(Pack(cmp, Short4(0x0000)));
+			aMask = SignMask(PackSigned(cmp, Short4(0x0000)));
 			break;
 		case ALPHA_LESS:           // a < b ~ b > a
 			cmp = CmpGT(*Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)), alpha);
-			aMask = SignMask(Pack(cmp, Short4(0x0000)));
+			aMask = SignMask(PackSigned(cmp, Short4(0x0000)));
 			break;
 		case ALPHA_GREATEREQUAL:   // a >= b ~ (a > b) || (a == b) ~ !(b > a)   // TODO: Approximate
 			equal = CmpEQ(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)));
 			cmp = CmpGT(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)));
 			cmp |= equal;
-			aMask = SignMask(Pack(cmp, Short4(0x0000)));
+			aMask = SignMask(PackSigned(cmp, Short4(0x0000)));
 			break;
 		case ALPHA_LESSEQUAL:      // a <= b ~ !(a > b)
 			cmp = CmpGT(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4))) ^ Short4(0xFFFFu);   // FIXME
-			aMask = SignMask(Pack(cmp, Short4(0x0000)));
+			aMask = SignMask(PackSigned(cmp, Short4(0x0000)));
 			break;
 		case ALPHA_GREATER:        // a > b
 			cmp = CmpGT(alpha, *Pointer<Short4>(data + OFFSET(DrawData,factor.alphaReference4)));
-			aMask = SignMask(Pack(cmp, Short4(0x0000)));
+			aMask = SignMask(PackSigned(cmp, Short4(0x0000)));
 			break;
 		default:
 			ASSERT(false);
@@ -1000,7 +991,7 @@
 
 	bool PixelRoutine::isSRGB(int index) const
 	{
-		return state.targetFormat[index] == FORMAT_SRGB8_A8 || state.targetFormat[index] == FORMAT_SRGB8_X8;
+		return Surface::isSRGBformat(state.targetFormat[index]);
 	}
 
 	void PixelRoutine::readPixel(int index, Pointer<Byte> &cBuffer, Int &x, Vector4s &pixel)
@@ -1071,6 +1062,16 @@
 			pixel.y = Short4(0x0000);
 			pixel.z = Short4(0x0000);
 			break;
+		case FORMAT_R8:
+			buffer = cBuffer + 1 * x;
+			pixel.x = Insert(pixel.x, *Pointer<Short>(buffer), 0);
+			buffer += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
+			pixel.x = Insert(pixel.x, *Pointer<Short>(buffer), 1);
+			pixel.x = UnpackLow(As<Byte8>(pixel.x), As<Byte8>(pixel.x));
+			pixel.y = Short4(0x0000);
+			pixel.z = Short4(0x0000);
+			pixel.w = Short4(0xFFFFu);
+			break;
 		case FORMAT_X8R8G8B8:
 			buffer = cBuffer + 4 * x;
 			c01 = *Pointer<Short4>(buffer);
@@ -1089,6 +1090,16 @@
 			pixel.z = UnpackLow(As<Byte8>(pixel.z), As<Byte8>(pixel.z));
 			pixel.w = Short4(0xFFFFu);
 			break;
+		case FORMAT_G8R8:
+			buffer = cBuffer + 2 * x;
+			c01 = As<Short4>(Insert(As<Int2>(c01), *Pointer<Int>(buffer), 0));
+			buffer += *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
+			c01 = As<Short4>(Insert(As<Int2>(c01), *Pointer<Int>(buffer), 1));
+			pixel.x = (c01 & Short4(0x00FFu)) | (c01 << 8);
+			pixel.y = (c01 & Short4(0xFF00u)) | As<Short4>(As<UShort4>(c01) >> 8);
+			pixel.z = Short4(0x0000u);
+			pixel.w = Short4(0xFFFFu);
+			break;
 		case FORMAT_X8B8G8R8:
 		case FORMAT_SRGB8_X8:
 			buffer = cBuffer + 4 * x;
@@ -1447,8 +1458,8 @@
 				current.y = As<Short4>(As<UShort4>(current.y) >> 8);
 				current.z = As<Short4>(As<UShort4>(current.z) >> 8);
 
-				current.z = As<Short4>(Pack(As<UShort4>(current.z), As<UShort4>(current.x)));
-				current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.y)));
+				current.z = As<Short4>(PackUnsigned(current.z, current.x));
+				current.y = As<Short4>(PackUnsigned(current.y, current.y));
 
 				current.x = current.z;
 				current.z = UnpackLow(As<Byte8>(current.z), As<Byte8>(current.y));
@@ -1464,8 +1475,8 @@
 				current.z = As<Short4>(As<UShort4>(current.z) >> 8);
 				current.w = As<Short4>(As<UShort4>(current.w) >> 8);
 
-				current.z = As<Short4>(Pack(As<UShort4>(current.z), As<UShort4>(current.x)));
-				current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.w)));
+				current.z = As<Short4>(PackUnsigned(current.z, current.x));
+				current.y = As<Short4>(PackUnsigned(current.y, current.w));
 
 				current.x = current.z;
 				current.z = UnpackLow(As<Byte8>(current.z), As<Byte8>(current.y));
@@ -1485,8 +1496,8 @@
 				current.y = As<Short4>(As<UShort4>(current.y) >> 8);
 				current.z = As<Short4>(As<UShort4>(current.z) >> 8);
 
-				current.z = As<Short4>(Pack(As<UShort4>(current.x), As<UShort4>(current.z)));
-				current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.y)));
+				current.z = As<Short4>(PackUnsigned(current.x, current.z));
+				current.y = As<Short4>(PackUnsigned(current.y, current.y));
 
 				current.x = current.z;
 				current.z = UnpackLow(As<Byte8>(current.z), As<Byte8>(current.y));
@@ -1502,8 +1513,8 @@
 				current.z = As<Short4>(As<UShort4>(current.z) >> 8);
 				current.w = As<Short4>(As<UShort4>(current.w) >> 8);
 
-				current.z = As<Short4>(Pack(As<UShort4>(current.x), As<UShort4>(current.z)));
-				current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.w)));
+				current.z = As<Short4>(PackUnsigned(current.x, current.z));
+				current.y = As<Short4>(PackUnsigned(current.y, current.w));
 
 				current.x = current.z;
 				current.z = UnpackLow(As<Byte8>(current.z), As<Byte8>(current.y));
@@ -1516,17 +1527,17 @@
 		case FORMAT_G8R8:
 			current.x = As<Short4>(As<UShort4>(current.x) >> 8);
 			current.y = As<Short4>(As<UShort4>(current.y) >> 8);
-			current.x = As<Short4>(Pack(As<UShort4>(current.x), As<UShort4>(current.x)));
-			current.y = As<Short4>(Pack(As<UShort4>(current.y), As<UShort4>(current.y)));
+			current.x = As<Short4>(PackUnsigned(current.x, current.x));
+			current.y = As<Short4>(PackUnsigned(current.y, current.y));
 			current.x = UnpackLow(As<Byte8>(current.x), As<Byte8>(current.y));
 			break;
 		case FORMAT_R8:
 			current.x = As<Short4>(As<UShort4>(current.x) >> 8);
-			current.x = As<Short4>(Pack(As<UShort4>(current.x), As<UShort4>(current.x)));
+			current.x = As<Short4>(PackUnsigned(current.x, current.x));
 			break;
 		case FORMAT_A8:
 			current.w = As<Short4>(As<UShort4>(current.w) >> 8);
-			current.w = As<Short4>(Pack(As<UShort4>(current.w), As<UShort4>(current.w)));
+			current.w = As<Short4>(PackUnsigned(current.w, current.w));
 			break;
 		case FORMAT_G16R16:
 			current.z = current.x;
@@ -1753,7 +1764,6 @@
 				value = Insert(value, *Pointer<Short>(buffer), 0);
 				Int pitch = *Pointer<Int>(data + OFFSET(DrawData, colorPitchB[index]));
 				value = Insert(value, *Pointer<Short>(buffer + pitch), 1);
-				value = UnpackLow(As<Byte8>(value), As<Byte8>(value));
 
 				current.x &= *Pointer<Short4>(constants + OFFSET(Constants, maskB4Q) + 8 * xMask);
 				value &= *Pointer<Short4>(constants + OFFSET(Constants, invMaskB4Q) + 8 * xMask);
@@ -1771,7 +1781,6 @@
 				value = Insert(value, *Pointer<Short>(buffer), 0);
 				Int pitch = *Pointer<Int>(data + OFFSET(DrawData,colorPitchB[index]));
 				value = Insert(value, *Pointer<Short>(buffer + pitch), 1);
-				value = UnpackLow(As<Byte8>(value), As<Byte8>(value));
 
 				current.w &= *Pointer<Short4>(constants + OFFSET(Constants,maskB4Q) + 8 * xMask);
 				value &= *Pointer<Short4>(constants + OFFSET(Constants,invMaskB4Q) + 8 * xMask);
@@ -2071,6 +2080,7 @@
 			break;
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_A32B32G32R32I:
 		case FORMAT_A32B32G32R32UI:
 			buffer = cBuffer;
@@ -2080,7 +2090,8 @@
 			pixel.z = *Pointer<Float4>(buffer + 16 * x, 16);
 			pixel.w = *Pointer<Float4>(buffer + 16 * x + 16, 16);
 			transpose4x4(pixel.x, pixel.y, pixel.z, pixel.w);
-			if(state.targetFormat[index] == FORMAT_X32B32G32R32F)
+			if(state.targetFormat[index] == FORMAT_X32B32G32R32F ||
+			   state.targetFormat[index] == FORMAT_X32B32G32R32F_UNSIGNED)
 			{
 				pixel.w = Float4(1.0f);
 			}
@@ -2232,6 +2243,7 @@
 			break;
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_A32B32G32R32I:
 		case FORMAT_A32B32G32R32UI:
 		case FORMAT_A16B16G16R16I:
@@ -2362,11 +2374,11 @@
 				Short4 tmpCol = Short4(As<Int4>(oC.x));
 				if(state.targetFormat[index] == FORMAT_R8I)
 				{
-					tmpCol = As<Short4>(Pack(tmpCol, tmpCol));
+					tmpCol = As<Short4>(PackSigned(tmpCol, tmpCol));
 				}
 				else
 				{
-					tmpCol = As<Short4>(Pack(As<UShort4>(tmpCol), As<UShort4>(tmpCol)));
+					tmpCol = As<Short4>(PackUnsigned(tmpCol, tmpCol));
 				}
 				packedCol = Extract(As<Int2>(tmpCol), 0);
 
@@ -2461,11 +2473,11 @@
 
 				if(state.targetFormat[index] == FORMAT_G8R8I)
 				{
-					packedCol = As<Int2>(Pack(Short4(As<Int4>(oC.x)), Short4(As<Int4>(oC.y))));
+					packedCol = As<Int2>(PackSigned(Short4(As<Int4>(oC.x)), Short4(As<Int4>(oC.y))));
 				}
 				else
 				{
-					packedCol = As<Int2>(Pack(UShort4(As<Int4>(oC.x)), UShort4(As<Int4>(oC.y))));
+					packedCol = As<Int2>(PackUnsigned(Short4(As<Int4>(oC.x)), Short4(As<Int4>(oC.y))));
 				}
 
 				UInt2 mergedMask = *Pointer<UInt2>(constants + OFFSET(Constants, maskW4Q) + xMask * 8);
@@ -2485,6 +2497,7 @@
 			break;
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_A32B32G32R32I:
 		case FORMAT_A32B32G32R32UI:
 			buffer = cBuffer + 16 * x;
@@ -2599,11 +2612,11 @@
 
 				if(state.targetFormat[index] == FORMAT_A8B8G8R8I)
 				{
-					packedCol = As<UInt2>(Pack(Short4(As<Int4>(oC.x)), Short4(As<Int4>(oC.y))));
+					packedCol = As<UInt2>(PackSigned(Short4(As<Int4>(oC.x)), Short4(As<Int4>(oC.y))));
 				}
 				else
 				{
-					packedCol = As<UInt2>(Pack(UShort4(As<Int4>(oC.x)), UShort4(As<Int4>(oC.y))));
+					packedCol = As<UInt2>(PackUnsigned(Short4(As<Int4>(oC.x)), Short4(As<Int4>(oC.y))));
 				}
 				value = *Pointer<UInt2>(buffer, 16);
 				mergedMask = *Pointer<UInt2>(constants + OFFSET(Constants, maskD01Q) + xMask * 8);
@@ -2617,11 +2630,11 @@
 
 				if(state.targetFormat[index] == FORMAT_A8B8G8R8I)
 				{
-					packedCol = As<UInt2>(Pack(Short4(As<Int4>(oC.z)), Short4(As<Int4>(oC.w))));
+					packedCol = As<UInt2>(PackSigned(Short4(As<Int4>(oC.z)), Short4(As<Int4>(oC.w))));
 				}
 				else
 				{
-					packedCol = As<UInt2>(Pack(UShort4(As<Int4>(oC.z)), UShort4(As<Int4>(oC.w))));
+					packedCol = As<UInt2>(PackUnsigned(Short4(As<Int4>(oC.z)), Short4(As<Int4>(oC.w))));
 				}
 				value = *Pointer<UInt2>(buffer, 16);
 				mergedMask = *Pointer<UInt2>(constants + OFFSET(Constants, maskD23Q) + xMask * 8);
@@ -2644,17 +2657,12 @@
 
 	void PixelRoutine::sRGBtoLinear16_12_16(Vector4s &c)
 	{
+		Pointer<Byte> LUT = constants + OFFSET(Constants,sRGBtoLinear12_16);
+
 		c.x = As<UShort4>(c.x) >> 4;
 		c.y = As<UShort4>(c.y) >> 4;
 		c.z = As<UShort4>(c.z) >> 4;
 
-		sRGBtoLinear12_16(c);
-	}
-
-	void PixelRoutine::sRGBtoLinear12_16(Vector4s &c)
-	{
-		Pointer<Byte> LUT = constants + OFFSET(Constants,sRGBtoLinear12_16);
-
 		c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 0))), 0);
 		c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 1))), 1);
 		c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 2))), 2);
diff --git a/src/Shader/PixelRoutine.hpp b/src/Shader/PixelRoutine.hpp
index d57f2cb..1cd076e 100644
--- a/src/Shader/PixelRoutine.hpp
+++ b/src/Shader/PixelRoutine.hpp
@@ -15,7 +15,7 @@
 #ifndef sw_PixelRoutine_hpp
 #define sw_PixelRoutine_hpp
 
-#include "QuadRasterizer.hpp"
+#include "Renderer/QuadRasterizer.hpp"
 
 namespace sw
 {
@@ -65,8 +65,6 @@
 		UShort4 convertFixed16(Float4 &cf, bool saturate = true);
 		void linearToSRGB12_16(Vector4s &c);
 
-		SamplerCore *sampler[TEXTURE_IMAGE_UNITS];
-
 	private:
 		Float4 interpolateCentroid(Float4 &x, Float4 &y, Float4 &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective);
 		void stencilTest(Pointer<Byte> &sBuffer, int q, Int &x, Int &sMask, Int &cMask);
@@ -85,7 +83,6 @@
 		void writeDepth(Pointer<Byte> &zBuffer, int q, Int &x, Float4 &z, Int &zMask);
 
 		void sRGBtoLinear16_12_16(Vector4s &c);
-		void sRGBtoLinear12_16(Vector4s &c);
 		void linearToSRGB16_12_16(Vector4s &c);
 		Float4 sRGBtoLinear(const Float4 &x);
 
diff --git a/src/Shader/PixelShader.cpp b/src/Shader/PixelShader.cpp
index c659248..9e281d9 100644
--- a/src/Shader/PixelShader.cpp
+++ b/src/Shader/PixelShader.cpp
@@ -14,7 +14,7 @@
 
 #include "PixelShader.hpp"
 
-#include "Debug.hpp"
+#include "Common/Debug.hpp"
 
 #include <string.h>
 
@@ -22,7 +22,7 @@
 {
 	PixelShader::PixelShader(const PixelShader *ps) : Shader()
 	{
-		version = 0x0300;
+		shaderModel = 0x0300;
 		vPosDeclared = false;
 		vFaceDeclared = false;
 		centroid = false;
@@ -167,11 +167,11 @@
 	{
 		zOverride = false;
 
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(const auto &inst : instruction)
 		{
-			if(instruction[i]->opcode == Shader::OPCODE_TEXM3X2DEPTH ||
-			   instruction[i]->opcode == Shader::OPCODE_TEXDEPTH ||
-			   instruction[i]->dst.type == Shader::PARAMETER_DEPTHOUT)
+			if(inst->opcode == Shader::OPCODE_TEXM3X2DEPTH ||
+			   inst->opcode == Shader::OPCODE_TEXDEPTH ||
+			   inst->dst.type == Shader::PARAMETER_DEPTHOUT)
 			{
 				zOverride = true;
 
@@ -184,10 +184,10 @@
 	{
 		kill = false;
 
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(const auto &inst : instruction)
 		{
-			if(instruction[i]->opcode == Shader::OPCODE_TEXKILL ||
-			   instruction[i]->opcode == Shader::OPCODE_DISCARD)
+			if(inst->opcode == Shader::OPCODE_TEXKILL ||
+			   inst->opcode == Shader::OPCODE_DISCARD)
 			{
 				kill = true;
 
@@ -198,7 +198,7 @@
 
 	void PixelShader::analyzeInterpolants()
 	{
-		if(version < 0x0300)
+		if(shaderModel < 0x0300)
 		{
 			// Set default mapping; disable unused interpolants below
 			input[0][0] = Semantic(Shader::USAGE_COLOR, 0);
@@ -226,25 +226,25 @@
 				samplerType[i] = Shader::SAMPLER_UNKNOWN;
 			}
 
-			for(unsigned int i = 0; i < instruction.size(); i++)
+			for(const auto &inst : instruction)
 			{
-				if(instruction[i]->dst.type == Shader::PARAMETER_SAMPLER)
+				if(inst->dst.type == Shader::PARAMETER_SAMPLER)
 				{
-					int sampler = instruction[i]->dst.index;
+					int sampler = inst->dst.index;
 
-					samplerType[sampler] = instruction[i]->samplerType;
+					samplerType[sampler] = inst->samplerType;
 				}
 			}
 
 			bool interpolant[MAX_FRAGMENT_INPUTS][4] = {{false}};   // Interpolants in use
 
-			for(unsigned int i = 0; i < instruction.size(); i++)
+			for(const auto &inst : instruction)
 			{
-				if(instruction[i]->dst.type == Shader::PARAMETER_TEXTURE)
+				if(inst->dst.type == Shader::PARAMETER_TEXTURE)
 				{
-					int index = instruction[i]->dst.index + 2;
+					int index = inst->dst.index + 2;
 
-					switch(instruction[i]->opcode)
+					switch(inst->opcode)
 					{
 					case Shader::OPCODE_TEX:
 					case Shader::OPCODE_TEXBEM:
@@ -288,7 +288,7 @@
 					case Shader::OPCODE_DCL:
 						break;   // Ignore
 					default:   // Arithmetic instruction
-						if(version >= 0x0104)
+						if(shaderModel >= 0x0104)
 						{
 							ASSERT(false);
 						}
@@ -297,38 +297,41 @@
 
 				for(int argument = 0; argument < 4; argument++)
 				{
-					if(instruction[i]->src[argument].type == Shader::PARAMETER_INPUT ||
-					   instruction[i]->src[argument].type == Shader::PARAMETER_TEXTURE)
+					if(inst->src[argument].type == Shader::PARAMETER_INPUT ||
+					   inst->src[argument].type == Shader::PARAMETER_TEXTURE)
 					{
-						int index = instruction[i]->src[argument].index;
-						int swizzle = instruction[i]->src[argument].swizzle;
-						int mask = instruction[i]->dst.mask;
+						int index = inst->src[argument].index;
+						int swizzle = inst->src[argument].swizzle;
+						int mask = inst->dst.mask;
 
-						if(instruction[i]->src[argument].type == Shader::PARAMETER_TEXTURE)
+						if(inst->src[argument].type == Shader::PARAMETER_TEXTURE)
 						{
 							index += 2;
 						}
 
-						switch(instruction[i]->opcode)
+						switch(inst->opcode)
 						{
 						case Shader::OPCODE_TEX:
 						case Shader::OPCODE_TEXLDD:
 						case Shader::OPCODE_TEXLDL:
+						case Shader::OPCODE_TEXLOD:
+						case Shader::OPCODE_TEXBIAS:
 						case Shader::OPCODE_TEXOFFSET:
-						case Shader::OPCODE_TEXLDLOFFSET:
+						case Shader::OPCODE_TEXOFFSETBIAS:
+						case Shader::OPCODE_TEXLODOFFSET:
 						case Shader::OPCODE_TEXELFETCH:
 						case Shader::OPCODE_TEXELFETCHOFFSET:
 						case Shader::OPCODE_TEXGRAD:
 						case Shader::OPCODE_TEXGRADOFFSET:
 							{
-								int sampler = instruction[i]->src[1].index;
+								int sampler = inst->src[1].index;
 
 								switch(samplerType[sampler])
 								{
 								case Shader::SAMPLER_UNKNOWN:
-									if(version == 0x0104)
+									if(shaderModel == 0x0104)
 									{
-										if((instruction[i]->src[0].swizzle & 0x30) == 0x20)   // .xyz
+										if((inst->src[0].swizzle & 0x30) == 0x20)   // .xyz
 										{
 											interpolant[index][0] = true;
 											interpolant[index][1] = true;
@@ -367,24 +370,24 @@
 									ASSERT(false);
 								}
 
-								if(instruction[i]->bias)
+								if(inst->bias)
 								{
 									interpolant[index][3] = true;
 								}
 
-								if(instruction[i]->project)
+								if(inst->project)
 								{
 									interpolant[index][3] = true;
 								}
 
-								if(version == 0x0104 && instruction[i]->opcode == Shader::OPCODE_TEX)
+								if(shaderModel == 0x0104 && inst->opcode == Shader::OPCODE_TEX)
 								{
-									if(instruction[i]->src[0].modifier == Shader::MODIFIER_DZ)
+									if(inst->src[0].modifier == Shader::MODIFIER_DZ)
 									{
 										interpolant[index][2] = true;
 									}
 
-									if(instruction[i]->src[0].modifier == Shader::MODIFIER_DW)
+									if(inst->src[0].modifier == Shader::MODIFIER_DW)
 									{
 										interpolant[index][3] = true;
 									}
@@ -680,25 +683,25 @@
 		}
 		else   // Shader Model 3.0 input declaration; v# indexable
 		{
-			for(unsigned int i = 0; i < instruction.size(); i++)
+			for(const auto &inst : instruction)
 			{
-				if(instruction[i]->opcode == Shader::OPCODE_DCL)
+				if(inst->opcode == Shader::OPCODE_DCL)
 				{
-					if(instruction[i]->dst.type == Shader::PARAMETER_INPUT)
+					if(inst->dst.type == Shader::PARAMETER_INPUT)
 					{
-						unsigned char usage = instruction[i]->usage;
-						unsigned char index = instruction[i]->usageIndex;
-						unsigned char mask = instruction[i]->dst.mask;
-						unsigned char reg = instruction[i]->dst.index;
+						unsigned char usage = inst->usage;
+						unsigned char index = inst->usageIndex;
+						unsigned char mask = inst->dst.mask;
+						unsigned char reg = inst->dst.index;
 
-						if(mask & 0x01)	input[reg][0] = Semantic(usage, index);
+						if(mask & 0x01) input[reg][0] = Semantic(usage, index);
 						if(mask & 0x02) input[reg][1] = Semantic(usage, index);
 						if(mask & 0x04) input[reg][2] = Semantic(usage, index);
-						if(mask & 0x08)	input[reg][3] = Semantic(usage, index);
+						if(mask & 0x08) input[reg][3] = Semantic(usage, index);
 					}
-					else if(instruction[i]->dst.type == Shader::PARAMETER_MISCTYPE)
+					else if(inst->dst.type == Shader::PARAMETER_MISCTYPE)
 					{
-						unsigned char index = instruction[i]->dst.index;
+						unsigned char index = inst->dst.index;
 
 						if(index == Shader::VPosIndex)
 						{
@@ -714,16 +717,16 @@
 			}
 		}
 
-		if(version >= 0x0200)
+		if(shaderModel >= 0x0200)
 		{
-			for(unsigned int i = 0; i < instruction.size(); i++)
+			for(const auto &inst : instruction)
 			{
-				if(instruction[i]->opcode == Shader::OPCODE_DCL)
+				if(inst->opcode == Shader::OPCODE_DCL)
 				{
-					bool centroid = instruction[i]->dst.centroid;
-					unsigned char reg = instruction[i]->dst.index;
+					bool centroid = inst->dst.centroid;
+					unsigned char reg = inst->dst.index;
 
-					switch(instruction[i]->dst.type)
+					switch(inst->dst.type)
 					{
 					case Shader::PARAMETER_INPUT:
 						input[reg][0].centroid = centroid;
diff --git a/src/Shader/SamplerCore.cpp b/src/Shader/SamplerCore.cpp
index 62f76fa..8fa378f 100644
--- a/src/Shader/SamplerCore.cpp
+++ b/src/Shader/SamplerCore.cpp
@@ -15,7 +15,7 @@
 #include "SamplerCore.hpp"
 
 #include "Constants.hpp"
-#include "Debug.hpp"
+#include "Common/Debug.hpp"
 
 namespace
 {
@@ -56,13 +56,15 @@
 	{
 	}
 
-	void SamplerCore::sampleTexture(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy)
+	Vector4s SamplerCore::sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy)
 	{
-		sampleTexture(texture, c, u, v, w, q, dsx, dsy, dsx, Implicit, true);
+		return sampleTexture(texture, u, v, w, q, q, dsx, dsy, (dsx), Implicit, true);
 	}
 
-	void SamplerCore::sampleTexture(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function, bool fixed12)
+	Vector4s SamplerCore::sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function, bool fixed12)
 	{
+		Vector4s c;
+
 		#if PERF_PROFILE
 			AddAtomic(Pointer<Long>(&profiler.texOperations), 4);
 
@@ -72,10 +74,6 @@
 			}
 		#endif
 
-		Float4 uuuu = u;
-		Float4 vvvv = v;
-		Float4 wwww = w;
-
 		if(state.textureType == TEXTURE_NULL)
 		{
 			c.x = Short4(0x0000);
@@ -93,84 +91,59 @@
 		}
 		else
 		{
+			Float4 uuuu = u;
+			Float4 vvvv = v;
+			Float4 wwww = w;
+			Float4 qqqq = q;
+
 			Int face[4];
-			Float4 lodX;
-			Float4 lodY;
-			Float4 lodZ;
-
-			if(state.textureType == TEXTURE_CUBE)
-			{
-				cubeFace(face, uuuu, vvvv, lodX, lodY, lodZ, u, v, w);
-			}
-
 			Float lod;
 			Float anisotropy;
 			Float4 uDelta;
 			Float4 vDelta;
-			Float lodBias = (function == Fetch) ? Float4(As<Int4>(q)).x : q.x;
 
 			if(state.textureType != TEXTURE_3D)
 			{
 				if(state.textureType != TEXTURE_CUBE)
 				{
-					computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, lodBias, dsx, dsy, function);
+					computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, bias.x, dsx, dsy, function);
 				}
 				else
 				{
-					computeLodCube(texture, lod, lodX, lodY, lodZ, lodBias, dsx, dsy, function);
+					Float4 M;
+					cubeFace(face, uuuu, vvvv, u, v, w, M);
+					computeLodCube(texture, lod, u, v, w, bias.x, dsx, dsy, M, function);
 				}
 			}
 			else
 			{
-				computeLod3D(texture, lod, uuuu, vvvv, wwww, lodBias, dsx, dsy, function);
+				computeLod3D(texture, lod, uuuu, vvvv, wwww, bias.x, dsx, dsy, function);
 			}
 
 			if(!hasFloatTexture())
 			{
-				sampleFilter(texture, c, uuuu, vvvv, wwww, offset, lod, anisotropy, uDelta, vDelta, face, function);
+				c = sampleFilter(texture, uuuu, vvvv, wwww, offset, lod, anisotropy, uDelta, vDelta, face, function);
 			}
 			else
 			{
-				Vector4f cf;
-
-				sampleFloatFilter(texture, cf, uuuu, vvvv, wwww, offset, lod, anisotropy, uDelta, vDelta, face, function);
+				Vector4f cf = sampleFloatFilter(texture, uuuu, vvvv, wwww, qqqq, offset, lod, anisotropy, uDelta, vDelta, face, function);
 
 				convertFixed12(c, cf);
 			}
 
-			if(fixed12 && !hasFloatTexture())
+			if(fixed12)
 			{
-				if(has16bitTextureFormat())
+				if(!hasFloatTexture())
 				{
-					switch(state.textureFormat)
+					if(state.textureFormat == FORMAT_R5G6B5)
 					{
-					case FORMAT_R5G6B5:
-						if(state.sRGB)
-						{
-							sRGBtoLinear16_5_12(c.x);
-							sRGBtoLinear16_6_12(c.y);
-							sRGBtoLinear16_5_12(c.z);
-						}
-						else
-						{
-							c.x = MulHigh(As<UShort4>(c.x), UShort4(0x10000000 / 0xF800));
-							c.y = MulHigh(As<UShort4>(c.y), UShort4(0x10000000 / 0xFC00));
-							c.z = MulHigh(As<UShort4>(c.z), UShort4(0x10000000 / 0xF800));
-						}
-						break;
-					default:
-						ASSERT(false);
+						c.x = MulHigh(As<UShort4>(c.x), UShort4(0x10000000 / 0xF800));
+						c.y = MulHigh(As<UShort4>(c.y), UShort4(0x10000000 / 0xFC00));
+						c.z = MulHigh(As<UShort4>(c.z), UShort4(0x10000000 / 0xF800));
 					}
-				}
-				else
-				{
-					for(int component = 0; component < textureComponentCount(); component++)
+					else
 					{
-						if(state.sRGB && isRGBComponent(component))
-						{
-							sRGBtoLinear16_8_12(c[component]);   // FIXME: Perform linearization at surface level for read-only textures
-						}
-						else
+						for(int component = 0; component < textureComponentCount(); component++)
 						{
 							if(hasUnsignedTextureComponent(component))
 							{
@@ -183,122 +156,128 @@
 						}
 					}
 				}
-			}
 
-			if(fixed12 && state.textureFilter != FILTER_GATHER)
-			{
-				int componentCount = textureComponentCount();
-				short defaultColorValue = colorsDefaultToZero ? 0x0000 : 0x1000;
-
-				switch(state.textureFormat)
+				if(state.textureFilter != FILTER_GATHER)
 				{
-				case FORMAT_R8I_SNORM:
-				case FORMAT_G8R8I_SNORM:
-				case FORMAT_X8B8G8R8I_SNORM:
-				case FORMAT_A8B8G8R8I_SNORM:
-				case FORMAT_R8:
-				case FORMAT_R5G6B5:
-				case FORMAT_G8R8:
-				case FORMAT_R8I:
-				case FORMAT_R8UI:
-				case FORMAT_G8R8I:
-				case FORMAT_G8R8UI:
-				case FORMAT_X8B8G8R8I:
-				case FORMAT_X8B8G8R8UI:
-				case FORMAT_A8B8G8R8I:
-				case FORMAT_A8B8G8R8UI:
-				case FORMAT_R16I:
-				case FORMAT_R16UI:
-				case FORMAT_G16R16:
-				case FORMAT_G16R16I:
-				case FORMAT_G16R16UI:
-				case FORMAT_X16B16G16R16I:
-				case FORMAT_X16B16G16R16UI:
-				case FORMAT_A16B16G16R16:
-				case FORMAT_A16B16G16R16I:
-				case FORMAT_A16B16G16R16UI:
-				case FORMAT_R32I:
-				case FORMAT_R32UI:
-				case FORMAT_G32R32I:
-				case FORMAT_G32R32UI:
-				case FORMAT_X32B32G32R32I:
-				case FORMAT_X32B32G32R32UI:
-				case FORMAT_A32B32G32R32I:
-				case FORMAT_A32B32G32R32UI:
-				case FORMAT_X8R8G8B8:
-				case FORMAT_X8B8G8R8:
-				case FORMAT_A8R8G8B8:
-				case FORMAT_A8B8G8R8:
-				case FORMAT_SRGB8_X8:
-				case FORMAT_SRGB8_A8:
-				case FORMAT_V8U8:
-				case FORMAT_Q8W8V8U8:
-				case FORMAT_X8L8V8U8:
-				case FORMAT_V16U16:
-				case FORMAT_A16W16V16U16:
-				case FORMAT_Q16W16V16U16:
-				case FORMAT_YV12_BT601:
-				case FORMAT_YV12_BT709:
-				case FORMAT_YV12_JFIF:
-					if(componentCount < 2) c.y = Short4(defaultColorValue);
-					if(componentCount < 3) c.z = Short4(defaultColorValue);
-					if(componentCount < 4) c.w = Short4(0x1000);
-					break;
-				case FORMAT_A8:
-					c.w = c.x;
-					c.x = Short4(0x0000);
-					c.y = Short4(0x0000);
-					c.z = Short4(0x0000);
-					break;
-				case FORMAT_L8:
-				case FORMAT_L16:
-					c.y = c.x;
-					c.z = c.x;
-					c.w = Short4(0x1000);
-					break;
-				case FORMAT_A8L8:
-					c.w = c.y;
-					c.y = c.x;
-					c.z = c.x;
-					break;
-				case FORMAT_R32F:
-					c.y = Short4(defaultColorValue);
-				case FORMAT_G32R32F:
-					c.z = Short4(defaultColorValue);
-				case FORMAT_X32B32G32R32F:
-					c.w = Short4(0x1000);
-				case FORMAT_A32B32G32R32F:
-					break;
-				case FORMAT_D32F:
-				case FORMAT_D32F_LOCKABLE:
-				case FORMAT_D32FS8_TEXTURE:
-				case FORMAT_D32FS8_SHADOW:
-					c.y = c.x;
-					c.z = c.x;
-					c.w = c.x;
-					break;
-				default:
-					ASSERT(false);
+					int componentCount = textureComponentCount();
+					short defaultColorValue = colorsDefaultToZero ? 0x0000 : 0x1000;
+
+					switch(state.textureFormat)
+					{
+					case FORMAT_R8_SNORM:
+					case FORMAT_G8R8_SNORM:
+					case FORMAT_X8B8G8R8_SNORM:
+					case FORMAT_A8B8G8R8_SNORM:
+					case FORMAT_R8:
+					case FORMAT_R5G6B5:
+					case FORMAT_G8R8:
+					case FORMAT_R8I:
+					case FORMAT_R8UI:
+					case FORMAT_G8R8I:
+					case FORMAT_G8R8UI:
+					case FORMAT_X8B8G8R8I:
+					case FORMAT_X8B8G8R8UI:
+					case FORMAT_A8B8G8R8I:
+					case FORMAT_A8B8G8R8UI:
+					case FORMAT_R16I:
+					case FORMAT_R16UI:
+					case FORMAT_G16R16:
+					case FORMAT_G16R16I:
+					case FORMAT_G16R16UI:
+					case FORMAT_X16B16G16R16I:
+					case FORMAT_X16B16G16R16UI:
+					case FORMAT_A16B16G16R16:
+					case FORMAT_A16B16G16R16I:
+					case FORMAT_A16B16G16R16UI:
+					case FORMAT_R32I:
+					case FORMAT_R32UI:
+					case FORMAT_G32R32I:
+					case FORMAT_G32R32UI:
+					case FORMAT_X32B32G32R32I:
+					case FORMAT_X32B32G32R32UI:
+					case FORMAT_A32B32G32R32I:
+					case FORMAT_A32B32G32R32UI:
+					case FORMAT_X8R8G8B8:
+					case FORMAT_X8B8G8R8:
+					case FORMAT_A8R8G8B8:
+					case FORMAT_A8B8G8R8:
+					case FORMAT_SRGB8_X8:
+					case FORMAT_SRGB8_A8:
+					case FORMAT_V8U8:
+					case FORMAT_Q8W8V8U8:
+					case FORMAT_X8L8V8U8:
+					case FORMAT_V16U16:
+					case FORMAT_A16W16V16U16:
+					case FORMAT_Q16W16V16U16:
+					case FORMAT_YV12_BT601:
+					case FORMAT_YV12_BT709:
+					case FORMAT_YV12_JFIF:
+						if(componentCount < 2) c.y = Short4(defaultColorValue);
+						if(componentCount < 3) c.z = Short4(defaultColorValue);
+						if(componentCount < 4) c.w = Short4(0x1000);
+						break;
+					case FORMAT_A8:
+						c.w = c.x;
+						c.x = Short4(0x0000);
+						c.y = Short4(0x0000);
+						c.z = Short4(0x0000);
+						break;
+					case FORMAT_L8:
+					case FORMAT_L16:
+						c.y = c.x;
+						c.z = c.x;
+						c.w = Short4(0x1000);
+						break;
+					case FORMAT_A8L8:
+						c.w = c.y;
+						c.y = c.x;
+						c.z = c.x;
+						break;
+					case FORMAT_R32F:
+						c.y = Short4(defaultColorValue);
+					case FORMAT_G32R32F:
+						c.z = Short4(defaultColorValue);
+					case FORMAT_X32B32G32R32F:
+					case FORMAT_X32B32G32R32F_UNSIGNED:
+						c.w = Short4(0x1000);
+					case FORMAT_A32B32G32R32F:
+						break;
+					case FORMAT_D32F:
+					case FORMAT_D32FS8:
+					case FORMAT_D32F_LOCKABLE:
+					case FORMAT_D32FS8_TEXTURE:
+					case FORMAT_D32F_SHADOW:
+					case FORMAT_D32FS8_SHADOW:
+						c.y = c.x;
+						c.z = c.x;
+						c.w = c.x;
+						break;
+					default:
+						ASSERT(false);
+					}
+				}
+
+				if((state.swizzleR != SWIZZLE_RED) ||
+				   (state.swizzleG != SWIZZLE_GREEN) ||
+				   (state.swizzleB != SWIZZLE_BLUE) ||
+				   (state.swizzleA != SWIZZLE_ALPHA))
+				{
+					const Vector4s col(c);
+					applySwizzle(state.swizzleR, c.x, col);
+					applySwizzle(state.swizzleG, c.y, col);
+					applySwizzle(state.swizzleB, c.z, col);
+					applySwizzle(state.swizzleA, c.w, col);
 				}
 			}
 		}
 
-		if(fixed12 &&
-		   ((state.swizzleR != SWIZZLE_RED) ||
-		    (state.swizzleG != SWIZZLE_GREEN) ||
-		    (state.swizzleB != SWIZZLE_BLUE) ||
-		    (state.swizzleA != SWIZZLE_ALPHA)))
-		{
-			const Vector4s col(c);
-			applySwizzle(state.swizzleR, c.x, col);
-			applySwizzle(state.swizzleG, c.y, col);
-			applySwizzle(state.swizzleB, c.z, col);
-			applySwizzle(state.swizzleA, c.w, col);
-		}
+		return c;
 	}
 
-	void SamplerCore::sampleTexture(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
+	Vector4f SamplerCore::sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
 	{
+		Vector4f c;
+
 		#if PERF_PROFILE
 			AddAtomic(Pointer<Long>(&profiler.texOperations), 4);
 
@@ -317,47 +296,42 @@
 		}
 		else
 		{
-			// FIXME: YUV and sRGB are not supported by the floating point path
-			bool forceFloatFiltering = state.highPrecisionFiltering && !state.sRGB && !hasYuvFormat() && (state.textureFilter != FILTER_POINT);
-			if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering)   // FIXME: Mostly identical to integer sampling
+			// FIXME: YUV is not supported by the floating point path
+			bool forceFloatFiltering = state.highPrecisionFiltering && !hasYuvFormat() && (state.textureFilter != FILTER_POINT);
+			bool seamlessCube = (state.addressingModeU == ADDRESSING_SEAMLESS);
+			bool rectangleTexture = (state.textureType == TEXTURE_RECTANGLE);
+			if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering || seamlessCube || rectangleTexture)   // FIXME: Mostly identical to integer sampling
 			{
 				Float4 uuuu = u;
 				Float4 vvvv = v;
 				Float4 wwww = w;
+				Float4 qqqq = q;
 
 				Int face[4];
-				Float4 lodX;
-				Float4 lodY;
-				Float4 lodZ;
-
-				if(state.textureType == TEXTURE_CUBE)
-				{
-					cubeFace(face, uuuu, vvvv, lodX, lodY, lodZ, u, v, w);
-				}
-
 				Float lod;
 				Float anisotropy;
 				Float4 uDelta;
 				Float4 vDelta;
-				Float lodBias = (function == Fetch) ? Float4(As<Int4>(q)).x : q.x;
 
 				if(state.textureType != TEXTURE_3D)
 				{
 					if(state.textureType != TEXTURE_CUBE)
 					{
-						computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, lodBias, dsx, dsy, function);
+						computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, bias.x, dsx, dsy, function);
 					}
 					else
 					{
-						computeLodCube(texture, lod, lodX, lodY, lodZ, lodBias, dsx, dsy, function);
+						Float4 M;
+						cubeFace(face, uuuu, vvvv, u, v, w, M);
+						computeLodCube(texture, lod, u, v, w, bias.x, dsx, dsy, M, function);
 					}
 				}
 				else
 				{
-					computeLod3D(texture, lod, uuuu, vvvv, wwww, lodBias, dsx, dsy, function);
+					computeLod3D(texture, lod, uuuu, vvvv, wwww, bias.x, dsx, dsy, function);
 				}
 
-				sampleFloatFilter(texture, c, uuuu, vvvv, wwww, offset, lod, anisotropy, uDelta, vDelta, face, function);
+				c = sampleFloatFilter(texture, uuuu, vvvv, wwww, qqqq, offset, lod, anisotropy, uDelta, vDelta, face, function);
 
 				if(!hasFloatTexture() && !hasUnnormalizedIntegerTexture())
 				{
@@ -385,56 +359,25 @@
 			}
 			else
 			{
-				Vector4s cs;
+				Vector4s cs = sampleTexture(texture, u, v, w, q, bias, dsx, dsy, offset, function, false);
 
-				sampleTexture(texture, cs, u, v, w, q, dsx, dsy, offset, function, false);
-
-				if(has16bitTextureFormat())
+				if(state.textureFormat ==  FORMAT_R5G6B5)
 				{
-					switch(state.textureFormat)
-					{
-					case FORMAT_R5G6B5:
-						if(state.sRGB)
-						{
-							sRGBtoLinear16_5_12(cs.x);
-							sRGBtoLinear16_6_12(cs.y);
-							sRGBtoLinear16_5_12(cs.z);
-
-							convertSigned12(c.x, cs.x);
-							convertSigned12(c.y, cs.y);
-							convertSigned12(c.z, cs.z);
-						}
-						else
-						{
-							c.x = Float4(As<UShort4>(cs.x)) * Float4(1.0f / 0xF800);
-							c.y = Float4(As<UShort4>(cs.y)) * Float4(1.0f / 0xFC00);
-							c.z = Float4(As<UShort4>(cs.z)) * Float4(1.0f / 0xF800);
-						}
-						break;
-					default:
-						ASSERT(false);
-					}
+					c.x = Float4(As<UShort4>(cs.x)) * Float4(1.0f / 0xF800);
+					c.y = Float4(As<UShort4>(cs.y)) * Float4(1.0f / 0xFC00);
+					c.z = Float4(As<UShort4>(cs.z)) * Float4(1.0f / 0xF800);
 				}
 				else
 				{
 					for(int component = 0; component < textureComponentCount(); component++)
 					{
-						// Normalized integer formats
-						if(state.sRGB && isRGBComponent(component))
+						if(hasUnsignedTextureComponent(component))
 						{
-							sRGBtoLinear16_8_12(cs[component]);   // FIXME: Perform linearization at surface level for read-only textures
-							convertSigned12(c[component], cs[component]);
+							convertUnsigned16(c[component], cs[component]);
 						}
 						else
 						{
-							if(hasUnsignedTextureComponent(component))
-							{
-								convertUnsigned16(c[component], cs[component]);
-							}
-							else
-							{
-								convertSigned15(c[component], cs[component]);
-							}
+							convertSigned15(c[component], cs[component]);
 						}
 					}
 				}
@@ -475,10 +418,10 @@
 				case FORMAT_A32B32G32R32I:
 				case FORMAT_A32B32G32R32UI:
 					break;
-				case FORMAT_R8I_SNORM:
-				case FORMAT_G8R8I_SNORM:
-				case FORMAT_X8B8G8R8I_SNORM:
-				case FORMAT_A8B8G8R8I_SNORM:
+				case FORMAT_R8_SNORM:
+				case FORMAT_G8R8_SNORM:
+				case FORMAT_X8B8G8R8_SNORM:
+				case FORMAT_A8B8G8R8_SNORM:
 				case FORMAT_R8:
 				case FORMAT_R5G6B5:
 				case FORMAT_G8R8:
@@ -525,38 +468,45 @@
 				case FORMAT_G32R32F:
 					c.z = Float4(defaultColorValue);
 				case FORMAT_X32B32G32R32F:
+				case FORMAT_X32B32G32R32F_UNSIGNED:
 					c.w = Float4(1.0f);
 				case FORMAT_A32B32G32R32F:
 					break;
 				case FORMAT_D32F:
+				case FORMAT_D32FS8:
 				case FORMAT_D32F_LOCKABLE:
 				case FORMAT_D32FS8_TEXTURE:
+				case FORMAT_D32F_SHADOW:
 				case FORMAT_D32FS8_SHADOW:
-					c.y = c.x;
-					c.z = c.x;
-					c.w = c.x;
+					c.y = Float4(0.0f);
+					c.z = Float4(0.0f);
+					c.w = Float4(1.0f);
 					break;
 				default:
 					ASSERT(false);
 				}
 			}
+
+			if((state.swizzleR != SWIZZLE_RED) ||
+			   (state.swizzleG != SWIZZLE_GREEN) ||
+			   (state.swizzleB != SWIZZLE_BLUE) ||
+			   (state.swizzleA != SWIZZLE_ALPHA))
+			{
+				const Vector4f col(c);
+				applySwizzle(state.swizzleR, c.x, col);
+				applySwizzle(state.swizzleG, c.y, col);
+				applySwizzle(state.swizzleB, c.z, col);
+				applySwizzle(state.swizzleA, c.w, col);
+			}
 		}
 
-		if((state.swizzleR != SWIZZLE_RED) ||
-		   (state.swizzleG != SWIZZLE_GREEN) ||
-		   (state.swizzleB != SWIZZLE_BLUE) ||
-		   (state.swizzleA != SWIZZLE_ALPHA))
-		{
-			const Vector4f col(c);
-			applySwizzle(state.swizzleR, c.x, col);
-			applySwizzle(state.swizzleG, c.y, col);
-			applySwizzle(state.swizzleB, c.z, col);
-			applySwizzle(state.swizzleA, c.w, col);
-		}
+		return c;
 	}
 
-	void SamplerCore::textureSize(Pointer<Byte> &texture, Vector4f &size, Float4 &lod)
+	Vector4f SamplerCore::textureSize(Pointer<Byte> &texture, Float4 &lod)
 	{
+		Vector4f size;
+
 		for(int i = 0; i < 4; ++i)
 		{
 			Int baseLevel = *Pointer<Int>(texture + OFFSET(Texture, baseLevel));
@@ -565,12 +515,14 @@
 			size.y = Insert(size.y, As<Float>(Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, height)))), i);
 			size.z = Insert(size.z, As<Float>(Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, depth)))), i);
 		}
+
+		return size;
 	}
 
 	void SamplerCore::border(Short4 &mask, Float4 &coordinates)
 	{
 		Int4 border = As<Int4>(CmpLT(Abs(coordinates - Float4(0.5f)), Float4(0.5f)));
-		mask = As<Short4>(Int2(As<Int4>(Pack(border, border))));
+		mask = As<Short4>(Int2(As<Int4>(PackSigned(border, border))));
 	}
 
 	void SamplerCore::border(Int4 &mask, Float4 &coordinates)
@@ -615,20 +567,18 @@
 		return uvw;
 	}
 
-	void SamplerCore::sampleFilter(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function)
+	Vector4s SamplerCore::sampleFilter(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function)
 	{
-		sampleAniso(texture, c, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, false, function);
+		Vector4s c = sampleAniso(texture, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, false, function);
 
 		if(function == Fetch)
 		{
-			return;
+			return c;
 		}
 
-		if(state.mipmapFilter > MIPMAP_POINT)
+		if(state.mipmapFilter == MIPMAP_LINEAR)
 		{
-			Vector4s cc;
-
-			sampleAniso(texture, cc, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, true, function);
+			Vector4s cc = sampleAniso(texture, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, true, function);
 
 			lod *= Float(1 << 16);
 
@@ -714,13 +664,17 @@
 			c.z = (borderMask & c.z) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[2])) >> (hasUnsignedTextureComponent(2) ? 0 : 1)));
 			c.w = (borderMask & c.w) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[3])) >> (hasUnsignedTextureComponent(3) ? 0 : 1)));
 		}
+
+		return c;
 	}
 
-	void SamplerCore::sampleAniso(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function)
+	Vector4s SamplerCore::sampleAniso(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function)
 	{
+		Vector4s c;
+
 		if(state.textureFilter != FILTER_ANISOTROPIC || function == Lod || function == Fetch)
 		{
-			sampleQuad(texture, c, u, v, w, offset, lod, face, secondLOD, function);
+			c = sampleQuad(texture, u, v, w, offset, lod, face, secondLOD, function);
 		}
 		else
 		{
@@ -751,7 +705,7 @@
 
 			Do
 			{
-				sampleQuad(texture, c, u0, v0, w, offset, lod, face, secondLOD, function);
+				c = sampleQuad(texture, u0, v0, w, offset, lod, face, secondLOD, function);
 
 				u0 += du;
 				v0 += dv;
@@ -770,22 +724,26 @@
 			if(hasUnsignedTextureComponent(2)) c.z = cSum.z; else c.z = AddSat(cSum.z, cSum.z);
 			if(hasUnsignedTextureComponent(3)) c.w = cSum.w; else c.w = AddSat(cSum.w, cSum.w);
 		}
+
+		return c;
 	}
 
-	void SamplerCore::sampleQuad(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
+	Vector4s SamplerCore::sampleQuad(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
 	{
 		if(state.textureType != TEXTURE_3D)
 		{
-			sampleQuad2D(texture, c, u, v, w, offset, lod, face, secondLOD, function);
+			return sampleQuad2D(texture, u, v, w, offset, lod, face, secondLOD, function);
 		}
 		else
 		{
-			sample3D(texture, c, u, v, w, offset, lod, secondLOD, function);
+			return sample3D(texture, u, v, w, offset, lod, secondLOD, function);
 		}
 	}
 
-	void SamplerCore::sampleQuad2D(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
+	Vector4s SamplerCore::sampleQuad2D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
 	{
+		Vector4s c;
+
 		int componentCount = textureComponentCount();
 		bool gather = state.textureFilter == FILTER_GATHER;
 
@@ -973,10 +931,14 @@
 				c.w = c0.x;
 			}
 		}
+
+		return c;
 	}
 
-	void SamplerCore::sample3D(Pointer<Byte> &texture, Vector4s &c_, Float4 &u_, Float4 &v_, Float4 &w_, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function)
+	Vector4s SamplerCore::sample3D(Pointer<Byte> &texture, Float4 &u_, Float4 &v_, Float4 &w_, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function)
 	{
+		Vector4s c_;
+
 		int componentCount = textureComponentCount();
 
 		Pointer<Byte> mipmap;
@@ -1094,22 +1056,22 @@
 			if(componentCount >= 3) if(!hasUnsignedTextureComponent(2)) c_.z = AddSat(c_.z, c_.z);
 			if(componentCount >= 4) if(!hasUnsignedTextureComponent(3)) c_.w = AddSat(c_.w, c_.w);
 		}
+
+		return c_;
 	}
 
-	void SamplerCore::sampleFloatFilter(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function)
+	Vector4f SamplerCore::sampleFloatFilter(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function)
 	{
-		sampleFloatAniso(texture, c, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, false, function);
+		Vector4f c = sampleFloatAniso(texture, u, v, w, q, offset, lod, anisotropy, uDelta, vDelta, face, false, function);
 
 		if(function == Fetch)
 		{
-			return;
+			return c;
 		}
 
-		if(state.mipmapFilter > MIPMAP_POINT)
+		if(state.mipmapFilter == MIPMAP_LINEAR)
 		{
-			Vector4f cc;
-
-			sampleFloatAniso(texture, cc, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, true, function);
+			Vector4f cc = sampleFloatAniso(texture, u, v, w, q, offset, lod, anisotropy, uDelta, vDelta, face, true, function);
 
 			Float4 lod4 = Float4(Frac(lod));
 
@@ -1174,13 +1136,17 @@
 			c.z = As<Float4>((borderMask & As<Int4>(c.z)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[2]))));
 			c.w = As<Float4>((borderMask & As<Int4>(c.w)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[3]))));
 		}
+
+		return c;
 	}
 
-	void SamplerCore::sampleFloatAniso(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function)
+	Vector4f SamplerCore::sampleFloatAniso(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function)
 	{
+		Vector4f c;
+
 		if(state.textureFilter != FILTER_ANISOTROPIC || function == Lod || function == Fetch)
 		{
-			sampleFloat(texture, c, u, v, w, offset, lod, face, secondLOD, function);
+			c = sampleFloat(texture, u, v, w, q, offset, lod, face, secondLOD, function);
 		}
 		else
 		{
@@ -1209,7 +1175,7 @@
 
 			Do
 			{
-				sampleFloat(texture, c, u0, v0, w, offset, lod, face, secondLOD, function);
+				c = sampleFloat(texture, u0, v0, w, q, offset, lod, face, secondLOD, function);
 
 				u0 += du;
 				v0 += dv;
@@ -1228,22 +1194,26 @@
 			c.z = cSum.z;
 			c.w = cSum.w;
 		}
+
+		return c;
 	}
 
-	void SamplerCore::sampleFloat(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
+	Vector4f SamplerCore::sampleFloat(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
 	{
 		if(state.textureType != TEXTURE_3D)
 		{
-			sampleFloat2D(texture, c, u, v, w, offset, lod, face, secondLOD, function);
+			return sampleFloat2D(texture, u, v, w, q, offset, lod, face, secondLOD, function);
 		}
 		else
 		{
-			sampleFloat3D(texture, c, u, v, w, offset, lod, secondLOD, function);
+			return sampleFloat3D(texture, u, v, w, offset, lod, secondLOD, function);
 		}
 	}
 
-	void SamplerCore::sampleFloat2D(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
+	Vector4f SamplerCore::sampleFloat2D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
 	{
+		Vector4f c;
+
 		int componentCount = textureComponentCount();
 		bool gather = state.textureFilter == FILTER_GATHER;
 
@@ -1255,9 +1225,9 @@
 		Int4 x0, x1, y0, y1, z0;
 		Float4 fu, fv;
 		Int4 filter = computeFilterOffset(lod);
-		address(w, z0, z0, fv, mipmap, offset.z, filter, OFFSET(Mipmap, depth), state.addressingModeW, function);
-		address(v, y0, y1, fv, mipmap, offset.y, filter, OFFSET(Mipmap, height), state.addressingModeV, function);
 		address(u, x0, x1, fu, mipmap, offset.x, filter, OFFSET(Mipmap, width), state.addressingModeU, function);
+		address(v, y0, y1, fv, mipmap, offset.y, filter, OFFSET(Mipmap, height), state.addressingModeV, function);
+		address(w, z0, z0, fv, mipmap, offset.z, filter, OFFSET(Mipmap, depth), state.addressingModeW, function);
 
 		Int4 pitchP = *Pointer<Int4>(mipmap + OFFSET(Mipmap, pitchP), 16);
 		y0 *= pitchP;
@@ -1269,16 +1239,16 @@
 
 		if(state.textureFilter == FILTER_POINT || (function == Fetch))
 		{
-			c = sampleTexel(x0, y0, z0, w, mipmap, buffer, function);
+			c = sampleTexel(x0, y0, z0, q, mipmap, buffer, function);
 		}
 		else
 		{
 			y1 *= pitchP;
 
-			Vector4f c0 = sampleTexel(x0, y0, z0, w, mipmap, buffer, function);
-			Vector4f c1 = sampleTexel(x1, y0, z0, w, mipmap, buffer, function);
-			Vector4f c2 = sampleTexel(x0, y1, z0, w, mipmap, buffer, function);
-			Vector4f c3 = sampleTexel(x1, y1, z0, w, mipmap, buffer, function);
+			Vector4f c0 = sampleTexel(x0, y0, z0, q, mipmap, buffer, function);
+			Vector4f c1 = sampleTexel(x1, y0, z0, q, mipmap, buffer, function);
+			Vector4f c2 = sampleTexel(x0, y1, z0, q, mipmap, buffer, function);
+			Vector4f c3 = sampleTexel(x1, y1, z0, q, mipmap, buffer, function);
 
 			if(!gather)   // Blend
 			{
@@ -1305,10 +1275,14 @@
 				c.w = c0.x;
 			}
 		}
+
+		return c;
 	}
 
-	void SamplerCore::sampleFloat3D(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function)
+	Vector4f SamplerCore::sampleFloat3D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function)
 	{
+		Vector4f c;
+
 		int componentCount = textureComponentCount();
 
 		Pointer<Byte> mipmap;
@@ -1385,6 +1359,8 @@
 			if(componentCount >= 3) c.z = c0.z + fw * (c4.z - c0.z);
 			if(componentCount >= 4) c.w = c0.w + fw * (c4.w - c0.w);
 		}
+
+		return c;
 	}
 
 	Float SamplerCore::log2sqrt(Float lod)
@@ -1397,13 +1373,22 @@
 		return lod;
 	}
 
+	Float SamplerCore::log2(Float lod)
+	{
+		lod *= lod;                                      // Squaring doubles the exponent and produces an extra bit of precision.
+		lod = Float(As<Int>(lod)) - Float(0x3F800000);   // Interpret as integer and subtract the exponent bias.
+		lod *= As<Float>(Int(0x33800000));               // Scale by 0.5 * 2^-23 (mantissa length).
+
+		return lod;
+	}
+
 	void SamplerCore::computeLod(Pointer<Byte> &texture, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Float4 &uuuu, Float4 &vvvv, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function)
 	{
 		if(function != Lod && function != Fetch)
 		{
 			Float4 duvdxy;
 
-			if(function != Grad)
+			if(function != Grad)   // Implicit
 			{
 				duvdxy = Float4(uuuu.yz, vvvv.yz) - Float4(uuuu.xx, vvvv.xx);
 			}
@@ -1415,7 +1400,7 @@
 				duvdxy = Float4(dudxy.xz, dvdxy.xz);
 			}
 
-			// Scale by texture dimensions and LOD
+			// Scale by texture dimensions and global LOD.
 			Float4 dUVdxy = duvdxy * *Pointer<Float4>(texture + OFFSET(Texture,widthHeightLOD));
 
 			Float4 dUV2dxy = dUVdxy * dUVdxy;
@@ -1449,55 +1434,124 @@
 				lod += lodBias;
 			}
 		}
-		else
+		else if(function == Lod)
 		{
-			lod = lodBias + Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
+			lod = lodBias;
 		}
+		else if(function == Fetch)
+		{
+			// TODO: Eliminate int-float-int conversion.
+			lod = Float(As<Int>(lodBias));
+		}
+		else if(function == Base)
+		{
+			lod = Float(0);
+		}
+		else assert(false);
 
 		lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod)));
 		lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod)));
 	}
 
-	void SamplerCore::computeLodCube(Pointer<Byte> &texture, Float &lod, Float4 &u, Float4 &v, Float4 &s, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function)
+	void SamplerCore::computeLodCube(Pointer<Byte> &texture, Float &lod, Float4 &u, Float4 &v, Float4 &w, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, Float4 &M, SamplerFunction function)
 	{
 		if(function != Lod && function != Fetch)
 		{
-			if(function != Grad)
+			Float4 dudxy, dvdxy, dsdxy;
+
+			if(function != Grad)  // Implicit
 			{
-				Float4 dudxy = u.ywyw - u;
-				Float4 dvdxy = v.ywyw - v;
-				Float4 dsdxy = s.ywyw - s;
+				Float4 U = u * M;
+				Float4 V = v * M;
+				Float4 W = w * M;
 
-				// Scale by texture dimensions and LOD
-				dudxy *= *Pointer<Float4>(texture + OFFSET(Texture,widthLOD));
-				dvdxy *= *Pointer<Float4>(texture + OFFSET(Texture,widthLOD));
-				dsdxy *= *Pointer<Float4>(texture + OFFSET(Texture,widthLOD));
-
-				dudxy *= dudxy;
-				dvdxy *= dvdxy;
-				dsdxy *= dsdxy;
-
-				dudxy += dvdxy;
-				dudxy += dsdxy;
-
-				lod = Max(Float(dudxy.x), Float(dudxy.y));   // FIXME: Max(dudxy.x, dudxy.y);
+				dudxy = Abs(U - U.xxxx);
+				dvdxy = Abs(V - V.xxxx);
+				dsdxy = Abs(W - W.xxxx);
 			}
 			else
 			{
-				Float4 dudxy = Float4(dsx.x.xx, dsy.x.xx);
-				Float4 dvdxy = Float4(dsx.y.xx, dsy.y.xx);
+				dudxy = Float4(dsx.x.xx, dsy.x.xx);
+				dvdxy = Float4(dsx.y.xx, dsy.y.xx);
+				dsdxy = Float4(dsx.z.xx, dsy.z.xx);
 
-				Float4 duvdxy = Float4(dudxy.xz, dvdxy.xz);
-
-				// Scale by texture dimensions and LOD
-				Float4 dUVdxy = duvdxy * *Pointer<Float4>(texture + OFFSET(Texture,widthLOD));
-
-				Float4 dUV2dxy = dUVdxy * dUVdxy;
-				Float4 dUV2 = dUV2dxy.xy + dUV2dxy.zw;
-
-				lod = Max(Float(dUV2.x), Float(dUV2.y));   // Square length of major axis
+				dudxy = Abs(dudxy * Float4(M.x));
+				dvdxy = Abs(dvdxy * Float4(M.x));
+				dsdxy = Abs(dsdxy * Float4(M.x));
 			}
 
+			// Compute the largest Manhattan distance in two dimensions.
+			// This takes the footprint across adjacent faces into account.
+			Float4 duvdxy = dudxy + dvdxy;
+			Float4 dusdxy = dudxy + dsdxy;
+			Float4 dvsdxy = dvdxy + dsdxy;
+
+			dudxy = Max(Max(duvdxy, dusdxy), dvsdxy);
+
+			lod = Max(Float(dudxy.y), Float(dudxy.z));   // FIXME: Max(dudxy.y, dudxy.z);
+
+			// Scale by texture dimension and global LOD.
+			lod *= *Pointer<Float>(texture + OFFSET(Texture,widthLOD));
+
+			lod = log2(lod);
+
+			if(function == Bias)
+			{
+				lod += lodBias;
+			}
+		}
+		else if(function == Lod)
+		{
+			lod = lodBias;
+		}
+		else if(function == Fetch)
+		{
+			// TODO: Eliminate int-float-int conversion.
+			lod = Float(As<Int>(lodBias));
+		}
+		else if(function == Base)
+		{
+			lod = Float(0);
+		}
+		else assert(false);
+
+		lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod)));
+		lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod)));
+	}
+
+	void SamplerCore::computeLod3D(Pointer<Byte> &texture, Float &lod, Float4 &uuuu, Float4 &vvvv, Float4 &wwww, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function)
+	{
+		if(function != Lod && function != Fetch)
+		{
+			Float4 dudxy, dvdxy, dsdxy;
+
+			if(function != Grad)   // Implicit
+			{
+				dudxy = uuuu - uuuu.xxxx;
+				dvdxy = vvvv - vvvv.xxxx;
+				dsdxy = wwww - wwww.xxxx;
+			}
+			else
+			{
+				dudxy = Float4(dsx.x.xx, dsy.x.xx);
+				dvdxy = Float4(dsx.y.xx, dsy.y.xx);
+				dsdxy = Float4(dsx.z.xx, dsy.z.xx);
+			}
+
+			// Scale by texture dimensions and global LOD.
+			dudxy *= *Pointer<Float4>(texture + OFFSET(Texture,widthLOD));
+			dvdxy *= *Pointer<Float4>(texture + OFFSET(Texture,heightLOD));
+			dsdxy *= *Pointer<Float4>(texture + OFFSET(Texture,depthLOD));
+
+			dudxy *= dudxy;
+			dvdxy *= dvdxy;
+			dsdxy *= dsdxy;
+
+			dudxy += dvdxy;
+			dudxy += dsdxy;
+
+			lod = Max(Float(dudxy.y), Float(dudxy.z));   // FIXME: Max(dudxy.y, dudxy.z);
+
 			lod = log2sqrt(lod);   // log2(sqrt(lod))
 
 			if(function == Bias)
@@ -1505,81 +1559,26 @@
 				lod += lodBias;
 			}
 		}
-		else
+		else if(function == Lod)
 		{
-			lod = lodBias + Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
+			lod = lodBias;
 		}
+		else if(function == Fetch)
+		{
+			// TODO: Eliminate int-float-int conversion.
+			lod = Float(As<Int>(lodBias));
+		}
+		else if(function == Base)
+		{
+			lod = Float(0);
+		}
+		else assert(false);
 
 		lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod)));
 		lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod)));
 	}
 
-	void SamplerCore::computeLod3D(Pointer<Byte> &texture, Float &lod, Float4 &uuuu, Float4 &vvvv, Float4 &wwww, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function)
-	{
-		if(state.mipmapFilter == MIPMAP_NONE)
-		{
-		}
-		else   // Point and linear filter
-		{
-			if(function != Lod && function != Fetch)
-			{
-				Float4 dudxy;
-				Float4 dvdxy;
-				Float4 dsdxy;
-
-				if(function != Grad)
-				{
-					dudxy = uuuu.ywyw - uuuu;
-					dvdxy = vvvv.ywyw - vvvv;
-					dsdxy = wwww.ywyw - wwww;
-				}
-				else
-				{
-					dudxy = dsx.x;
-					dvdxy = dsx.y;
-					dsdxy = dsx.z;
-
-					dudxy = Float4(dudxy.xx, dsy.x.xx);
-					dvdxy = Float4(dvdxy.xx, dsy.y.xx);
-					dsdxy = Float4(dsdxy.xx, dsy.z.xx);
-
-					dudxy = Float4(dudxy.xz, dudxy.xz);
-					dvdxy = Float4(dvdxy.xz, dvdxy.xz);
-					dsdxy = Float4(dsdxy.xz, dsdxy.xz);
-				}
-
-				// Scale by texture dimensions and LOD
-				dudxy *= *Pointer<Float4>(texture + OFFSET(Texture,widthLOD));
-				dvdxy *= *Pointer<Float4>(texture + OFFSET(Texture,heightLOD));
-				dsdxy *= *Pointer<Float4>(texture + OFFSET(Texture,depthLOD));
-
-				dudxy *= dudxy;
-				dvdxy *= dvdxy;
-				dsdxy *= dsdxy;
-
-				dudxy += dvdxy;
-				dudxy += dsdxy;
-
-				lod = Max(Float(dudxy.x), Float(dudxy.y));   // FIXME: Max(dudxy.x, dudxy.y);
-
-				lod = log2sqrt(lod);   // log2(sqrt(lod))
-
-				if(function == Bias)
-				{
-					lod += lodBias;
-				}
-			}
-			else
-			{
-				lod = lodBias + Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
-			}
-
-			lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod)));
-			lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod)));
-		}
-	}
-
-	void SamplerCore::cubeFace(Int face[4], Float4 &U, Float4 &V, Float4 &lodX, Float4 &lodY, Float4 &lodZ, Float4 &x, Float4 &y, Float4 &z)
+	void SamplerCore::cubeFace(Int face[4], Float4 &U, Float4 &V, Float4 &x, Float4 &y, Float4 &z, Float4 &M)
 	{
 		Int4 xn = CmpLT(x, Float4(0.0f));   // x < 0
 		Int4 yn = CmpLT(y, Float4(0.0f));   // y < 0
@@ -1617,9 +1616,9 @@
 		face[3] = (face[0] >> 12) & 0x7;
 		face[0] &= 0x7;
 
-		Float4 M = Max(Max(absX, absY), absZ);
+		M = Max(Max(absX, absY), absZ);
 
-		// U = xMajor ? (neg ^ -z) : (zMajor & neg) ^ x)
+		// U = xMajor ? (neg ^ -z) : ((zMajor & neg) ^ x)
 		U = As<Float4>((xMajor & (n ^ As<Int4>(-z))) | (~xMajor & ((zMajor & n) ^ As<Int4>(x))));
 
 		// V = !yMajor ? -y : (n ^ z)
@@ -1628,10 +1627,6 @@
 		M = reciprocal(M) * Float4(0.5f);
 		U = U * M + Float4(0.5f);
 		V = V * M + Float4(0.5f);
-
-		lodX = x * M;
-		lodY = y * M;
-		lodZ = z * M;
 	}
 
 	Short4 SamplerCore::applyOffset(Short4 &uvw, Float4 &offset, const Int4 &whd, AddressingMode mode)
@@ -1639,7 +1634,7 @@
 		Int4 tmp = Int4(As<UShort4>(uvw));
 		tmp = tmp + As<Int4>(offset);
 
-		switch (mode)
+		switch(mode)
 		{
 		case AddressingMode::ADDRESSING_WRAP:
 			tmp = (tmp + whd * Int4(-MIN_PROGRAM_TEXEL_OFFSET)) % whd;
@@ -1652,6 +1647,8 @@
 			break;
 		case ADDRESSING_TEXELFETCH:
 			break;
+		case AddressingMode::ADDRESSING_SEAMLESS:
+			ASSERT(false);   // Cube sampling doesn't support offset.
 		default:
 			ASSERT(false);
 		}
@@ -1672,8 +1669,10 @@
 
 		if(hasOffset)
 		{
-			uuuu = applyOffset(uuuu, offset.x, Int4(*Pointer<UShort4>(mipmap + OFFSET(Mipmap, width))), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeU);
-			vvvv = applyOffset(vvvv, offset.y, Int4(*Pointer<UShort4>(mipmap + OFFSET(Mipmap, height))), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeV);
+			UShort4 w = *Pointer<UShort4>(mipmap + OFFSET(Mipmap, width));
+			uuuu = applyOffset(uuuu, offset.x, Int4(w), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeU);
+			UShort4 h = *Pointer<UShort4>(mipmap + OFFSET(Mipmap, height));
+			vvvv = applyOffset(vvvv, offset.y, Int4(h), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeV);
 		}
 
 		Short4 uuu2 = uuuu;
@@ -1690,24 +1689,29 @@
 				{
 					wwww = MulHigh(As<UShort4>(wwww), *Pointer<UShort4>(mipmap + OFFSET(Mipmap, depth)));
 				}
+
 				if(hasOffset)
 				{
-					wwww = applyOffset(wwww, offset.z, Int4(*Pointer<UShort4>(mipmap + OFFSET(Mipmap, depth))), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeW);
+					UShort4 d = *Pointer<UShort4>(mipmap + OFFSET(Mipmap, depth));
+					wwww = applyOffset(wwww, offset.z, Int4(d), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeW);
 				}
 			}
-			Short4 www2 = wwww;
-			wwww = As<Short4>(UnpackLow(wwww, Short4(0x0000)));
-			www2 = As<Short4>(UnpackHigh(www2, Short4(0x0000)));
-			wwww = As<Short4>(MulAdd(wwww, *Pointer<Short4>(mipmap + OFFSET(Mipmap,sliceP))));
-			www2 = As<Short4>(MulAdd(www2, *Pointer<Short4>(mipmap + OFFSET(Mipmap,sliceP))));
-			uuuu = As<Short4>(As<Int2>(uuuu) + As<Int2>(wwww));
-			uuu2 = As<Short4>(As<Int2>(uuu2) + As<Int2>(www2));
-		}
 
-		index[0] = Extract(As<Int2>(uuuu), 0);
-		index[1] = Extract(As<Int2>(uuuu), 1);
-		index[2] = Extract(As<Int2>(uuu2), 0);
-		index[3] = Extract(As<Int2>(uuu2), 1);
+			UInt4 uv(As<UInt2>(uuuu), As<UInt2>(uuu2));
+			uv += As<UInt4>(Int4(As<UShort4>(wwww))) * *Pointer<UInt4>(mipmap + OFFSET(Mipmap, sliceP));
+
+			index[0] = Extract(As<Int4>(uv), 0);
+			index[1] = Extract(As<Int4>(uv), 1);
+			index[2] = Extract(As<Int4>(uv), 2);
+			index[3] = Extract(As<Int4>(uv), 3);
+		}
+		else
+		{
+			index[0] = Extract(As<Int2>(uuuu), 0);
+			index[1] = Extract(As<Int2>(uuuu), 1);
+			index[2] = Extract(As<Int2>(uuu2), 0);
+			index[3] = Extract(As<Int2>(uuu2), 1);
+		}
 
 		if(texelFetch)
 		{
@@ -1795,7 +1799,7 @@
 						break;
 					case FORMAT_A8B8G8R8:
 					case FORMAT_A8B8G8R8I:
-					case FORMAT_A8B8G8R8I_SNORM:
+					case FORMAT_A8B8G8R8_SNORM:
 					case FORMAT_Q8W8V8U8:
 					case FORMAT_SRGB8_A8:
 						c.z = As<Short4>(UnpackHigh(c.x, c.y));
@@ -1849,7 +1853,7 @@
 						c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(c.y));
 						c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(c.x));
 						break;
-					case FORMAT_X8B8G8R8I_SNORM:
+					case FORMAT_X8B8G8R8_SNORM:
 					case FORMAT_X8B8G8R8I:
 					case FORMAT_X8B8G8R8:
 					case FORMAT_X8L8V8U8:
@@ -1890,7 +1894,7 @@
 				switch(state.textureFormat)
 				{
 				case FORMAT_G8R8:
-				case FORMAT_G8R8I_SNORM:
+				case FORMAT_G8R8_SNORM:
 				case FORMAT_V8U8:
 				case FORMAT_A8L8:
 					c.y = (c.x & Short4(0xFF00u)) | As<Short4>(As<UShort4>(c.x) >> 8);
@@ -1951,6 +1955,13 @@
 				c.w = Pointer<Short4>(buffer[f3])[index[3]];
 				transpose4x4(c.x, c.y, c.z, c.w);
 				break;
+			case 3:
+				c.x = Pointer<Short4>(buffer[f0])[index[0]];
+				c.y = Pointer<Short4>(buffer[f1])[index[1]];
+				c.z = Pointer<Short4>(buffer[f2])[index[2]];
+				c.w = Pointer<Short4>(buffer[f3])[index[3]];
+				transpose4x3(c.x, c.y, c.z, c.w);
+				break;
 			case 2:
 				c.x = *Pointer<Short4>(buffer[f0] + 4 * index[0]);
 				c.x = As<Short4>(UnpackLow(c.x, *Pointer<Short4>(buffer[f1] + 4 * index[1])));
@@ -1972,6 +1983,26 @@
 		}
 		else ASSERT(false);
 
+		if(state.sRGB)
+		{
+			if(state.textureFormat == FORMAT_R5G6B5)
+			{
+				sRGBtoLinear16_5_16(c.x);
+				sRGBtoLinear16_6_16(c.y);
+				sRGBtoLinear16_5_16(c.z);
+			}
+			else
+			{
+				for(int i = 0; i < textureComponentCount(); i++)
+				{
+					if(isRGBComponent(i))
+					{
+						sRGBtoLinear16_8_16(c[i]);
+					}
+				}
+			}
+		}
+
 		return c;
 	}
 
@@ -2109,13 +2140,11 @@
 				transpose4x4(c.x, c.y, c.z, c.w);
 				break;
 			case 3:
-				ASSERT(state.textureFormat == FORMAT_X32B32G32R32F);
 				c.x = *Pointer<Float4>(buffer[f0] + index[0] * 16, 16);
 				c.y = *Pointer<Float4>(buffer[f1] + index[1] * 16, 16);
 				c.z = *Pointer<Float4>(buffer[f2] + index[2] * 16, 16);
 				c.w = *Pointer<Float4>(buffer[f3] + index[3] * 16, 16);
 				transpose4x3(c.x, c.y, c.z, c.w);
-				c.w = Float4(1.0f);
 				break;
 			case 2:
 				// FIXME: Optimal shuffling?
@@ -2133,17 +2162,40 @@
 				c.x.y = *Pointer<Float>(buffer[f1] + index[1] * 4);
 				c.x.z = *Pointer<Float>(buffer[f2] + index[2] * 4);
 				c.x.w = *Pointer<Float>(buffer[f3] + index[3] * 4);
-
-				if(state.textureFormat == FORMAT_D32FS8_SHADOW && state.textureFilter != FILTER_GATHER)
-				{
-					Float4 d = Min(Max(z, Float4(0.0f)), Float4(1.0f));
-
-					c.x = As<Float4>(As<Int4>(CmpNLT(c.x, d)) & As<Int4>(Float4(1.0f)));   // FIXME: Only less-equal?
-				}
 				break;
 			default:
 				ASSERT(false);
 			}
+
+			if(state.compare != COMPARE_BYPASS)
+			{
+				Float4 ref = z;
+
+				if(!hasFloatTexture())
+				{
+					ref = Min(Max(ref, Float4(0.0f)), Float4(1.0f));
+				}
+
+				Int4 boolean;
+
+				switch(state.compare)
+				{
+				case COMPARE_LESSEQUAL:    boolean = CmpLE(ref, c.x);  break;
+				case COMPARE_GREATEREQUAL: boolean = CmpNLT(ref, c.x); break;
+				case COMPARE_LESS:         boolean = CmpLT(ref, c.x);  break;
+				case COMPARE_GREATER:      boolean = CmpNLE(ref, c.x); break;
+				case COMPARE_EQUAL:        boolean = CmpEQ(ref, c.x);  break;
+				case COMPARE_NOTEQUAL:     boolean = CmpNEQ(ref, c.x); break;
+				case COMPARE_ALWAYS:       boolean = Int4(-1);         break;
+				case COMPARE_NEVER:        boolean = Int4(0);          break;
+				default:                   ASSERT(false);
+				}
+
+				c.x = As<Float4>(boolean & As<Int4>(Float4(1.0f)));
+				c.y = Float4(0.0f);
+				c.z = Float4(0.0f);
+				c.w = Float4(1.0f);
+			}
 		}
 		else
 		{
@@ -2153,7 +2205,7 @@
 
 			bool isInteger = Surface::isNonNormalizedInteger(state.textureFormat);
 			int componentCount = textureComponentCount();
-			for(int n = 0; n < componentCount; ++n)
+			for(int n = 0; n < componentCount; n++)
 			{
 				if(hasUnsignedTextureComponent(n))
 				{
@@ -2185,7 +2237,7 @@
 
 	void SamplerCore::selectMipmap(Pointer<Byte> &texture, Pointer<Byte> buffer[4], Pointer<Byte> &mipmap, Float &lod, Int face[4], bool secondLOD)
 	{
-		if(state.mipmapFilter < MIPMAP_POINT)
+		if(state.mipmapFilter == MIPMAP_NONE)
 		{
 			mipmap = texture + OFFSET(Texture,mipmap[0]);
 		}
@@ -2197,7 +2249,7 @@
 			{
 				ilod = RoundInt(lod);
 			}
-			else   // Linear
+			else   // MIPMAP_LINEAR
 			{
 				ilod = Int(lod);
 			}
@@ -2226,20 +2278,25 @@
 
 	Int4 SamplerCore::computeFilterOffset(Float &lod)
 	{
-		Int4 filtering((state.textureFilter == FILTER_POINT) ? 0 : 1);
-		if(state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT)
+		Int4 filter = -1;
+
+		if(state.textureFilter == FILTER_POINT)
 		{
-			filtering &= CmpNLE(Float4(lod), Float4(0.0f));
+			filter = 0;
+		}
+		else if(state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT)
+		{
+			filter = CmpNLE(Float4(lod), Float4(0.0f));
 		}
 		else if(state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR)
 		{
-			filtering &= CmpLE(Float4(lod), Float4(0.0f));
+			filter = CmpLE(Float4(lod), Float4(0.0f));
 		}
 
-		return filtering;
+		return filter;
 	}
 
-	Short4 SamplerCore::address(Float4 &uw, AddressingMode addressingMode, Pointer<Byte>& mipmap)
+	Short4 SamplerCore::address(Float4 &uw, AddressingMode addressingMode, Pointer<Byte> &mipmap)
 	{
 		if(addressingMode == ADDRESSING_LAYER && state.textureType != TEXTURE_2D_ARRAY)
 		{
@@ -2249,7 +2306,7 @@
 		{
 			return Min(Max(Short4(RoundInt(uw)), Short4(0)), *Pointer<Short4>(mipmap + OFFSET(Mipmap, depth)) - Short4(1));
 		}
-		else if(addressingMode == ADDRESSING_CLAMP)
+		else if(addressingMode == ADDRESSING_CLAMP || addressingMode == ADDRESSING_BORDER)
 		{
 			Float4 clamp = Min(Max(uw, Float4(0.0f)), Float4(65535.0f / 65536.0f));
 
@@ -2271,21 +2328,21 @@
 
 			// Clamp
 			convert -= Int4(0x00008000, 0x00008000, 0x00008000, 0x00008000);
-			convert = As<Int4>(Pack(convert, convert));
+			convert = As<Int4>(PackSigned(convert, convert));
 
 			return As<Short4>(Int2(convert)) + Short4(0x8000u);
 		}
-		else   // Wrap (or border)
+		else   // Wrap
 		{
 			return Short4(Int4(uw * Float4(1 << 16)));
 		}
 	}
 
-	void SamplerCore::address(Float4 &uvw, Int4& xyz0, Int4& xyz1, Float4& f, Pointer<Byte>& mipmap, Float4 &texOffset, Int4 &filter, int whd, AddressingMode addressingMode, SamplerFunction function)
+	void SamplerCore::address(Float4 &uvw, Int4 &xyz0, Int4 &xyz1, Float4 &f, Pointer<Byte> &mipmap, Float4 &texOffset, Int4 &filter, int whd, AddressingMode addressingMode, SamplerFunction function)
 	{
 		if(addressingMode == ADDRESSING_LAYER && state.textureType != TEXTURE_2D_ARRAY)
 		{
-			return; // Unused
+			return;   // Unused
 		}
 
 		Int4 dim = Int4(*Pointer<Short4>(mipmap + whd, 16));
@@ -2295,98 +2352,140 @@
 		{
 			xyz0 = Min(Max(((function.option == Offset) && (addressingMode != ADDRESSING_LAYER)) ? As<Int4>(uvw) + As<Int4>(texOffset) : As<Int4>(uvw), Int4(0)), maxXYZ);
 		}
-		else if(addressingMode == ADDRESSING_LAYER && state.textureType == TEXTURE_2D_ARRAY) // Note: Offset does not apply to array layers
+		else if(addressingMode == ADDRESSING_LAYER && state.textureType == TEXTURE_2D_ARRAY)   // Note: Offset does not apply to array layers
 		{
 			xyz0 = Min(Max(RoundInt(uvw), Int4(0)), maxXYZ);
 		}
 		else
 		{
-			const int halfBits = 0x3effffff; // Value just under 0.5f
-			const int oneBits  = 0x3f7fffff; // Value just under 1.0f
-			const int twoBits  = 0x3fffffff; // Value just under 2.0f
+			const int halfBits = 0x3EFFFFFF;   // Value just under 0.5f
+			const int oneBits  = 0x3F7FFFFF;   // Value just under 1.0f
+			const int twoBits  = 0x3FFFFFFF;   // Value just under 2.0f
 
-			Float4 coord = Float4(dim);
-			switch(addressingMode)
+			bool pointFilter = state.textureFilter == FILTER_POINT ||
+			                   state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR ||
+			                   state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT;
+
+			Float4 coord = uvw;
+
+			if(state.textureType == TEXTURE_RECTANGLE)
 			{
-			case ADDRESSING_CLAMP:
+				coord = Min(Max(coord, Float4(0.0f)), Float4(dim - Int4(1)));
+			}
+			else
+			{
+				switch(addressingMode)
 				{
-					Float4 one = As<Float4>(Int4(oneBits));
-					coord *= Min(Max(uvw, Float4(0.0f)), one);
-				}
-				break;
-			case ADDRESSING_MIRROR:
+				case ADDRESSING_CLAMP:
+				case ADDRESSING_BORDER:
+				case ADDRESSING_SEAMLESS:
+					// Linear filtering of cube doesn't require clamping because the coordinates
+					// are already in [0, 1] range and numerical imprecision is tolerated.
+					if(addressingMode != ADDRESSING_SEAMLESS || pointFilter)
+					{
+						Float4 one = As<Float4>(Int4(oneBits));
+						coord = Min(Max(coord, Float4(0.0f)), one);
+					}
+					break;
+				case ADDRESSING_MIRROR:
 				{
 					Float4 half = As<Float4>(Int4(halfBits));
 					Float4 one = As<Float4>(Int4(oneBits));
 					Float4 two = As<Float4>(Int4(twoBits));
-					coord *= one - Abs(two * Frac(uvw * half) - one);
+					coord = one - Abs(two * Frac(coord * half) - one);
 				}
 				break;
-			case ADDRESSING_MIRRORONCE:
+				case ADDRESSING_MIRRORONCE:
 				{
 					Float4 half = As<Float4>(Int4(halfBits));
 					Float4 one = As<Float4>(Int4(oneBits));
 					Float4 two = As<Float4>(Int4(twoBits));
-					coord *= one - Abs(two * Frac(Min(Max(uvw, -one), two) * half) - one);
+					coord = one - Abs(two * Frac(Min(Max(coord, -one), two) * half) - one);
 				}
 				break;
-			default:   // Wrap (or border)
-				coord *= Frac(uvw);
-				break;
+				default:   // Wrap
+					coord = Frac(coord);
+					break;
+				}
+
+				coord = coord * Float4(dim);
 			}
 
-			xyz0 = Int4(coord);
+			if(state.textureFilter == FILTER_POINT ||
+			   state.textureFilter == FILTER_GATHER)
+			{
+				xyz0 = Int4(coord);
+			}
+			else
+			{
+				if(state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR ||
+				   state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT)
+				{
+					coord -= As<Float4>(As<Int4>(Float4(0.5f)) & filter);
+				}
+				else
+				{
+					coord -= Float4(0.5f);
+				}
+
+				Float4 floor = Floor(coord);
+				xyz0 = Int4(floor);
+				f = coord - floor;
+			}
 
 			if(function.option == Offset)
 			{
 				xyz0 += As<Int4>(texOffset);
+			}
+
+			if(addressingMode == ADDRESSING_SEAMLESS)
+			{
+				xyz0 += Int4(1);
+			}
+
+			xyz1 = xyz0 - filter;   // Increment
+
+			if(function.option == Offset)
+			{
 				switch(addressingMode)
 				{
+				case ADDRESSING_SEAMLESS:
+					ASSERT(false);   // Cube sampling doesn't support offset.
 				case ADDRESSING_MIRROR:
 				case ADDRESSING_MIRRORONCE:
 				case ADDRESSING_BORDER:
-					// FIXME: Implement ADDRESSING_MIRROR, ADDRESSING_MIRRORONCE and ADDRESSING_BORDER. Fall through to Clamp.
+					// FIXME: Implement ADDRESSING_MIRROR, ADDRESSING_MIRRORONCE, and ADDRESSING_BORDER.
+					// Fall through to Clamp.
 				case ADDRESSING_CLAMP:
 					xyz0 = Min(Max(xyz0, Int4(0)), maxXYZ);
+					xyz1 = Min(Max(xyz1, Int4(0)), maxXYZ);
 					break;
 				default:   // Wrap
 					xyz0 = (xyz0 + dim * Int4(-MIN_PROGRAM_TEXEL_OFFSET)) % dim;
+					xyz1 = (xyz1 + dim * Int4(-MIN_PROGRAM_TEXEL_OFFSET)) % dim;
 					break;
 				}
 			}
-
-			if(state.textureFilter != FILTER_POINT) // Compute 2nd coordinate, if needed
+			else if(state.textureFilter != FILTER_POINT)
 			{
-				bool gather = state.textureFilter == FILTER_GATHER;
-
-				xyz1 = xyz0 + filter; // Increment
-
-				if(!gather)
-				{
-					Float4 frac = Frac(coord);
-					f = Abs(frac - Float4(0.5f));
-					xyz1 -= CmpLT(frac, Float4(0.5f)) & (filter + filter); // Decrement xyz if necessary
-				}
-
 				switch(addressingMode)
 				{
+				case ADDRESSING_SEAMLESS:
+					break;
 				case ADDRESSING_MIRROR:
 				case ADDRESSING_MIRRORONCE:
 				case ADDRESSING_BORDER:
-					// FIXME: Implement ADDRESSING_MIRROR, ADDRESSING_MIRRORONCE and ADDRESSING_BORDER. Fall through to Clamp.
 				case ADDRESSING_CLAMP:
-					xyz1 = gather ? Min(xyz1, maxXYZ) : Min(Max(xyz1, Int4(0)), maxXYZ);
+					xyz0 = Max(xyz0, Int4(0));
+					xyz1 = Min(xyz1, maxXYZ);
 					break;
 				default:   // Wrap
 					{
-						// The coordinates overflow or underflow by at most 1
-						Int4 over = CmpNLT(xyz1, dim);
-						xyz1 = (over & Int4(0)) | (~over & xyz1); // xyz >= dim ? 0 : xyz
-						if(!gather)
-						{
-							Int4 under = CmpLT(xyz1, Int4(0));
-							xyz1 = (under & maxXYZ) | (~under & xyz1); // xyz < 0 ? dim - 1 : xyz
-						}
+						Int4 under = CmpLT(xyz0, Int4(0));
+						xyz0 = (under & maxXYZ) | (~under & xyz0);   // xyz < 0 ? dim - 1 : xyz   // FIXME: IfThenElse()
+
+						Int4 nover = CmpLT(xyz1, dim);
+						xyz1 = nover & xyz1;   // xyz >= dim ? 0 : xyz
 					}
 					break;
 				}
@@ -2430,11 +2529,11 @@
 		cf = Float4(As<UShort4>(cs)) * Float4(1.0f / 0xFFFF);
 	}
 
-	void SamplerCore::sRGBtoLinear16_8_12(Short4 &c)
+	void SamplerCore::sRGBtoLinear16_8_16(Short4 &c)
 	{
 		c = As<UShort4>(c) >> 8;
 
-		Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear8_12));
+		Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear8_16));
 
 		c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
 		c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
@@ -2442,11 +2541,11 @@
 		c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 3))), 3);
 	}
 
-	void SamplerCore::sRGBtoLinear16_6_12(Short4 &c)
+	void SamplerCore::sRGBtoLinear16_6_16(Short4 &c)
 	{
 		c = As<UShort4>(c) >> 10;
 
-		Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear6_12));
+		Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear6_16));
 
 		c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
 		c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
@@ -2454,11 +2553,11 @@
 		c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 3))), 3);
 	}
 
-	void SamplerCore::sRGBtoLinear16_5_12(Short4 &c)
+	void SamplerCore::sRGBtoLinear16_5_16(Short4 &c)
 	{
 		c = As<UShort4>(c) >> 11;
 
-		Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear5_12));
+		Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear5_16));
 
 		c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
 		c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
@@ -2497,10 +2596,10 @@
 		{
 		case FORMAT_R5G6B5:
 			return true;
-		case FORMAT_R8I_SNORM:
-		case FORMAT_G8R8I_SNORM:
-		case FORMAT_X8B8G8R8I_SNORM:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_R8_SNORM:
+		case FORMAT_G8R8_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 		case FORMAT_R8I:
 		case FORMAT_R8UI:
 		case FORMAT_G8R8I:
@@ -2531,13 +2630,16 @@
 		case FORMAT_G32R32F:
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_A8:
 		case FORMAT_R8:
 		case FORMAT_L8:
 		case FORMAT_A8L8:
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		case FORMAT_L16:
 		case FORMAT_G16R16:
@@ -2582,10 +2684,10 @@
 		case FORMAT_R8:
 		case FORMAT_L8:
 		case FORMAT_A8L8:
-		case FORMAT_R8I_SNORM:
-		case FORMAT_G8R8I_SNORM:
-		case FORMAT_X8B8G8R8I_SNORM:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_R8_SNORM:
+		case FORMAT_G8R8_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 		case FORMAT_R8I:
 		case FORMAT_R8UI:
 		case FORMAT_G8R8I:
@@ -2600,9 +2702,12 @@
 		case FORMAT_G32R32F:
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		case FORMAT_L16:
 		case FORMAT_G16R16:
@@ -2642,10 +2747,10 @@
 		switch(state.textureFormat)
 		{
 		case FORMAT_R5G6B5:
-		case FORMAT_R8I_SNORM:
-		case FORMAT_G8R8I_SNORM:
-		case FORMAT_X8B8G8R8I_SNORM:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_R8_SNORM:
+		case FORMAT_G8R8_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 		case FORMAT_R8I:
 		case FORMAT_R8UI:
 		case FORMAT_G8R8I:
@@ -2676,13 +2781,16 @@
 		case FORMAT_G32R32F:
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_A8:
 		case FORMAT_R8:
 		case FORMAT_L8:
 		case FORMAT_A8L8:
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		case FORMAT_YV12_BT601:
 		case FORMAT_YV12_BT709:
@@ -2715,10 +2823,10 @@
 		switch(state.textureFormat)
 		{
 		case FORMAT_R5G6B5:
-		case FORMAT_R8I_SNORM:
-		case FORMAT_G8R8I_SNORM:
-		case FORMAT_X8B8G8R8I_SNORM:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_R8_SNORM:
+		case FORMAT_G8R8_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 		case FORMAT_R8I:
 		case FORMAT_R8UI:
 		case FORMAT_G8R8I:
@@ -2755,13 +2863,16 @@
 		case FORMAT_G32R32F:
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_A8:
 		case FORMAT_R8:
 		case FORMAT_L8:
 		case FORMAT_A8L8:
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		case FORMAT_YV12_BT601:
 		case FORMAT_YV12_BT709:
@@ -2792,10 +2903,10 @@
 		case FORMAT_YV12_JFIF:
 			return true;
 		case FORMAT_R5G6B5:
-		case FORMAT_R8I_SNORM:
-		case FORMAT_G8R8I_SNORM:
-		case FORMAT_X8B8G8R8I_SNORM:
-		case FORMAT_A8B8G8R8I_SNORM:
+		case FORMAT_R8_SNORM:
+		case FORMAT_G8R8_SNORM:
+		case FORMAT_X8B8G8R8_SNORM:
+		case FORMAT_A8B8G8R8_SNORM:
 		case FORMAT_R8I:
 		case FORMAT_R8UI:
 		case FORMAT_G8R8I:
@@ -2826,13 +2937,16 @@
 		case FORMAT_G32R32F:
 		case FORMAT_X32B32G32R32F:
 		case FORMAT_A32B32G32R32F:
+		case FORMAT_X32B32G32R32F_UNSIGNED:
 		case FORMAT_A8:
 		case FORMAT_R8:
 		case FORMAT_L8:
 		case FORMAT_A8L8:
 		case FORMAT_D32F:
+		case FORMAT_D32FS8:
 		case FORMAT_D32F_LOCKABLE:
 		case FORMAT_D32FS8_TEXTURE:
+		case FORMAT_D32F_SHADOW:
 		case FORMAT_D32FS8_SHADOW:
 		case FORMAT_L16:
 		case FORMAT_G16R16:
@@ -2861,10 +2975,10 @@
 		switch(state.textureFormat)
 		{
 		case FORMAT_R5G6B5:         return component < 3;
-		case FORMAT_R8I_SNORM:      return component < 1;
-		case FORMAT_G8R8I_SNORM:    return component < 2;
-		case FORMAT_X8B8G8R8I_SNORM: return component < 3;
-		case FORMAT_A8B8G8R8I_SNORM: return component < 3;
+		case FORMAT_R8_SNORM:      return component < 1;
+		case FORMAT_G8R8_SNORM:    return component < 2;
+		case FORMAT_X8B8G8R8_SNORM: return component < 3;
+		case FORMAT_A8B8G8R8_SNORM: return component < 3;
 		case FORMAT_R8I:            return component < 1;
 		case FORMAT_R8UI:           return component < 1;
 		case FORMAT_G8R8I:          return component < 2;
@@ -2895,13 +3009,16 @@
 		case FORMAT_G32R32F:        return component < 2;
 		case FORMAT_X32B32G32R32F:  return component < 3;
 		case FORMAT_A32B32G32R32F:  return component < 3;
+		case FORMAT_X32B32G32R32F_UNSIGNED: return component < 3;
 		case FORMAT_A8:             return false;
 		case FORMAT_R8:             return component < 1;
 		case FORMAT_L8:             return component < 1;
 		case FORMAT_A8L8:           return component < 1;
 		case FORMAT_D32F:           return false;
+		case FORMAT_D32FS8:         return false;
 		case FORMAT_D32F_LOCKABLE:  return false;
 		case FORMAT_D32FS8_TEXTURE: return false;
+		case FORMAT_D32F_SHADOW:    return false;
 		case FORMAT_D32FS8_SHADOW:  return false;
 		case FORMAT_L16:            return component < 1;
 		case FORMAT_G16R16:         return component < 2;
diff --git a/src/Shader/SamplerCore.hpp b/src/Shader/SamplerCore.hpp
index 9f8e85b..684c1a7 100644
--- a/src/Shader/SamplerCore.hpp
+++ b/src/Shader/SamplerCore.hpp
@@ -22,17 +22,18 @@
 {
 	enum SamplerMethod
 	{
-		Implicit,
-		Bias,
-		Lod,
-		Grad,
-		Fetch
+		Implicit,  // Compute gradients (pixel shader only).
+		Bias,      // Compute gradients and add provided bias.
+		Lod,       // Use provided LOD.
+		Grad,      // Use provided gradients.
+		Fetch,     // Use provided integer coordinates.
+		Base       // Sample base level.
 	};
 
 	enum SamplerOption
 	{
 		None,
-		Offset
+		Offset   // Offset sample location by provided integer coordinates.
 	};
 
 	struct SamplerFunction
@@ -47,38 +48,38 @@
 	class SamplerCore
 	{
 	public:
-		SamplerCore(Pointer<Byte> &r, const Sampler::State &state);
+		SamplerCore(Pointer<Byte> &constants, const Sampler::State &state);
 
-		void sampleTexture(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy);
-		void sampleTexture(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
-		void textureSize(Pointer<Byte> &mipmap, Vector4f &size, Float4 &lod);
+		Vector4s sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy);
+		Vector4f sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
+		static Vector4f textureSize(Pointer<Byte> &mipmap, Float4 &lod);
 
 	private:
-		void sampleTexture(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function, bool fixed12);
+		Vector4s sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function, bool fixed12);
 
 		void border(Short4 &mask, Float4 &coordinates);
 		void border(Int4 &mask, Float4 &coordinates);
 		Short4 offsetSample(Short4 &uvw, Pointer<Byte> &mipmap, int halfOffset, bool wrap, int count, Float &lod);
-		void sampleFilter(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function);
-		void sampleAniso(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function);
-		void sampleQuad(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function);
-		void sampleQuad2D(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function);
-		void sample3D(Pointer<Byte> &texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function);
-		void sampleFloatFilter(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function);
-		void sampleFloatAniso(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function);
-		void sampleFloat(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function);
-		void sampleFloat2D(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function);
-		void sampleFloat3D(Pointer<Byte> &texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function);
+		Vector4s sampleFilter(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function);
+		Vector4s sampleAniso(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function);
+		Vector4s sampleQuad(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function);
+		Vector4s sampleQuad2D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function);
+		Vector4s sample3D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function);
+		Vector4f sampleFloatFilter(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function);
+		Vector4f sampleFloatAniso(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function);
+		Vector4f sampleFloat(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function);
+		Vector4f sampleFloat2D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function);
+		Vector4f sampleFloat3D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function);
 		Float log2sqrt(Float lod);
+		Float log2(Float lod);
 		void computeLod(Pointer<Byte> &texture, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Float4 &u, Float4 &v, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function);
-		void computeLodCube(Pointer<Byte> &texture, Float &lod, Float4 &x, Float4 &y, Float4 &z, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function);
+		void computeLodCube(Pointer<Byte> &texture, Float &lod, Float4 &u, Float4 &v, Float4 &w, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, Float4 &M, SamplerFunction function);
 		void computeLod3D(Pointer<Byte> &texture, Float &lod, Float4 &u, Float4 &v, Float4 &w, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function);
-		void cubeFace(Int face[4], Float4 &U, Float4 &V, Float4 &lodX, Float4 &lodY, Float4 &lodZ, Float4 &x, Float4 &y, Float4 &z);
+		void cubeFace(Int face[4], Float4 &U, Float4 &V, Float4 &x, Float4 &y, Float4 &z, Float4 &M);
 		Short4 applyOffset(Short4 &uvw, Float4 &offset, const Int4 &whd, AddressingMode mode);
 		void computeIndices(UInt index[4], Short4 uuuu, Short4 vvvv, Short4 wwww, Vector4f &offset, const Pointer<Byte> &mipmap, SamplerFunction function);
 		void computeIndices(UInt index[4], Int4& uuuu, Int4& vvvv, Int4& wwww, const Pointer<Byte> &mipmap, SamplerFunction function);
 		Vector4s sampleTexel(Short4 &u, Short4 &v, Short4 &s, Vector4f &offset, Pointer<Byte> &mipmap, Pointer<Byte> buffer[4], SamplerFunction function);
-		Vector4f sampleTexel(Short4 &u, Short4 &v, Short4 &s, Vector4f &offset, Float4 &z, Pointer<Byte> &mipmap, Pointer<Byte> buffer[4], SamplerFunction function);
 		Vector4s sampleTexel(UInt index[4], Pointer<Byte> buffer[4]);
 		Vector4f sampleTexel(Int4 &u, Int4 &v, Int4 &s, Float4 &z, Pointer<Byte> &mipmap, Pointer<Byte> buffer[4], SamplerFunction function);
 		void selectMipmap(Pointer<Byte> &texture, Pointer<Byte> buffer[4], Pointer<Byte> &mipmap, Float &lod, Int face[4], bool secondLOD);
@@ -91,9 +92,9 @@
 		void convertSigned12(Float4 &cf, Short4 &ci);
 		void convertSigned15(Float4 &cf, Short4 &ci);
 		void convertUnsigned16(Float4 &cf, Short4 &ci);
-		void sRGBtoLinear16_8_12(Short4 &c);
-		void sRGBtoLinear16_6_12(Short4 &c);
-		void sRGBtoLinear16_5_12(Short4 &c);
+		void sRGBtoLinear16_8_16(Short4 &c);
+		void sRGBtoLinear16_6_16(Short4 &c);
+		void sRGBtoLinear16_5_16(Short4 &c);
 
 		bool hasFloatTexture() const;
 		bool hasUnnormalizedIntegerTexture() const;
diff --git a/src/Shader/SetupRoutine.cpp b/src/Shader/SetupRoutine.cpp
index 2fd1883..d733c2d 100644
--- a/src/Shader/SetupRoutine.cpp
+++ b/src/Shader/SetupRoutine.cpp
@@ -224,7 +224,9 @@
 
 				if(state.multiSample > 1)
 				{
-					Short x = Short((X[0] + 0xF) >> 4);
+					Int xMin = *Pointer<Int>(data + OFFSET(DrawData, scissorX0));
+					Int xMax = *Pointer<Int>(data + OFFSET(DrawData, scissorX1));
+					Short x = Short(Clamp((X[0] + 0xF) >> 4, xMin, xMax));
 
 					For(Int y = yMin - 1, y < yMax + 1, y++)
 					{
diff --git a/src/Shader/SetupRoutine.hpp b/src/Shader/SetupRoutine.hpp
index ebcc080..c1c3205 100644
--- a/src/Shader/SetupRoutine.hpp
+++ b/src/Shader/SetupRoutine.hpp
@@ -15,7 +15,7 @@
 #ifndef sw_SetupRoutine_hpp
 #define sw_SetupRoutine_hpp
 
-#include "SetupProcessor.hpp"
+#include "Renderer/SetupProcessor.hpp"
 #include "Reactor/Reactor.hpp"
 
 namespace sw
diff --git a/src/Shader/Shader.cpp b/src/Shader/Shader.cpp
index ff1482e..025b5d5 100644
--- a/src/Shader/Shader.cpp
+++ b/src/Shader/Shader.cpp
@@ -16,8 +16,8 @@
 
 #include "VertexShader.hpp"
 #include "PixelShader.hpp"
-#include "Math.hpp"
-#include "Debug.hpp"
+#include "Common/Math.hpp"
+#include "Common/Debug.hpp"
 
 #include <set>
 #include <fstream>
@@ -317,11 +317,6 @@
 
 		std::string modifierString;
 
-		if(integer)
-		{
-			modifierString += "_int";
-		}
-
 		if(saturate)
 		{
 			modifierString += "_sat";
@@ -508,6 +503,24 @@
 		return "";
 	}
 
+	std::string Shader::SourceParameter::string(ShaderType shaderType, unsigned short version) const
+	{
+		if(type == PARAMETER_CONST && bufferIndex >= 0)
+		{
+			std::ostringstream buffer;
+			buffer << bufferIndex;
+
+			std::ostringstream offset;
+			offset << index;
+
+			return "cb" + buffer.str() + "[" + offset.str() + "]";
+		}
+		else
+		{
+			return Parameter::string(shaderType, version);
+		}
+	}
+
 	std::string Shader::SourceParameter::swizzleString() const
 	{
 		return Instruction::swizzleString(type, swizzle);
@@ -747,232 +760,234 @@
 	{
 		switch(opcode)
 		{
-		case OPCODE_NULL:			return "null";
-		case OPCODE_NOP:			return "nop";
-		case OPCODE_MOV:			return "mov";
-		case OPCODE_ADD:			return "add";
-		case OPCODE_IADD:			return "iadd";
-		case OPCODE_SUB:			return "sub";
-		case OPCODE_ISUB:			return "isub";
-		case OPCODE_MAD:			return "mad";
-		case OPCODE_IMAD:			return "imad";
-		case OPCODE_MUL:			return "mul";
-		case OPCODE_IMUL:			return "imul";
-		case OPCODE_RCPX:			return "rcpx";
-		case OPCODE_DIV:			return "div";
-		case OPCODE_IDIV:			return "idiv";
-		case OPCODE_UDIV:			return "udiv";
-		case OPCODE_MOD:			return "mod";
-		case OPCODE_IMOD:			return "imod";
-		case OPCODE_UMOD:			return "umod";
-		case OPCODE_SHL:			return "shl";
-		case OPCODE_ISHR:			return "ishr";
-		case OPCODE_USHR:			return "ushr";
-		case OPCODE_RSQX:			return "rsqx";
-		case OPCODE_SQRT:			return "sqrt";
-		case OPCODE_RSQ:			return "rsq";
-		case OPCODE_LEN2:			return "len2";
-		case OPCODE_LEN3:			return "len3";
-		case OPCODE_LEN4:			return "len4";
-		case OPCODE_DIST1:			return "dist1";
-		case OPCODE_DIST2:			return "dist2";
-		case OPCODE_DIST3:			return "dist3";
-		case OPCODE_DIST4:			return "dist4";
-		case OPCODE_DP3:			return "dp3";
-		case OPCODE_DP4:			return "dp4";
-		case OPCODE_DET2:			return "det2";
-		case OPCODE_DET3:			return "det3";
-		case OPCODE_DET4:			return "det4";
-		case OPCODE_MIN:			return "min";
-		case OPCODE_IMIN:			return "imin";
-		case OPCODE_UMIN:			return "umin";
-		case OPCODE_MAX:			return "max";
-		case OPCODE_IMAX:			return "imax";
-		case OPCODE_UMAX:			return "umax";
-		case OPCODE_SLT:			return "slt";
-		case OPCODE_SGE:			return "sge";
-		case OPCODE_EXP2X:			return "exp2x";
-		case OPCODE_LOG2X:			return "log2x";
-		case OPCODE_LIT:			return "lit";
-		case OPCODE_ATT:			return "att";
-		case OPCODE_LRP:			return "lrp";
-		case OPCODE_STEP:			return "step";
-		case OPCODE_SMOOTH:			return "smooth";
-		case OPCODE_FLOATBITSTOINT:	 return "floatBitsToInt";
+		case OPCODE_NULL:            return "null";
+		case OPCODE_NOP:             return "nop";
+		case OPCODE_MOV:             return "mov";
+		case OPCODE_ADD:             return "add";
+		case OPCODE_IADD:            return "iadd";
+		case OPCODE_SUB:             return "sub";
+		case OPCODE_ISUB:            return "isub";
+		case OPCODE_MAD:             return "mad";
+		case OPCODE_IMAD:            return "imad";
+		case OPCODE_MUL:             return "mul";
+		case OPCODE_IMUL:            return "imul";
+		case OPCODE_RCPX:            return "rcpx";
+		case OPCODE_DIV:             return "div";
+		case OPCODE_IDIV:            return "idiv";
+		case OPCODE_UDIV:            return "udiv";
+		case OPCODE_MOD:             return "mod";
+		case OPCODE_IMOD:            return "imod";
+		case OPCODE_UMOD:            return "umod";
+		case OPCODE_SHL:             return "shl";
+		case OPCODE_ISHR:            return "ishr";
+		case OPCODE_USHR:            return "ushr";
+		case OPCODE_RSQX:            return "rsqx";
+		case OPCODE_SQRT:            return "sqrt";
+		case OPCODE_RSQ:             return "rsq";
+		case OPCODE_LEN2:            return "len2";
+		case OPCODE_LEN3:            return "len3";
+		case OPCODE_LEN4:            return "len4";
+		case OPCODE_DIST1:           return "dist1";
+		case OPCODE_DIST2:           return "dist2";
+		case OPCODE_DIST3:           return "dist3";
+		case OPCODE_DIST4:           return "dist4";
+		case OPCODE_DP3:             return "dp3";
+		case OPCODE_DP4:             return "dp4";
+		case OPCODE_DET2:            return "det2";
+		case OPCODE_DET3:            return "det3";
+		case OPCODE_DET4:            return "det4";
+		case OPCODE_MIN:             return "min";
+		case OPCODE_IMIN:            return "imin";
+		case OPCODE_UMIN:            return "umin";
+		case OPCODE_MAX:             return "max";
+		case OPCODE_IMAX:            return "imax";
+		case OPCODE_UMAX:            return "umax";
+		case OPCODE_SLT:             return "slt";
+		case OPCODE_SGE:             return "sge";
+		case OPCODE_EXP2X:           return "exp2x";
+		case OPCODE_LOG2X:           return "log2x";
+		case OPCODE_LIT:             return "lit";
+		case OPCODE_ATT:             return "att";
+		case OPCODE_LRP:             return "lrp";
+		case OPCODE_STEP:            return "step";
+		case OPCODE_SMOOTH:          return "smooth";
+		case OPCODE_FLOATBITSTOINT:  return "floatBitsToInt";
 		case OPCODE_FLOATBITSTOUINT: return "floatBitsToUInt";
-		case OPCODE_INTBITSTOFLOAT:	 return "intBitsToFloat";
+		case OPCODE_INTBITSTOFLOAT:  return "intBitsToFloat";
 		case OPCODE_UINTBITSTOFLOAT: return "uintBitsToFloat";
-		case OPCODE_PACKSNORM2x16:	 return "packSnorm2x16";
-		case OPCODE_PACKUNORM2x16:	 return "packUnorm2x16";
-		case OPCODE_PACKHALF2x16:	 return "packHalf2x16";
+		case OPCODE_PACKSNORM2x16:   return "packSnorm2x16";
+		case OPCODE_PACKUNORM2x16:   return "packUnorm2x16";
+		case OPCODE_PACKHALF2x16:    return "packHalf2x16";
 		case OPCODE_UNPACKSNORM2x16: return "unpackSnorm2x16";
 		case OPCODE_UNPACKUNORM2x16: return "unpackUnorm2x16";
-		case OPCODE_UNPACKHALF2x16:	 return "unpackHalf2x16";
-		case OPCODE_FRC:			return "frc";
-		case OPCODE_M4X4:			return "m4x4";
-		case OPCODE_M4X3:			return "m4x3";
-		case OPCODE_M3X4:			return "m3x4";
-		case OPCODE_M3X3:			return "m3x3";
-		case OPCODE_M3X2:			return "m3x2";
-		case OPCODE_CALL:			return "call";
-		case OPCODE_CALLNZ:			return "callnz";
-		case OPCODE_LOOP:			return "loop";
-		case OPCODE_RET:			return "ret";
-		case OPCODE_ENDLOOP:		return "endloop";
-		case OPCODE_LABEL:			return "label";
-		case OPCODE_DCL:			return "dcl";
-		case OPCODE_POWX:			return "powx";
-		case OPCODE_CRS:			return "crs";
-		case OPCODE_SGN:			return "sgn";
-		case OPCODE_ISGN:			return "isgn";
-		case OPCODE_ABS:			return "abs";
-		case OPCODE_IABS:			return "iabs";
-		case OPCODE_NRM2:			return "nrm2";
-		case OPCODE_NRM3:			return "nrm3";
-		case OPCODE_NRM4:			return "nrm4";
-		case OPCODE_SINCOS:			return "sincos";
-		case OPCODE_REP:			return "rep";
-		case OPCODE_ENDREP:			return "endrep";
-		case OPCODE_IF:				return "if";
-		case OPCODE_IFC:			return "ifc";
-		case OPCODE_ELSE:			return "else";
-		case OPCODE_ENDIF:			return "endif";
-		case OPCODE_BREAK:			return "break";
-		case OPCODE_BREAKC:			return "breakc";
-		case OPCODE_MOVA:			return "mova";
-		case OPCODE_DEFB:			return "defb";
-		case OPCODE_DEFI:			return "defi";
-		case OPCODE_TEXCOORD:		return "texcoord";
-		case OPCODE_TEXKILL:		return "texkill";
-		case OPCODE_DISCARD:		return "discard";
+		case OPCODE_UNPACKHALF2x16:  return "unpackHalf2x16";
+		case OPCODE_FRC:             return "frc";
+		case OPCODE_M4X4:            return "m4x4";
+		case OPCODE_M4X3:            return "m4x3";
+		case OPCODE_M3X4:            return "m3x4";
+		case OPCODE_M3X3:            return "m3x3";
+		case OPCODE_M3X2:            return "m3x2";
+		case OPCODE_CALL:            return "call";
+		case OPCODE_CALLNZ:          return "callnz";
+		case OPCODE_LOOP:            return "loop";
+		case OPCODE_RET:             return "ret";
+		case OPCODE_ENDLOOP:         return "endloop";
+		case OPCODE_LABEL:           return "label";
+		case OPCODE_DCL:             return "dcl";
+		case OPCODE_POWX:            return "powx";
+		case OPCODE_CRS:             return "crs";
+		case OPCODE_SGN:             return "sgn";
+		case OPCODE_ISGN:            return "isgn";
+		case OPCODE_ABS:             return "abs";
+		case OPCODE_IABS:            return "iabs";
+		case OPCODE_NRM2:            return "nrm2";
+		case OPCODE_NRM3:            return "nrm3";
+		case OPCODE_NRM4:            return "nrm4";
+		case OPCODE_SINCOS:          return "sincos";
+		case OPCODE_REP:             return "rep";
+		case OPCODE_ENDREP:          return "endrep";
+		case OPCODE_IF:              return "if";
+		case OPCODE_IFC:             return "ifc";
+		case OPCODE_ELSE:            return "else";
+		case OPCODE_ENDIF:           return "endif";
+		case OPCODE_BREAK:           return "break";
+		case OPCODE_BREAKC:          return "breakc";
+		case OPCODE_MOVA:            return "mova";
+		case OPCODE_DEFB:            return "defb";
+		case OPCODE_DEFI:            return "defi";
+		case OPCODE_TEXCOORD:        return "texcoord";
+		case OPCODE_TEXKILL:         return "texkill";
+		case OPCODE_DISCARD:         return "discard";
 		case OPCODE_TEX:
-			if(version < 0x0104)	return "tex";
-			else					return "texld";
-		case OPCODE_TEXBEM:			return "texbem";
-		case OPCODE_TEXBEML:		return "texbeml";
-		case OPCODE_TEXREG2AR:		return "texreg2ar";
-		case OPCODE_TEXREG2GB:		return "texreg2gb";
-		case OPCODE_TEXM3X2PAD:		return "texm3x2pad";
-		case OPCODE_TEXM3X2TEX:		return "texm3x2tex";
-		case OPCODE_TEXM3X3PAD:		return "texm3x3pad";
-		case OPCODE_TEXM3X3TEX:		return "texm3x3tex";
-		case OPCODE_RESERVED0:		return "reserved0";
-		case OPCODE_TEXM3X3SPEC:	return "texm3x3spec";
-		case OPCODE_TEXM3X3VSPEC:	return "texm3x3vspec";
-		case OPCODE_EXPP:			return "expp";
-		case OPCODE_LOGP:			return "logp";
-		case OPCODE_CND:			return "cnd";
-		case OPCODE_DEF:			return "def";
-		case OPCODE_TEXREG2RGB:		return "texreg2rgb";
-		case OPCODE_TEXDP3TEX:		return "texdp3tex";
-		case OPCODE_TEXM3X2DEPTH:	return "texm3x2depth";
-		case OPCODE_TEXDP3:			return "texdp3";
-		case OPCODE_TEXM3X3:		return "texm3x3";
-		case OPCODE_TEXDEPTH:		return "texdepth";
-		case OPCODE_CMP0:			return "cmp0";
-		case OPCODE_ICMP:			return "icmp";
-		case OPCODE_UCMP:			return "ucmp";
-		case OPCODE_SELECT:			return "select";
-		case OPCODE_EXTRACT:		return "extract";
-		case OPCODE_INSERT:			return "insert";
-		case OPCODE_BEM:			return "bem";
-		case OPCODE_DP2ADD:			return "dp2add";
-		case OPCODE_DFDX:			return "dFdx";
-		case OPCODE_DFDY:			return "dFdy";
-		case OPCODE_FWIDTH:			return "fwidth";
-		case OPCODE_TEXLDD:			return "texldd";
-		case OPCODE_CMP:			return "cmp";
-		case OPCODE_TEXLDL:			return "texldl";
-		case OPCODE_TEXOFFSET:		return "texoffset";
-		case OPCODE_TEXLDLOFFSET:	return "texldloffset";
-		case OPCODE_TEXELFETCH:		return "texelfetch";
+			if(version < 0x0104)     return "tex";
+			else                     return "texld";
+		case OPCODE_TEXBEM:          return "texbem";
+		case OPCODE_TEXBEML:         return "texbeml";
+		case OPCODE_TEXREG2AR:       return "texreg2ar";
+		case OPCODE_TEXREG2GB:       return "texreg2gb";
+		case OPCODE_TEXM3X2PAD:      return "texm3x2pad";
+		case OPCODE_TEXM3X2TEX:      return "texm3x2tex";
+		case OPCODE_TEXM3X3PAD:      return "texm3x3pad";
+		case OPCODE_TEXM3X3TEX:      return "texm3x3tex";
+		case OPCODE_RESERVED0:       return "reserved0";
+		case OPCODE_TEXM3X3SPEC:     return "texm3x3spec";
+		case OPCODE_TEXM3X3VSPEC:    return "texm3x3vspec";
+		case OPCODE_EXPP:            return "expp";
+		case OPCODE_LOGP:            return "logp";
+		case OPCODE_CND:             return "cnd";
+		case OPCODE_DEF:             return "def";
+		case OPCODE_TEXREG2RGB:      return "texreg2rgb";
+		case OPCODE_TEXDP3TEX:       return "texdp3tex";
+		case OPCODE_TEXM3X2DEPTH:    return "texm3x2depth";
+		case OPCODE_TEXDP3:          return "texdp3";
+		case OPCODE_TEXM3X3:         return "texm3x3";
+		case OPCODE_TEXDEPTH:        return "texdepth";
+		case OPCODE_CMP0:            return "cmp0";
+		case OPCODE_ICMP:            return "icmp";
+		case OPCODE_UCMP:            return "ucmp";
+		case OPCODE_SELECT:          return "select";
+		case OPCODE_EXTRACT:         return "extract";
+		case OPCODE_INSERT:          return "insert";
+		case OPCODE_BEM:             return "bem";
+		case OPCODE_DP2ADD:          return "dp2add";
+		case OPCODE_DFDX:            return "dFdx";
+		case OPCODE_DFDY:            return "dFdy";
+		case OPCODE_FWIDTH:          return "fwidth";
+		case OPCODE_TEXLDD:          return "texldd";
+		case OPCODE_CMP:             return "cmp";
+		case OPCODE_TEXLDL:          return "texldl";
+		case OPCODE_TEXBIAS:         return "texbias";
+		case OPCODE_TEXOFFSET:       return "texoffset";
+		case OPCODE_TEXOFFSETBIAS:   return "texoffsetbias";
+		case OPCODE_TEXLODOFFSET:    return "texlodoffset";
+		case OPCODE_TEXELFETCH:      return "texelfetch";
 		case OPCODE_TEXELFETCHOFFSET: return "texelfetchoffset";
-		case OPCODE_TEXGRAD:		return "texgrad";
-		case OPCODE_TEXGRADOFFSET:	return "texgradoffset";
-		case OPCODE_BREAKP:			return "breakp";
-		case OPCODE_TEXSIZE:        return "texsize";
-		case OPCODE_PHASE:			return "phase";
-		case OPCODE_COMMENT:		return "comment";
-		case OPCODE_END:			return "end";
-		case OPCODE_PS_1_0:			return "ps_1_0";
-		case OPCODE_PS_1_1:			return "ps_1_1";
-		case OPCODE_PS_1_2:			return "ps_1_2";
-		case OPCODE_PS_1_3:			return "ps_1_3";
-		case OPCODE_PS_1_4:			return "ps_1_4";
-		case OPCODE_PS_2_0:			return "ps_2_0";
-		case OPCODE_PS_2_x:			return "ps_2_x";
-		case OPCODE_PS_3_0:			return "ps_3_0";
-		case OPCODE_VS_1_0:			return "vs_1_0";
-		case OPCODE_VS_1_1:			return "vs_1_1";
-		case OPCODE_VS_2_0:			return "vs_2_0";
-		case OPCODE_VS_2_x:			return "vs_2_x";
-		case OPCODE_VS_2_sw:		return "vs_2_sw";
-		case OPCODE_VS_3_0:			return "vs_3_0";
-		case OPCODE_VS_3_sw:		return "vs_3_sw";
-		case OPCODE_WHILE:          return "while";
-		case OPCODE_ENDWHILE:       return "endwhile";
-		case OPCODE_COS:            return "cos";
-		case OPCODE_SIN:            return "sin";
-		case OPCODE_TAN:            return "tan";
-		case OPCODE_ACOS:           return "acos";
-		case OPCODE_ASIN:           return "asin";
-		case OPCODE_ATAN:           return "atan";
-		case OPCODE_ATAN2:          return "atan2";
-		case OPCODE_COSH:           return "cosh";
-		case OPCODE_SINH:           return "sinh";
-		case OPCODE_TANH:           return "tanh";
-		case OPCODE_ACOSH:          return "acosh";
-		case OPCODE_ASINH:          return "asinh";
-		case OPCODE_ATANH:          return "atanh";
-		case OPCODE_DP1:            return "dp1";
-		case OPCODE_DP2:            return "dp2";
-		case OPCODE_TRUNC:          return "trunc";
-		case OPCODE_FLOOR:          return "floor";
-		case OPCODE_ROUND:          return "round";
-		case OPCODE_ROUNDEVEN:      return "roundEven";
-		case OPCODE_CEIL:           return "ceil";
-		case OPCODE_EXP2:           return "exp2";
-		case OPCODE_LOG2:           return "log2";
-		case OPCODE_EXP:            return "exp";
-		case OPCODE_LOG:            return "log";
-		case OPCODE_POW:            return "pow";
-		case OPCODE_F2B:            return "f2b";
-		case OPCODE_B2F:            return "b2f";
-		case OPCODE_F2I:            return "f2i";
-		case OPCODE_I2F:            return "i2f";
-		case OPCODE_F2U:            return "f2u";
-		case OPCODE_U2F:            return "u2f";
-		case OPCODE_B2I:            return "b2i";
-		case OPCODE_I2B:            return "i2b";
-		case OPCODE_ALL:            return "all";
-		case OPCODE_ANY:            return "any";
-		case OPCODE_NEG:            return "neg";
-		case OPCODE_INEG:           return "ineg";
-		case OPCODE_ISNAN:          return "isnan";
-		case OPCODE_ISINF:          return "isinf";
-		case OPCODE_NOT:            return "not";
-		case OPCODE_OR:             return "or";
-		case OPCODE_XOR:            return "xor";
-		case OPCODE_AND:            return "and";
-		case OPCODE_EQ:             return "eq";
-		case OPCODE_NE:             return "neq";
-		case OPCODE_FORWARD1:       return "forward1";
-		case OPCODE_FORWARD2:       return "forward2";
-		case OPCODE_FORWARD3:       return "forward3";
-		case OPCODE_FORWARD4:       return "forward4";
-		case OPCODE_REFLECT1:       return "reflect1";
-		case OPCODE_REFLECT2:       return "reflect2";
-		case OPCODE_REFLECT3:       return "reflect3";
-		case OPCODE_REFLECT4:       return "reflect4";
-		case OPCODE_REFRACT1:       return "refract1";
-		case OPCODE_REFRACT2:       return "refract2";
-		case OPCODE_REFRACT3:       return "refract3";
-		case OPCODE_REFRACT4:       return "refract4";
-		case OPCODE_LEAVE:          return "leave";
-		case OPCODE_CONTINUE:       return "continue";
-		case OPCODE_TEST:           return "test";
-		case OPCODE_SWITCH:         return "switch";
-		case OPCODE_ENDSWITCH:      return "endswitch";
+		case OPCODE_TEXGRAD:         return "texgrad";
+		case OPCODE_TEXGRADOFFSET:   return "texgradoffset";
+		case OPCODE_BREAKP:          return "breakp";
+		case OPCODE_TEXSIZE:         return "texsize";
+		case OPCODE_PHASE:           return "phase";
+		case OPCODE_COMMENT:         return "comment";
+		case OPCODE_END:             return "end";
+		case OPCODE_PS_1_0:          return "ps_1_0";
+		case OPCODE_PS_1_1:          return "ps_1_1";
+		case OPCODE_PS_1_2:          return "ps_1_2";
+		case OPCODE_PS_1_3:          return "ps_1_3";
+		case OPCODE_PS_1_4:          return "ps_1_4";
+		case OPCODE_PS_2_0:          return "ps_2_0";
+		case OPCODE_PS_2_x:          return "ps_2_x";
+		case OPCODE_PS_3_0:          return "ps_3_0";
+		case OPCODE_VS_1_0:          return "vs_1_0";
+		case OPCODE_VS_1_1:          return "vs_1_1";
+		case OPCODE_VS_2_0:          return "vs_2_0";
+		case OPCODE_VS_2_x:          return "vs_2_x";
+		case OPCODE_VS_2_sw:         return "vs_2_sw";
+		case OPCODE_VS_3_0:          return "vs_3_0";
+		case OPCODE_VS_3_sw:         return "vs_3_sw";
+		case OPCODE_WHILE:           return "while";
+		case OPCODE_ENDWHILE:        return "endwhile";
+		case OPCODE_COS:             return "cos";
+		case OPCODE_SIN:             return "sin";
+		case OPCODE_TAN:             return "tan";
+		case OPCODE_ACOS:            return "acos";
+		case OPCODE_ASIN:            return "asin";
+		case OPCODE_ATAN:            return "atan";
+		case OPCODE_ATAN2:           return "atan2";
+		case OPCODE_COSH:            return "cosh";
+		case OPCODE_SINH:            return "sinh";
+		case OPCODE_TANH:            return "tanh";
+		case OPCODE_ACOSH:           return "acosh";
+		case OPCODE_ASINH:           return "asinh";
+		case OPCODE_ATANH:           return "atanh";
+		case OPCODE_DP1:             return "dp1";
+		case OPCODE_DP2:             return "dp2";
+		case OPCODE_TRUNC:           return "trunc";
+		case OPCODE_FLOOR:           return "floor";
+		case OPCODE_ROUND:           return "round";
+		case OPCODE_ROUNDEVEN:       return "roundEven";
+		case OPCODE_CEIL:            return "ceil";
+		case OPCODE_EXP2:            return "exp2";
+		case OPCODE_LOG2:            return "log2";
+		case OPCODE_EXP:             return "exp";
+		case OPCODE_LOG:             return "log";
+		case OPCODE_POW:             return "pow";
+		case OPCODE_F2B:             return "f2b";
+		case OPCODE_B2F:             return "b2f";
+		case OPCODE_F2I:             return "f2i";
+		case OPCODE_I2F:             return "i2f";
+		case OPCODE_F2U:             return "f2u";
+		case OPCODE_U2F:             return "u2f";
+		case OPCODE_B2I:             return "b2i";
+		case OPCODE_I2B:             return "i2b";
+		case OPCODE_ALL:             return "all";
+		case OPCODE_ANY:             return "any";
+		case OPCODE_NEG:             return "neg";
+		case OPCODE_INEG:            return "ineg";
+		case OPCODE_ISNAN:           return "isnan";
+		case OPCODE_ISINF:           return "isinf";
+		case OPCODE_NOT:             return "not";
+		case OPCODE_OR:              return "or";
+		case OPCODE_XOR:             return "xor";
+		case OPCODE_AND:             return "and";
+		case OPCODE_EQ:              return "eq";
+		case OPCODE_NE:              return "neq";
+		case OPCODE_FORWARD1:        return "forward1";
+		case OPCODE_FORWARD2:        return "forward2";
+		case OPCODE_FORWARD3:        return "forward3";
+		case OPCODE_FORWARD4:        return "forward4";
+		case OPCODE_REFLECT1:        return "reflect1";
+		case OPCODE_REFLECT2:        return "reflect2";
+		case OPCODE_REFLECT3:        return "reflect3";
+		case OPCODE_REFLECT4:        return "reflect4";
+		case OPCODE_REFRACT1:        return "refract1";
+		case OPCODE_REFRACT2:        return "refract2";
+		case OPCODE_REFRACT3:        return "refract3";
+		case OPCODE_REFRACT4:        return "refract4";
+		case OPCODE_LEAVE:           return "leave";
+		case OPCODE_CONTINUE:        return "continue";
+		case OPCODE_TEST:            return "test";
+		case OPCODE_SWITCH:          return "switch";
+		case OPCODE_ENDSWITCH:       return "endswitch";
 		default:
 			ASSERT(false);
 		}
@@ -1121,10 +1136,10 @@
 
 	Shader::~Shader()
 	{
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(auto &inst : instruction)
 		{
-			delete instruction[i];
-			instruction[i] = 0;
+			delete inst;
+			inst = 0;
 		}
 	}
 
@@ -1168,12 +1183,12 @@
 
 	int Shader::size(unsigned long opcode) const
 	{
-		return size(opcode, version);
+		return size(opcode, shaderModel);
 	}
 
-	int Shader::size(unsigned long opcode, unsigned short version)
+	int Shader::size(unsigned long opcode, unsigned short shaderModel)
 	{
-		if(version > 0x0300)
+		if(shaderModel > 0x0300)
 		{
 			ASSERT(false);
 		}
@@ -1320,7 +1335,7 @@
 		   opcode != OPCODE_PHASE &&
 		   opcode != OPCODE_END)
 		{
-			if(version >= 0x0200)
+			if(shaderModel >= 0x0200)
 			{
 				length = (opcode & 0x0F000000) >> 24;
 			}
@@ -1335,7 +1350,7 @@
 			ASSERT(false);
 		}
 
-		if(version == 0x0104)
+		if(shaderModel == 0x0104)
 		{
 			switch(opcode & 0x0000FFFF)
 			{
@@ -1423,9 +1438,9 @@
 		return shaderType;
 	}
 
-	unsigned short Shader::getVersion() const
+	unsigned short Shader::getShaderModel() const
 	{
-		return version;
+		return shaderModel;
 	}
 
 	void Shader::print(const char *fileName, ...) const
@@ -1439,9 +1454,9 @@
 
 		std::ofstream file(fullName, std::ofstream::out);
 
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(const auto &inst : instruction)
 		{
-			file << instruction[i]->string(shaderType, version) << std::endl;
+			file << inst->string(shaderType, shaderModel) << std::endl;
 		}
 	}
 
@@ -1449,7 +1464,7 @@
 	{
 		std::ofstream file(fileName, std::ofstream::out | std::ofstream::app);
 
-		file << instruction[index]->string(shaderType, version) << std::endl;
+		file << instruction[index]->string(shaderType, shaderModel) << std::endl;
 	}
 
 	void Shader::append(Instruction *instruction)
@@ -1459,7 +1474,10 @@
 
 	void Shader::declareSampler(int i)
 	{
-		usedSamplers |= 1 << i;
+		if(i >= 0 && i < 16)
+		{
+			usedSamplers |= 1 << i;
+		}
 	}
 
 	const Shader::Instruction *Shader::getInstruction(size_t i) const
@@ -1502,11 +1520,11 @@
 			calledFunctions.clear();
 			rescan = false;
 
-			for(unsigned int i = 0; i < instruction.size(); i++)
+			for(const auto &inst : instruction)
 			{
-				if(instruction[i]->isCall())
+				if(inst->isCall())
 				{
-					calledFunctions.insert(instruction[i]->dst.label);
+					calledFunctions.insert(inst->dst.label);
 				}
 			}
 
@@ -1579,26 +1597,26 @@
 		dirtyConstantsI = 0;
 		dirtyConstantsB = 0;
 
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(const auto &inst : instruction)
 		{
-			switch(instruction[i]->opcode)
+			switch(inst->opcode)
 			{
 			case OPCODE_DEF:
-				if(instruction[i]->dst.index + 1 > dirtyConstantsF)
+				if(inst->dst.index + 1 > dirtyConstantsF)
 				{
-					dirtyConstantsF = instruction[i]->dst.index + 1;
+					dirtyConstantsF = inst->dst.index + 1;
 				}
 				break;
 			case OPCODE_DEFI:
-				if(instruction[i]->dst.index + 1 > dirtyConstantsI)
+				if(inst->dst.index + 1 > dirtyConstantsI)
 				{
-					dirtyConstantsI = instruction[i]->dst.index + 1;
+					dirtyConstantsI = inst->dst.index + 1;
 				}
 				break;
 			case OPCODE_DEFB:
-				if(instruction[i]->dst.index + 1 > dirtyConstantsB)
+				if(inst->dst.index + 1 > dirtyConstantsB)
 				{
-					dirtyConstantsB = instruction[i]->dst.index + 1;
+					dirtyConstantsB = inst->dst.index + 1;
 				}
 				break;
 			default:
@@ -1616,9 +1634,9 @@
 		containsDefine = false;
 
 		// Determine global presence of branching instructions
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(const auto &inst : instruction)
 		{
-			switch(instruction[i]->opcode)
+			switch(inst->opcode)
 			{
 			case OPCODE_CALLNZ:
 			case OPCODE_IF:
@@ -1629,22 +1647,22 @@
 			case OPCODE_BREAKP:
 			case OPCODE_LEAVE:
 			case OPCODE_CONTINUE:
-				if(instruction[i]->src[0].type != PARAMETER_CONSTBOOL)
+				if(inst->src[0].type != PARAMETER_CONSTBOOL)
 				{
 					dynamicBranching = true;
 				}
 
-				if(instruction[i]->opcode == OPCODE_LEAVE)
+				if(inst->opcode == OPCODE_LEAVE)
 				{
 					containsLeave = true;
 				}
 
-				if(instruction[i]->isBreak())
+				if(inst->isBreak())
 				{
 					containsBreak = true;
 				}
 
-				if(instruction[i]->opcode == OPCODE_CONTINUE)
+				if(inst->opcode == OPCODE_CONTINUE)
 				{
 					containsContinue = true;
 				}
@@ -1666,12 +1684,12 @@
 
 		for(unsigned int i = 0; i < instruction.size(); i++)
 		{
-			// If statements
-			if(instruction[i]->isBranch())
+			// If statements and loops
+			if(instruction[i]->isBranch() || instruction[i]->isLoop())
 			{
 				branchDepth++;
 			}
-			else if(instruction[i]->opcode == OPCODE_ENDIF)
+			else if(instruction[i]->opcode == OPCODE_ENDIF || instruction[i]->isEndLoop())
 			{
 				branchDepth--;
 			}
@@ -1779,36 +1797,36 @@
 	void Shader::markFunctionAnalysis(unsigned int functionLabel, Analysis flag)
 	{
 		bool marker = false;
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(auto &inst : instruction)
 		{
 			if(!marker)
 			{
-				if(instruction[i]->opcode == OPCODE_LABEL && instruction[i]->dst.label == functionLabel)
+				if(inst->opcode == OPCODE_LABEL && inst->dst.label == functionLabel)
 				{
 					marker = true;
 				}
 			}
 			else
 			{
-				if(instruction[i]->opcode == OPCODE_RET)
+				if(inst->opcode == OPCODE_RET)
 				{
 					break;
 				}
-				else if(instruction[i]->isCall())
+				else if(inst->isCall())
 				{
-					markFunctionAnalysis(instruction[i]->dst.label, flag);
+					markFunctionAnalysis(inst->dst.label, flag);
 				}
 
-				instruction[i]->analysis |= flag;
+				inst->analysis |= flag;
 			}
 		}
 	}
 
 	void Shader::analyzeSamplers()
 	{
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(const auto &inst : instruction)
 		{
-			switch(instruction[i]->opcode)
+			switch(inst->opcode)
 			{
 			case OPCODE_TEX:
 			case OPCODE_TEXBEM:
@@ -1824,15 +1842,17 @@
 			case OPCODE_TEXM3X2DEPTH:
 			case OPCODE_TEXLDD:
 			case OPCODE_TEXLDL:
+			case OPCODE_TEXLOD:
 			case OPCODE_TEXOFFSET:
-			case OPCODE_TEXLDLOFFSET:
+			case OPCODE_TEXOFFSETBIAS:
+			case OPCODE_TEXLODOFFSET:
 			case OPCODE_TEXELFETCH:
 			case OPCODE_TEXELFETCHOFFSET:
 			case OPCODE_TEXGRAD:
 			case OPCODE_TEXGRADOFFSET:
 				{
-					Parameter &dst = instruction[i]->dst;
-					Parameter &src1 = instruction[i]->src[1];
+					Parameter &dst = inst->dst;
+					Parameter &src1 = inst->src[1];
 
 					if(majorVersion >= 2)
 					{
@@ -1856,13 +1876,13 @@
 	{
 		int callSiteIndex[2048] = {0};
 
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(auto &inst : instruction)
 		{
-			if(instruction[i]->opcode == OPCODE_CALL || instruction[i]->opcode == OPCODE_CALLNZ)
+			if(inst->opcode == OPCODE_CALL || inst->opcode == OPCODE_CALLNZ)
 			{
-				int label = instruction[i]->dst.label;
+				int label = inst->dst.label;
 
-				instruction[i]->dst.callSite = callSiteIndex[label]++;
+				inst->dst.callSite = callSiteIndex[label]++;
 			}
 		}
 	}
@@ -1873,14 +1893,14 @@
 		dynamicallyIndexedInput = false;
 		dynamicallyIndexedOutput = false;
 
-		for(unsigned int i = 0; i < instruction.size(); i++)
+		for(const auto &inst : instruction)
 		{
-			if(instruction[i]->dst.rel.type == PARAMETER_ADDR ||
-			   instruction[i]->dst.rel.type == PARAMETER_LOOP ||
-			   instruction[i]->dst.rel.type == PARAMETER_TEMP ||
-			   instruction[i]->dst.rel.type == PARAMETER_CONST)
+			if(inst->dst.rel.type == PARAMETER_ADDR ||
+			   inst->dst.rel.type == PARAMETER_LOOP ||
+			   inst->dst.rel.type == PARAMETER_TEMP ||
+			   inst->dst.rel.type == PARAMETER_CONST)
 			{
-				switch(instruction[i]->dst.type)
+				switch(inst->dst.type)
 				{
 				case PARAMETER_TEMP:   dynamicallyIndexedTemporaries = true; break;
 				case PARAMETER_INPUT:  dynamicallyIndexedInput = true;       break;
@@ -1891,12 +1911,12 @@
 
 			for(int j = 0; j < 3; j++)
 			{
-				if(instruction[i]->src[j].rel.type == PARAMETER_ADDR ||
-				   instruction[i]->src[j].rel.type == PARAMETER_LOOP ||
-				   instruction[i]->src[j].rel.type == PARAMETER_TEMP ||
-				   instruction[i]->src[j].rel.type == PARAMETER_CONST)
+				if(inst->src[j].rel.type == PARAMETER_ADDR ||
+				   inst->src[j].rel.type == PARAMETER_LOOP ||
+				   inst->src[j].rel.type == PARAMETER_TEMP ||
+				   inst->src[j].rel.type == PARAMETER_CONST)
 				{
-					switch(instruction[i]->src[j].type)
+					switch(inst->src[j].type)
 					{
 					case PARAMETER_TEMP:   dynamicallyIndexedTemporaries = true; break;
 					case PARAMETER_INPUT:  dynamicallyIndexedInput = true;       break;
diff --git a/src/Shader/Shader.hpp b/src/Shader/Shader.hpp
index ee69e8b..6755cd4 100644
--- a/src/Shader/Shader.hpp
+++ b/src/Shader/Shader.hpp
@@ -118,7 +118,6 @@
 			OPCODE_CMP,   // D3DSIO_SETP
 			OPCODE_TEXLDL,
 			OPCODE_BREAKP,
-			OPCODE_TEXSIZE,
 
 			OPCODE_PHASE = 0xFFFD,
 			OPCODE_COMMENT = 0xFFFE,
@@ -207,11 +206,15 @@
 			OPCODE_ISNAN,
 			OPCODE_ISINF,
 			OPCODE_TEXOFFSET,
-			OPCODE_TEXLDLOFFSET,
+			OPCODE_TEXLODOFFSET,
 			OPCODE_TEXELFETCH,
 			OPCODE_TEXELFETCHOFFSET,
 			OPCODE_TEXGRAD,
 			OPCODE_TEXGRADOFFSET,
+			OPCODE_TEXBIAS,
+			OPCODE_TEXLOD,
+			OPCODE_TEXOFFSETBIAS,
+			OPCODE_TEXSIZE,
 			OPCODE_FLOATBITSTOINT,
 			OPCODE_FLOATBITSTOUINT,
 			OPCODE_INTBITSTOFLOAT,
@@ -393,6 +396,15 @@
 			ANALYSIS_LEAVE    = 0x00000008,
 		};
 
+		struct Relative
+		{
+			ParameterType type : 8;
+			unsigned int index;
+			unsigned int swizzle : 8;
+			unsigned int scale;
+			bool deterministic;   // Equal accross shader instances run in lockstep (e.g. unrollable loop couters)
+		};
+
 		struct Parameter
 		{
 			union
@@ -401,14 +413,7 @@
 				{
 					unsigned int index;   // For registers types
 
-					struct
-					{
-						ParameterType type : 8;
-						unsigned int index;
-						unsigned int swizzle : 8;
-						unsigned int scale;
-						bool deterministic;   // Equal accross shader instances run in lockstep (e.g. unrollable loop couters)
-					} rel;
+					Relative rel;
 				};
 
 				float value[4];       // For float constants
@@ -453,7 +458,7 @@
 				};
 			};
 
-			DestinationParameter() : mask(0xF), integer(false), saturate(false), partialPrecision(false), centroid(false), shift(0)
+			DestinationParameter() : mask(0xF), saturate(false), partialPrecision(false), centroid(false), shift(0)
 			{
 			}
 
@@ -461,7 +466,6 @@
 			std::string shiftString() const;
 			std::string maskString() const;
 
-			bool integer          : 1;
 			bool saturate         : 1;
 			bool partialPrecision : 1;
 			bool centroid         : 1;
@@ -474,6 +478,7 @@
 			{
 			}
 
+			std::string string(ShaderType shaderType, unsigned short version) const;
 			std::string swizzleString() const;
 			std::string preModifierString() const;
 			std::string postModifierString() const;
@@ -555,14 +560,14 @@
 		int getSerialID() const;
 		size_t getLength() const;
 		ShaderType getShaderType() const;
-		unsigned short getVersion() const;
+		unsigned short getShaderModel() const;
 
 		void append(Instruction *instruction);
 		void declareSampler(int i);
 
 		const Instruction *getInstruction(size_t i) const;
 		int size(unsigned long opcode) const;
-		static int size(unsigned long opcode, unsigned short version);
+		static int size(unsigned long opcode, unsigned short shaderModel);
 
 		void print(const char *fileName, ...) const;
 		void printInstruction(int index, const char *fileName) const;
@@ -629,7 +634,7 @@
 
 		union
 		{
-			unsigned short version;
+			unsigned short shaderModel;
 
 			struct
 			{
diff --git a/src/Shader/ShaderCore.cpp b/src/Shader/ShaderCore.cpp
index 5799d3f..883131c 100644
--- a/src/Shader/ShaderCore.cpp
+++ b/src/Shader/ShaderCore.cpp
@@ -114,35 +114,30 @@
 
 	Float4 exponential2(RValue<Float4> x, bool pp)
 	{
-		Float4 x0;
-		Float4 x1;
-		Int4 x2;
+		// This implementation is based on 2^(i + f) = 2^i * 2^f,
+		// where i is the integer part of x and f is the fraction.
 
-		x0 = x;
-
+		// For 2^i we can put the integer part directly in the exponent of
+		// the IEEE-754 floating-point number. Clamp to prevent overflow
+		// past the representation of infinity.
+		Float4 x0 = x;
 		x0 = Min(x0, As<Float4>(Int4(0x43010000)));   // 129.00000e+0f
 		x0 = Max(x0, As<Float4>(Int4(0xC2FDFFFF)));   // -126.99999e+0f
-		x1 = x0;
-		x1 -= Float4(0.5f);
-		x2 = RoundInt(x1);
-		x1 = Float4(x2);
-		x2 += Int4(0x0000007F);   // 127
-		x2 = x2 << 23;
-		x0 -= x1;
-		x1 = As<Float4>(Int4(0x3AF61905));   // 1.8775767e-3f
-		x1 *= x0;
-		x1 += As<Float4>(Int4(0x3C134806));   // 8.9893397e-3f
-		x1 *= x0;
-		x1 += As<Float4>(Int4(0x3D64AA23));   // 5.5826318e-2f
-		x1 *= x0;
-		x1 += As<Float4>(Int4(0x3E75EAD4));   // 2.4015361e-1f
-		x1 *= x0;
-		x1 += As<Float4>(Int4(0x3F31727B));   // 6.9315308e-1f
-		x1 *= x0;
-		x1 += As<Float4>(Int4(0x3F7FFFFF));   // 9.9999994e-1f
-		x1 *= As<Float4>(x2);
 
-		return x1;
+		Int4 i = RoundInt(x0 - Float4(0.5f));
+		Float4 ii = As<Float4>((i + Int4(127)) << 23);   // Add single-precision bias, and shift into exponent.
+
+		// For the fractional part use a polynomial
+		// which approximates 2^f in the 0 to 1 range.
+		Float4 f = x0 - Float4(i);
+		Float4 ff = As<Float4>(Int4(0x3AF61905));     // 1.8775767e-3f
+		ff = ff * f + As<Float4>(Int4(0x3C134806));   // 8.9893397e-3f
+		ff = ff * f + As<Float4>(Int4(0x3D64AA23));   // 5.5826318e-2f
+		ff = ff * f + As<Float4>(Int4(0x3E75EAD4));   // 2.4015361e-1f
+		ff = ff * f + As<Float4>(Int4(0x3F31727B));   // 6.9315308e-1f
+		ff = ff * f + Float4(1.0f);
+
+		return ii * ff;
 	}
 
 	Float4 logarithm2(RValue<Float4> x, bool absolute, bool pp)
@@ -166,13 +161,14 @@
 
 		x1 += (x0 - Float4(1.0f)) * x2;
 
-		return x1;
+		Int4 pos_inf_x = CmpEQ(As<Int4>(x), Int4(0x7F800000));
+		return As<Float4>((pos_inf_x & As<Int4>(x)) | (~pos_inf_x & As<Int4>(x1)));
 	}
 
 	Float4 exponential(RValue<Float4> x, bool pp)
 	{
 		// FIXME: Propagate the constant
-		return exponential2(Float4(1.44269541f) * x, pp);   // 1/ln(2)
+		return exponential2(Float4(1.44269504f) * x, pp);   // 1/ln(2)
 	}
 
 	Float4 logarithm(RValue<Float4> x, bool absolute, bool pp)
@@ -226,7 +222,7 @@
 
 		Float4 rsq;
 
-		if(!pp && rsqPrecision >= IEEE)
+		if(!pp)
 		{
 			rsq = Float4(1.0f) / Sqrt(abs);
 		}
@@ -238,10 +234,9 @@
 			{
 				rsq = rsq * (Float4(3.0f) - rsq * rsq * abs) * Float4(0.5f);
 			}
-		}
 
-		int big = 0x7F7FFFFF;
-		rsq = Min(rsq, Float4((float&)big));
+			rsq = As<Float4>(CmpNEQ(As<Int4>(abs), Int4(0x7F800000)) & As<Int4>(rsq));
+		}
 
 		return rsq;
 	}
@@ -287,6 +282,21 @@
 		Float4 y = x * Float4(1.59154943e-1f);   // 1/2pi
 		y = y - Round(y);
 
+		if(!pp)
+		{
+			// From the paper: "A Fast, Vectorizable Algorithm for Producing Single-Precision Sine-Cosine Pairs"
+			// This implementation passes OpenGL ES 3.0 precision requirements, at the cost of more operations:
+			// !pp : 17 mul, 7 add, 1 sub, 1 reciprocal
+			//  pp : 4 mul, 2 add, 2 abs
+
+			Float4 y2 = y * y;
+			Float4 c1 = y2 * (y2 * (y2 * Float4(-0.0204391631f) + Float4(0.2536086171f)) + Float4(-1.2336977925f)) + Float4(1.0f);
+			Float4 s1 = y * (y2 * (y2 * (y2 * Float4(-0.0046075748f) + Float4(0.0796819754f)) + Float4(-0.645963615f)) + Float4(1.5707963235f));
+			Float4 c2 = (c1 * c1) - (s1 * s1);
+			Float4 s2 = Float4(2.0f) * s1 * c1;
+			return Float4(2.0f) * s2 * c2 * reciprocal(s2 * s2 + c2 * c2, pp, true);
+		}
+
 		const Float4 A = Float4(-16.0f);
 		const Float4 B = Float4(8.0f);
 		const Float4 C = Float4(7.75160950e-1f);
@@ -324,51 +334,95 @@
 
 	Float4 arcsin(RValue<Float4> x, bool pp)
 	{
-		// x*(pi/2-sqrt(1-x*x)*pi/5)
-		return x * (Float4(1.57079632e+0f) - Sqrt(Float4(1.0f) - x*x) * Float4(6.28318531e-1f));
+		if(false) // Simpler implementation fails even lowp precision tests
+		{
+			// x*(pi/2-sqrt(1-x*x)*pi/5)
+			return x * (Float4(1.57079632e+0f) - Sqrt(Float4(1.0f) - x*x) * Float4(6.28318531e-1f));
+		}
+		else
+		{
+			// From 4.4.45, page 81 of the Handbook of Mathematical Functions, by Milton Abramowitz and Irene Stegun
+			const Float4 half_pi(1.57079632f);
+			const Float4 a0(1.5707288f);
+			const Float4 a1(-0.2121144f);
+			const Float4 a2(0.0742610f);
+			const Float4 a3(-0.0187293f);
+			Float4 absx = Abs(x);
+			return As<Float4>(As<Int4>(half_pi - Sqrt(Float4(1.0f) - absx) * (a0 + absx * (a1 + absx * (a2 + absx * a3)))) ^
+			       (As<Int4>(x) & Int4(0x80000000)));
+		}
+	}
+
+	// Approximation of atan in [0..1]
+	Float4 arctan_01(Float4 x, bool pp)
+	{
+		if(pp)
+		{
+			return x * (Float4(-0.27f) * x + Float4(1.05539816f));
+		}
+		else
+		{
+			// From 4.4.49, page 81 of the Handbook of Mathematical Functions, by Milton Abramowitz and Irene Stegun
+			const Float4 a2(-0.3333314528f);
+			const Float4 a4(0.1999355085f);
+			const Float4 a6(-0.1420889944f);
+			const Float4 a8(0.1065626393f);
+			const Float4 a10(-0.0752896400f);
+			const Float4 a12(0.0429096138f);
+			const Float4 a14(-0.0161657367f);
+			const Float4 a16(0.0028662257f);
+			Float4 x2 = x * x;
+			return (x + x * (x2 * (a2 + x2 * (a4 + x2 * (a6 + x2 * (a8 + x2 * (a10 + x2 * (a12 + x2 * (a14 + x2 * a16)))))))));
+		}
 	}
 
 	Float4 arctan(RValue<Float4> x, bool pp)
 	{
-		Int4 O = CmpNLT(Abs(x), Float4(1.0f));
-		Float4 y = As<Float4>((O & As<Int4>(Float4(1.0f) / x)) | (~O & As<Int4>(x)));   // FIXME: Vector select
+		Float4 absx = Abs(x);
+		Int4 O = CmpNLT(absx, Float4(1.0f));
+		Float4 y = As<Float4>((O & As<Int4>(Float4(1.0f) / absx)) | (~O & As<Int4>(absx))); // FIXME: Vector select
 
-		// Approximation of atan in [-1..1]
-		Float4 theta = y * (Float4(-0.27f) * Abs(y) + Float4(1.05539816f));
-
-		// +/-pi/2 depending on sign of x
-		Float4 sgnPi_2 = As<Float4>(As<Int4>(Float4(1.57079632e+0f)) ^ (As<Int4>(x) & Int4(0x80000000)));
-
-		theta = As<Float4>((O & As<Int4>(sgnPi_2 - theta)) | (~O & As<Int4>(theta)));   // FIXME: Vector select
-
-		return theta;
+		const Float4 half_pi(1.57079632f);
+		Float4 theta = arctan_01(y, pp);
+		return As<Float4>(((O & As<Int4>(half_pi - theta)) | (~O & As<Int4>(theta))) ^ // FIXME: Vector select
+		       (As<Int4>(x) & Int4(0x80000000)));
 	}
 
 	Float4 arctan(RValue<Float4> y, RValue<Float4> x, bool pp)
 	{
+		const Float4 pi(3.14159265f);            // pi
+		const Float4 minus_pi(-3.14159265f);     // -pi
+		const Float4 half_pi(1.57079632f);       // pi/2
+		const Float4 quarter_pi(7.85398163e-1f); // pi/4
+
 		// Rotate to upper semicircle when in lower semicircle
 		Int4 S = CmpLT(y, Float4(0.0f));
-		Float4 theta = As<Float4>(S & As<Int4>(Float4(-3.14159265e+0f)));   // -pi
+		Float4 theta = As<Float4>(S & As<Int4>(minus_pi));
 		Float4 x0 = As<Float4>((As<Int4>(y) & Int4(0x80000000)) ^ As<Int4>(x));
 		Float4 y0 = Abs(y);
 
 		// Rotate to right quadrant when in left quadrant
-		Int4 Q = CmpLT(x0, Float4(0.0f));
-		theta += As<Float4>(Q & As<Int4>(Float4(1.57079632e+0f)));   // pi/2
-		Float4 x1 = As<Float4>((Q & As<Int4>(y0)) | (~Q & As<Int4>(x0)));    // FIXME: Vector select
-		Float4 y1 = As<Float4>((Q & As<Int4>(-x0)) | (~Q & As<Int4>(y0)));   // FIXME: Vector select
+		Int4 non_zero_y = CmpNEQ(y0, Float4(0.0f));
+		Int4 Q = CmpLT(x0, Float4(0.0f)) & non_zero_y;
+		theta += As<Float4>(Q & As<Int4>(half_pi));
+		Float4 x1 = As<Float4>((Q & As<Int4>(y0)) | (~Q & As<Int4>(x0)));  // FIXME: Vector select
+		Float4 y1 = As<Float4>((Q & As<Int4>(-x0)) | (~Q & As<Int4>(y0))); // FIXME: Vector select
 
-		// Rotate to first octant when in second octant
-		Int4 O = CmpNLT(y1, x1);
-		theta += As<Float4>(O & As<Int4>(Float4(7.85398163e-1f)));   // pi/4
-		Float4 x2 = As<Float4>((O & As<Int4>(Float4(7.07106781e-1f) * x1 + Float4(7.07106781e-1f) * y1)) | (~O & As<Int4>(x1)));   // sqrt(2)/2   // FIXME: Vector select
-		Float4 y2 = As<Float4>((O & As<Int4>(Float4(7.07106781e-1f) * y1 - Float4(7.07106781e-1f) * x1)) | (~O & As<Int4>(y1)));   // FIXME: Vector select
+		// Mirror to first octant when in second octant
+		Int4 O = CmpNLT(y1, x1) & non_zero_y;
+		Float4 x2 = As<Float4>((O & As<Int4>(y1)) | (~O & As<Int4>(x1))); // FIXME: Vector select
+		Float4 y2 = As<Float4>((O & As<Int4>(x1)) | (~O & As<Int4>(y1))); // FIXME: Vector select
 
 		// Approximation of atan in [0..1]
-		Float4 y_x = y2 / x2;
-		theta += y_x * (Float4(-0.27f) * y_x + Float4(1.05539816f));
+		Int4 zero_x = CmpEQ(x2, Float4(0.0f));
+		Int4 inf_y = IsInf(y2); // Since x2 >= y2, this means x2 == y2 == inf, so we use 45 degrees or pi/4
+		Float4 atan2_theta = arctan_01(y2 / x2, pp);
+		theta += As<Float4>((~zero_x & ~inf_y & non_zero_y & ((O & As<Int4>(half_pi - atan2_theta)) | (~O & (As<Int4>(atan2_theta))))) | // FIXME: Vector select
+		                    (inf_y & As<Int4>(quarter_pi)));
 
-		return theta;
+		// Recover loss of precision for tiny theta angles
+		Int4 precision_loss = S & Q & O & ~inf_y; // This combination results in (-pi + half_pi + half_pi - atan2_theta) which is equivalent to -atan2_theta
+		return As<Float4>((precision_loss & As<Int4>(-atan2_theta)) | (~precision_loss & As<Int4>(theta))); // FIXME: Vector select
 	}
 
 	Float4 sineh(RValue<Float4> x, bool pp)
@@ -431,6 +485,18 @@
 		row3 = UnpackHigh(tmp0, tmp1);
 	}
 
+	void transpose4x3(Short4 &row0, Short4 &row1, Short4 &row2, Short4 &row3)
+	{
+		Int2 tmp0 = UnpackHigh(row0, row1);
+		Int2 tmp1 = UnpackHigh(row2, row3);
+		Int2 tmp2 = UnpackLow(row0, row1);
+		Int2 tmp3 = UnpackLow(row2, row3);
+
+		row0 = UnpackLow(tmp2, tmp3);
+		row1 = UnpackHigh(tmp2, tmp3);
+		row2 = UnpackLow(tmp0, tmp1);
+	}
+
 	void transpose4x4(Float4 &row0, Float4 &row1, Float4 &row2, Float4 &row3)
 	{
 		Float4 tmp0 = UnpackLow(row0, row1);
@@ -656,7 +722,7 @@
 
 	void ShaderCore::rcpx(Vector4f &dst, const Vector4f &src, bool pp)
 	{
-		Float4 rcp = reciprocal(src.x, pp, true);
+		Float4 rcp = reciprocal(src.x, pp, true, true);
 
 		dst.x = rcp;
 		dst.y = rcp;
@@ -708,24 +774,27 @@
 
 	void ShaderCore::imod(Vector4f &dst, const Vector4f &src0, const Vector4f &src1)
 	{
-		cmp0i(dst.x, src1.x, src0.x, src1.x);
+		Float4 intMax(As<Float4>(Int4(INT_MAX)));
+		cmp0i(dst.x, src1.x, intMax, src1.x);
 		dst.x = As<Float4>(As<Int4>(src0.x) % As<Int4>(dst.x));
-		cmp0i(dst.y, src1.y, src0.y, src1.y);
+		cmp0i(dst.y, src1.y, intMax, src1.y);
 		dst.y = As<Float4>(As<Int4>(src0.y) % As<Int4>(dst.y));
-		cmp0i(dst.z, src1.z, src0.z, src1.z);
+		cmp0i(dst.z, src1.z, intMax, src1.z);
 		dst.z = As<Float4>(As<Int4>(src0.z) % As<Int4>(dst.z));
-		cmp0i(dst.w, src1.w, src0.w, src1.w);
+		cmp0i(dst.w, src1.w, intMax, src1.w);
 		dst.w = As<Float4>(As<Int4>(src0.w) % As<Int4>(dst.w));
 	}
+
 	void ShaderCore::umod(Vector4f &dst, const Vector4f &src0, const Vector4f &src1)
 	{
-		cmp0i(dst.x, src1.x, src0.x, src1.x);
+		Float4 uintMax(As<Float4>(UInt4(UINT_MAX)));
+		cmp0i(dst.x, src1.x, uintMax, src1.x);
 		dst.x = As<Float4>(As<UInt4>(src0.x) % As<UInt4>(dst.x));
-		cmp0i(dst.y, src1.y, src0.y, src1.y);
+		cmp0i(dst.y, src1.y, uintMax, src1.y);
 		dst.y = As<Float4>(As<UInt4>(src0.y) % As<UInt4>(dst.y));
-		cmp0i(dst.z, src1.z, src0.z, src1.z);
+		cmp0i(dst.z, src1.z, uintMax, src1.z);
 		dst.z = As<Float4>(As<UInt4>(src0.z) % As<UInt4>(dst.z));
-		cmp0i(dst.w, src1.w, src0.w, src1.w);
+		cmp0i(dst.w, src1.w, uintMax, src1.w);
 		dst.w = As<Float4>(As<UInt4>(src0.w) % As<UInt4>(dst.w));
 	}
 
@@ -1027,6 +1096,22 @@
 		dst.w = src0.w * (src1.w - src2.w) + src2.w;
 	}
 
+	void ShaderCore::isinf(Vector4f &dst, const Vector4f &src)
+	{
+		dst.x = As<Float4>(IsInf(src.x));
+		dst.y = As<Float4>(IsInf(src.y));
+		dst.z = As<Float4>(IsInf(src.z));
+		dst.w = As<Float4>(IsInf(src.w));
+	}
+
+	void ShaderCore::isnan(Vector4f &dst, const Vector4f &src)
+	{
+		dst.x = As<Float4>(IsNan(src.x));
+		dst.y = As<Float4>(IsNan(src.y));
+		dst.z = As<Float4>(IsNan(src.z));
+		dst.w = As<Float4>(IsNan(src.w));
+	}
+
 	void ShaderCore::smooth(Vector4f &dst, const Vector4f &edge0, const Vector4f &edge1, const Vector4f &x)
 	{
 		Float4 tx = Min(Max((x.x - edge0.x) / (edge1.x - edge0.x), Float4(0.0f)), Float4(1.0f)); dst.x = tx * tx * (Float4(3.0f) - Float4(2.0f) * tx);
@@ -1515,9 +1600,9 @@
 		dst.w = arctanh(src.w, pp);
 	}
 
-	void ShaderCore::expp(Vector4f &dst, const Vector4f &src, unsigned short version)
+	void ShaderCore::expp(Vector4f &dst, const Vector4f &src, unsigned short shaderModel)
 	{
-		if(version < 0x0200)
+		if(shaderModel < 0x0200)
 		{
 			Float4 frc = Frac(src.x);
 			Float4 floor = src.x - frc;
@@ -1533,9 +1618,9 @@
 		}
 	}
 
-	void ShaderCore::logp(Vector4f &dst, const Vector4f &src, unsigned short version)
+	void ShaderCore::logp(Vector4f &dst, const Vector4f &src, unsigned short shaderModel)
 	{
-		if(version < 0x0200)
+		if(shaderModel < 0x0200)
 		{
 			Float4 tmp0;
 			Float4 tmp1;
diff --git a/src/Shader/ShaderCore.hpp b/src/Shader/ShaderCore.hpp
index c7b8be4..249e058 100644
--- a/src/Shader/ShaderCore.hpp
+++ b/src/Shader/ShaderCore.hpp
@@ -15,9 +15,9 @@
 #ifndef sw_ShaderCore_hpp
 #define sw_ShaderCore_hpp
 
-#include "Debug.hpp"
 #include "Shader.hpp"
 #include "Reactor/Reactor.hpp"
+#include "Common/Debug.hpp"
 
 namespace sw
 {
@@ -82,6 +82,7 @@
 	Float4 dot4(const Vector4f &v0, const Vector4f &v1);
 
 	void transpose4x4(Short4 &row0, Short4 &row1, Short4 &row2, Short4 &row3);
+	void transpose4x3(Short4 &row0, Short4 &row1, Short4 &row2, Short4 &row3);
 	void transpose4x4(Float4 &row0, Float4 &row1, Float4 &row2, Float4 &row3);
 	void transpose4x3(Float4 &row0, Float4 &row1, Float4 &row2, Float4 &row3);
 	void transpose4x2(Float4 &row0, Float4 &row1, Float4 &row2, Float4 &row3);
@@ -282,6 +283,8 @@
 		void lit(Vector4f &dst, const Vector4f &src);
 		void att(Vector4f &dst, const Vector4f &src0, const Vector4f &src1);
 		void lrp(Vector4f &dst, const Vector4f &src0, const Vector4f &src1, const Vector4f &src2);
+		void isinf(Vector4f &dst, const Vector4f &src);
+		void isnan(Vector4f &dst, const Vector4f &src);
 		void smooth(Vector4f &dst, const Vector4f &src0, const Vector4f &src1, const Vector4f &src2);
 		void packHalf2x16(Vector4f &dst, const Vector4f &src);
 		void unpackHalf2x16(Vector4f &dst, const Vector4f &src);
@@ -331,8 +334,8 @@
 		void acosh(Vector4f &dst, const Vector4f &src, bool pp = false);
 		void asinh(Vector4f &dst, const Vector4f &src, bool pp = false);
 		void atanh(Vector4f &dst, const Vector4f &src, bool pp = false);
-		void expp(Vector4f &dst, const Vector4f &src, unsigned short version);
-		void logp(Vector4f &dst, const Vector4f &src, unsigned short version);
+		void expp(Vector4f &dst, const Vector4f &src, unsigned short shaderModel);
+		void logp(Vector4f &dst, const Vector4f &src, unsigned short shaderModel);
 		void cmp0(Vector4f &dst, const Vector4f &src0, const Vector4f &src1, const Vector4f &src2);
 		void cmp(Vector4f &dst, const Vector4f &src0, const Vector4f &src1, Control control);
 		void icmp(Vector4f &dst, const Vector4f &src0, const Vector4f &src1, Control control);
diff --git a/src/Shader/VertexPipeline.cpp b/src/Shader/VertexPipeline.cpp
index 8792884..129d8a8 100644
--- a/src/Shader/VertexPipeline.cpp
+++ b/src/Shader/VertexPipeline.cpp
@@ -14,9 +14,9 @@
 
 #include "VertexPipeline.hpp"
 
-#include "Vertex.hpp"
-#include "Renderer.hpp"
-#include "Debug.hpp"
+#include "Renderer/Vertex.hpp"
+#include "Renderer/Renderer.hpp"
+#include "Common/Debug.hpp"
 
 #include <string.h>
 #include <stdlib.h>
diff --git a/src/Shader/VertexPipeline.hpp b/src/Shader/VertexPipeline.hpp
index e3c0cbe..0736afb 100644
--- a/src/Shader/VertexPipeline.hpp
+++ b/src/Shader/VertexPipeline.hpp
@@ -17,8 +17,8 @@
 
 #include "VertexRoutine.hpp"
 
-#include "Context.hpp"
-#include "VertexProcessor.hpp"
+#include "Renderer/Context.hpp"
+#include "Renderer/VertexProcessor.hpp"
 
 namespace sw
 {
diff --git a/src/Shader/VertexProgram.cpp b/src/Shader/VertexProgram.cpp
index c9ed8aa..4f8ba1a 100644
--- a/src/Shader/VertexProgram.cpp
+++ b/src/Shader/VertexProgram.cpp
@@ -14,12 +14,12 @@
 
 #include "VertexProgram.hpp"
 
-#include "Renderer.hpp"
 #include "VertexShader.hpp"
-#include "Vertex.hpp"
-#include "Half.hpp"
 #include "SamplerCore.hpp"
-#include "Debug.hpp"
+#include "Renderer/Renderer.hpp"
+#include "Renderer/Vertex.hpp"
+#include "Common/Half.hpp"
+#include "Common/Debug.hpp"
 
 namespace sw
 {
@@ -28,7 +28,6 @@
 	{
 		ifDepth = 0;
 		loopRepDepth = 0;
-		breakDepth = 0;
 		currentLabel = -1;
 		whileTest = false;
 
@@ -40,12 +39,12 @@
 		loopDepth = -1;
 		enableStack[0] = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 
-		if(shader && shader->containsBreakInstruction())
+		if(shader->containsBreakInstruction())
 		{
 			enableBreak = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 		}
 
-		if(shader && shader->containsContinueInstruction())
+		if(shader->containsContinueInstruction())
 		{
 			enableContinue = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 		}
@@ -58,19 +57,10 @@
 
 	VertexProgram::~VertexProgram()
 	{
-		for(int i = 0; i < VERTEX_TEXTURE_IMAGE_UNITS; i++)
-		{
-			delete sampler[i];
-		}
 	}
 
 	void VertexProgram::pipeline(UInt& index)
 	{
-		for(int i = 0; i < VERTEX_TEXTURE_IMAGE_UNITS; i++)
-		{
-			sampler[i] = new SamplerCore(constants, state.samplerState[i]);
-		}
-
 		if(!state.preTransformed)
 		{
 			program(index);
@@ -85,7 +75,7 @@
 	{
 	//	shader->print("VertexShader-%0.8X.txt", state.shaderID);
 
-		unsigned short version = shader->getVersion();
+		unsigned short shaderModel = shader->getShaderModel();
 
 		enableIndex = 0;
 		stackIndex = 0;
@@ -201,7 +191,7 @@
 			case Shader::OPCODE_ATT:        att(d, s0, s1);                 break;
 			case Shader::OPCODE_EXP2X:      exp2x(d, s0, pp);               break;
 			case Shader::OPCODE_EXP2:       exp2(d, s0, pp);                break;
-			case Shader::OPCODE_EXPP:       expp(d, s0, version);           break;
+			case Shader::OPCODE_EXPP:       expp(d, s0, shaderModel);       break;
 			case Shader::OPCODE_EXP:        exp(d, s0, pp);                 break;
 			case Shader::OPCODE_FRC:        frc(d, s0);                     break;
 			case Shader::OPCODE_TRUNC:      trunc(d, s0);                   break;
@@ -212,11 +202,13 @@
 			case Shader::OPCODE_LIT:        lit(d, s0);                     break;
 			case Shader::OPCODE_LOG2X:      log2x(d, s0, pp);               break;
 			case Shader::OPCODE_LOG2:       log2(d, s0, pp);                break;
-			case Shader::OPCODE_LOGP:       logp(d, s0, version);           break;
+			case Shader::OPCODE_LOGP:       logp(d, s0, shaderModel);       break;
 			case Shader::OPCODE_LOG:        log(d, s0, pp);                 break;
 			case Shader::OPCODE_LRP:        lrp(d, s0, s1, s2);             break;
 			case Shader::OPCODE_STEP:       step(d, s0, s1);                break;
 			case Shader::OPCODE_SMOOTH:     smooth(d, s0, s1, s2);          break;
+			case Shader::OPCODE_ISINF:      isinf(d, s0);                   break;
+			case Shader::OPCODE_ISNAN:      isnan(d, s0);                   break;
 			case Shader::OPCODE_FLOATBITSTOINT:
 			case Shader::OPCODE_FLOATBITSTOUINT:
 			case Shader::OPCODE_INTBITSTOFLOAT:
@@ -335,14 +327,15 @@
 			case Shader::OPCODE_AND:        bitwise_and(d, s0, s1);         break;
 			case Shader::OPCODE_EQ:         equal(d, s0, s1);               break;
 			case Shader::OPCODE_NE:         notEqual(d, s0, s1);            break;
-			case Shader::OPCODE_TEXLDL:     TEXLDL(d, s0, src1);            break;
+			case Shader::OPCODE_TEXLDL:     TEXLOD(d, s0, src1, s0.w);      break;
+			case Shader::OPCODE_TEXLOD:     TEXLOD(d, s0, src1, s2.x);      break;
 			case Shader::OPCODE_TEX:        TEX(d, s0, src1);               break;
 			case Shader::OPCODE_TEXOFFSET:  TEXOFFSET(d, s0, src1, s2);     break;
-			case Shader::OPCODE_TEXLDLOFFSET: TEXLDL(d, s0, src1, s2);      break;
-			case Shader::OPCODE_TEXELFETCH: TEXELFETCH(d, s0, src1);        break;
-			case Shader::OPCODE_TEXELFETCHOFFSET: TEXELFETCH(d, s0, src1, s2); break;
+			case Shader::OPCODE_TEXLODOFFSET: TEXLODOFFSET(d, s0, src1, s2, s3.x); break;
+			case Shader::OPCODE_TEXELFETCH: TEXELFETCH(d, s0, src1, s2.x);  break;
+			case Shader::OPCODE_TEXELFETCHOFFSET: TEXELFETCHOFFSET(d, s0, src1, s2, s3.x); break;
 			case Shader::OPCODE_TEXGRAD:    TEXGRAD(d, s0, src1, s2, s3);   break;
-			case Shader::OPCODE_TEXGRADOFFSET: TEXGRAD(d, s0, src1, s2, s3, s4); break;
+			case Shader::OPCODE_TEXGRADOFFSET: TEXGRADOFFSET(d, s0, src1, s2, s3, s4); break;
 			case Shader::OPCODE_TEXSIZE:    TEXSIZE(d, s0.x, src1);         break;
 			case Shader::OPCODE_END:                                        break;
 			default:
@@ -351,21 +344,6 @@
 
 			if(dst.type != Shader::PARAMETER_VOID && dst.type != Shader::PARAMETER_LABEL && opcode != Shader::OPCODE_NOP)
 			{
-				if(dst.integer)
-				{
-					switch(opcode)
-					{
-					case Shader::OPCODE_DIV:
-						if(dst.x) d.x = Trunc(d.x);
-						if(dst.y) d.y = Trunc(d.y);
-						if(dst.z) d.z = Trunc(d.z);
-						if(dst.w) d.w = Trunc(d.w);
-						break;
-					default:
-						break;   // No truncation to integer required when arguments are integer
-					}
-				}
-
 				if(dst.saturate)
 				{
 					if(dst.x) d.x = Max(d.x, Float4(0.0f));
@@ -432,7 +410,7 @@
 						break;
 					case Shader::PARAMETER_TEXCRDOUT:
 				//	case Shader::PARAMETER_OUTPUT:
-						if(version < 0x0300)
+						if(shaderModel < 0x0300)
 						{
 							if(dst.x) pDst.x = o[T0 + dst.index].x;
 							if(dst.y) pDst.y = o[T0 + dst.index].y;
@@ -563,7 +541,7 @@
 					break;
 				case Shader::PARAMETER_TEXCRDOUT:
 			//	case Shader::PARAMETER_OUTPUT:
-					if(version < 0x0300)
+					if(shaderModel < 0x0300)
 					{
 						if(dst.x) o[T0 + dst.index].x = d.x;
 						if(dst.y) o[T0 + dst.index].y = d.y;
@@ -1032,25 +1010,7 @@
 
 	void VertexProgram::BREAK()
 	{
-		BasicBlock *deadBlock = Nucleus::createBasicBlock();
-		BasicBlock *endBlock = loopRepEndBlock[loopRepDepth - 1];
-
-		if(breakDepth == 0)
-		{
-			enableIndex = enableIndex - breakDepth;
-			Nucleus::createBr(endBlock);
-		}
-		else
-		{
-			enableBreak = enableBreak & ~enableStack[enableIndex];
-			Bool allBreak = SignMask(enableBreak) == 0x0;
-
-			enableIndex = enableIndex - breakDepth;
-			branch(allBreak, endBlock, deadBlock);
-		}
-
-		Nucleus::setInsertBlock(deadBlock);
-		enableIndex = enableIndex + breakDepth;
+		enableBreak = enableBreak & ~enableStack[enableIndex];
 	}
 
 	void VertexProgram::BREAKC(Vector4f &src0, Vector4f &src1, Control control)
@@ -1059,12 +1019,12 @@
 
 		switch(control)
 		{
-		case Shader::CONTROL_GT: condition = CmpNLE(src0.x,  src1.x);	break;
-		case Shader::CONTROL_EQ: condition = CmpEQ(src0.x, src1.x);		break;
-		case Shader::CONTROL_GE: condition = CmpNLT(src0.x, src1.x);	break;
-		case Shader::CONTROL_LT: condition = CmpLT(src0.x,  src1.x);	break;
-		case Shader::CONTROL_NE: condition = CmpNEQ(src0.x, src1.x);	break;
-		case Shader::CONTROL_LE: condition = CmpLE(src0.x, src1.x);		break;
+		case Shader::CONTROL_GT: condition = CmpNLE(src0.x, src1.x); break;
+		case Shader::CONTROL_EQ: condition = CmpEQ(src0.x, src1.x);  break;
+		case Shader::CONTROL_GE: condition = CmpNLT(src0.x, src1.x); break;
+		case Shader::CONTROL_LT: condition = CmpLT(src0.x, src1.x);  break;
+		case Shader::CONTROL_NE: condition = CmpNEQ(src0.x, src1.x); break;
+		case Shader::CONTROL_LE: condition = CmpLE(src0.x, src1.x);  break;
 		default:
 			ASSERT(false);
 		}
@@ -1088,17 +1048,7 @@
 	{
 		condition &= enableStack[enableIndex];
 
-		BasicBlock *continueBlock = Nucleus::createBasicBlock();
-		BasicBlock *endBlock = loopRepEndBlock[loopRepDepth - 1];
-
 		enableBreak = enableBreak & ~condition;
-		Bool allBreak = SignMask(enableBreak) == 0x0;
-
-		enableIndex = enableIndex - breakDepth;
-		branch(allBreak, endBlock, continueBlock);
-
-		Nucleus::setInsertBlock(continueBlock);
-		enableIndex = enableIndex + breakDepth;
 	}
 
 	void VertexProgram::CONTINUE()
@@ -1242,7 +1192,6 @@
 
 		if(isConditionalIf[ifDepth])
 		{
-			breakDepth--;
 			enableIndex--;
 		}
 	}
@@ -1288,7 +1237,6 @@
 		Nucleus::setInsertBlock(endBlock);
 
 		enableIndex--;
-		enableBreak = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 		whileTest = false;
 	}
 
@@ -1298,11 +1246,8 @@
 
 		BasicBlock *endBlock = loopRepEndBlock[loopRepDepth];
 
-		Nucleus::createBr(loopRepEndBlock[loopRepDepth]);
+		Nucleus::createBr(endBlock);
 		Nucleus::setInsertBlock(endBlock);
-
-		enableIndex--;
-		enableBreak = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 	}
 
 	void VertexProgram::IF(const Src &src)
@@ -1362,12 +1307,12 @@
 
 		switch(control)
 		{
-		case Shader::CONTROL_GT: condition = CmpNLE(src0.x,  src1.x);	break;
-		case Shader::CONTROL_EQ: condition = CmpEQ(src0.x, src1.x);		break;
-		case Shader::CONTROL_GE: condition = CmpNLT(src0.x, src1.x);	break;
-		case Shader::CONTROL_LT: condition = CmpLT(src0.x,  src1.x);	break;
-		case Shader::CONTROL_NE: condition = CmpNEQ(src0.x, src1.x);	break;
-		case Shader::CONTROL_LE: condition = CmpLE(src0.x, src1.x);		break;
+		case Shader::CONTROL_GT: condition = CmpNLE(src0.x, src1.x); break;
+		case Shader::CONTROL_EQ: condition = CmpEQ(src0.x, src1.x);  break;
+		case Shader::CONTROL_GE: condition = CmpNLT(src0.x, src1.x); break;
+		case Shader::CONTROL_LT: condition = CmpLT(src0.x, src1.x);  break;
+		case Shader::CONTROL_NE: condition = CmpNEQ(src0.x, src1.x); break;
+		case Shader::CONTROL_LE: condition = CmpLE(src0.x, src1.x);  break;
 		default:
 			ASSERT(false);
 		}
@@ -1393,7 +1338,6 @@
 		ifFalseBlock[ifDepth] = falseBlock;
 
 		ifDepth++;
-		breakDepth++;
 	}
 
 	void VertexProgram::LABEL(int labelIndex)
@@ -1438,7 +1382,6 @@
 		iteration[loopDepth] = iteration[loopDepth] - 1;   // FIXME: --
 
 		loopRepDepth++;
-		breakDepth = 0;
 	}
 
 	void VertexProgram::REP(const Src &integerRegister)
@@ -1465,7 +1408,6 @@
 		iteration[loopDepth] = iteration[loopDepth] - 1;   // FIXME: --
 
 		loopRepDepth++;
-		breakDepth = 0;
 	}
 
 	void VertexProgram::WHILE(const Src &temporaryRegister)
@@ -1482,7 +1424,7 @@
 		Int4 restoreBreak = enableBreak;
 		Int4 restoreContinue = enableContinue;
 
-		// FIXME: jump(testBlock)
+		// TODO: jump(testBlock)
 		Nucleus::createBr(testBlock);
 		Nucleus::setInsertBlock(testBlock);
 		enableContinue = restoreContinue;
@@ -1491,6 +1433,7 @@
 		Int4 condition = As<Int4>(src.x);
 		condition &= enableStack[enableIndex - 1];
 		if(shader->containsLeaveInstruction()) condition &= enableLeave;
+		if(shader->containsBreakInstruction()) condition &= enableBreak;
 		enableStack[enableIndex] = condition;
 
 		Bool notAllFalse = SignMask(condition) != 0;
@@ -1502,21 +1445,25 @@
 		Nucleus::setInsertBlock(loopBlock);
 
 		loopRepDepth++;
-		breakDepth = 0;
 	}
 
 	void VertexProgram::SWITCH()
 	{
-		enableIndex++;
-		enableStack[enableIndex] = Int4(0xFFFFFFFF);
-
 		BasicBlock *endBlock = Nucleus::createBasicBlock();
 
 		loopRepTestBlock[loopRepDepth] = nullptr;
 		loopRepEndBlock[loopRepDepth] = endBlock;
 
+		Int4 restoreBreak = enableBreak;
+
+		BasicBlock *currentBlock = Nucleus::getInsertBlock();
+
+		Nucleus::setInsertBlock(endBlock);
+		enableBreak = restoreBreak;
+
+		Nucleus::setInsertBlock(currentBlock);
+
 		loopRepDepth++;
-		breakDepth = 0;
 	}
 
 	void VertexProgram::RET()
@@ -1565,62 +1512,59 @@
 		// FIXME: Use enableLeave in other control-flow constructs
 	}
 
-	void VertexProgram::TEXLDL(Vector4f &dst, Vector4f &src0, const Src &src1)
-	{
-		sampleTexture(dst, src1, src0, a0, a0, src0, Lod);
-	}
-
 	void VertexProgram::TEX(Vector4f &dst, Vector4f &src0, const Src &src1)
 	{
-		src0.w = Float(0.0f);
-		sampleTexture(dst, src1, src0, a0, a0, src0, Lod);
+		dst = sampleTexture(src1, src0, (src0.x), (src0), (src0), (src0), Base);
 	}
 
-	void VertexProgram::TEXOFFSET(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &src2)
+	void VertexProgram::TEXOFFSET(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &offset)
 	{
-		src0.w = Float(0.0f);
-		sampleTexture(dst, src1, src0, a0, a0, src2, {Lod, Offset});
+		dst = sampleTexture(src1, src0, (src0.x), (src0), (src0), offset, {Base, Offset});
 	}
 
-	void VertexProgram::TEXLDL(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &offset)
+	void VertexProgram::TEXLOD(Vector4f &dst, Vector4f &src0, const Src& src1, Float4 &lod)
 	{
-		sampleTexture(dst, src1, src0, a0, a0, offset, {Lod, Offset});
+		dst = sampleTexture(src1, src0, lod, (src0), (src0), (src0), Lod);
 	}
 
-	void VertexProgram::TEXELFETCH(Vector4f &dst, Vector4f &src0, const Src& src1)
+	void VertexProgram::TEXLODOFFSET(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &offset, Float4 &lod)
 	{
-		sampleTexture(dst, src1, src0, src0, src0, src0, Fetch);
+		dst = sampleTexture(src1, src0, lod, (src0), (src0), offset, {Lod, Offset});
 	}
 
-	void VertexProgram::TEXELFETCH(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &offset)
+	void VertexProgram::TEXELFETCH(Vector4f &dst, Vector4f &src0, const Src& src1, Float4 &lod)
 	{
-		sampleTexture(dst, src1, src0, src0, src0, offset, {Fetch, Offset});
+		dst = sampleTexture(src1, src0, lod, (src0), (src0), (src0), Fetch);
 	}
 
-	void VertexProgram::TEXGRAD(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &src2, Vector4f &src3)
+	void VertexProgram::TEXELFETCHOFFSET(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &offset, Float4 &lod)
 	{
-		sampleTexture(dst, src1, src0, src2, src3, src0, Grad);
+		dst = sampleTexture(src1, src0, lod, (src0), (src0), offset, {Fetch, Offset});
 	}
 
-	void VertexProgram::TEXGRAD(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &src2, Vector4f &src3, Vector4f &offset)
+	void VertexProgram::TEXGRAD(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &dsx, Vector4f &dsy)
 	{
-		sampleTexture(dst, src1, src0, src2, src3, offset, {Grad, Offset});
+		dst = sampleTexture(src1, src0, (src0.x), dsx, dsy, src0, Grad);
+	}
+
+	void VertexProgram::TEXGRADOFFSET(Vector4f &dst, Vector4f &src0, const Src& src1, Vector4f &dsx, Vector4f &dsy, Vector4f &offset)
+	{
+		dst = sampleTexture(src1, src0, (src0.x), dsx, dsy, offset, {Grad, Offset});
 	}
 
 	void VertexProgram::TEXSIZE(Vector4f &dst, Float4 &lod, const Src &src1)
 	{
-		Pointer<Byte> texture = data + OFFSET(DrawData, mipmap[16]) + src1.index * sizeof(Texture);
-		sampler[src1.index]->textureSize(texture, dst, lod);
+		Pointer<Byte> texture = data + OFFSET(DrawData, mipmap[TEXTURE_IMAGE_UNITS]) + src1.index * sizeof(Texture);
+		dst = SamplerCore::textureSize(texture, lod);
 	}
 
-	void VertexProgram::sampleTexture(Vector4f &c, const Src &s, Vector4f &uvwq, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
+	Vector4f VertexProgram::sampleTexture(const Src &s, Vector4f &uvwq, Float4 &lod, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
 	{
 		Vector4f tmp;
 
 		if(s.type == Shader::PARAMETER_SAMPLER && s.rel.type == Shader::PARAMETER_VOID)
 		{
-			Pointer<Byte> texture = data + OFFSET(DrawData, mipmap[TEXTURE_IMAGE_UNITS]) + s.index * sizeof(Texture);
-			sampler[s.index]->sampleTexture(texture, tmp, uvwq.x, uvwq.y, uvwq.z, uvwq.w, dsx, dsy, offset, function);
+			tmp = sampleTexture(s.index, uvwq, lod, dsx, dsy, offset, function);
 		}
 		else
 		{
@@ -1632,17 +1576,25 @@
 				{
 					If(index == i)
 					{
-						Pointer<Byte> texture = data + OFFSET(DrawData, mipmap[TEXTURE_IMAGE_UNITS]) + i * sizeof(Texture);
-						sampler[i]->sampleTexture(texture, tmp, uvwq.x, uvwq.y, uvwq.z, uvwq.w, dsx, dsy, offset, function);
+						tmp = sampleTexture(i, uvwq, lod, dsx, dsy, offset, function);
 						// FIXME: When the sampler states are the same, we could use one sampler and just index the texture
 					}
 				}
 			}
 		}
 
+		Vector4f c;
 		c.x = tmp[(s.swizzle >> 0) & 0x3];
 		c.y = tmp[(s.swizzle >> 2) & 0x3];
 		c.z = tmp[(s.swizzle >> 4) & 0x3];
 		c.w = tmp[(s.swizzle >> 6) & 0x3];
+
+		return c;
+	}
+
+	Vector4f VertexProgram::sampleTexture(int sampler, Vector4f &uvwq, Float4 &lod, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
+	{
+		Pointer<Byte> texture = data + OFFSET(DrawData, mipmap[TEXTURE_IMAGE_UNITS]) + sampler * sizeof(Texture);
+		return SamplerCore(constants, state.sampler[sampler]).sampleTexture(texture, uvwq.x, uvwq.y, uvwq.z, uvwq.w, lod, dsx, dsy, offset, function);
 	}
 }
diff --git a/src/Shader/VertexProgram.hpp b/src/Shader/VertexProgram.hpp
index b537af3..c42ab71 100644
--- a/src/Shader/VertexProgram.hpp
+++ b/src/Shader/VertexProgram.hpp
@@ -17,10 +17,10 @@
 
 #include "VertexRoutine.hpp"
 #include "ShaderCore.hpp"
-#include "SamplerCore.hpp"
 
-#include "Stream.hpp"
-#include "Types.hpp"
+#include "SamplerCore.hpp"
+#include "Renderer/Stream.hpp"
+#include "Common/Types.hpp"
 
 namespace sw
 {
@@ -107,23 +107,21 @@
 		void SWITCH();
 		void RET();
 		void LEAVE();
-		void TEXLDL(Vector4f &dst, Vector4f &src, const Src&);
 		void TEX(Vector4f &dst, Vector4f &src, const Src&);
-		void TEXOFFSET(Vector4f &dst, Vector4f &src, const Src&, Vector4f &src2);
-		void TEXLDL(Vector4f &dst, Vector4f &src, const Src&, Vector4f &src2);
-		void TEXELFETCH(Vector4f &dst, Vector4f &src, const Src&);
-		void TEXELFETCH(Vector4f &dst, Vector4f &src, const Src&, Vector4f &src2);
-		void TEXGRAD(Vector4f &dst, Vector4f &src, const Src&, Vector4f &src2, Vector4f &src3);
-		void TEXGRAD(Vector4f &dst, Vector4f &src, const Src&, Vector4f &src2, Vector4f &src3, Vector4f &src4);
+		void TEXOFFSET(Vector4f &dst, Vector4f &src, const Src&, Vector4f &offset);
+		void TEXLOD(Vector4f &dst, Vector4f &src, const Src&, Float4 &lod);
+		void TEXLODOFFSET(Vector4f &dst, Vector4f &src, const Src&, Vector4f &offset, Float4 &lod);
+		void TEXELFETCH(Vector4f &dst, Vector4f &src, const Src&, Float4 &lod);
+		void TEXELFETCHOFFSET(Vector4f &dst, Vector4f &src, const Src&, Vector4f &offset, Float4 &lod);
+		void TEXGRAD(Vector4f &dst, Vector4f &src, const Src&, Vector4f &dsx, Vector4f &dsy);
+		void TEXGRADOFFSET(Vector4f &dst, Vector4f &src, const Src&, Vector4f &dsx, Vector4f &dsy, Vector4f &offset);
 		void TEXSIZE(Vector4f &dst, Float4 &lod, const Src&);
 
-		void sampleTexture(Vector4f &c, const Src &s, Vector4f &uvwq, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
-
-		SamplerCore *sampler[VERTEX_TEXTURE_IMAGE_UNITS];
+		Vector4f sampleTexture(const Src &s, Vector4f &uvwq, Float4 &lod, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
+		Vector4f sampleTexture(int sampler, Vector4f &uvwq, Float4 &lod, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
 
 		int ifDepth;
 		int loopRepDepth;
-		int breakDepth;
 		int currentLabel;
 		bool whileTest;
 
diff --git a/src/Shader/VertexRoutine.cpp b/src/Shader/VertexRoutine.cpp
index 0f1ccdf..2d7c2c6 100644
--- a/src/Shader/VertexRoutine.cpp
+++ b/src/Shader/VertexRoutine.cpp
@@ -15,11 +15,11 @@
 #include "VertexRoutine.hpp"
 
 #include "VertexShader.hpp"
-#include "Vertex.hpp"
-#include "Half.hpp"
-#include "Renderer.hpp"
 #include "Constants.hpp"
-#include "Debug.hpp"
+#include "Renderer/Vertex.hpp"
+#include "Renderer/Renderer.hpp"
+#include "Common/Half.hpp"
+#include "Common/Debug.hpp"
 
 namespace sw
 {
diff --git a/src/Shader/VertexShader.cpp b/src/Shader/VertexShader.cpp
index 361c76f..33c2241 100644
--- a/src/Shader/VertexShader.cpp
+++ b/src/Shader/VertexShader.cpp
@@ -14,8 +14,8 @@
 
 #include "VertexShader.hpp"
 
-#include "Vertex.hpp"
-#include "Debug.hpp"
+#include "Renderer/Vertex.hpp"
+#include "Common/Debug.hpp"
 
 #include <string.h>
 
@@ -23,7 +23,7 @@
 {
 	VertexShader::VertexShader(const VertexShader *vs) : Shader()
 	{
-		version = 0x0300;
+		shaderModel = 0x0300;
 		positionRegister = Pos;
 		pointSizeRegister = Unused;
 		instanceIdDeclared = false;
@@ -226,16 +226,16 @@
 
 	void VertexShader::analyzeOutput()
 	{
-		if(version < 0x0300)
+		if(shaderModel < 0x0300)
 		{
 			output[Pos][0] = Semantic(Shader::USAGE_POSITION, 0);
 			output[Pos][1] = Semantic(Shader::USAGE_POSITION, 0);
 			output[Pos][2] = Semantic(Shader::USAGE_POSITION, 0);
 			output[Pos][3] = Semantic(Shader::USAGE_POSITION, 0);
 
-			for(unsigned int i = 0; i < instruction.size(); i++)
+			for(const auto &inst : instruction)
 			{
-				const DestinationParameter &dst = instruction[i]->dst;
+				const DestinationParameter &dst = inst->dst;
 
 				switch(dst.type)
 				{
@@ -285,15 +285,15 @@
 		}
 		else   // Shader Model 3.0 input declaration
 		{
-			for(unsigned int i = 0; i < instruction.size(); i++)
+			for(const auto &inst : instruction)
 			{
-				if(instruction[i]->opcode == Shader::OPCODE_DCL &&
-				   instruction[i]->dst.type == Shader::PARAMETER_OUTPUT)
+				if(inst->opcode == Shader::OPCODE_DCL &&
+				   inst->dst.type == Shader::PARAMETER_OUTPUT)
 				{
-					unsigned char usage = instruction[i]->usage;
-					unsigned char usageIndex = instruction[i]->usageIndex;
+					unsigned char usage = inst->usage;
+					unsigned char usageIndex = inst->usageIndex;
 
-					const DestinationParameter &dst = instruction[i]->dst;
+					const DestinationParameter &dst = inst->dst;
 
 					if(dst.x) output[dst.index][0] = Semantic(usage, usageIndex);
 					if(dst.y) output[dst.index][1] = Semantic(usage, usageIndex);
@@ -318,11 +318,12 @@
 	{
 		textureSampling = false;
 
-		for(unsigned int i = 0; i < instruction.size() && !textureSampling; i++)
+		for(const auto &inst : instruction)
 		{
-			if(instruction[i]->src[1].type == PARAMETER_SAMPLER)
+			if(inst->src[1].type == PARAMETER_SAMPLER)
 			{
 				textureSampling = true;
+				break;
 			}
 		}
 	}
diff --git a/src/SwiftShader/SwiftShader.vcxproj b/src/SwiftShader/SwiftShader.vcxproj
index 77ab670..ee9521e 100644
--- a/src/SwiftShader/SwiftShader.vcxproj
+++ b/src/SwiftShader/SwiftShader.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -29,43 +29,44 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{7B02CB19-4CDF-4F79-BC9B-7F3F6164A003}</ProjectGuid>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>false</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>false</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

@@ -117,7 +118,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>

       <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>

       <OmitFramePointers>false</OmitFramePointers>

-      <AdditionalIncludeDirectories>..\;..\Main;..\Renderer;..\Shader;..\Common;..\SwiftAsm;..\libjpeg;..\SwiftShader;..\D3D9;..\Reactor;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NO_SANITIZE_FUNCTION=;_DEBUG;_LIB;_HAS_EXCEPTIONS=0;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <MinimalRebuild>true</MinimalRebuild>

       <ExceptionHandling>false</ExceptionHandling>

@@ -134,6 +135,7 @@
       <RuntimeTypeInfo>false</RuntimeTypeInfo>

       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Lib>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -152,7 +154,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>

       <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>

       <OmitFramePointers>false</OmitFramePointers>

-      <AdditionalIncludeDirectories>..\;..\Main;..\Renderer;..\Shader;..\Common;..\SwiftAsm;..\libjpeg;..\SwiftShader;..\D3D9;..\Reactor;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NO_SANITIZE_FUNCTION=;_DEBUG;_LIB;_HAS_EXCEPTIONS=0;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <MinimalRebuild>true</MinimalRebuild>

       <ExceptionHandling>false</ExceptionHandling>

@@ -169,6 +171,7 @@
       <RuntimeTypeInfo>false</RuntimeTypeInfo>

       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Lib>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -185,7 +188,7 @@
       <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

       <OmitFramePointers>true</OmitFramePointers>

       <WholeProgramOptimization>true</WholeProgramOptimization>

-      <AdditionalIncludeDirectories>..\;..\Main;..\Renderer;..\Shader;..\Common;..\SwiftAsm;..\libjpeg;..\SwiftShader;..\D3D9;..\Reactor;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NO_SANITIZE_FUNCTION=;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <ExceptionHandling>false</ExceptionHandling>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

@@ -204,6 +207,7 @@
       <RuntimeTypeInfo>false</RuntimeTypeInfo>

       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Lib>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -220,7 +224,7 @@
       <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

       <OmitFramePointers>false</OmitFramePointers>

       <WholeProgramOptimization>false</WholeProgramOptimization>

-      <AdditionalIncludeDirectories>..\;..\Main;..\Renderer;..\Shader;..\Common;..\SwiftAsm;..\libjpeg;..\SwiftShader;..\D3D9;..\Reactor;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NO_SANITIZE_FUNCTION=;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <ExceptionHandling>false</ExceptionHandling>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

@@ -237,6 +241,7 @@
       <FloatingPointExceptions>false</FloatingPointExceptions>

       <RuntimeTypeInfo>false</RuntimeTypeInfo>

       <TreatWarningAsError>true</TreatWarningAsError>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Lib>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -256,7 +261,7 @@
       <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

       <OmitFramePointers>true</OmitFramePointers>

       <WholeProgramOptimization>true</WholeProgramOptimization>

-      <AdditionalIncludeDirectories>..\;..\Main;..\Renderer;..\Shader;..\Common;..\SwiftAsm;..\libjpeg;..\SwiftShader;..\D3D9;..\Reactor;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NO_SANITIZE_FUNCTION=;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <ExceptionHandling>false</ExceptionHandling>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

@@ -275,6 +280,7 @@
       <RuntimeTypeInfo>false</RuntimeTypeInfo>

       <TreatWarningAsError>true</TreatWarningAsError>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Lib>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -294,7 +300,7 @@
       <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>

       <OmitFramePointers>false</OmitFramePointers>

       <WholeProgramOptimization>false</WholeProgramOptimization>

-      <AdditionalIncludeDirectories>..\;..\Main;..\Renderer;..\Shader;..\Common;..\SwiftAsm;..\libjpeg;..\SwiftShader;..\D3D9;..\Reactor;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <PreprocessorDefinitions>WIN32;NO_SANITIZE_FUNCTION=;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <ExceptionHandling>false</ExceptionHandling>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

@@ -311,6 +317,7 @@
       <FloatingPointExceptions>false</FloatingPointExceptions>

       <RuntimeTypeInfo>false</RuntimeTypeInfo>

       <TreatWarningAsError>true</TreatWarningAsError>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Lib>

       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>

@@ -323,6 +330,7 @@
     <ClCompile Include="..\Common\Socket.cpp" />

     <ClCompile Include="..\Common\Thread.cpp" />

     <ClCompile Include="..\Main\Config.cpp" />

+    <ClCompile Include="..\Main\FrameBufferOzone.cpp" />

     <ClCompile Include="..\Main\FrameBufferWin.cpp" />

     <ClCompile Include="..\Renderer\ETC_Decoder.cpp" />

     <ClCompile Include="..\Shader\Constants.cpp" />

diff --git a/src/SwiftShader/SwiftShader.vcxproj.filters b/src/SwiftShader/SwiftShader.vcxproj.filters
index b7618d0..64569cd 100644
--- a/src/SwiftShader/SwiftShader.vcxproj.filters
+++ b/src/SwiftShader/SwiftShader.vcxproj.filters
@@ -173,6 +173,9 @@
     <ClCompile Include="..\Renderer\ETC_Decoder.cpp">

       <Filter>Source Files\Renderer</Filter>

     </ClCompile>

+    <ClCompile Include="..\Main\FrameBufferOzone.cpp">

+      <Filter>Source Files\Main</Filter>

+    </ClCompile>

   </ItemGroup>

   <ItemGroup>

     <ClInclude Include="..\Shader\Constants.hpp">

diff --git a/src/swiftshader.gni b/src/swiftshader.gni
index 9148762..01efa20 100644
--- a/src/swiftshader.gni
+++ b/src/swiftshader.gni
@@ -45,3 +45,14 @@
     }
   }
 }
+
+template("swiftshader_static_library") {
+  static_library(target_name) {
+    configs -= configs_to_delete
+    configs += configs_to_add
+    forward_variables_from(invoker, "*", [ "configs" ])
+    if (defined(invoker.configs)) {
+      configs += invoker.configs
+    }
+  }
+}
diff --git a/tests/OGLSimpleCube/OGLSimpleCube.vcxproj b/tests/OGLSimpleCube/OGLSimpleCube.vcxproj
index 153d29e..2c56e57 100644
--- a/tests/OGLSimpleCube/OGLSimpleCube.vcxproj
+++ b/tests/OGLSimpleCube/OGLSimpleCube.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -22,31 +22,32 @@
     <ProjectGuid>{27E15292-4A8D-4BA0-8D9B-5D1ECFF85747}</ProjectGuid>

     <Keyword>Win32Proj</Keyword>

     <RootNamespace>OGLSimpleCube</RootNamespace>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

diff --git a/tests/fuzzers/VertexRoutineFuzzer.cpp b/tests/fuzzers/VertexRoutineFuzzer.cpp
new file mode 100644
index 0000000..11ac1a4
--- /dev/null
+++ b/tests/fuzzers/VertexRoutineFuzzer.cpp
@@ -0,0 +1,213 @@
+// Copyright 2017 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "OpenGL/compiler/InitializeGlobals.h"
+#include "OpenGL/compiler/InitializeParseContext.h"
+#include "OpenGL/compiler/TranslatorASM.h"
+
+// TODO: Debug macros of the GLSL compiler clash with core SwiftShader's.
+// They should not be exposed through the interface headers above.
+#undef ASSERT
+#undef UNIMPLEMENTED
+
+#include "Renderer/VertexProcessor.hpp"
+#include "Shader/VertexProgram.hpp"
+
+#include <cstdint>
+#include <memory>
+#include <cassert>
+
+namespace {
+
+// TODO(cwallez@google.com): Like in ANGLE, disable most of the pool allocator for fuzzing
+// This is a helper class to make sure all the resources used by the compiler are initialized
+class ScopedPoolAllocatorAndTLS {
+	public:
+		ScopedPoolAllocatorAndTLS() {
+			InitializeParseContextIndex();
+			InitializePoolIndex();
+			SetGlobalPoolAllocator(&allocator);
+		}
+		~ScopedPoolAllocatorAndTLS() {
+			SetGlobalPoolAllocator(nullptr);
+			FreePoolIndex();
+			FreeParseContextIndex();
+		}
+
+	private:
+		TPoolAllocator allocator;
+};
+
+// Trivial implementation of the glsl::Shader interface that fakes being an API-level
+// shader object.
+class FakeVS : public glsl::Shader {
+	public:
+		FakeVS(sw::VertexShader* bytecode) : bytecode(bytecode) {
+		}
+
+		sw::Shader *getShader() const override {
+			return bytecode;
+		}
+		sw::VertexShader *getVertexShader() const override {
+			return bytecode;
+		}
+
+	private:
+		sw::VertexShader* bytecode;
+};
+
+} // anonymous namespace
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+	// Data layout:
+	//
+	// byte: boolean states
+	// {
+	//   byte: stream type
+	//   byte: stream count and normalized
+	// } [MAX_VERTEX_INPUTS]
+	// {
+	//   byte[32]: reserved sampler state
+	// } [VERTEX_TEXTURE_IMAGE_UNITS]
+	//
+	// char source[] // null terminated
+	const size_t kHeaderSize = 1 + 2 * sw::MAX_VERTEX_INPUTS + 32 * sw::VERTEX_TEXTURE_IMAGE_UNITS;
+
+	if(size <= kHeaderSize)
+	{
+		return 0;
+	}
+
+	if (data[size -1] != 0)
+	{
+		return 0;
+	}
+
+	std::unique_ptr<ScopedPoolAllocatorAndTLS> allocatorAndTLS(new ScopedPoolAllocatorAndTLS);
+	std::unique_ptr<sw::VertexShader> shader(new sw::VertexShader);
+	std::unique_ptr<FakeVS> fakeVS(new FakeVS(shader.get()));
+	
+	std::unique_ptr<TranslatorASM> glslCompiler(new TranslatorASM(fakeVS.get(), GL_VERTEX_SHADER));
+
+	// TODO(cwallez@google.com): have a function to init to default values somewhere
+	ShBuiltInResources resources;
+	resources.MaxVertexAttribs = sw::MAX_VERTEX_INPUTS;
+	resources.MaxVertexUniformVectors = sw::VERTEX_UNIFORM_VECTORS - 3;
+	resources.MaxVaryingVectors = MIN(sw::MAX_VERTEX_OUTPUTS, sw::MAX_VERTEX_INPUTS);
+	resources.MaxVertexTextureImageUnits = sw::VERTEX_TEXTURE_IMAGE_UNITS;
+	resources.MaxCombinedTextureImageUnits = sw::TEXTURE_IMAGE_UNITS + sw::VERTEX_TEXTURE_IMAGE_UNITS;
+	resources.MaxTextureImageUnits = sw::TEXTURE_IMAGE_UNITS;
+	resources.MaxFragmentUniformVectors = sw::FRAGMENT_UNIFORM_VECTORS - 3;
+	resources.MaxDrawBuffers = sw::RENDERTARGETS;
+	resources.MaxVertexOutputVectors = 16; // ???
+	resources.MaxFragmentInputVectors = 15; // ???
+	resources.MinProgramTexelOffset = sw::MIN_PROGRAM_TEXEL_OFFSET;
+	resources.MaxProgramTexelOffset = sw::MAX_PROGRAM_TEXEL_OFFSET;
+	resources.OES_standard_derivatives = 1;
+	resources.OES_fragment_precision_high = 1;
+	resources.OES_EGL_image_external = 1;
+	resources.EXT_draw_buffers = 1;
+	resources.ARB_texture_rectangle = 1;
+	resources.MaxCallStackDepth = 16;
+
+	glslCompiler->Init(resources);
+
+	const char* glslSource = reinterpret_cast<const char*>(data + kHeaderSize);
+	if (!glslCompiler->compile(&glslSource, 1, SH_OBJECT_CODE))
+	{
+		return 0;
+	}
+
+	std::unique_ptr<sw::VertexShader> bytecodeShader(new sw::VertexShader(fakeVS->getVertexShader()));
+
+	sw::VertexProcessor::State state;
+
+	state.textureSampling = bytecodeShader->containsTextureSampling();
+	state.positionRegister = bytecodeShader->getPositionRegister();
+	state.pointSizeRegister = bytecodeShader->getPointSizeRegister();
+
+	state.preTransformed = (data[0] & 0x01) != 0;
+	state.superSampling = (data[0] & 0x02) != 0;
+	state.multiSampling = (data[0] & 0x04) != 0;
+
+	state.transformFeedbackQueryEnabled = (data[0] & 0x08) != 0;
+	state.transformFeedbackEnabled = (data[0] & 0x10) != 0;
+	state.verticesPerPrimitive = 1 + ((data[0] & 0x20) != 0) + ((data[0] & 0x40) != 0);
+
+	if((data[0] & 0x80) != 0)   // Unused/reserved.
+	{
+		return 0;
+	}
+
+	constexpr int MAX_ATTRIBUTE_COMPONENTS = 4;
+
+	struct Stream
+	{
+		uint8_t count : BITS(MAX_ATTRIBUTE_COMPONENTS);
+		bool normalized : 1;
+		uint8_t reserved : 8 - BITS(MAX_ATTRIBUTE_COMPONENTS) - 1;
+	};
+
+	for(int i = 0; i < sw::MAX_VERTEX_INPUTS; i++)
+	{
+		sw::StreamType type = (sw::StreamType)data[1 + 2 * i + 0];
+		Stream stream = (Stream&)data[1 + 2 * i + 1];
+
+		if(type > sw::STREAMTYPE_LAST) return 0;
+		if(stream.count > MAX_ATTRIBUTE_COMPONENTS) return 0;
+		if(stream.reserved != 0) return 0;
+
+		state.input[i].type = type;
+		state.input[i].count = stream.count;
+		state.input[i].normalized = stream.normalized;
+		state.input[i].attribType = bytecodeShader->getAttribType(i);
+	}
+
+	for(unsigned int i = 0; i < sw::VERTEX_TEXTURE_IMAGE_UNITS; i++)
+	{
+		// TODO
+	//	if(bytecodeShader->usesSampler(i))
+	//	{
+	//		state.samplerState[i] = context->sampler[sw::TEXTURE_IMAGE_UNITS + i].samplerState();
+	//	}
+
+		for(int j = 0; j < 32; j++)
+		{
+			if(data[1 + 2 * sw::MAX_VERTEX_INPUTS + 32 * i + j] != 0)
+			{
+				return 0;
+			}
+		}
+	}
+
+	for(int i = 0; i < sw::MAX_VERTEX_OUTPUTS; i++)
+	{
+		state.output[i].xWrite = bytecodeShader->getOutput(i, 0).active();
+		state.output[i].yWrite = bytecodeShader->getOutput(i, 1).active();
+		state.output[i].zWrite = bytecodeShader->getOutput(i, 2).active();
+		state.output[i].wWrite = bytecodeShader->getOutput(i, 3).active();
+	}
+
+	sw::VertexProgram program(state, bytecodeShader.get());
+	program.generate();
+
+	sw::Routine *routine = program(L"VertexRoutine");
+	assert(routine);
+	const void *entry = routine->getEntry();
+	assert(entry); (void)entry;
+	delete routine;
+
+	return 0;
+}
diff --git a/tests/unittests/unittests.cpp b/tests/unittests/unittests.cpp
index 8861424..7ae84da 100644
--- a/tests/unittests/unittests.cpp
+++ b/tests/unittests/unittests.cpp
@@ -17,11 +17,15 @@
 
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
 
 #if defined(_WIN32)
 #include <Windows.h>
 #endif
 
+#define EXPECT_GLENUM_EQ(expected, actual) EXPECT_EQ(static_cast<GLenum>(expected), static_cast<GLenum>(actual))
+
 class SwiftShaderTest : public testing::Test
 {
 protected:
@@ -37,151 +41,679 @@
 			EXPECT_NE((HMODULE)NULL, libGLESv2);
 		#endif
 	}
+
+	void compareColor(unsigned char referenceColor[4])
+	{
+		unsigned char color[4] = { 0 };
+		glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color);
+		EXPECT_EQ(color[0], referenceColor[0]);
+		EXPECT_EQ(color[1], referenceColor[1]);
+		EXPECT_EQ(color[2], referenceColor[2]);
+		EXPECT_EQ(color[3], referenceColor[3]);
+	}
+
+	void Initialize(int version, bool withChecks)
+	{
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+
+		display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+		if(withChecks)
+		{
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_NE(EGL_NO_DISPLAY, display);
+
+			eglQueryString(display, EGL_VENDOR);
+			EXPECT_EQ(EGL_NOT_INITIALIZED, eglGetError());
+		}
+
+		EGLint major;
+		EGLint minor;
+		EGLBoolean initialized = eglInitialize(display, &major, &minor);
+
+		if(withChecks)
+		{
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_EQ((EGLBoolean)EGL_TRUE, initialized);
+			EXPECT_EQ(1, major);
+			EXPECT_EQ(4, minor);
+
+			const char *eglVendor = eglQueryString(display, EGL_VENDOR);
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_STREQ("Google Inc.", eglVendor);
+
+			const char *eglVersion = eglQueryString(display, EGL_VERSION);
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_THAT(eglVersion, testing::HasSubstr("1.4 SwiftShader "));
+		}
+
+		eglBindAPI(EGL_OPENGL_ES_API);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+
+		const EGLint configAttributes[] =
+		{
+			EGL_SURFACE_TYPE,		EGL_PBUFFER_BIT,
+			EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES2_BIT,
+			EGL_ALPHA_SIZE,			8,
+			EGL_NONE
+		};
+		EGLint num_config = -1;
+		EGLBoolean success = eglChooseConfig(display, configAttributes, &config, 1, &num_config);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ(num_config, 1);
+		EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+
+		if(withChecks)
+		{
+			EGLint conformant = 0;
+			eglGetConfigAttrib(display, config, EGL_CONFORMANT, &conformant);
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_TRUE(conformant & EGL_OPENGL_ES2_BIT);
+
+			EGLint renderableType = 0;
+			eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType);
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_TRUE(renderableType & EGL_OPENGL_ES2_BIT);
+
+			EGLint surfaceType = 0;
+			eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &surfaceType);
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_TRUE(surfaceType & EGL_WINDOW_BIT);
+		}
+
+		EGLint surfaceAttributes[] =
+		{
+			EGL_WIDTH, 1920,
+			EGL_HEIGHT, 1080,
+			EGL_NONE
+		};
+
+		surface = eglCreatePbufferSurface(display, config, surfaceAttributes);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_NE(EGL_NO_SURFACE, surface);
+
+		EGLint contextAttributes[] =
+		{
+			EGL_CONTEXT_CLIENT_VERSION, version,
+			EGL_NONE
+		};
+
+		context = eglCreateContext(display, config, NULL, contextAttributes);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_NE(EGL_NO_CONTEXT, context);
+
+		success = eglMakeCurrent(display, surface, surface, context);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+
+		if(withChecks)
+		{
+			EGLDisplay currentDisplay = eglGetCurrentDisplay();
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_EQ(display, currentDisplay);
+
+			EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_EQ(surface, currentDrawSurface);
+
+			EGLSurface currentReadSurface = eglGetCurrentSurface(EGL_READ);
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_EQ(surface, currentReadSurface);
+
+			EGLContext currentContext = eglGetCurrentContext();
+			EXPECT_EQ(EGL_SUCCESS, eglGetError());
+			EXPECT_EQ(context, currentContext);
+		}
+
+		EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError());
+	}
+
+	void Uninitialize()
+	{
+		EGLBoolean success = eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+
+		EGLDisplay currentDisplay = eglGetCurrentDisplay();
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ(EGL_NO_DISPLAY, currentDisplay);
+
+		EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ(EGL_NO_SURFACE, currentDrawSurface);
+
+		EGLSurface currentReadSurface = eglGetCurrentSurface(EGL_READ);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ(EGL_NO_SURFACE, currentReadSurface);
+
+		EGLContext currentContext = eglGetCurrentContext();
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ(EGL_NO_CONTEXT, currentContext);
+
+		success = eglDestroyContext(display, context);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+
+		success = eglDestroySurface(display, surface);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+
+		success = eglTerminate(display);
+		EXPECT_EQ(EGL_SUCCESS, eglGetError());
+		EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+	}
+
+	GLuint createProgram(const std::string& vs, const std::string& fs)
+	{
+		GLuint program = glCreateProgram();
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+		GLuint vsShader = glCreateShader(GL_VERTEX_SHADER);
+		const char* vsSource[1] = { vs.c_str() };
+		glShaderSource(vsShader, 1, vsSource, nullptr);
+		glCompileShader(vsShader);
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+		GLuint fsShader = glCreateShader(GL_FRAGMENT_SHADER);
+		const char* fsSource[1] = { fs.c_str() };
+		glShaderSource(fsShader, 1, fsSource, nullptr);
+		glCompileShader(fsShader);
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+		glAttachShader(program, vsShader);
+		glAttachShader(program, fsShader);
+		glLinkProgram(program);
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+		return program;
+	}
+
+	void drawQuad(GLuint program)
+	{
+		GLint prevProgram = 0;
+		glGetIntegerv(GL_CURRENT_PROGRAM, &prevProgram);
+
+		glUseProgram(program);
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+		GLint posLoc = glGetAttribLocation(program, "position");
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+		GLint location = glGetUniformLocation(program, "tex");
+		ASSERT_NE(-1, location);
+		glUniform1i(location, 0);
+
+		float vertices[18] = { -1.0f,  1.0f, 0.5f,
+		                       -1.0f, -1.0f, 0.5f,
+		                        1.0f, -1.0f, 0.5f,
+		                       -1.0f,  1.0f, 0.5f,
+		                        1.0f, -1.0f, 0.5f,
+		                        1.0f,  1.0f, 0.5f };
+
+		glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, vertices);
+		glEnableVertexAttribArray(posLoc);
+		glDrawArrays(GL_TRIANGLES, 0, 6);
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
+		glDisableVertexAttribArray(posLoc);
+		glUseProgram(prevProgram);
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	}
+
+	EGLDisplay getDisplay() const { return display; }
+	EGLDisplay getConfig() const { return config; }
+	EGLSurface getSurface() const { return surface; }
+	EGLContext getContext() const { return context; }
+private:
+	EGLDisplay display;
+	EGLConfig config;
+	EGLSurface surface;
+	EGLContext context;
 };
 
 TEST_F(SwiftShaderTest, Initalization)
 {
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-
-	EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_NE(EGL_NO_DISPLAY, display);
-
-	eglQueryString(display, EGL_VENDOR);
-	EXPECT_EQ(EGL_NOT_INITIALIZED, eglGetError());
-
-	EGLint major;
-	EGLint minor;
-	EGLBoolean initialized = eglInitialize(display, &major, &minor);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ((EGLBoolean)EGL_TRUE, initialized);
-	EXPECT_EQ(1, major);
-	EXPECT_EQ(4, minor);
-
-	const char *eglVendor = eglQueryString(display, EGL_VENDOR);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_STREQ("Google Inc.", eglVendor);
-
-	const char *eglVersion = eglQueryString(display, EGL_VERSION);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_THAT(eglVersion, testing::HasSubstr("1.4 SwiftShader "));
-
-	eglBindAPI(EGL_OPENGL_ES_API);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-
-	const EGLint configAttributes[] =
-	{
-		EGL_SURFACE_TYPE,		EGL_PBUFFER_BIT,
-		EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES2_BIT,
-		EGL_NONE
-	};
-
-	EGLConfig config;
-	EGLint num_config = -1;
-	EGLBoolean success = eglChooseConfig(display, configAttributes, &config, 1, &num_config);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ(num_config, 1);
-	EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
-
-	EGLint conformant = 0;
-	eglGetConfigAttrib(display, config, EGL_CONFORMANT, &conformant);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_TRUE(conformant & EGL_OPENGL_ES2_BIT);
-
-	EGLint renderableType = 0;
-	eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_TRUE(renderableType & EGL_OPENGL_ES2_BIT);
-
-	EGLint surfaceType = 0;
-	eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &surfaceType);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_TRUE(surfaceType & EGL_WINDOW_BIT);
-
-	EGLint surfaceAttributes[] =
-	{
-		EGL_WIDTH, 1920,
-		EGL_HEIGHT, 1080,
-		EGL_NONE
-	};
-
-	EGLSurface surface = eglCreatePbufferSurface(display, config, surfaceAttributes);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_NE(EGL_NO_SURFACE, surface);
-
-	EGLint contextAttributes[] =
-	{
-		EGL_CONTEXT_CLIENT_VERSION, 2,
-		EGL_NONE
-	};
-
-	EGLContext context = eglCreateContext(display, config, NULL, contextAttributes);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_NE(EGL_NO_CONTEXT, context);
-
-	success = eglMakeCurrent(display, surface, surface, context);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
-
-	EGLDisplay currentDisplay = eglGetCurrentDisplay();
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ(display, currentDisplay);
-
-	EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ(surface, currentDrawSurface);
-
-	EGLSurface currentReadSurface = eglGetCurrentSurface(EGL_READ);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ(surface, currentReadSurface);
-
-	EGLContext currentContext = eglGetCurrentContext();
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ(context, currentContext);
-
-	EXPECT_EQ((GLenum)GL_NO_ERROR, glGetError());
+	Initialize(2, true);
 
 	const GLubyte *glVendor = glGetString(GL_VENDOR);
-	EXPECT_EQ((GLenum)GL_NO_ERROR, glGetError());
+	EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError());
 	EXPECT_STREQ("Google Inc.", (const char*)glVendor);
 
 	const GLubyte *glRenderer = glGetString(GL_RENDERER);
-	EXPECT_EQ((GLenum)GL_NO_ERROR, glGetError());
+	EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError());
 	EXPECT_STREQ("Google SwiftShader", (const char*)glRenderer);
 
 	const GLubyte *glVersion = glGetString(GL_VERSION);
-	EXPECT_EQ((GLenum)GL_NO_ERROR, glGetError());
+	EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError());
 	EXPECT_THAT((const char*)glVersion, testing::HasSubstr("OpenGL ES 2.0 SwiftShader "));
 
-	success = eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+	Uninitialize();
+}
 
-	currentDisplay = eglGetCurrentDisplay();
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ(EGL_NO_DISPLAY, currentDisplay);
+// Note: GL_ARB_texture_rectangle is part of gl2extchromium.h in the Chromium repo
+// GL_ARB_texture_rectangle
+#ifndef GL_ARB_texture_rectangle
+#define GL_ARB_texture_rectangle 1
 
-	currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ(EGL_NO_SURFACE, currentDrawSurface);
+#ifndef GL_SAMPLER_2D_RECT_ARB
+#define GL_SAMPLER_2D_RECT_ARB 0x8B63
+#endif
 
-	currentReadSurface = eglGetCurrentSurface(EGL_READ);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ(EGL_NO_SURFACE, currentReadSurface);
+#ifndef GL_TEXTURE_BINDING_RECTANGLE_ARB
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6
+#endif
 
-	currentContext = eglGetCurrentContext();
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ(EGL_NO_CONTEXT, currentContext);
+#ifndef GL_TEXTURE_RECTANGLE_ARB
+#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
+#endif
 
-	success = eglDestroyContext(display, context);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+#ifndef GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif
 
-	success = eglDestroySurface(display, surface);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+#endif  // GL_ARB_texture_rectangle
 
-	success = eglTerminate(display);
-	EXPECT_EQ(EGL_SUCCESS, eglGetError());
-	EXPECT_EQ((EGLBoolean)EGL_TRUE, success);
+// Test using TexImage2D to define a rectangle texture
+
+TEST_F(SwiftShaderTest, TextureRectangle_TexImage2D)
+{
+	Initialize(2, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+
+	// Defining level 0 is allowed
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	// Defining level other than 0 is not allowed
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 1, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+	EXPECT_GLENUM_EQ(GL_INVALID_VALUE, glGetError());
+
+	GLint maxSize = 0;
+	glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &maxSize);
+
+	// Defining a texture of the max size is allowed
+	{
+		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, maxSize, maxSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+		GLenum error = glGetError();
+		ASSERT_TRUE(error == GL_NO_ERROR || error == GL_OUT_OF_MEMORY);
+	}
+
+	// Defining a texture larger than the max size is disallowed
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, maxSize + 1, maxSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+	EXPECT_GLENUM_EQ(GL_INVALID_VALUE, glGetError());
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, maxSize, maxSize + 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+	EXPECT_GLENUM_EQ(GL_INVALID_VALUE, glGetError());
+
+	Uninitialize();
+}
+
+// Test using CompressedTexImage2D cannot be used on a retangle texture
+TEST_F(SwiftShaderTest, TextureRectangle_CompressedTexImage2DDisallowed)
+{
+	Initialize(2, false);
+
+	const char data[128] = { 0 };
+
+	// Control case: 2D texture
+	{
+		GLuint tex = 1;
+		glBindTexture(GL_TEXTURE_2D, tex);
+		glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 16, 16, 0, 128, data);
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	}
+
+	// Rectangle textures cannot be compressed
+	{
+		GLuint tex = 2;
+		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+		glCompressedTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 16, 16, 0, 128, data);
+		EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+	}
+
+	Uninitialize();
+}
+
+// Test using TexStorage2D to define a rectangle texture (ES3)
+TEST_F(SwiftShaderTest, TextureRectangle_TexStorage2D)
+{
+	Initialize(3, false);
+
+	// Defining one level is allowed
+	{
+		GLuint tex = 1;
+		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+		glTexStorage2D(GL_TEXTURE_RECTANGLE_ARB, 1, GL_RGBA8UI, 16, 16);
+		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	}
+
+	// Having more than one level is not allowed
+	{
+		GLuint tex = 2;
+		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+		// Use 5 levels because the EXT_texture_storage extension requires a mip chain all the way
+		// to a 1x1 mip.
+		glTexStorage2D(GL_TEXTURE_RECTANGLE_ARB, 5, GL_RGBA8UI, 16, 16);
+		EXPECT_GLENUM_EQ(GL_INVALID_VALUE, glGetError());
+	}
+
+	GLint maxSize = 0;
+	glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &maxSize);
+
+	// Defining a texture of the max size is allowed but still allow for OOM
+	{
+		GLuint tex = 3;
+		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+		glTexStorage2D(GL_TEXTURE_RECTANGLE_ARB, 1, GL_RGBA8UI, maxSize, maxSize);
+		GLenum error = glGetError();
+		ASSERT_TRUE(error == GL_NO_ERROR || error == GL_OUT_OF_MEMORY);
+	}
+
+	// Defining a texture larger than the max size is disallowed
+	{
+		GLuint tex = 4;
+		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+		glTexStorage2D(GL_TEXTURE_RECTANGLE_ARB, 1, GL_RGBA8UI, maxSize + 1, maxSize);
+		EXPECT_GLENUM_EQ(GL_INVALID_VALUE, glGetError());
+		glTexStorage2D(GL_TEXTURE_RECTANGLE_ARB, 1, GL_RGBA8UI, maxSize, maxSize + 1);
+		EXPECT_GLENUM_EQ(GL_INVALID_VALUE, glGetError());
+	}
+
+	// Compressed formats are disallowed
+	GLuint tex = 5;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+	glTexStorage2D(GL_TEXTURE_RECTANGLE_ARB, 1, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 16, 16);
+	EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+
+	Uninitialize();
+}
+
+// Test validation of disallowed texture parameters
+TEST_F(SwiftShaderTest, TextureRectangle_TexParameterRestriction)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+
+	// Only wrap mode CLAMP_TO_EDGE is supported
+	// Wrap S
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+	EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+
+	// Wrap T
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_REPEAT);
+	EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+	EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+
+	// Min filter has to be nearest or linear
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+	EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
+	EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+	EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+	EXPECT_GLENUM_EQ(GL_INVALID_ENUM, glGetError());
+
+	// Base level has to be 0
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_BASE_LEVEL, 0);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_BASE_LEVEL, 1);
+	EXPECT_GLENUM_EQ(GL_INVALID_OPERATION, glGetError());
+
+	Uninitialize();
+}
+
+// Test validation of "level" in FramebufferTexture2D
+TEST_F(SwiftShaderTest, TextureRectangle_FramebufferTexture2DLevel)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	GLuint fbo = 1;
+	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+	// Using level 0 of a rectangle texture is valid.
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, tex, 0);
+	EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	// Setting level != 0 is invalid
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, tex, 1);
+	EXPECT_GLENUM_EQ(GL_INVALID_VALUE, glGetError());
+
+	Uninitialize();
+}
+
+// Test sampling from a rectangle texture
+TEST_F(SwiftShaderTest, TextureRectangle_SamplingFromRectangle)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	unsigned char green[4] = { 0, 255, 0, 255 };
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, green);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	const std::string vs =
+		"attribute vec4 position;\n"
+		"void main()\n"
+		"{\n"
+		"    gl_Position = vec4(position.xy, 0.0, 1.0);\n"
+		"}\n";
+
+	const std::string fs =
+		"#extension GL_ARB_texture_rectangle : require\n"
+		"precision mediump float;\n"
+		"uniform sampler2DRect tex;\n"
+		"void main()\n"
+		"{\n"
+		"    gl_FragColor = texture2DRect(tex, vec2(0, 0));\n"
+		"}\n";
+
+	GLuint program = createProgram(vs, fs);
+
+	glUseProgram(program);
+	GLint location = glGetUniformLocation(program, "tex");
+	ASSERT_NE(-1, location);
+	glUniform1i(location, 0);
+
+	glClearColor(0.0, 0.0, 0.0, 0.0);
+	glClear(GL_COLOR_BUFFER_BIT);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	drawQuad(program);
+
+	compareColor(green);
+
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	Uninitialize();
+}
+
+// Test sampling from a rectangle texture
+TEST_F(SwiftShaderTest, TextureRectangle_SamplingFromRectangleESSL3)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	unsigned char green[4] = { 0, 255, 0, 255 };
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, green);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	const std::string vs =
+		"#version 300 es\n"
+		"in vec4 position;\n"
+		"void main()\n"
+		"{\n"
+		"    gl_Position = vec4(position.xy, 0.0, 1.0);\n"
+		"}\n";
+
+	const std::string fs =
+		"#version 300 es\n"
+		"#extension GL_ARB_texture_rectangle : require\n"
+		"precision mediump float;\n"
+		"uniform sampler2DRect tex;\n"
+		"out vec4 fragColor;\n"
+		"void main()\n"
+		"{\n"
+		"    fragColor = texture(tex, vec2(0, 0));\n"
+		"}\n";
+
+	GLuint program = createProgram(vs, fs);
+	glUseProgram(program);
+	GLint location = glGetUniformLocation(program, "tex");
+	ASSERT_NE(-1, location);
+	glUniform1i(location, 0);
+
+	glClearColor(0.0, 0.0, 0.0, 0.0);
+	glClear(GL_COLOR_BUFFER_BIT);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	drawQuad(program);
+
+	compareColor(green);
+
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	Uninitialize();
+}
+
+// Test attaching a rectangle texture and rendering to it.
+TEST_F(SwiftShaderTest, TextureRectangle_RenderToRectangle)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+	unsigned char black[4] = { 0, 0, 0, 255 };
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
+
+	GLuint fbo = 1;
+	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, tex, 0);
+	EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	// Clearing a texture is just as good as checking we can render to it, right?
+	glClearColor(0.0, 1.0, 0.0, 1.0);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	unsigned char green[4] = { 0, 255, 0, 255 };
+	compareColor(green);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	Uninitialize();
+}
+
+TEST_F(SwiftShaderTest, TextureRectangle_DefaultSamplerParameters)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+
+	GLint minFilter = 0;
+	glGetTexParameteriv(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, &minFilter);
+	EXPECT_GLENUM_EQ(GL_LINEAR, minFilter);
+
+	GLint wrapS = 0;
+	glGetTexParameteriv(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, &wrapS);
+	EXPECT_GLENUM_EQ(GL_CLAMP_TO_EDGE, wrapS);
+
+	GLint wrapT = 0;
+	glGetTexParameteriv(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, &wrapT);
+	EXPECT_GLENUM_EQ(GL_CLAMP_TO_EDGE, wrapT);
+
+	Uninitialize();
+}
+
+// Test glCopyTexImage with rectangle textures (ES3)
+TEST_F(SwiftShaderTest, TextureRectangle_CopyTexImage)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+
+	glBindFramebuffer(GL_FRAMEBUFFER, 0);
+	glClearColor(0, 1, 0, 1);
+	glClear(GL_COLOR_BUFFER_BIT);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	// Error case: level != 0
+	glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 1, GL_RGBA8, 0, 0, 1, 1, 0);
+	EXPECT_GLENUM_EQ(GL_INVALID_VALUE, glGetError());
+
+	// level = 0 works and defines the texture.
+	glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, 0, 0, 1, 1, 0);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	GLuint fbo = 1;
+	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, tex, 0);
+
+	unsigned char green[4] = { 0, 255, 0, 255 };
+	compareColor(green);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	Uninitialize();
+}
+
+// Test glCopyTexSubImage with rectangle textures (ES3)
+TEST_F(SwiftShaderTest, TextureRectangle_CopyTexSubImage)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+	unsigned char black[4] = { 0, 0, 0, 255 };
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
+
+	glBindFramebuffer(GL_FRAMEBUFFER, 0);
+	glClearColor(0, 1, 0, 1);
+	glClear(GL_COLOR_BUFFER_BIT);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	// Error case: level != 0
+	glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 1, 0, 0, 0, 0, 1, 1);
+	EXPECT_GLENUM_EQ(GL_INVALID_VALUE, glGetError());
+
+	// level = 0 works and defines the texture.
+	glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, 0, 0, 1, 1);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	GLuint fbo = 1;
+	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, tex, 0);
+
+	unsigned char green[4] = { 0, 255, 0, 255 };
+	compareColor(green);
+	EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+
+	Uninitialize();
 }
diff --git a/tests/unittests/unittests.vcxproj b/tests/unittests/unittests.vcxproj
index 537801f..b92398f 100644
--- a/tests/unittests/unittests.vcxproj
+++ b/tests/unittests/unittests.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -22,32 +22,32 @@
     <ProjectGuid>{CF8EBC89-8762-49DC-9440-6C82B3499913}</ProjectGuid>

     <Keyword>Win32Proj</Keyword>

     <RootNamespace>unittests</RootNamespace>

-    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>Unicode</CharacterSet>

   </PropertyGroup>

@@ -96,6 +96,7 @@
       <AdditionalIncludeDirectories>$(SolutionDir)include\;$(SolutionDir)third_party\googletest\googletest\include\;$(SolutionDir)third_party\googletest\googletest\;$(SolutionDir)third_party\googletest\googlemock\include\;SubmoduleCheck;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <ForcedIncludeFiles>

       </ForcedIncludeFiles>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

@@ -113,6 +114,7 @@
       <AdditionalIncludeDirectories>$(SolutionDir)include\;$(SolutionDir)third_party\googletest\googletest\include\;$(SolutionDir)third_party\googletest\googletest\;$(SolutionDir)third_party\googletest\googlemock\include\;SubmoduleCheck;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <ForcedIncludeFiles>

       </ForcedIncludeFiles>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

@@ -132,6 +134,7 @@
       <AdditionalIncludeDirectories>$(SolutionDir)include\;$(SolutionDir)third_party\googletest\googletest\include\;$(SolutionDir)third_party\googletest\googletest\;$(SolutionDir)third_party\googletest\googlemock\include\;SubmoduleCheck;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <ForcedIncludeFiles>

       </ForcedIncludeFiles>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

@@ -153,6 +156,7 @@
       <AdditionalIncludeDirectories>$(SolutionDir)include\;$(SolutionDir)third_party\googletest\googletest\include\;$(SolutionDir)third_party\googletest\googletest\;$(SolutionDir)third_party\googletest\googlemock\include\;SubmoduleCheck;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <ForcedIncludeFiles>

       </ForcedIncludeFiles>

+      <TreatSpecificWarningsAsErrors>4018;5038</TreatSpecificWarningsAsErrors>

     </ClCompile>

     <Link>

       <SubSystem>Console</SubSystem>

diff --git a/tests/unittests/unittests.vcxproj.user b/tests/unittests/unittests.vcxproj.user
index 234e386..567b191 100644
--- a/tests/unittests/unittests.vcxproj.user
+++ b/tests/unittests/unittests.vcxproj.user
@@ -3,6 +3,7 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

     <LocalDebuggerEnvironment>PATH=$(SolutionDir)lib\$(Configuration)_$(Platform)</LocalDebuggerEnvironment>

     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>

+    <LocalDebuggerCommandArguments>--gtest_break_on_failure</LocalDebuggerCommandArguments>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

     <LocalDebuggerEnvironment>PATH=$(SolutionDir)lib\$(Configuration)_$(Platform)</LocalDebuggerEnvironment>

@@ -11,6 +12,7 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

     <LocalDebuggerEnvironment>PATH=$(SolutionDir)lib\$(Configuration)_$(Platform)</LocalDebuggerEnvironment>

     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>

+    <LocalDebuggerCommandArguments>--gtest_break_on_failure</LocalDebuggerCommandArguments>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

     <LocalDebuggerEnvironment>PATH=$(SolutionDir)lib\$(Configuration)_$(Platform)</LocalDebuggerEnvironment>

diff --git a/third_party/LLVM/Android.mk b/third_party/LLVM/Android.mk
index a3dcdae..069645d 100644
--- a/third_party/LLVM/Android.mk
+++ b/third_party/LLVM/Android.mk
@@ -396,8 +396,8 @@
 	lib/VMCore/ValueTypes.cpp \
 	lib/VMCore/Verifier.cpp \
 
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libLLVM_swiftshader\" \
+LOCAL_CFLAGS += \
+	-DLOG_TAG=\"libLLVM_swiftshader\" \
 	-Wall \
 	-Werror \
 	-Wno-implicit-exception-spec-mismatch \
@@ -410,6 +410,7 @@
 	-Wno-unused-parameter \
 	-Wno-unused-private-field \
 	-Wno-unused-variable \
+	-Wno-unknown-warning-option
 
 ifneq (16,${PLATFORM_SDK_VERSION})
 LOCAL_CFLAGS += -Xclang -fuse-init-array
diff --git a/third_party/LLVM/BUILD.gn b/third_party/LLVM/BUILD.gn
index 3fc4d22..ad6b576 100644
--- a/third_party/LLVM/BUILD.gn
+++ b/third_party/LLVM/BUILD.gn
@@ -463,6 +463,8 @@
     include_dirs += [ "include-linux" ]
   } else if (is_mac) {
     include_dirs += [ "include-osx" ]
+  } else if (is_fuchsia) {
+    include_dirs += [ "include-fuchsia" ]
   }
 
   include_dirs += [ "include" ]
diff --git a/third_party/LLVM/include-fuchsia/llvm/Config/config.h b/third_party/LLVM/include-fuchsia/llvm/Config/config.h
new file mode 100644
index 0000000..0e46979
--- /dev/null
+++ b/third_party/LLVM/include-fuchsia/llvm/Config/config.h
@@ -0,0 +1,712 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Bug report URL. */
+#define BUG_REPORT_URL ""
+
+/* Relative directory for resource files */
+#define CLANG_RESOURCE_DIR ""
+
+/* 32 bit multilib directory. */
+#define CXX_INCLUDE_32BIT_DIR ""
+
+/* 64 bit multilib directory. */
+#define CXX_INCLUDE_64BIT_DIR ""
+
+/* Arch the libstdc++ headers. */
+#define CXX_INCLUDE_ARCH ""
+
+/* Directory with the libstdc++ headers. */
+#define CXX_INCLUDE_ROOT ""
+
+/* Directories clang will search for headers */
+#define C_INCLUDE_DIRS ""
+
+/* Define if CBE is enabled for printf %a output */
+#define ENABLE_CBE_PRINTF_A 1
+
+/* Define if position independent code is enabled */
+#define ENABLE_PIC
+
+/* Define if threads enabled */
+#define ENABLE_THREADS 1
+
+/* Define if timestamp information (e.g., __DATE___) is allowed */
+#define ENABLE_TIMESTAMPS 0
+
+/* Define to 1 if you have the `argz_append' function. */
+#define HAVE_ARGZ_APPEND 1
+
+/* Define to 1 if you have the `argz_create_sep' function. */
+#define HAVE_ARGZ_CREATE_SEP 1
+
+/* Define to 1 if you have the <argz.h> header file. */
+#define HAVE_ARGZ_H 1
+
+/* Define to 1 if you have the `argz_insert' function. */
+#define HAVE_ARGZ_INSERT 1
+
+/* Define to 1 if you have the `argz_next' function. */
+#define HAVE_ARGZ_NEXT 1
+
+/* Define to 1 if you have the `argz_stringify' function. */
+#define HAVE_ARGZ_STRINGIFY 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `backtrace' function. */
+#undef HAVE_BACKTRACE
+
+/* Define to 1 if you have the `bcopy' function. */
+#undef HAVE_BCOPY
+
+/* Define to 1 if you have the `ceilf' function. */
+#define HAVE_CEILF 1
+
+/* Define if the neat program is available */
+/* #undef HAVE_CIRCO */
+
+/* Define to 1 if you have the `closedir' function. */
+#define HAVE_CLOSEDIR 1
+
+/* Define to 1 if you have the <CrashReporterClient.h> header file. */
+#undef HAVE_CRASHREPORTERCLIENT_H
+
+/* Define if __crashreporter_info__ exists. */
+#undef HAVE_CRASHREPORTER_INFO
+
+/* Define to 1 if you have the <ctype.h> header file. */
+#define HAVE_CTYPE_H 1
+
+/* Define to 1 if you have the declaration of `strerror_s', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRERROR_S 0
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+   */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the GNU dld library. */
+#undef HAVE_DLD
+
+/* Define to 1 if you have the <dld.h> header file. */
+/* #undef HAVE_DLD_H */
+
+/* Define to 1 if you have the `dlerror' function. */
+#define HAVE_DLERROR 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if dlopen() is available on this platform. */
+#define HAVE_DLOPEN 1
+
+/* Define to 1 if you have the <dl.h> header file. */
+/* #undef HAVE_DL_H */
+
+/* Define if the dot program is available */
+/* #undef HAVE_DOT */
+
+/* Define if the dotty program is available */
+/* #undef HAVE_DOTTY */
+
+/* Define if you have the _dyld_func_lookup function. */
+#undef HAVE_DYLD
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if the system has the type `error_t'. */
+#define HAVE_ERROR_T 1
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+/* #undef HAVE_EXECINFO_H */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if the neat program is available */
+/* #undef HAVE_FDP */
+
+/* Define to 1 if you have the <fenv.h> header file. */
+#define HAVE_FENV_H 1
+
+/* Define if libffi is available on this platform. */
+/* #undef HAVE_FFI_CALL */
+
+/* Define to 1 if you have the <ffi/ffi.h> header file. */
+/* #undef HAVE_FFI_FFI_H */
+
+/* Define to 1 if you have the <ffi.h> header file. */
+/* #undef HAVE_FFI_H */
+
+/* Set to 1 if the finite function is found in <ieeefp.h> */
+/* #undef HAVE_FINITE_IN_IEEEFP_H */
+
+/* Define to 1 if you have the `floorf' function. */
+#define HAVE_FLOORF 1
+
+/* Define to 1 if you have the `fmodf' function. */
+#define HAVE_FMODF 1
+
+/* Define to 1 if you have the `getcwd' function. */
+#define HAVE_GETCWD 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the `getrusage' function. */
+#define HAVE_GETRUSAGE 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define if the Graphviz program is available */
+#undef HAVE_GRAPHVIZ
+
+/* Define if the gv program is available */
+/* #undef HAVE_GV */
+
+/* Define to 1 if you have the `index' function. */
+#define HAVE_INDEX 1
+
+/* Define to 1 if the system has the type `int64_t'. */
+#define HAVE_INT64_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `isatty' function. */
+#define HAVE_ISATTY 1
+
+/* Set to 1 if the isinf function is found in <cmath> */
+/* #undef HAVE_ISINF_IN_CMATH */
+
+/* Set to 1 if the isinf function is found in <math.h> */
+#define HAVE_ISINF_IN_MATH_H 1
+
+/* Set to 1 if the isnan function is found in <cmath> */
+/* #undef HAVE_ISNAN_IN_CMATH */
+
+/* Set to 1 if the isnan function is found in <math.h> */
+#define HAVE_ISNAN_IN_MATH_H 1
+
+/* Define if you have the libdl library or equivalent. */
+#define HAVE_LIBDL 1
+
+/* Define to 1 if you have the `imagehlp' library (-limagehlp). */
+/* #undef HAVE_LIBIMAGEHLP */
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `psapi' library (-lpsapi). */
+/* #undef HAVE_LIBPSAPI */
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#define HAVE_LIBPTHREAD 1
+
+/* Define to 1 if you have the `udis86' library (-ludis86). */
+#undef HAVE_LIBUDIS86
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if you can use -Wl,-export-dynamic. */
+#define HAVE_LINK_EXPORT_DYNAMIC 1
+
+/* Define to 1 if you have the <link.h> header file. */
+#define HAVE_LINK_H 1
+
+/* Define if you can use -Wl,-R. to pass -R. to the linker, in order to add
+   the current directory to the dynamic linker search path. */
+#undef HAVE_LINK_R
+
+/* Define to 1 if you have the `longjmp' function. */
+#define HAVE_LONGJMP 1
+
+/* Define to 1 if you have the <mach/mach.h> header file. */
+/* #undef HAVE_MACH_MACH_H */
+
+/* Define to 1 if you have the <mach-o/dyld.h> header file. */
+/* #undef HAVE_MACH_O_DYLD_H */
+
+/* Define if mallinfo() is available on this platform. */
+/* #undef HAVE_MALLINFO */
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <malloc/malloc.h> header file. */
+/* #undef HAVE_MALLOC_MALLOC_H */
+
+/* Define to 1 if you have the `malloc_zone_statistics' function. */
+/* #undef HAVE_MALLOC_ZONE_STATISTICS */
+
+/* Define to 1 if you have the `memcpy' function. */
+#define HAVE_MEMCPY 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkdtemp' function. */
+#define HAVE_MKDTEMP 1
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have the `mktemp' function. */
+#define HAVE_MKTEMP 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define if mmap() uses MAP_ANONYMOUS to map anonymous pages, or undefine if
+   it uses MAP_ANON */
+#undef HAVE_MMAP_ANONYMOUS
+
+/* Define if mmap() can map files into memory */
+#undef HAVE_MMAP_FILE
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+/* #undef HAVE_NDIR_H */
+
+/* Define to 1 if you have the `nearbyintf' function. */
+#define HAVE_NEARBYINTF 1
+
+/* Define if the neat program is available */
+/* #undef HAVE_NEATO */
+
+/* Define to 1 if you have the `opendir' function. */
+#define HAVE_OPENDIR 1
+
+/* Define to 1 if you have the `posix_spawn' function. */
+/* #undef HAVE_POSIX_SPAWN */
+
+/* Define to 1 if you have the `powf' function. */
+/* #undef HAVE_POWF */
+
+/* Define if libtool can extract symbol lists from object files. */
+#undef HAVE_PRELOADED_SYMBOLS
+
+/* Define to have the %a format string */
+#undef HAVE_PRINTF_A
+
+/* Have pthread_getspecific */
+#define HAVE_PTHREAD_GETSPECIFIC 1
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#define HAVE_PTHREAD_H 1
+
+/* Have pthread_mutex_lock */
+#define HAVE_PTHREAD_MUTEX_LOCK 1
+
+/* Have pthread_rwlock_init */
+#define HAVE_PTHREAD_RWLOCK_INIT 1
+
+/* Define to 1 if srand48/lrand48/drand48 exist in <stdlib.h> */
+#define HAVE_RAND48 1
+
+/* Define to 1 if you have the `readdir' function. */
+#define HAVE_READDIR 1
+
+/* Define to 1 if you have the `realpath' function. */
+#undef HAVE_REALPATH
+
+/* Define to 1 if you have the `rindex' function. */
+#define HAVE_RINDEX 1
+
+/* Define to 1 if you have the `rintf' function. */
+#undef HAVE_RINTF
+
+/* Define to 1 if you have the `round' function. */
+/* #undef HAVE_ROUND */
+
+/* Define to 1 if you have the `roundf' function. */
+#undef HAVE_ROUNDF
+
+/* Define to 1 if you have the `sbrk' function. */
+/* #undef HAVE_SBRK */
+
+/* Define to 1 if you have the `setenv' function. */
+#define HAVE_SETENV 1
+
+/* Define to 1 if you have the `setjmp' function. */
+#define HAVE_SETJMP 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define if you have the shl_load function. */
+#undef HAVE_SHL_LOAD
+
+/* Define to 1 if you have the `siglongjmp' function. */
+#define HAVE_SIGLONGJMP 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+/* #undef HAVE_SIGNAL_H */
+
+/* Define to 1 if you have the `sigsetjmp' function. */
+/* #undef HAVE_SIGSETJMP */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Set to 1 if the std::isinf function is found in <cmath> */
+#undef HAVE_STD_ISINF_IN_CMATH
+
+/* Set to 1 if the std::isnan function is found in <cmath> */
+#undef HAVE_STD_ISNAN_IN_CMATH
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strcmp' function. */
+#define HAVE_STRCMP 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strrchr' function. */
+#define HAVE_STRRCHR 1
+
+/* Define to 1 if you have the `strtof' function. */
+/* #undef HAVE_STRTOF */
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if you have the `strtoq' function. */
+#define HAVE_STRTOQ 1
+
+/* Define to 1 if you have the `sysconf' function. */
+#undef HAVE_SYSCONF
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+   */
+#define HAVE_SYS_DIR_H 1
+
+/* Define to 1 if you have the <sys/dl.h> header file. */
+/* #undef HAVE_SYS_DL_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+   */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define if the neat program is available */
+/* #undef HAVE_TWOPI */
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if the system has the type `u_int64_t'. */
+#define HAVE_U_INT64_T 1
+
+/* Define to 1 if you have the <valgrind/valgrind.h> header file. */
+/* #undef HAVE_VALGRIND_VALGRIND_H */
+
+/* Define to 1 if you have the <windows.h> header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the `writev' function. */
+#define HAVE_WRITEV 1
+
+/* Define if the xdot.py program is available */
+/* #undef HAVE_XDOT_PY */
+
+/* Have host's _alloca */
+/* #undef HAVE__ALLOCA */
+
+/* Have host's __alloca */
+/* #undef HAVE___ALLOCA */
+
+/* Have host's __ashldi3 */
+/* #undef HAVE___ASHLDI3 */
+
+/* Have host's __ashrdi3 */
+/* #undef HAVE___ASHRDI3 */
+
+/* Have host's __chkstk */
+/* #undef HAVE___CHKSTK */
+
+/* Have host's __cmpdi2 */
+/* #undef HAVE___CMPDI2 */
+
+/* Have host's __divdi3 */
+/* #undef HAVE___DIVDI3 */
+
+/* Define to 1 if you have the `__dso_handle' function. */
+#undef HAVE___DSO_HANDLE
+
+/* Have host's __fixdfdi */
+/* #undef HAVE___FIXDFDI */
+
+/* Have host's __fixsfdi */
+/* #undef HAVE___FIXSFDI */
+
+/* Have host's __floatdidf */
+/* #undef HAVE___FLOATDIDF */
+
+/* Have host's __lshrdi3 */
+/* #undef HAVE___LSHRDI3 */
+
+/* Have host's __main */
+/* #undef HAVE___MAIN */
+
+/* Have host's __moddi3 */
+/* #undef HAVE___MODDI3 */
+
+/* Have host's __udivdi3 */
+/* #undef HAVE___UDIVDI3 */
+
+/* Have host's __umoddi3 */
+/* #undef HAVE___UMODDI3 */
+
+/* Have host's ___chkstk */
+/* #undef HAVE____CHKSTK */
+
+/* Linker version detected at compile time. */
+#undef HOST_LINK_VERSION
+
+/* Installation directory for binary executables */
+/* #undef LLVM_BINDIR */
+
+/* Time at which LLVM was configured */
+/* #undef LLVM_CONFIGTIME */
+
+/* Installation directory for data files */
+/* #undef LLVM_DATADIR */
+
+/* Installation directory for documentation */
+/* #undef LLVM_DOCSDIR */
+
+/* Installation directory for config files */
+/* #undef LLVM_ETCDIR */
+
+/* Has gcc/MSVC atomic intrinsics */
+#define LLVM_HAS_ATOMICS 1
+
+/* Host triple we were built on */
+#define LLVM_HOSTTRIPLE "i686-pc-linux-gnu"
+
+/* Installation directory for include files */
+/* #undef LLVM_INCLUDEDIR */
+
+/* Installation directory for .info files */
+/* #undef LLVM_INFODIR */
+
+/* Installation directory for libraries */
+/* #undef LLVM_LIBDIR */
+
+/* Installation directory for man pages */
+/* #undef LLVM_MANDIR */
+
+/* LLVM architecture name for the native architecture, if available */
+#define LLVM_NATIVE_ARCH X86
+
+/* LLVM name for the native AsmParser init function, if available */
+/* #undef LLVM_NATIVE_ASMPARSER */
+
+/* LLVM name for the native AsmPrinter init function, if available */
+#define LLVM_NATIVE_ASMPRINTER LLVMInitializeX86AsmPrinter
+
+/* LLVM name for the native Target init function, if available */
+#define LLVM_NATIVE_TARGET LLVMInitializeX86Target
+
+/* LLVM name for the native TargetInfo init function, if available */
+#define LLVM_NATIVE_TARGETINFO LLVMInitializeX86TargetInfo
+
+/* LLVM name for the native target MC init function, if available */
+#define LLVM_NATIVE_TARGETMC LLVMInitializeX86TargetMC
+
+/* Define if this is Unixish platform */
+#define LLVM_ON_UNIX 1
+
+/* Define if this is Win32ish platform */
+/* #undef LLVM_ON_WIN32 */
+
+/* Define to path to circo program if found or 'echo circo' otherwise */
+/* #undef LLVM_PATH_CIRCO */
+
+/* Define to path to dot program if found or 'echo dot' otherwise */
+/* #undef LLVM_PATH_DOT */
+
+/* Define to path to dotty program if found or 'echo dotty' otherwise */
+/* #undef LLVM_PATH_DOTTY */
+
+/* Define to path to fdp program if found or 'echo fdp' otherwise */
+/* #undef LLVM_PATH_FDP */
+
+/* Define to path to Graphviz program if found or 'echo Graphviz' otherwise */
+/* #undef LLVM_PATH_GRAPHVIZ */
+
+/* Define to path to gv program if found or 'echo gv' otherwise */
+/* #undef LLVM_PATH_GV */
+
+/* Define to path to neato program if found or 'echo neato' otherwise */
+/* #undef LLVM_PATH_NEATO */
+
+/* Define to path to twopi program if found or 'echo twopi' otherwise */
+/* #undef LLVM_PATH_TWOPI */
+
+/* Define to path to xdot.py program if found or 'echo xdot.py' otherwise */
+/* #undef LLVM_PATH_XDOT_PY */
+
+/* Installation prefix directory */
+#define LLVM_PREFIX "/usr/local"
+
+/* Define if the OS needs help to load dependent libraries for dlopen(). */
+/* #undef LTDL_DLOPEN_DEPLIBS */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LTDL_OBJDIR
+
+/* Define to the name of the environment variable that determines the dynamic
+   library search path. */
+#define LTDL_SHLIBPATH_VAR "LD_LIBRARY_PATH"
+
+/* Define to the extension used for shared libraries, say, ".so". */
+#define LTDL_SHLIB_EXT ".so"
+
+/* Define to the system default library search path. */
+/* #undef LTDL_SYSSEARCHPATH */
+
+/* Define if /dev/zero should be used when mapping RWX memory, or undefine if
+   its not necessary */
+#undef NEED_DEV_ZERO_FOR_MMAP
+
+/* Define if dlsym() requires a leading underscore in symbol names. */
+#undef NEED_USCORE
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "llvmbugs@cs.uiuc.edu"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "llvm"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "llvm 3.0"
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "3.0"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#undef STAT_MACROS_BROKEN
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define if we have the oprofile JIT-support library */
+#undef USE_OPROFILE
+
+/* Define if use udis86 library */
+#undef USE_UDIS86
+
+/* Type of 1st arg on ELM Callback */
+/* #undef WIN32_ELMCB_PCSTR */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to a type to use for `error_t' if it is not otherwise available. */
+/* #undef error_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to a function replacing strtoll */
+/* #undef strtoll */
+
+/* Define to a function implementing strtoull */
+/* #undef strtoull */
+
+/* Define to a function implementing stricmp */
+/* #undef stricmp */
+
+/* Define to a function implementing strdup */
+/* #undef strdup */
+
+/* Define to 1 if you have the `_chsize_s' function. */
+/* #undef HAVE__CHSIZE_S */
+
+/* Added by Kevin -- Maximum path length */
+#define MAXPATHLEN 2024
+
+#endif
diff --git a/third_party/LLVM/include-fuchsia/llvm/Config/llvm-config.h b/third_party/LLVM/include-fuchsia/llvm/Config/llvm-config.h
new file mode 100644
index 0000000..11e4e5c
--- /dev/null
+++ b/third_party/LLVM/include-fuchsia/llvm/Config/llvm-config.h
@@ -0,0 +1,106 @@
+/*===-- llvm/config/llvm-config.h - llvm configure variable -------*- C -*-===*/
+/*                                                                            */
+/*                     The LLVM Compiler Infrastructure                       */
+/*                                                                            */
+/* This file is distributed under the University of Illinois Open Source      */
+/* License. See LICENSE.TXT for details.                                      */
+/*                                                                            */
+/*===----------------------------------------------------------------------===*/
+
+/* This file enumerates all of the llvm variables from configure so that
+   they can be in exported headers and won't override package specific
+   directives.  This is a C file so we can include it in the llvm-c headers.  */
+
+/* To avoid multiple inclusions of these variables when we include the exported
+   headers and config.h, conditionally include these.  */
+/* TODO: This is a bit of a hack.  */
+#ifndef CONFIG_H
+
+/* Installation directory for binary executables */
+/* #undef LLVM_BINDIR */
+
+/* Time at which LLVM was configured */
+/* #undef LLVM_CONFIGTIME */
+
+/* Installation directory for data files */
+/* #undef LLVM_DATADIR */
+
+/* Installation directory for documentation */
+/* #undef LLVM_DOCSDIR */
+
+/* Installation directory for config files */
+/* #undef LLVM_ETCDIR */
+
+/* Has gcc/MSVC atomic intrinsics */
+#define LLVM_HAS_ATOMICS 1
+
+/* Host triple we were built on */
+#define LLVM_HOSTTRIPLE "i686-pc-linux-gnu"
+
+/* Installation directory for include files */
+/* #undef LLVM_INCLUDEDIR */
+
+/* Installation directory for .info files */
+/* #undef LLVM_INFODIR */
+
+/* Installation directory for libraries */
+/* #undef LLVM_LIBDIR */
+
+/* Installation directory for man pages */
+/* #undef LLVM_MANDIR */
+
+/* LLVM architecture name for the native architecture, if available */
+#define LLVM_NATIVE_ARCH X86
+
+/* LLVM name for the native AsmParser init function, if available */
+/* #undef LLVM_NATIVE_ASMPARSER */
+
+/* LLVM name for the native AsmPrinter init function, if available */
+#define LLVM_NATIVE_ASMPRINTER LLVMInitializeX86AsmPrinter
+
+/* LLVM name for the native Target init function, if available */
+#define LLVM_NATIVE_TARGET LLVMInitializeX86Target
+
+/* LLVM name for the native TargetInfo init function, if available */
+#define LLVM_NATIVE_TARGETINFO LLVMInitializeX86TargetInfo
+
+/* LLVM name for the native target MC init function, if available */
+#define LLVM_NATIVE_TARGETMC LLVMInitializeX86TargetMC
+
+/* Define if this is Unixish platform */
+#define LLVM_ON_UNIX 1
+
+/* Define if this is Win32ish platform */
+/* #undef LLVM_ON_WIN32 */
+
+/* Define to path to circo program if found or 'echo circo' otherwise */
+/* #undef LLVM_PATH_CIRCO */
+
+/* Define to path to dot program if found or 'echo dot' otherwise */
+/* #undef LLVM_PATH_DOT */
+
+/* Define to path to dotty program if found or 'echo dotty' otherwise */
+/* #undef LLVM_PATH_DOTTY */
+
+/* Define to path to fdp program if found or 'echo fdp' otherwise */
+/* #undef LLVM_PATH_FDP */
+
+/* Define to path to Graphviz program if found or 'echo Graphviz' otherwise */
+/* #undef LLVM_PATH_GRAPHVIZ */
+
+/* Define to path to gv program if found or 'echo gv' otherwise */
+/* #undef LLVM_PATH_GV */
+
+/* Define to path to neato program if found or 'echo neato' otherwise */
+/* #undef LLVM_PATH_NEATO */
+
+/* Define to path to twopi program if found or 'echo twopi' otherwise */
+/* #undef LLVM_PATH_TWOPI */
+
+/* Define to path to xdot.py program if found or 'echo xdot.py' otherwise */
+/* #undef LLVM_PATH_XDOT_PY */
+
+/* Installation prefix directory */
+#define LLVM_PREFIX "/usr/local"
+
+#endif
\ No newline at end of file
diff --git a/third_party/LLVM/include-fuchsia/llvm/Support/DataTypes.h b/third_party/LLVM/include-fuchsia/llvm/Support/DataTypes.h
new file mode 100644
index 0000000..180c4b9
--- /dev/null
+++ b/third_party/LLVM/include-fuchsia/llvm/Support/DataTypes.h
@@ -0,0 +1,197 @@
+/*===-- include/Support/DataTypes.h - Define fixed size types -----*- C -*-===*\
+|*                                                                            *|
+|*                     The LLVM Compiler Infrastructure                       *|
+|*                                                                            *|
+|* This file is distributed under the University of Illinois Open Source      *|
+|* License. See LICENSE.TXT for details.                                      *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* This file contains definitions to figure out the size of _HOST_ data types.*|
+|* This file is important because different host OS's define different macros,*|
+|* which makes portability tough.  This file exports the following            *|
+|* definitions:                                                               *|
+|*                                                                            *|
+|*   [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*|
+|*   [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values.     *|
+|*                                                                            *|
+|* No library is required when using these functions.                         *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*/
+
+/* Please leave this file C-compatible. */
+
+/* Please keep this file in sync with DataTypes.h.in */
+
+#ifndef SUPPORT_DATATYPES_H
+#define SUPPORT_DATATYPES_H
+
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_UINT64_T 1
+#define HAVE_U_INT64_T 1
+
+#ifdef __cplusplus
+#include <cmath>
+#else
+#include <math.h>
+#endif
+
+#ifndef _MSC_VER
+
+/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS
+   being defined.  We would define it here, but in order to prevent Bad Things
+   happening when system headers or C++ STL headers include stdint.h before we
+   define it here, we define it on the g++ command line (in Makefile.rules). */
+#if !defined(__STDC_LIMIT_MACROS)
+# error "Must #define __STDC_LIMIT_MACROS before #including Support/DataTypes.h"
+#endif
+
+#if !defined(__STDC_CONSTANT_MACROS)
+# error "Must #define __STDC_CONSTANT_MACROS before " \
+        "#including Support/DataTypes.h"
+#endif
+
+/* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef _AIX
+#include "llvm/Support/AIXDataTypesFix.h"
+#endif
+
+/* Handle incorrect definition of uint64_t as u_int64_t */
+#ifndef HAVE_UINT64_T
+#ifdef HAVE_U_INT64_T
+typedef u_int64_t uint64_t;
+#else
+# error "Don't have a definition for uint64_t on this platform"
+#endif
+#endif
+
+#ifdef _OpenBSD_
+#define INT8_MAX 127
+#define INT8_MIN -128
+#define UINT8_MAX 255
+#define INT16_MAX 32767
+#define INT16_MIN -32768
+#define UINT16_MAX 65535
+#define INT32_MAX 2147483647
+#define INT32_MIN -2147483648
+#define UINT32_MAX 4294967295U
+#endif
+
+#else /* _MSC_VER */
+/* Visual C++ doesn't provide standard integer headers, but it does provide
+   built-in data types. */
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/types.h>
+#ifdef __cplusplus
+#include <cmath>
+#else
+#include <math.h>
+#endif
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed int ssize_t;
+#ifndef INT8_MAX
+# define INT8_MAX 127
+#endif
+#ifndef INT8_MIN
+# define INT8_MIN -128
+#endif
+#ifndef UINT8_MAX
+# define UINT8_MAX 255
+#endif
+#ifndef INT16_MAX
+# define INT16_MAX 32767
+#endif
+#ifndef INT16_MIN
+# define INT16_MIN -32768
+#endif
+#ifndef UINT16_MAX
+# define UINT16_MAX 65535
+#endif
+#ifndef INT32_MAX
+# define INT32_MAX 2147483647
+#endif
+#ifndef INT32_MIN
+/* MSC treats -2147483648 as -(2147483648U). */
+# define INT32_MIN (-INT32_MAX - 1)
+#endif
+#ifndef UINT32_MAX
+# define UINT32_MAX 4294967295U
+#endif
+/* Certain compatibility updates to VC++ introduce the `cstdint'
+ * header, which defines the INT*_C macros. On default installs they
+ * are absent. */
+#ifndef INT8_C
+# define INT8_C(C)   C##i8
+#endif
+#ifndef UINT8_C
+# define UINT8_C(C)  C##ui8
+#endif
+#ifndef INT16_C
+# define INT16_C(C)  C##i16
+#endif
+#ifndef UINT16_C
+# define UINT16_C(C) C##ui16
+#endif
+#ifndef INT32_C
+# define INT32_C(C)  C##i32
+#endif
+#ifndef UINT32_C
+# define UINT32_C(C) C##ui32
+#endif
+#ifndef INT64_C
+# define INT64_C(C)  C##i64
+#endif
+#ifndef UINT64_C
+# define UINT64_C(C) C##ui64
+#endif
+
+#ifndef PRIx64
+# define PRIx64 "I64x"
+#endif
+
+#endif /* _MSC_VER */
+
+/* Set defaults for constants which we cannot find. */
+#if !defined(INT64_MAX)
+# define INT64_MAX 9223372036854775807LL
+#endif
+#if !defined(INT64_MIN)
+# define INT64_MIN ((-INT64_MAX)-1)
+#endif
+#if !defined(UINT64_MAX)
+# define UINT64_MAX 0xffffffffffffffffULL
+#endif
+
+#if __GNUC__ > 3
+#define END_WITH_NULL __attribute__((sentinel))
+#else
+#define END_WITH_NULL
+#endif
+
+#ifndef HUGE_VALF
+#define HUGE_VALF (float)HUGE_VAL
+#endif
+
+#endif  /* SUPPORT_DATATYPES_H */
\ No newline at end of file
diff --git a/third_party/LLVM/include/llvm/intrinsics_gen.vcxproj b/third_party/LLVM/include/llvm/intrinsics_gen.vcxproj
index aa49160..f53a817 100644
--- a/third_party/LLVM/include/llvm/intrinsics_gen.vcxproj
+++ b/third_party/LLVM/include/llvm/intrinsics_gen.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,43 +31,44 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>intrinsics_gen</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Analysis/LLVMAnalysis.vcxproj b/third_party/LLVM/lib/Analysis/LLVMAnalysis.vcxproj
index 5cb2ae2..b5349c1 100644
--- a/third_party/LLVM/lib/Analysis/LLVMAnalysis.vcxproj
+++ b/third_party/LLVM/lib/Analysis/LLVMAnalysis.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMAnalysis</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/CodeGen/LLVMCodeGen.vcxproj b/third_party/LLVM/lib/CodeGen/LLVMCodeGen.vcxproj
index 2e09532..ce7ffa3 100644
--- a/third_party/LLVM/lib/CodeGen/LLVMCodeGen.vcxproj
+++ b/third_party/LLVM/lib/CodeGen/LLVMCodeGen.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMCodeGen</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/CodeGen/SelectionDAG/LLVMSelectionDAG.vcxproj b/third_party/LLVM/lib/CodeGen/SelectionDAG/LLVMSelectionDAG.vcxproj
index d3ad90a..1098f13 100644
--- a/third_party/LLVM/lib/CodeGen/SelectionDAG/LLVMSelectionDAG.vcxproj
+++ b/third_party/LLVM/lib/CodeGen/SelectionDAG/LLVMSelectionDAG.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMSelectionDAG</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/ExecutionEngine/JIT/LLVMJIT.vcxproj b/third_party/LLVM/lib/ExecutionEngine/JIT/LLVMJIT.vcxproj
index f2934b0..735fc9e 100644
--- a/third_party/LLVM/lib/ExecutionEngine/JIT/LLVMJIT.vcxproj
+++ b/third_party/LLVM/lib/ExecutionEngine/JIT/LLVMJIT.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMJIT</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/ExecutionEngine/LLVMExecutionEngine.vcxproj b/third_party/LLVM/lib/ExecutionEngine/LLVMExecutionEngine.vcxproj
index 91a01a3..54a4ae5 100644
--- a/third_party/LLVM/lib/ExecutionEngine/LLVMExecutionEngine.vcxproj
+++ b/third_party/LLVM/lib/ExecutionEngine/LLVMExecutionEngine.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMExecutionEngine</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/MC/LLVMMC.vcxproj b/third_party/LLVM/lib/MC/LLVMMC.vcxproj
index 8c5e86b..41a20fd 100644
--- a/third_party/LLVM/lib/MC/LLVMMC.vcxproj
+++ b/third_party/LLVM/lib/MC/LLVMMC.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMMC</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Support/LLVMSupport.vcxproj b/third_party/LLVM/lib/Support/LLVMSupport.vcxproj
index 8004f5a..d52d9a8 100644
--- a/third_party/LLVM/lib/Support/LLVMSupport.vcxproj
+++ b/third_party/LLVM/lib/Support/LLVMSupport.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMSupport</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Support/Mutex.cpp b/third_party/LLVM/lib/Support/Mutex.cpp
index 8874e94..acc011f 100644
--- a/third_party/LLVM/lib/Support/Mutex.cpp
+++ b/third_party/LLVM/lib/Support/Mutex.cpp
@@ -75,7 +75,7 @@
     errorcode = pthread_mutexattr_settype(&attr, kind);
     assert(errorcode == 0);
 
-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__)
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__Fuchsia__)
     // Make it a process local mutex
     errorcode = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
     assert(errorcode == 0);
diff --git a/third_party/LLVM/lib/Support/Unix/Process.inc b/third_party/LLVM/lib/Support/Unix/Process.inc
index bf81969..27aaa39 100644
--- a/third_party/LLVM/lib/Support/Unix/Process.inc
+++ b/third_party/LLVM/lib/Support/Unix/Process.inc
@@ -77,6 +77,8 @@
     return EndOfMemory - StartOfMemory;

   else

     return 0;

+#elif defined(__Fuchsia__)

+  return 0;

 #else

 #warning Cannot get malloc info on this platform

   return 0;

diff --git a/third_party/LLVM/lib/TableGen/LLVMTableGen.vcxproj b/third_party/LLVM/lib/TableGen/LLVMTableGen.vcxproj
index a7a7b9a..f7bd0a9 100644
--- a/third_party/LLVM/lib/TableGen/LLVMTableGen.vcxproj
+++ b/third_party/LLVM/lib/TableGen/LLVMTableGen.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMTableGen</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Target/LLVMTarget.vcxproj b/third_party/LLVM/lib/Target/LLVMTarget.vcxproj
index c3d28c2..f552d4e 100644
--- a/third_party/LLVM/lib/Target/LLVMTarget.vcxproj
+++ b/third_party/LLVM/lib/Target/LLVMTarget.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMTarget</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Target/X86/InstPrinter/LLVMX86AsmPrinter.vcxproj b/third_party/LLVM/lib/Target/X86/InstPrinter/LLVMX86AsmPrinter.vcxproj
index a31a7b9..f2d67ad 100644
--- a/third_party/LLVM/lib/Target/X86/InstPrinter/LLVMX86AsmPrinter.vcxproj
+++ b/third_party/LLVM/lib/Target/X86/InstPrinter/LLVMX86AsmPrinter.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMX86AsmPrinter</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Target/X86/LLVMX86CodeGen.vcxproj b/third_party/LLVM/lib/Target/X86/LLVMX86CodeGen.vcxproj
index ff36f1c..4030687 100644
--- a/third_party/LLVM/lib/Target/X86/LLVMX86CodeGen.vcxproj
+++ b/third_party/LLVM/lib/Target/X86/LLVMX86CodeGen.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMX86CodeGen</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Target/X86/MCTargetDesc/LLVMX86Desc.vcxproj b/third_party/LLVM/lib/Target/X86/MCTargetDesc/LLVMX86Desc.vcxproj
index 88d1c7b..1a19a97 100644
--- a/third_party/LLVM/lib/Target/X86/MCTargetDesc/LLVMX86Desc.vcxproj
+++ b/third_party/LLVM/lib/Target/X86/MCTargetDesc/LLVMX86Desc.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMX86Desc</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Target/X86/TargetInfo/LLVMX86Info.vcxproj b/third_party/LLVM/lib/Target/X86/TargetInfo/LLVMX86Info.vcxproj
index a120eb5..c8dd335 100644
--- a/third_party/LLVM/lib/Target/X86/TargetInfo/LLVMX86Info.vcxproj
+++ b/third_party/LLVM/lib/Target/X86/TargetInfo/LLVMX86Info.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMX86Info</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Target/X86/Utils/LLVMX86Utils.vcxproj b/third_party/LLVM/lib/Target/X86/Utils/LLVMX86Utils.vcxproj
index 05873eb..df78cee 100644
--- a/third_party/LLVM/lib/Target/X86/Utils/LLVMX86Utils.vcxproj
+++ b/third_party/LLVM/lib/Target/X86/Utils/LLVMX86Utils.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMX86Utils</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Target/X86/X86CommonTableGen.vcxproj b/third_party/LLVM/lib/Target/X86/X86CommonTableGen.vcxproj
index 6abfa37..0f076d4 100644
--- a/third_party/LLVM/lib/Target/X86/X86CommonTableGen.vcxproj
+++ b/third_party/LLVM/lib/Target/X86/X86CommonTableGen.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,43 +31,44 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>X86CommonTableGen</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>Utility</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Transforms/InstCombine/LLVMInstCombine.vcxproj b/third_party/LLVM/lib/Transforms/InstCombine/LLVMInstCombine.vcxproj
index 133e494..baa3f10 100644
--- a/third_party/LLVM/lib/Transforms/InstCombine/LLVMInstCombine.vcxproj
+++ b/third_party/LLVM/lib/Transforms/InstCombine/LLVMInstCombine.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMInstCombine</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Transforms/Scalar/LLVMScalarOpts.vcxproj b/third_party/LLVM/lib/Transforms/Scalar/LLVMScalarOpts.vcxproj
index 774cfd2..c480d23 100644
--- a/third_party/LLVM/lib/Transforms/Scalar/LLVMScalarOpts.vcxproj
+++ b/third_party/LLVM/lib/Transforms/Scalar/LLVMScalarOpts.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMScalarOpts</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/Transforms/Utils/LLVMTransformUtils.vcxproj b/third_party/LLVM/lib/Transforms/Utils/LLVMTransformUtils.vcxproj
index 2b45eaf..4f2df89 100644
--- a/third_party/LLVM/lib/Transforms/Utils/LLVMTransformUtils.vcxproj
+++ b/third_party/LLVM/lib/Transforms/Utils/LLVMTransformUtils.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMTransformUtils</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/lib/VMCore/LLVMCore.vcxproj b/third_party/LLVM/lib/VMCore/LLVMCore.vcxproj
index e9c7424..681dfbe 100644
--- a/third_party/LLVM/lib/VMCore/LLVMCore.vcxproj
+++ b/third_party/LLVM/lib/VMCore/LLVMCore.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,47 +31,48 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>LLVMCore</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/LLVM/utils/TableGen/llvm-tblgen.vcxproj b/third_party/LLVM/utils/TableGen/llvm-tblgen.vcxproj
index 50a548c..0c21d51 100644
--- a/third_party/LLVM/utils/TableGen/llvm-tblgen.vcxproj
+++ b/third_party/LLVM/utils/TableGen/llvm-tblgen.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -31,43 +31,44 @@
     <Keyword>Win32Proj</Keyword>

     <Platform>Win32</Platform>

     <ProjectName>llvm-tblgen</ProjectName>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseOfMfc>false</UseOfMfc>

     <CharacterSet>NotSet</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/PowerVR_SDK/Examples/Advanced/ChameleonMan/OGLES2/Build/WindowsVC2010/OGLES2ChameleonMan.vcxproj b/third_party/PowerVR_SDK/Examples/Advanced/ChameleonMan/OGLES2/Build/WindowsVC2010/OGLES2ChameleonMan.vcxproj
index 8b408a9..9d6dadc 100644
--- a/third_party/PowerVR_SDK/Examples/Advanced/ChameleonMan/OGLES2/Build/WindowsVC2010/OGLES2ChameleonMan.vcxproj
+++ b/third_party/PowerVR_SDK/Examples/Advanced/ChameleonMan/OGLES2/Build/WindowsVC2010/OGLES2ChameleonMan.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -21,33 +21,34 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{9CF4408B-9B08-481F-95DA-3DF0846DABE4}</ProjectGuid>

     <RootNamespace>OGLES2ChameleonMan</RootNamespace>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/PowerVR_SDK/Examples/Beginner/01_HelloAPI/OGLES2/Build/WindowsVC2010/OGLES2HelloAPI.vcxproj b/third_party/PowerVR_SDK/Examples/Beginner/01_HelloAPI/OGLES2/Build/WindowsVC2010/OGLES2HelloAPI.vcxproj
index 803dd10..e4d373b 100644
--- a/third_party/PowerVR_SDK/Examples/Beginner/01_HelloAPI/OGLES2/Build/WindowsVC2010/OGLES2HelloAPI.vcxproj
+++ b/third_party/PowerVR_SDK/Examples/Beginner/01_HelloAPI/OGLES2/Build/WindowsVC2010/OGLES2HelloAPI.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -21,33 +21,34 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{9DAFEE32-19F6-4410-AA09-2B564FB86F62}</ProjectGuid>

     <RootNamespace>OGLES2HelloAPI</RootNamespace>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/PowerVR_SDK/Examples/Beginner/04_BasicTnL/OGLES/Build/WindowsVC2010/OGLESBasicTnL.vcxproj b/third_party/PowerVR_SDK/Examples/Beginner/04_BasicTnL/OGLES/Build/WindowsVC2010/OGLESBasicTnL.vcxproj
index 7612825..1a977d2 100644
--- a/third_party/PowerVR_SDK/Examples/Beginner/04_BasicTnL/OGLES/Build/WindowsVC2010/OGLESBasicTnL.vcxproj
+++ b/third_party/PowerVR_SDK/Examples/Beginner/04_BasicTnL/OGLES/Build/WindowsVC2010/OGLESBasicTnL.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -21,33 +21,34 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{AB1EB229-D86C-41B3-8E20-7A7E1FF5DDF5}</ProjectGuid>

     <RootNamespace>OGLESBasicTnL</RootNamespace>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/PowerVR_SDK/Examples/Intermediate/ColourGrading/OGLES3/Build/WindowsVC2010/OGLES3ColourGrading.vcxproj b/third_party/PowerVR_SDK/Examples/Intermediate/ColourGrading/OGLES3/Build/WindowsVC2010/OGLES3ColourGrading.vcxproj
index 2ed904f..363a529 100644
--- a/third_party/PowerVR_SDK/Examples/Intermediate/ColourGrading/OGLES3/Build/WindowsVC2010/OGLES3ColourGrading.vcxproj
+++ b/third_party/PowerVR_SDK/Examples/Intermediate/ColourGrading/OGLES3/Build/WindowsVC2010/OGLES3ColourGrading.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -21,33 +21,34 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{2EA5725B-25DA-44E2-B71E-BD9F55F3C2E2}</ProjectGuid>

     <RootNamespace>OGLES3ColourGrading</RootNamespace>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/PowerVR_SDK/Examples/Intermediate/DisplacementMap/OGLES2/Build/WindowsVC2010/OGLES2DisplacementMap.vcxproj b/third_party/PowerVR_SDK/Examples/Intermediate/DisplacementMap/OGLES2/Build/WindowsVC2010/OGLES2DisplacementMap.vcxproj
index 7de10d1..908b4dc 100644
--- a/third_party/PowerVR_SDK/Examples/Intermediate/DisplacementMap/OGLES2/Build/WindowsVC2010/OGLES2DisplacementMap.vcxproj
+++ b/third_party/PowerVR_SDK/Examples/Intermediate/DisplacementMap/OGLES2/Build/WindowsVC2010/OGLES2DisplacementMap.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -21,33 +21,34 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{04FC5430-3F1B-42A2-A18A-D8BB7E5B2733}</ProjectGuid>

     <RootNamespace>OGLES2DisplacementMap</RootNamespace>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>true</UseDebugLibraries>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>Application</ConfigurationType>

     <UseDebugLibraries>false</UseDebugLibraries>

     <WholeProgramOptimization>true</WholeProgramOptimization>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/PowerVR_SDK/Tools/OGLES2/Build/WindowsVC2010/OGLES2Tools.vcxproj b/third_party/PowerVR_SDK/Tools/OGLES2/Build/WindowsVC2010/OGLES2Tools.vcxproj
index 7c8d131..df193fa 100644
--- a/third_party/PowerVR_SDK/Tools/OGLES2/Build/WindowsVC2010/OGLES2Tools.vcxproj
+++ b/third_party/PowerVR_SDK/Tools/OGLES2/Build/WindowsVC2010/OGLES2Tools.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -22,29 +22,30 @@
     <ProjectGuid>{09ABE661-9BC0-4152-A820-1FB0522CAC01}</ProjectGuid>

     <RootNamespace>OGLES2Tools</RootNamespace>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>MultiByte</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>MultiByte</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/PowerVR_SDK/Tools/OGLES3/Build/WindowsVC2010/OGLES3Tools.vcxproj b/third_party/PowerVR_SDK/Tools/OGLES3/Build/WindowsVC2010/OGLES3Tools.vcxproj
index dabdf51..8c190f7 100644
--- a/third_party/PowerVR_SDK/Tools/OGLES3/Build/WindowsVC2010/OGLES3Tools.vcxproj
+++ b/third_party/PowerVR_SDK/Tools/OGLES3/Build/WindowsVC2010/OGLES3Tools.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Debug|Win32">

       <Configuration>Debug</Configuration>

@@ -22,29 +22,30 @@
     <ProjectGuid>{9088FC9E-9843-4E0D-85D0-1B657AFC480A}</ProjectGuid>

     <RootNamespace>OGLES3Tools</RootNamespace>

     <Keyword>Win32Proj</Keyword>

+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>MultiByte</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>MultiByte</CharacterSet>

     <WholeProgramOptimization>true</WholeProgramOptimization>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

     <ConfigurationType>StaticLibrary</ConfigurationType>

     <CharacterSet>MultiByte</CharacterSet>

-    <PlatformToolset>v140</PlatformToolset>

+    <PlatformToolset>v141</PlatformToolset>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

   <ImportGroup Label="ExtensionSettings">

diff --git a/third_party/googletest b/third_party/googletest
index ecd5308..0fe9660 160000
--- a/third_party/googletest
+++ b/third_party/googletest
@@ -1 +1 @@
-Subproject commit ecd530865cefdfa7dea58e84f6aa1b548950363d
+Subproject commit 0fe96607d85cf3a25ac40da369db62bbee2939a5
diff --git a/third_party/llvm-subzero/lib/Support/NativeFormatting.cpp b/third_party/llvm-subzero/lib/Support/NativeFormatting.cpp
index bb86891..88a07bb 100644
--- a/third_party/llvm-subzero/lib/Support/NativeFormatting.cpp
+++ b/third_party/llvm-subzero/lib/Support/NativeFormatting.cpp
@@ -14,6 +14,8 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Format.h"
 
+#include <float.h>
+
 using namespace llvm;
 
 template<typename T, std::size_t N>
diff --git a/third_party/subzero/codereview.settings b/third_party/subzero/codereview.settings
index 19e1584..093bbe6 100644
--- a/third_party/subzero/codereview.settings
+++ b/third_party/subzero/codereview.settings
@@ -1,10 +1,6 @@
-# This file is used by gcl to get repository specific information.
+# This file is used by git-cl to get repository specific information.
+GERRIT_HOST: True
 CODE_REVIEW_SERVER: codereview.chromium.org
 CC_LIST: native-client-reviews@googlegroups.com
-VIEW_VC: https://gerrit.chromium.org/gerrit/gitweb?p=native_client/pnacl-subzero.git;a=commit;h=
+VIEW_VC: https://chromium.googlesource.com/native_client/pnacl-subzero/+/
 STATUS: http://nativeclient-status.appspot.com/status
-TRY_ON_UPLOAD: False
-TRYSERVER_PROJECT: nacl
-TRYSERVER_SVN_URL: svn://svn.chromium.org/chrome-try/try-nacl
-PUSH_URL_CONFIG: url.ssh://gerrit.chromium.org.pushinsteadof
-ORIGIN_URL_CONFIG: http://chromium.googlesource.com
diff --git a/third_party/subzero/src/IceAssemblerARM32.cpp b/third_party/subzero/src/IceAssemblerARM32.cpp
index 2cf09ff..4b1fcb9 100644
--- a/third_party/subzero/src/IceAssemblerARM32.cpp
+++ b/third_party/subzero/src/IceAssemblerARM32.cpp
@@ -606,6 +606,25 @@
                              "=pc not allowed when CC=1");
 }
 
+enum SIMDShiftType { ST_Vshl, ST_Vshr };
+
+IValueT encodeSIMDShiftImm6(SIMDShiftType Shift, Type ElmtTy,
+                            const IValueT Imm) {
+  assert(Imm > 0);
+  const SizeT MaxShift = getScalarIntBitWidth(ElmtTy);
+  assert(Imm < 2 * MaxShift);
+  assert(ElmtTy == IceType_i8 || ElmtTy == IceType_i16 ||
+         ElmtTy == IceType_i32);
+  const IValueT VshlImm = Imm - MaxShift;
+  const IValueT VshrImm = 2 * MaxShift - Imm;
+  return ((Shift == ST_Vshl) ? VshlImm : VshrImm) & (2 * MaxShift - 1);
+}
+
+IValueT encodeSIMDShiftImm6(SIMDShiftType Shift, Type ElmtTy,
+                            const ConstantInteger32 *Imm6) {
+  const IValueT Imm = Imm6->getValue();
+  return encodeSIMDShiftImm6(Shift, ElmtTy, Imm);
+}
 } // end of anonymous namespace
 
 namespace Ice {
@@ -2838,6 +2857,31 @@
   emitInst(Encoding);
 }
 
+void AssemblerARM32::vldrq(const Operand *OpQd, const Operand *OpAddress,
+                           CondARM32::Cond Cond, const TargetInfo &TInfo) {
+  // This is a pseudo-instruction which loads 64-bit data into a quadword
+  // vector register. It is implemented by loading into the lower doubleword.
+
+  // VLDR - ARM section A8.8.333, encoding A1.
+  //   vldr<c> <Dd>, [<Rn>{, #+/-<imm>}]
+  //
+  // cccc1101UD01nnnndddd1011iiiiiiii where cccc=Cond, nnnn=Rn, Ddddd=Rd,
+  // iiiiiiii=abs(Imm >> 2), and U=1 if Opcode>=0.
+  constexpr const char *Vldrd = "vldrd";
+  IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vldrd));
+  assert(CondARM32::isDefined(Cond));
+  IValueT Address;
+  EncodedOperand AddressEncoding =
+      encodeAddress(OpAddress, Address, TInfo, RotatedImm8Div4Address);
+  (void)AddressEncoding;
+  assert(AddressEncoding == EncodedAsImmRegOffset);
+  IValueT Encoding = B27 | B26 | B24 | B20 | B11 | B9 | B8 |
+                     (encodeCondition(Cond) << kConditionShift) |
+                     (getYInRegYXXXX(Dd) << 22) |
+                     (getXXXXInRegYXXXX(Dd) << 12) | Address;
+  emitInst(Encoding);
+}
+
 void AssemblerARM32::vldrs(const Operand *OpSd, const Operand *OpAddress,
                            CondARM32::Cond Cond, const TargetInfo &TInfo) {
   // VDLR - ARM section A8.8.333, encoding A2.
@@ -2893,6 +2937,38 @@
   emitInst(Encoding);
 }
 
+void AssemblerARM32::emitVMem1Op(IValueT Opcode, IValueT Dd, IValueT Rn,
+                                 IValueT Rm, size_t ElmtSize, IValueT Align,
+                                 const char *InstName) {
+  assert(Utils::IsAbsoluteUint(2, Align));
+  IValueT EncodedElmtSize;
+  switch (ElmtSize) {
+  default: {
+    std::string Buffer;
+    llvm::raw_string_ostream StrBuf(Buffer);
+    StrBuf << InstName << ": found invalid vector element size " << ElmtSize;
+    llvm::report_fatal_error(StrBuf.str());
+  }
+  case 8:
+    EncodedElmtSize = 0;
+    break;
+  case 16:
+    EncodedElmtSize = 1;
+    break;
+  case 32:
+    EncodedElmtSize = 2;
+    break;
+  case 64:
+    EncodedElmtSize = 3;
+  }
+  const IValueT Encoding =
+      Opcode | (encodeCondition(CondARM32::kNone) << kConditionShift) |
+      (getYInRegYXXXX(Dd) << 22) | (Rn << kRnShift) |
+      (getXXXXInRegYXXXX(Dd) << kRdShift) | (EncodedElmtSize << 10) |
+      (Align << 4) | Rm;
+  emitInst(Encoding);
+}
+
 void AssemblerARM32::vld1qr(size_t ElmtSize, const Operand *OpQd,
                             const Operand *OpAddress, const TargetInfo &TInfo) {
   // VLD1 (multiple single elements) - ARM section A8.8.320, encoding A1:
@@ -2915,6 +2991,36 @@
   emitVMem1Op(Opcode, Dd, Rn, Rm, DRegListSize2, ElmtSize, Align, Vld1qr);
 }
 
+void AssemblerARM32::vld1(size_t ElmtSize, const Operand *OpQd,
+                          const Operand *OpAddress, const TargetInfo &TInfo) {
+  // This is a pseudo-instruction for loading a single element of a quadword
+  // vector. For 64-bit the lower doubleword vector is loaded.
+
+  if (ElmtSize == 64) {
+    return vldrq(OpQd, OpAddress, Ice::CondARM32::AL, TInfo);
+  }
+
+  // VLD1 (single elements to one lane) - ARMv7-A/R section A8.6.308, encoding
+  // A1:
+  //   VLD1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>
+  //
+  // 111101001D10nnnnddddss00aaaammmm where tttt=DRegListSize2, Dddd=Qd,
+  // nnnn=Rn, aa=0 (use default alignment), size=ElmtSize, and ss is the
+  // encoding of ElmtSize.
+  constexpr const char *Vld1qr = "vld1qr";
+  const IValueT Qd = encodeQRegister(OpQd, "Qd", Vld1qr);
+  const IValueT Dd = mapQRegToDReg(Qd);
+  IValueT Address;
+  if (encodeAddress(OpAddress, Address, TInfo, NoImmOffsetAddress) !=
+      EncodedAsImmRegOffset)
+    llvm::report_fatal_error(std::string(Vld1qr) + ": malform memory address");
+  const IValueT Rn = mask(Address, kRnShift, 4);
+  constexpr IValueT Rm = RegARM32::Reg_pc;
+  constexpr IValueT Opcode = B26 | B23 | B21;
+  constexpr IValueT Align = 0; // use default alignment.
+  emitVMem1Op(Opcode, Dd, Rn, Rm, ElmtSize, Align, Vld1qr);
+}
+
 bool AssemblerARM32::vmovqc(const Operand *OpQd, const ConstantInteger32 *Imm) {
   // VMOV (immediate) - ARM section A8.8.320, encoding A1:
   //   VMOV.<dt> <Qd>, #<Imm>
@@ -3226,6 +3332,183 @@
   emitSIMDqqq(VmulqiOpcode, ElmtTy, OpQd, OpQn, OpQm, Vmulqi);
 }
 
+void AssemblerARM32::vmulh(Type ElmtTy, const Operand *OpQd,
+                           const Operand *OpQn, const Operand *OpQm,
+                           bool Unsigned) {
+  // Pseudo-instruction for multiplying the corresponding elements in the lower
+  // halves of two quadword vectors, and returning the high halves.
+
+  // VMULL (integer and polynomial) - ARMv7-A/R section A8.6.337, encoding A1:
+  //   VMUL<c>.<dt> <Dd>, <Dn>, <Dm>
+  //
+  // 1111001U1Dssnnnndddd11o0N0M0mmmm
+  assert(isScalarIntegerType(ElmtTy) &&
+         "vmull expects vector with integer element type");
+  assert(ElmtTy != IceType_i64 && "vmull on i64 vector not allowed");
+  constexpr const char *Vmull = "vmull";
+
+  constexpr IValueT ElmtShift = 20;
+  const IValueT ElmtSize = encodeElmtType(ElmtTy);
+  assert(Utils::IsUint(2, ElmtSize));
+
+  const IValueT VmullOpcode =
+      B25 | (Unsigned ? B24 : 0) | B23 | (B20) | B11 | B10;
+
+  const IValueT Qd = encodeQRegister(OpQd, "Qd", Vmull);
+  const IValueT Qn = encodeQRegister(OpQn, "Qn", Vmull);
+  const IValueT Qm = encodeQRegister(OpQm, "Qm", Vmull);
+
+  const IValueT Dd = mapQRegToDReg(Qd);
+  const IValueT Dn = mapQRegToDReg(Qn);
+  const IValueT Dm = mapQRegToDReg(Qm);
+
+  constexpr bool UseQRegs = false;
+  constexpr bool IsFloatTy = false;
+  emitSIMDBase(VmullOpcode | (ElmtSize << ElmtShift), Dd, Dn, Dm, UseQRegs,
+               IsFloatTy);
+
+  // Shift and narrow to obtain high halves.
+  constexpr IValueT VshrnOpcode = B25 | B23 | B11 | B4;
+  const IValueT Imm6 = encodeSIMDShiftImm6(ST_Vshr, IceType_i16, 16);
+  constexpr IValueT ImmShift = 16;
+
+  emitSIMDBase(VshrnOpcode | (Imm6 << ImmShift), Dd, 0, Dd, UseQRegs,
+               IsFloatTy);
+}
+
+void AssemblerARM32::vmlap(Type ElmtTy, const Operand *OpQd,
+                           const Operand *OpQn, const Operand *OpQm) {
+  // Pseudo-instruction for multiplying the corresponding elements in the lower
+  // halves of two quadword vectors, and pairwise-adding the results.
+
+  // VMULL (integer and polynomial) - ARM section A8.8.350, encoding A1:
+  //   vmull<c>.<dt> <Qd>, <Qn>, <Qm>
+  //
+  // 1111001U1Dssnnnndddd11o0N0M0mmmm
+  assert(isScalarIntegerType(ElmtTy) &&
+         "vmull expects vector with integer element type");
+  assert(ElmtTy != IceType_i64 && "vmull on i64 vector not allowed");
+  constexpr const char *Vmull = "vmull";
+
+  constexpr IValueT ElmtShift = 20;
+  const IValueT ElmtSize = encodeElmtType(ElmtTy);
+  assert(Utils::IsUint(2, ElmtSize));
+
+  bool Unsigned = false;
+  const IValueT VmullOpcode =
+      B25 | (Unsigned ? B24 : 0) | B23 | (B20) | B11 | B10;
+
+  const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmull));
+  const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmull));
+  const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmull));
+
+  constexpr bool UseQRegs = false;
+  constexpr bool IsFloatTy = false;
+  emitSIMDBase(VmullOpcode | (ElmtSize << ElmtShift), Dd, Dn, Dm, UseQRegs,
+               IsFloatTy);
+
+  // VPADD - ARM section A8.8.280, encoding A1:
+  //   vpadd.<dt> <Dd>, <Dm>, <Dn>
+  //
+  // 111100100Dssnnnndddd1011NQM1mmmm where Ddddd=<Dd>, Mmmmm=<Dm>, and
+  // Nnnnn=<Dn> and ss is the encoding of <dt>.
+  assert(ElmtTy != IceType_i64 && "vpadd doesn't allow i64!");
+  const IValueT VpaddOpcode =
+      B25 | B11 | B9 | B8 | B4 | ((encodeElmtType(ElmtTy) + 1) << 20);
+  emitSIMDBase(VpaddOpcode, Dd, Dd, Dd + 1, UseQRegs, IsFloatTy);
+}
+
+void AssemblerARM32::vdup(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
+                          IValueT Idx) {
+  // VDUP (scalar) - ARMv7-A/R section A8.6.302, encoding A1:
+  //   VDUP<c>.<size> <Qd>, <Dm[x]>
+  //
+  // 111100111D11iiiiddd011000QM0mmmm where Dddd=<Qd>, Mmmmm=<Dm>, and
+  // iiii=imm4 encodes <size> and [x].
+  constexpr const char *Vdup = "vdup";
+
+  const IValueT VdupOpcode = B25 | B24 | B23 | B21 | B20 | B11 | B10;
+
+  const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vdup));
+  const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vdup));
+
+  constexpr bool UseQRegs = true;
+  constexpr bool IsFloatTy = false;
+
+  IValueT Imm4 = 0;
+  bool Lower = true;
+  switch (ElmtTy) {
+  case IceType_i8:
+    assert(Idx < 16);
+    Lower = Idx < 8;
+    Imm4 = 1 | ((Idx & 0x7) << 1);
+    break;
+  case IceType_i16:
+    assert(Idx < 8);
+    Lower = Idx < 4;
+    Imm4 = 2 | ((Idx & 0x3) << 2);
+    break;
+  case IceType_i32:
+  case IceType_f32:
+    assert(Idx < 4);
+    Lower = Idx < 2;
+    Imm4 = 4 | ((Idx & 0x1) << 3);
+    break;
+  default:
+    assert(false && "vdup only supports 8, 16, and 32-bit elements");
+    break;
+  }
+
+  emitSIMDBase(VdupOpcode, Dd, Imm4, Dn + (Lower ? 0 : 1), UseQRegs, IsFloatTy);
+}
+
+void AssemblerARM32::vzip(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
+                          const Operand *OpQm) {
+  // Pseudo-instruction which interleaves the elements of the lower halves of
+  // two quadword registers.
+
+  // Vzip - ARMv7-A/R section A8.6.410, encoding A1:
+  //   VZIP<c>.<size> <Dd>, <Dm>
+  //
+  // 111100111D11ss10dddd00011QM0mmmm where Ddddd=<Dd>, Mmmmm=<Dm>, and
+  // ss=<size>
+  assert(ElmtTy != IceType_i64 && "vzip on i64 vector not allowed");
+
+  constexpr const char *Vzip = "vzip";
+  const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vzip));
+  const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vzip));
+  const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vzip));
+
+  constexpr bool UseQRegs = false;
+  constexpr bool IsFloatTy = false;
+
+  // VMOV Dd, Dm
+  // 111100100D10mmmmdddd0001MQM1mmmm
+  constexpr IValueT VmovOpcode = B25 | B21 | B8 | B4;
+
+  // Copy lower half of second source to upper half of destination.
+  emitSIMDBase(VmovOpcode, Dd + 1, Dm, Dm, UseQRegs, IsFloatTy);
+
+  // Copy lower half of first source to lower half of destination.
+  if (Dd != Dn)
+    emitSIMDBase(VmovOpcode, Dd, Dn, Dn, UseQRegs, IsFloatTy);
+
+  constexpr IValueT ElmtShift = 18;
+  const IValueT ElmtSize = encodeElmtType(ElmtTy);
+  assert(Utils::IsUint(2, ElmtSize));
+
+  if (ElmtTy != IceType_i32 && ElmtTy != IceType_f32) {
+    constexpr IValueT VzipOpcode = B25 | B24 | B23 | B21 | B20 | B17 | B8 | B7;
+    // Zip the lower and upper half of destination.
+    emitSIMDBase(VzipOpcode | (ElmtSize << ElmtShift), Dd, 0, Dd + 1, UseQRegs,
+                 IsFloatTy);
+  } else {
+    constexpr IValueT VtrnOpcode = B25 | B24 | B23 | B21 | B20 | B17 | B7;
+    emitSIMDBase(VtrnOpcode | (ElmtSize << ElmtShift), Dd, 0, Dd + 1, UseQRegs,
+                 IsFloatTy);
+  }
+}
+
 void AssemblerARM32::vmulqf(const Operand *OpQd, const Operand *OpQn,
                             const Operand *OpQm) {
   // VMUL (floating-point) - ARM section A8.8.351, encoding A1:
@@ -3256,6 +3539,110 @@
                mapQRegToDReg(Qm), UseQRegs, IsFloat);
 }
 
+void AssemblerARM32::vmovlq(const Operand *OpQd, const Operand *OpQn,
+                            const Operand *OpQm) {
+  // Pseudo-instruction to copy the first source operand and insert the lower
+  // half of the second operand into the lower half of the destination.
+
+  // VMOV (register) - ARMv7-A/R section A8.6.327, encoding A1:
+  //   VMOV<c> <Dd>, <Dm>
+  //
+  // 111100111D110000ddd001011QM0mmm0 where Dddd=Qd, Mmmm=Qm, and Q=0.
+
+  constexpr const char *Vmov = "vmov";
+  const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmov));
+  const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmov));
+  const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmov));
+
+  constexpr bool UseQRegs = false;
+  constexpr bool IsFloat = false;
+
+  const IValueT VmovOpcode = B25 | B21 | B8 | B4;
+
+  if (Dd != Dm)
+    emitSIMDBase(VmovOpcode, Dd, Dm, Dm, UseQRegs, IsFloat);
+  if (Dd + 1 != Dn + 1)
+    emitSIMDBase(VmovOpcode, Dd + 1, Dn + 1, Dn + 1, UseQRegs, IsFloat);
+}
+
+void AssemblerARM32::vmovhq(const Operand *OpQd, const Operand *OpQn,
+                            const Operand *OpQm) {
+  // Pseudo-instruction to copy the first source operand and insert the high
+  // half of the second operand into the high half of the destination.
+
+  // VMOV (register) - ARMv7-A/R section A8.6.327, encoding A1:
+  //   VMOV<c> <Dd>, <Dm>
+  //
+  // 111100111D110000ddd001011QM0mmm0 where Dddd=Qd, Mmmm=Qm, and Q=0.
+
+  constexpr const char *Vmov = "vmov";
+  const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmov));
+  const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmov));
+  const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmov));
+
+  constexpr bool UseQRegs = false;
+  constexpr bool IsFloat = false;
+
+  const IValueT VmovOpcode = B25 | B21 | B8 | B4;
+
+  if (Dd != Dn)
+    emitSIMDBase(VmovOpcode, Dd, Dn, Dn, UseQRegs, IsFloat);
+  if (Dd + 1 != Dm + 1)
+    emitSIMDBase(VmovOpcode, Dd + 1, Dm + 1, Dm + 1, UseQRegs, IsFloat);
+}
+
+void AssemblerARM32::vmovhlq(const Operand *OpQd, const Operand *OpQn,
+                             const Operand *OpQm) {
+  // Pseudo-instruction to copy the first source operand and insert the high
+  // half of the second operand into the lower half of the destination.
+
+  // VMOV (register) - ARMv7-A/R section A8.6.327, encoding A1:
+  //   VMOV<c> <Dd>, <Dm>
+  //
+  // 111100111D110000ddd001011QM0mmm0 where Dddd=Qd, Mmmm=Qm, and Q=0.
+
+  constexpr const char *Vmov = "vmov";
+  const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmov));
+  const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmov));
+  const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmov));
+
+  constexpr bool UseQRegs = false;
+  constexpr bool IsFloat = false;
+
+  const IValueT VmovOpcode = B25 | B21 | B8 | B4;
+
+  if (Dd != Dm + 1)
+    emitSIMDBase(VmovOpcode, Dd, Dm + 1, Dm + 1, UseQRegs, IsFloat);
+  if (Dd + 1 != Dn + 1)
+    emitSIMDBase(VmovOpcode, Dd + 1, Dn + 1, Dn + 1, UseQRegs, IsFloat);
+}
+
+void AssemblerARM32::vmovlhq(const Operand *OpQd, const Operand *OpQn,
+                             const Operand *OpQm) {
+  // Pseudo-instruction to copy the first source operand and insert the lower
+  // half of the second operand into the high half of the destination.
+
+  // VMOV (register) - ARMv7-A/R section A8.6.327, encoding A1:
+  //   VMOV<c> <Dd>, <Dm>
+  //
+  // 111100111D110000ddd001011QM0mmm0 where Dddd=Qd, Mmmm=Qm, and Q=0.
+
+  constexpr const char *Vmov = "vmov";
+  const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmov));
+  const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmov));
+  const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmov));
+
+  constexpr bool UseQRegs = false;
+  constexpr bool IsFloat = false;
+
+  const IValueT VmovOpcode = B25 | B21 | B8 | B4;
+
+  if (Dd + 1 != Dm)
+    emitSIMDBase(VmovOpcode, Dd + 1, Dm, Dm, UseQRegs, IsFloat);
+  if (Dd != Dn)
+    emitSIMDBase(VmovOpcode, Dd, Dn, Dn, UseQRegs, IsFloat);
+}
+
 void AssemblerARM32::vnegqs(Type ElmtTy, const Operand *OpQd,
                             const Operand *OpQm) {
   // VNEG - ARM section A8.8.355, encoding A1:
@@ -3314,6 +3701,31 @@
   emitInst(Encoding);
 }
 
+void AssemblerARM32::vstrq(const Operand *OpQd, const Operand *OpAddress,
+                           CondARM32::Cond Cond, const TargetInfo &TInfo) {
+  // This is a pseudo-instruction which stores 64-bit data into a quadword
+  // vector register. It is implemented by storing into the lower doubleword.
+
+  // VSTR - ARM section A8.8.413, encoding A1:
+  //   vstr<c> <Dd>, [<Rn>{, #+/-<Imm>}]
+  //
+  // cccc1101UD00nnnndddd1011iiiiiiii where cccc=Cond, nnnn=Rn, Ddddd=Rd,
+  // iiiiiiii=abs(Imm >> 2), and U=1 if Imm>=0.
+  constexpr const char *Vstrd = "vstrd";
+  IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Dd", Vstrd));
+  assert(CondARM32::isDefined(Cond));
+  IValueT Address;
+  IValueT AddressEncoding =
+      encodeAddress(OpAddress, Address, TInfo, RotatedImm8Div4Address);
+  (void)AddressEncoding;
+  assert(AddressEncoding == EncodedAsImmRegOffset);
+  IValueT Encoding = B27 | B26 | B24 | B11 | B9 | B8 |
+                     (encodeCondition(Cond) << kConditionShift) |
+                     (getYInRegYXXXX(Dd) << 22) |
+                     (getXXXXInRegYXXXX(Dd) << 12) | Address;
+  emitInst(Encoding);
+}
+
 void AssemblerARM32::vstrs(const Operand *OpSd, const Operand *OpAddress,
                            CondARM32::Cond Cond, const TargetInfo &TInfo) {
   // VSTR - ARM section A8.8.413, encoding A2:
@@ -3357,6 +3769,37 @@
   emitVMem1Op(Opcode, Dd, Rn, Rm, DRegListSize2, ElmtSize, Align, Vst1qr);
 }
 
+void AssemblerARM32::vst1(size_t ElmtSize, const Operand *OpQd,
+                          const Operand *OpAddress, const TargetInfo &TInfo) {
+
+  // This is a pseudo-instruction for storing a single element of a quadword
+  // vector. For 64-bit the lower doubleword vector is stored.
+
+  if (ElmtSize == 64) {
+    return vstrq(OpQd, OpAddress, Ice::CondARM32::AL, TInfo);
+  }
+
+  // VST1 (single element from one lane) - ARMv7-A/R section A8.6.392, encoding
+  // A1:
+  //   VST1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>
+  //
+  // 111101001D00nnnnddd0ss00aaaammmm where Dddd=Qd, nnnn=Rn,
+  // aaaa=0 (use default alignment), size=ElmtSize, and ss is the
+  // encoding of ElmtSize.
+  constexpr const char *Vst1qr = "vst1qr";
+  const IValueT Qd = encodeQRegister(OpQd, "Qd", Vst1qr);
+  const IValueT Dd = mapQRegToDReg(Qd);
+  IValueT Address;
+  if (encodeAddress(OpAddress, Address, TInfo, NoImmOffsetAddress) !=
+      EncodedAsImmRegOffset)
+    llvm::report_fatal_error(std::string(Vst1qr) + ": malform memory address");
+  const IValueT Rn = mask(Address, kRnShift, 4);
+  constexpr IValueT Rm = RegARM32::Reg_pc;
+  constexpr IValueT Opcode = B26 | B23;
+  constexpr IValueT Align = 0; // use default alignment.
+  emitVMem1Op(Opcode, Dd, Rn, Rm, ElmtSize, Align, Vst1qr);
+}
+
 void AssemblerARM32::vsubs(const Operand *OpSd, const Operand *OpSn,
                            const Operand *OpSm, CondARM32::Cond Cond) {
   // VSUB (floating-point) - ARM section A8.8.415, encoding A2:
@@ -3381,6 +3824,62 @@
   emitVFPddd(Cond, VsubdOpcode, OpDd, OpDn, OpDm, Vsubd);
 }
 
+void AssemblerARM32::vqaddqi(Type ElmtTy, const Operand *OpQd,
+                             const Operand *OpQm, const Operand *OpQn) {
+  // VQADD (integer) - ARM section A8.6.369, encoding A1:
+  //   vqadd<c><q>.s<size> {<Qd>,} <Qn>, <Qm>
+  //
+  // 111100100Dssnnn0ddd00000N1M1mmm0 where Dddd=OpQd, Nnnn=OpQn, Mmmm=OpQm,
+  // size is 8, 16, 32, or 64.
+  assert(isScalarIntegerType(ElmtTy) &&
+         "vqaddqi expects vector with integer element type");
+  constexpr const char *Vqaddqi = "vqaddqi";
+  constexpr IValueT VqaddqiOpcode = B4;
+  emitSIMDqqq(VqaddqiOpcode, ElmtTy, OpQd, OpQm, OpQn, Vqaddqi);
+}
+
+void AssemblerARM32::vqaddqu(Type ElmtTy, const Operand *OpQd,
+                             const Operand *OpQm, const Operand *OpQn) {
+  // VQADD (integer) - ARM section A8.6.369, encoding A1:
+  //   vqadd<c><q>.s<size> {<Qd>,} <Qn>, <Qm>
+  //
+  // 111100110Dssnnn0ddd00000N1M1mmm0 where Dddd=OpQd, Nnnn=OpQn, Mmmm=OpQm,
+  // size is 8, 16, 32, or 64.
+  assert(isScalarIntegerType(ElmtTy) &&
+         "vqaddqu expects vector with integer element type");
+  constexpr const char *Vqaddqu = "vqaddqu";
+  constexpr IValueT VqaddquOpcode = B24 | B4;
+  emitSIMDqqq(VqaddquOpcode, ElmtTy, OpQd, OpQm, OpQn, Vqaddqu);
+}
+
+void AssemblerARM32::vqsubqi(Type ElmtTy, const Operand *OpQd,
+                             const Operand *OpQm, const Operand *OpQn) {
+  // VQSUB (integer) - ARM section A8.6.369, encoding A1:
+  //   vqsub<c><q>.s<size> {<Qd>,} <Qn>, <Qm>
+  //
+  // 111100100Dssnnn0ddd00010N1M1mmm0 where Dddd=OpQd, Nnnn=OpQn, Mmmm=OpQm,
+  // size is 8, 16, 32, or 64.
+  assert(isScalarIntegerType(ElmtTy) &&
+         "vqsubqi expects vector with integer element type");
+  constexpr const char *Vqsubqi = "vqsubqi";
+  constexpr IValueT VqsubqiOpcode = B9 | B4;
+  emitSIMDqqq(VqsubqiOpcode, ElmtTy, OpQd, OpQm, OpQn, Vqsubqi);
+}
+
+void AssemblerARM32::vqsubqu(Type ElmtTy, const Operand *OpQd,
+                             const Operand *OpQm, const Operand *OpQn) {
+  // VQSUB (integer) - ARM section A8.6.369, encoding A1:
+  //   vqsub<c><q>.s<size> {<Qd>,} <Qn>, <Qm>
+  //
+  // 111100110Dssnnn0ddd00010N1M1mmm0 where Dddd=OpQd, Nnnn=OpQn, Mmmm=OpQm,
+  // size is 8, 16, 32, or 64.
+  assert(isScalarIntegerType(ElmtTy) &&
+         "vqsubqu expects vector with integer element type");
+  constexpr const char *Vqsubqu = "vqsubqu";
+  constexpr IValueT VqsubquOpcode = B24 | B9 | B4;
+  emitSIMDqqq(VqsubquOpcode, ElmtTy, OpQd, OpQm, OpQn, Vqsubqu);
+}
+
 void AssemblerARM32::vsubqi(Type ElmtTy, const Operand *OpQd,
                             const Operand *OpQm, const Operand *OpQn) {
   // VSUB (integer) - ARM section A8.8.414, encoding A1:
@@ -3395,6 +3894,59 @@
   emitSIMDqqq(VsubqiOpcode, ElmtTy, OpQd, OpQm, OpQn, Vsubqi);
 }
 
+void AssemblerARM32::vqmovn2(Type DestElmtTy, const Operand *OpQd,
+                             const Operand *OpQm, const Operand *OpQn,
+                             bool Unsigned, bool Saturating) {
+  // Pseudo-instruction for packing two quadword vectors into one quadword
+  // vector, narrowing each element using saturation or truncation.
+
+  // VQMOVN - ARMv7-A/R section A8.6.361, encoding A1:
+  //   V{Q}MOVN{U}N<c>.<type><size> <Dd>, <Qm>
+  //
+  // 111100111D11ss10dddd0010opM0mmm0 where Ddddd=OpQd, op = 10, Mmmm=OpQm,
+  // ss is 00 (16-bit), 01 (32-bit), or 10 (64-bit).
+
+  assert(DestElmtTy != IceType_i64 &&
+         "vmovn doesn't allow i64 destination vector elements!");
+
+  constexpr const char *Vqmovn = "vqmovn";
+  constexpr bool UseQRegs = false;
+  constexpr bool IsFloatTy = false;
+  const IValueT Qd = encodeQRegister(OpQd, "Qd", Vqmovn);
+  const IValueT Qm = encodeQRegister(OpQm, "Qm", Vqmovn);
+  const IValueT Qn = encodeQRegister(OpQn, "Qn", Vqmovn);
+  const IValueT Dd = mapQRegToDReg(Qd);
+  const IValueT Dm = mapQRegToDReg(Qm);
+  const IValueT Dn = mapQRegToDReg(Qn);
+
+  IValueT VqmovnOpcode = B25 | B24 | B23 | B21 | B20 | B17 | B9 |
+                         (Saturating ? (Unsigned ? B6 : B7) : 0);
+
+  constexpr IValueT ElmtShift = 18;
+  VqmovnOpcode |= (encodeElmtType(DestElmtTy) << ElmtShift);
+
+  if (Qm != Qd) {
+    // Narrow second source operand to upper half of destination.
+    emitSIMDBase(VqmovnOpcode, Dd + 1, 0, Dn, UseQRegs, IsFloatTy);
+    // Narrow first source operand to lower half of destination.
+    emitSIMDBase(VqmovnOpcode, Dd + 0, 0, Dm, UseQRegs, IsFloatTy);
+  } else if (Qn != Qd) {
+    // Narrow first source operand to lower half of destination.
+    emitSIMDBase(VqmovnOpcode, Dd + 0, 0, Dm, UseQRegs, IsFloatTy);
+    // Narrow second source operand to upper half of destination.
+    emitSIMDBase(VqmovnOpcode, Dd + 1, 0, Dn, UseQRegs, IsFloatTy);
+  } else {
+    // Narrow first source operand to lower half of destination.
+    emitSIMDBase(VqmovnOpcode, Dd, 0, Dm, UseQRegs, IsFloatTy);
+
+    // VMOV Dd, Dm
+    // 111100100D10mmmmdddd0001MQM1mmmm
+    const IValueT VmovOpcode = B25 | B21 | B8 | B4;
+
+    emitSIMDBase(VmovOpcode, Dd + 1, Dd, Dd, UseQRegs, IsFloatTy);
+  }
+}
+
 void AssemblerARM32::vsubqf(const Operand *OpQd, const Operand *OpQn,
                             const Operand *OpQm) {
   // VSUB (floating-point) - ARM section A8.8.415, Encoding A1:
@@ -3467,22 +4019,6 @@
   emitSIMDqqq(VshlOpcode, ElmtTy, OpQd, OpQn, OpQm, Vshl);
 }
 
-namespace {
-enum SIMDShiftType { ST_Vshl, ST_Vshr };
-IValueT encodeSIMDShiftImm6(SIMDShiftType Shift, Type ElmtTy,
-                            const ConstantInteger32 *Imm6) {
-  const IValueT Imm = Imm6->getValue();
-  assert(Imm > 0);
-  const SizeT MaxShift = getScalarIntBitWidth(ElmtTy);
-  assert(Imm < MaxShift);
-  assert(ElmtTy == IceType_i8 || ElmtTy == IceType_i16 ||
-         ElmtTy == IceType_i32);
-  const IValueT VshlImm = Imm - MaxShift;
-  const IValueT VshrImm = 2 * MaxShift - Imm;
-  return ((Shift == ST_Vshl) ? VshlImm : VshrImm) & (2 * MaxShift - 1);
-}
-} // end of anonymous namespace
-
 void AssemblerARM32::vshlqc(Type ElmtTy, const Operand *OpQd,
                             const Operand *OpQm,
                             const ConstantInteger32 *Imm6) {
@@ -3499,34 +4035,19 @@
                    encodeSIMDShiftImm6(ST_Vshl, ElmtTy, Imm6), Vshl);
 }
 
-void AssemblerARM32::vshrqic(Type ElmtTy, const Operand *OpQd,
-                             const Operand *OpQm,
-                             const ConstantInteger32 *Imm6) {
+void AssemblerARM32::vshrqc(Type ElmtTy, const Operand *OpQd,
+                            const Operand *OpQm, const ConstantInteger32 *Imm6,
+                            InstARM32::FPSign Sign) {
   // VSHR - ARM section A8.8.398, encoding A1:
   //   vshr Qd, Qm, #Imm
   //
   // 1111001U1Diiiiiidddd0101LQM1mmmm where Ddddd=Qd, Mmmmm=Qm, iiiiii=Imm6,
-  // 0=U, 1=Q, 0=L.
+  // U=Unsigned, Q=1, L=0.
   assert(isScalarIntegerType(ElmtTy) &&
          "vshr expects vector with integer element type");
   constexpr const char *Vshr = "vshr";
-  constexpr IValueT VshrOpcode = B23 | B4;
-  emitSIMDShiftqqc(VshrOpcode, OpQd, OpQm,
-                   encodeSIMDShiftImm6(ST_Vshr, ElmtTy, Imm6), Vshr);
-}
-
-void AssemblerARM32::vshrquc(Type ElmtTy, const Operand *OpQd,
-                             const Operand *OpQm,
-                             const ConstantInteger32 *Imm6) {
-  // VSHR - ARM section A8.8.398, encoding A1:
-  //   vshr Qd, Qm, #Imm
-  //
-  // 1111001U1Diiiiiidddd0101LQM1mmmm where Ddddd=Qd, Mmmmm=Qm, iiiiii=Imm6,
-  // 0=U, 1=Q, 0=L.
-  assert(isScalarIntegerType(ElmtTy) &&
-         "vshr expects vector with integer element type");
-  constexpr const char *Vshr = "vshr";
-  constexpr IValueT VshrOpcode = B23 | B4;
+  const IValueT VshrOpcode =
+      (Sign == InstARM32::FS_Unsigned ? B24 : 0) | B23 | B4;
   emitSIMDShiftqqc(VshrOpcode, OpQd, OpQm,
                    encodeSIMDShiftImm6(ST_Vshr, ElmtTy, Imm6), Vshr);
 }
diff --git a/third_party/subzero/src/IceAssemblerARM32.h b/third_party/subzero/src/IceAssemblerARM32.h
index 84ca973..43c3f56 100644
--- a/third_party/subzero/src/IceAssemblerARM32.h
+++ b/third_party/subzero/src/IceAssemblerARM32.h
@@ -440,16 +440,34 @@
     vldrs(OpSd, OpAddress, Cond, TInfo);
   }
 
+  void vldrq(const Operand *OpQd, const Operand *OpAddress,
+             CondARM32::Cond Cond, const TargetInfo &TInfo);
+
+  void vldrq(const Operand *OpQd, const Operand *OpAddress,
+             CondARM32::Cond Cond, const TargetLowering *Lowering) {
+    const TargetInfo TInfo(Lowering);
+    vldrq(OpQd, OpAddress, Cond, TInfo);
+  }
+
   // ElmtSize = #bits in vector element.
   void vld1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
               const TargetInfo &TInfo);
 
+  void vld1(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
+            const TargetInfo &TInfo);
+
   void vld1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
               const TargetLowering *Lowering) {
     const TargetInfo TInfo(Lowering);
     vld1qr(ElmtSize, OpQd, OpRn, TInfo);
   }
 
+  void vld1(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
+            const TargetLowering *Lowering) {
+    const TargetInfo TInfo(Lowering);
+    vld1(ElmtSize, OpQd, OpRn, TInfo);
+  }
+
   // Qn[i] = Imm for all i in vector. Returns true iff Imm can be defined as an
   // Imm8 using AdvSIMDExpandImm().
   bool vmovqc(const Operand *OpQd, const ConstantInteger32 *Imm);
@@ -520,6 +538,21 @@
   void vmulqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
               const Operand *OpQm);
 
+  // Integer vector multiply high.
+  void vmulh(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
+             const Operand *OpQm, bool Unsigned);
+
+  // Integer vector multiply add pairwise.
+  void vmlap(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
+             const Operand *OpQm);
+
+  // Vector element replication.
+  void vdup(Type ElmtTy, const Operand *OpQd, const Operand *OpQn, IValueT Idx);
+
+  // Vector interleave lower halves.
+  void vzip(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
+            const Operand *OpQm);
+
   // Float vector multiply.
   void vmulqf(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
 
@@ -528,6 +561,11 @@
 
   void vmvnq(const Operand *OpQd, const Operand *OpQm);
 
+  void vmovlq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
+  void vmovhq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
+  void vmovhlq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
+  void vmovlhq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
+
   void vnegqs(const Operand *OpQd, const Operand *OpQm);
 
   void vnegqs(Type ElmtTy, const Operand *OpQd, const Operand *OpQm);
@@ -549,11 +587,8 @@
   void vshlqc(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
               const ConstantInteger32 *OpQn);
 
-  void vshrqic(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
-               const ConstantInteger32 *OpQn);
-
-  void vshrquc(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
-               const ConstantInteger32 *OpQn);
+  void vshrqc(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
+              const ConstantInteger32 *OpQn, InstARM32::FPSign Sign);
 
   void vsqrtd(const Operand *OpDd, const Operand *OpDm, CondARM32::Cond Cond);
 
@@ -577,6 +612,15 @@
     vstrs(OpSd, OpAddress, Cond, TInfo);
   }
 
+  void vstrq(const Operand *OpQd, const Operand *OpAddress,
+             CondARM32::Cond Cond, const TargetInfo &TInfo);
+
+  void vstrq(const Operand *OpQd, const Operand *OpAddress,
+             CondARM32::Cond Cond, const TargetLowering *Lowering) {
+    const TargetInfo TInfo(Lowering);
+    vstrq(OpQd, OpAddress, Cond, TInfo);
+  }
+
   // ElmtSize = #bits in vector element.
   void vst1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpAddress,
               const TargetInfo &TInfo);
@@ -587,6 +631,15 @@
     vst1qr(ElmtSize, OpQd, OpRn, TInfo);
   }
 
+  void vst1(size_t ElmtSize, const Operand *OpQd, const Operand *OpAddress,
+            const TargetInfo &TInfo);
+
+  void vst1(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
+            const TargetLowering *Lowering) {
+    const TargetInfo TInfo(Lowering);
+    vst1(ElmtSize, OpQd, OpRn, TInfo);
+  }
+
   void vsubd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
              CondARM32::Cond Cond);
 
@@ -594,6 +647,22 @@
   void vsubqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
               const Operand *OpQn);
 
+  // Integer vector saturating subtract.
+  void vqsubqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
+               const Operand *OpQn);
+  void vqsubqu(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
+               const Operand *OpQn);
+
+  // Integer vector saturating add.
+  void vqaddqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
+               const Operand *OpQn);
+  void vqaddqu(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
+               const Operand *OpQn);
+
+  // Integer vector packing with optional saturation.
+  void vqmovn2(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
+               const Operand *OpQn, bool Unsigned, bool Saturating);
+
   // Float vector subtract
   void vsubqf(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn);
 
@@ -723,6 +792,11 @@
                    DRegListSize NumDRegs, size_t ElmtSize, IValueT Align,
                    const char *InstName);
 
+  // Pattern 111100000D00nnnnddddss00aaaammmm | Opcode where Ddddd=Dd, nnnn=Rn,
+  // mmmmm=Rm, ElmtSize in {8, 16, 32) and defines ss, and aa=Align.
+  void emitVMem1Op(IValueT Opcode, IValueT Dd, IValueT Rn, IValueT Rm,
+                   size_t ElmtSize, IValueT Align, const char *InstName);
+
   // Pattern cccc011100x1dddd1111mmmm0001nnn where cccc=Cond,
   // x=Opcode, dddd=Rd, nnnn=Rn, mmmm=Rm.
   void emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
diff --git a/third_party/subzero/src/IceGlobalContext.cpp b/third_party/subzero/src/IceGlobalContext.cpp
index 45fb999..3a21b3a 100644
--- a/third_party/subzero/src/IceGlobalContext.cpp
+++ b/third_party/subzero/src/IceGlobalContext.cpp
@@ -372,6 +372,11 @@
   }
 }
 
+void GlobalContext::translateFunctionsWrapper(ThreadContext *MyTLS) {
+  ICE_TLS_SET_FIELD(TLS, MyTLS);
+  translateFunctions();
+}
+
 void GlobalContext::translateFunctions() {
   TimerMarker Timer(TimerStack::TT_translateFunctions, this);
   while (std::unique_ptr<OptWorkItem> OptItem = optQueueBlockingPop()) {
@@ -454,6 +459,9 @@
 
 } // end of anonymous namespace
 
+// static
+void GlobalContext::TlsInit() { ICE_TLS_INIT_FIELD(TLS); }
+
 void GlobalContext::emitFileHeader() {
   TimerMarker T1(Ice::TimerStack::TT_emitAsm, this);
   if (getFlags().getOutFileType() == FT_Elf) {
@@ -556,6 +564,11 @@
   lowerGlobals(ProfileDataSection);
 }
 
+void GlobalContext::emitterWrapper(ThreadContext *MyTLS) {
+  ICE_TLS_SET_FIELD(TLS, MyTLS);
+  emitItems();
+}
+
 void GlobalContext::emitItems() {
   const bool Threaded = !getFlags().isSequential();
   // Pending is a vector containing the reassembled, ordered list of
@@ -987,6 +1000,38 @@
   return EmitQ.blockingPop();
 }
 
+void GlobalContext::initParserThread() {
+  ThreadContext *Tls = new ThreadContext();
+  auto Timers = getTimers();
+  Timers->initInto(Tls->Timers);
+  AllThreadContexts.push_back(Tls);
+  ICE_TLS_SET_FIELD(TLS, Tls);
+}
+
+void GlobalContext::startWorkerThreads() {
+  size_t NumWorkers = getFlags().getNumTranslationThreads();
+  auto Timers = getTimers();
+  for (size_t i = 0; i < NumWorkers; ++i) {
+    ThreadContext *WorkerTLS = new ThreadContext();
+    Timers->initInto(WorkerTLS->Timers);
+    AllThreadContexts.push_back(WorkerTLS);
+    TranslationThreads.push_back(std::thread(
+        &GlobalContext::translateFunctionsWrapper, this, WorkerTLS));
+  }
+  if (NumWorkers) {
+    ThreadContext *WorkerTLS = new ThreadContext();
+    Timers->initInto(WorkerTLS->Timers);
+    AllThreadContexts.push_back(WorkerTLS);
+    EmitterThreads.push_back(
+        std::thread(&GlobalContext::emitterWrapper, this, WorkerTLS));
+  }
+}
+
+void GlobalContext::resetStats() {
+  if (BuildDefs::dump())
+    ICE_TLS_GET_FIELD(TLS)->StatsFunction.reset();
+}
+
 void GlobalContext::dumpStats(const Cfg *Func) {
   if (!getFlags().getDumpStats())
     return;
@@ -997,6 +1042,54 @@
   }
 }
 
+void GlobalContext::statsUpdateEmitted(uint32_t InstCount) {
+  if (!getFlags().getDumpStats())
+    return;
+  ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
+  Tls->StatsFunction.update(CodeStats::CS_InstCount, InstCount);
+  Tls->StatsCumulative.update(CodeStats::CS_InstCount, InstCount);
+}
+
+void GlobalContext::statsUpdateRegistersSaved(uint32_t Num) {
+  if (!getFlags().getDumpStats())
+    return;
+  ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
+  Tls->StatsFunction.update(CodeStats::CS_RegsSaved, Num);
+  Tls->StatsCumulative.update(CodeStats::CS_RegsSaved, Num);
+}
+
+void GlobalContext::statsUpdateFrameBytes(uint32_t Bytes) {
+  if (!getFlags().getDumpStats())
+    return;
+  ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
+  Tls->StatsFunction.update(CodeStats::CS_FrameByte, Bytes);
+  Tls->StatsCumulative.update(CodeStats::CS_FrameByte, Bytes);
+}
+
+void GlobalContext::statsUpdateSpills() {
+  if (!getFlags().getDumpStats())
+    return;
+  ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
+  Tls->StatsFunction.update(CodeStats::CS_NumSpills);
+  Tls->StatsCumulative.update(CodeStats::CS_NumSpills);
+}
+
+void GlobalContext::statsUpdateFills() {
+  if (!getFlags().getDumpStats())
+    return;
+  ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
+  Tls->StatsFunction.update(CodeStats::CS_NumFills);
+  Tls->StatsCumulative.update(CodeStats::CS_NumFills);
+}
+
+void GlobalContext::statsUpdateRPImms() {
+  if (!getFlags().getDumpStats())
+    return;
+  ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
+  Tls->StatsFunction.update(CodeStats::CS_NumRPImms);
+  Tls->StatsCumulative.update(CodeStats::CS_NumRPImms);
+}
+
 void GlobalContext::dumpTimers(TimerStackIdT StackID, bool DumpCumulative) {
   if (!BuildDefs::timers())
     return;
diff --git a/third_party/subzero/src/IceGlobalContext.h b/third_party/subzero/src/IceGlobalContext.h
index aed4341..55b37d8 100644
--- a/third_party/subzero/src/IceGlobalContext.h
+++ b/third_party/subzero/src/IceGlobalContext.h
@@ -297,55 +297,16 @@
   ELFObjectWriter *getObjectWriter() const { return ObjectWriter.get(); }
 
   /// Reset stats at the beginning of a function.
-  void resetStats() {
-    if (BuildDefs::dump())
-      ICE_TLS_GET_FIELD(TLS)->StatsFunction.reset();
-  }
+  void resetStats();
   void dumpStats(const Cfg *Func = nullptr);
-  void statsUpdateEmitted(uint32_t InstCount) {
-    if (!getFlags().getDumpStats())
-      return;
-    ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
-    Tls->StatsFunction.update(CodeStats::CS_InstCount, InstCount);
-    Tls->StatsCumulative.update(CodeStats::CS_InstCount, InstCount);
-  }
-  void statsUpdateRegistersSaved(uint32_t Num) {
-    if (!getFlags().getDumpStats())
-      return;
-    ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
-    Tls->StatsFunction.update(CodeStats::CS_RegsSaved, Num);
-    Tls->StatsCumulative.update(CodeStats::CS_RegsSaved, Num);
-  }
-  void statsUpdateFrameBytes(uint32_t Bytes) {
-    if (!getFlags().getDumpStats())
-      return;
-    ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
-    Tls->StatsFunction.update(CodeStats::CS_FrameByte, Bytes);
-    Tls->StatsCumulative.update(CodeStats::CS_FrameByte, Bytes);
-  }
-  void statsUpdateSpills() {
-    if (!getFlags().getDumpStats())
-      return;
-    ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
-    Tls->StatsFunction.update(CodeStats::CS_NumSpills);
-    Tls->StatsCumulative.update(CodeStats::CS_NumSpills);
-  }
-  void statsUpdateFills() {
-    if (!getFlags().getDumpStats())
-      return;
-    ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
-    Tls->StatsFunction.update(CodeStats::CS_NumFills);
-    Tls->StatsCumulative.update(CodeStats::CS_NumFills);
-  }
+  void statsUpdateEmitted(uint32_t InstCount);
+  void statsUpdateRegistersSaved(uint32_t Num);
+  void statsUpdateFrameBytes(uint32_t Bytes);
+  void statsUpdateSpills();
+  void statsUpdateFills();
 
   /// Number of Randomized or Pooled Immediates
-  void statsUpdateRPImms() {
-    if (!getFlags().getDumpStats())
-      return;
-    ThreadContext *Tls = ICE_TLS_GET_FIELD(TLS);
-    Tls->StatsFunction.update(CodeStats::CS_NumRPImms);
-    Tls->StatsCumulative.update(CodeStats::CS_NumRPImms);
-  }
+  void statsUpdateRPImms();
 
   /// These are predefined TimerStackIdT values.
   enum TimerStackKind { TSK_Default = 0, TSK_Funcs, TSK_Num };
@@ -403,32 +364,8 @@
   std::unique_ptr<EmitterWorkItem> emitQueueBlockingPop();
   void emitQueueNotifyEnd() { EmitQ.notifyEnd(); }
 
-  void initParserThread() {
-    ThreadContext *Tls = new ThreadContext();
-    auto Timers = getTimers();
-    Timers->initInto(Tls->Timers);
-    AllThreadContexts.push_back(Tls);
-    ICE_TLS_SET_FIELD(TLS, Tls);
-  }
-
-  void startWorkerThreads() {
-    size_t NumWorkers = getFlags().getNumTranslationThreads();
-    auto Timers = getTimers();
-    for (size_t i = 0; i < NumWorkers; ++i) {
-      ThreadContext *WorkerTLS = new ThreadContext();
-      Timers->initInto(WorkerTLS->Timers);
-      AllThreadContexts.push_back(WorkerTLS);
-      TranslationThreads.push_back(std::thread(
-          &GlobalContext::translateFunctionsWrapper, this, WorkerTLS));
-    }
-    if (NumWorkers) {
-      ThreadContext *WorkerTLS = new ThreadContext();
-      Timers->initInto(WorkerTLS->Timers);
-      AllThreadContexts.push_back(WorkerTLS);
-      EmitterThreads.push_back(
-          std::thread(&GlobalContext::emitterWrapper, this, WorkerTLS));
-    }
-  }
+  void initParserThread();
+  void startWorkerThreads();
 
   void waitForWorkerThreads();
 
@@ -444,18 +381,12 @@
   }
 
   /// Translation thread startup routine.
-  void translateFunctionsWrapper(ThreadContext *MyTLS) {
-    ICE_TLS_SET_FIELD(TLS, MyTLS);
-    translateFunctions();
-  }
+  void translateFunctionsWrapper(ThreadContext *MyTLS);
   /// Translate functions from the Cfg queue until the queue is empty.
   void translateFunctions();
 
   /// Emitter thread startup routine.
-  void emitterWrapper(ThreadContext *MyTLS) {
-    ICE_TLS_SET_FIELD(TLS, MyTLS);
-    emitItems();
-  }
+  void emitterWrapper(ThreadContext *MyTLS);
   /// Emit functions and global initializers from the emitter queue until the
   /// queue is empty.
   void emitItems();
@@ -643,7 +574,7 @@
   ICE_TLS_DECLARE_FIELD(ThreadContext *, TLS);
 
 public:
-  static void TlsInit() { ICE_TLS_INIT_FIELD(TLS); }
+  static void TlsInit();
 };
 
 /// Helper class to push and pop a timer marker. The constructor pushes a
diff --git a/third_party/subzero/src/IceInst.h b/third_party/subzero/src/IceInst.h
index 889ead5..187c16d 100644
--- a/third_party/subzero/src/IceInst.h
+++ b/third_party/subzero/src/IceInst.h
@@ -997,35 +997,45 @@
     return Indexes[Pos];
   }
 
-  inline bool indexesAre(int32_t i0, int32_t i1, int32_t i2, int32_t i3,
-                         int32_t i4, int32_t i5, int32_t i6, int32_t i7) const {
+  int32_t getIndexValue(SizeT Pos) const { return getIndex(Pos)->getValue(); }
+
+  bool indexesAre(int32_t i0, int32_t i1, int32_t i2, int32_t i3) const {
+    static constexpr SizeT ExpectedNumElements = 4;
+    assert(ExpectedNumElements == getNumIndexes());
+    (void)ExpectedNumElements;
+
+    return getIndexValue(0) == i0 && getIndexValue(1) == i1 &&
+           getIndexValue(2) == i2 && getIndexValue(3) == i3;
+  }
+
+  bool indexesAre(int32_t i0, int32_t i1, int32_t i2, int32_t i3, int32_t i4,
+                  int32_t i5, int32_t i6, int32_t i7) const {
     static constexpr SizeT ExpectedNumElements = 8;
     assert(ExpectedNumElements == getNumIndexes());
     (void)ExpectedNumElements;
 
-    return getIndex(0)->getValue() == i0 && getIndex(1)->getValue() == i1 &&
-           getIndex(2)->getValue() == i2 && getIndex(3)->getValue() == i3 &&
-           getIndex(4)->getValue() == i4 && getIndex(5)->getValue() == i5 &&
-           getIndex(6)->getValue() == i6 && getIndex(7)->getValue() == i7;
+    return getIndexValue(0) == i0 && getIndexValue(1) == i1 &&
+           getIndexValue(2) == i2 && getIndexValue(3) == i3 &&
+           getIndexValue(4) == i4 && getIndexValue(5) == i5 &&
+           getIndexValue(6) == i6 && getIndexValue(7) == i7;
   }
 
-  inline bool indexesAre(int32_t i0, int32_t i1, int32_t i2, int32_t i3,
-                         int32_t i4, int32_t i5, int32_t i6, int32_t i7,
-                         int32_t i8, int32_t i9, int32_t i10, int32_t i11,
-                         int32_t i12, int32_t i13, int32_t i14,
-                         int32_t i15) const {
+  bool indexesAre(int32_t i0, int32_t i1, int32_t i2, int32_t i3, int32_t i4,
+                  int32_t i5, int32_t i6, int32_t i7, int32_t i8, int32_t i9,
+                  int32_t i10, int32_t i11, int32_t i12, int32_t i13,
+                  int32_t i14, int32_t i15) const {
     static constexpr SizeT ExpectedNumElements = 16;
     assert(ExpectedNumElements == getNumIndexes());
     (void)ExpectedNumElements;
 
-    return getIndex(0)->getValue() == i0 && getIndex(1)->getValue() == i1 &&
-           getIndex(2)->getValue() == i2 && getIndex(3)->getValue() == i3 &&
-           getIndex(4)->getValue() == i4 && getIndex(5)->getValue() == i5 &&
-           getIndex(6)->getValue() == i6 && getIndex(7)->getValue() == i7 &&
-           getIndex(8)->getValue() == i8 && getIndex(9)->getValue() == i9 &&
-           getIndex(10)->getValue() == i10 && getIndex(11)->getValue() == i11 &&
-           getIndex(12)->getValue() == i12 && getIndex(13)->getValue() == i13 &&
-           getIndex(14)->getValue() == i14 && getIndex(15)->getValue() == i15;
+    return getIndexValue(0) == i0 && getIndexValue(1) == i1 &&
+           getIndexValue(2) == i2 && getIndexValue(3) == i3 &&
+           getIndexValue(4) == i4 && getIndexValue(5) == i5 &&
+           getIndexValue(6) == i6 && getIndexValue(7) == i7 &&
+           getIndexValue(8) == i8 && getIndexValue(9) == i9 &&
+           getIndexValue(10) == i10 && getIndexValue(11) == i11 &&
+           getIndexValue(12) == i12 && getIndexValue(13) == i13 &&
+           getIndexValue(14) == i14 && getIndexValue(15) == i15;
   }
 
   bool isMemoryWrite() const override { return false; }
diff --git a/third_party/subzero/src/IceInstARM32.cpp b/third_party/subzero/src/IceInstARM32.cpp
index 4bd530c..646730f 100644
--- a/third_party/subzero/src/IceInstARM32.cpp
+++ b/third_party/subzero/src/IceInstARM32.cpp
@@ -903,6 +903,82 @@
   }
 }
 
+template <> void InstARM32Vmovl::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Variable *Dest = getDest();
+  switch (Dest->getType()) {
+  default:
+    llvm::report_fatal_error("Vmovlq not defined on type " +
+                             typeStdString(Dest->getType()));
+  case IceType_v4i1:
+  case IceType_v8i1:
+  case IceType_v16i1:
+  case IceType_v16i8:
+  case IceType_v8i16:
+  case IceType_v4i32:
+  case IceType_v4f32: {
+    Asm->vmovlq(Dest, getSrc(0), getSrc(1));
+  } break;
+  }
+}
+
+template <> void InstARM32Vmovh::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Variable *Dest = getDest();
+  switch (Dest->getType()) {
+  default:
+    llvm::report_fatal_error("Vmovhq not defined on type " +
+                             typeStdString(Dest->getType()));
+  case IceType_v4i1:
+  case IceType_v8i1:
+  case IceType_v16i1:
+  case IceType_v16i8:
+  case IceType_v8i16:
+  case IceType_v4i32:
+  case IceType_v4f32: {
+    Asm->vmovhq(Dest, getSrc(0), getSrc(1));
+  } break;
+  }
+}
+
+template <> void InstARM32Vmovhl::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Variable *Dest = getDest();
+  switch (Dest->getType()) {
+  default:
+    llvm::report_fatal_error("Vmovhlq not defined on type " +
+                             typeStdString(Dest->getType()));
+  case IceType_v4i1:
+  case IceType_v8i1:
+  case IceType_v16i1:
+  case IceType_v16i8:
+  case IceType_v8i16:
+  case IceType_v4i32:
+  case IceType_v4f32: {
+    Asm->vmovhlq(Dest, getSrc(0), getSrc(1));
+  } break;
+  }
+}
+
+template <> void InstARM32Vmovlh::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Variable *Dest = getDest();
+  switch (Dest->getType()) {
+  default:
+    llvm::report_fatal_error("Vmovlhq not defined on type " +
+                             typeStdString(Dest->getType()));
+  case IceType_v4i1:
+  case IceType_v8i1:
+  case IceType_v16i1:
+  case IceType_v16i8:
+  case IceType_v8i16:
+  case IceType_v4i32:
+  case IceType_v4f32: {
+    Asm->vmovlhq(Dest, getSrc(0), getSrc(1));
+  } break;
+  }
+}
+
 template <> void InstARM32Vneg::emitIAS(const Cfg *Func) const {
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   const Variable *Dest = getDest();
@@ -999,15 +1075,13 @@
   case IceType_v4i32: {
     const Type ElmtTy = typeElementType(DestTy);
     const auto *Imm6 = llvm::cast<ConstantInteger32>(getSrc(1));
-    assert(Sign != InstARM32::FS_None);
     switch (Sign) {
-    case InstARM32::FS_None: // defaults to unsigned.
-    case InstARM32::FS_Unsigned:
-      Asm->vshrquc(ElmtTy, Dest, getSrc(0), Imm6);
-      break;
     case InstARM32::FS_Signed:
-      Asm->vshrqic(ElmtTy, Dest, getSrc(0), Imm6);
+    case InstARM32::FS_Unsigned:
+      Asm->vshrqc(ElmtTy, Dest, getSrc(0), Imm6, Sign);
       break;
+    default:
+      assert(false && "Vshr requires signedness specification.");
     }
   } break;
   }
@@ -1039,6 +1113,146 @@
   assert(!Asm->needsTextFixup());
 }
 
+template <> void InstARM32Vqadd::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Variable *Dest = getDest();
+  Type DestTy = Dest->getType();
+  switch (DestTy) {
+  default:
+    llvm::report_fatal_error("Vqadd not defined on type " +
+                             typeStdString(DestTy));
+  case IceType_v16i8:
+  case IceType_v8i16:
+  case IceType_v4i32:
+    switch (Sign) {
+    case InstARM32::FS_None: // defaults to unsigned.
+    case InstARM32::FS_Unsigned:
+      Asm->vqaddqu(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
+      break;
+    case InstARM32::FS_Signed:
+      Asm->vqaddqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
+      break;
+    }
+    break;
+  }
+  assert(!Asm->needsTextFixup());
+}
+
+template <> void InstARM32Vqsub::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Variable *Dest = getDest();
+  Type DestTy = Dest->getType();
+  switch (DestTy) {
+  default:
+    llvm::report_fatal_error("Vqsub not defined on type " +
+                             typeStdString(DestTy));
+  case IceType_v16i8:
+  case IceType_v8i16:
+  case IceType_v4i32:
+    switch (Sign) {
+    case InstARM32::FS_None: // defaults to unsigned.
+    case InstARM32::FS_Unsigned:
+      Asm->vqsubqu(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
+      break;
+    case InstARM32::FS_Signed:
+      Asm->vqsubqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
+      break;
+    }
+    break;
+  }
+  assert(!Asm->needsTextFixup());
+}
+
+template <> void InstARM32Vqmovn2::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Operand *Src0 = getSrc(0);
+  const Operand *Src1 = getSrc(1);
+  Type SrcTy = Src0->getType();
+  Type DestTy = Dest->getType();
+  bool Unsigned = true;
+  bool Saturating = true;
+  switch (SrcTy) {
+  default:
+    llvm::report_fatal_error("Vqmovn2 not defined on type " +
+                             typeStdString(SrcTy));
+  case IceType_v8i16:
+  case IceType_v4i32:
+    switch (Sign) {
+    case InstARM32::FS_None:
+      Unsigned = true;
+      Saturating = false;
+      Asm->vqmovn2(typeElementType(DestTy), Dest, Src0, Src1, Unsigned,
+                   Saturating);
+      break;
+    case InstARM32::FS_Unsigned:
+      Unsigned = true;
+      Saturating = true;
+      Asm->vqmovn2(typeElementType(DestTy), Dest, Src0, Src1, Unsigned,
+                   Saturating);
+      break;
+    case InstARM32::FS_Signed:
+      Unsigned = false;
+      Saturating = true;
+      Asm->vqmovn2(typeElementType(DestTy), Dest, Src0, Src1, Unsigned,
+                   Saturating);
+      break;
+    }
+    break;
+  }
+  assert(!Asm->needsTextFixup());
+}
+
+template <> void InstARM32Vmulh::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Operand *Src0 = getSrc(0);
+  Type SrcTy = Src0->getType();
+  bool Unsigned = true;
+  switch (SrcTy) {
+  default:
+    llvm::report_fatal_error("Vmulh not defined on type " +
+                             typeStdString(SrcTy));
+  case IceType_v8i16:
+    switch (Sign) {
+    case InstARM32::FS_None: // defaults to unsigned.
+    case InstARM32::FS_Unsigned:
+      Unsigned = true;
+      Asm->vmulh(typeElementType(SrcTy), Dest, getSrc(0), getSrc(1), Unsigned);
+      break;
+    case InstARM32::FS_Signed:
+      Unsigned = false;
+      Asm->vmulh(typeElementType(SrcTy), Dest, getSrc(0), getSrc(1), Unsigned);
+      break;
+    }
+    break;
+  }
+  assert(!Asm->needsTextFixup());
+}
+
+template <> void InstARM32Vmlap::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Operand *Src0 = getSrc(0);
+  const Operand *Src1 = getSrc(1);
+  Type SrcTy = Src0->getType();
+  switch (SrcTy) {
+  default:
+    llvm::report_fatal_error("Vmlap not defined on type " +
+                             typeStdString(SrcTy));
+  case IceType_v8i16:
+    Asm->vmlap(typeElementType(SrcTy), Dest, Src0, Src1);
+    break;
+  }
+  assert(!Asm->needsTextFixup());
+}
+
+template <> void InstARM32Vzip::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Operand *Src0 = getSrc(0);
+  const Operand *Src1 = getSrc(1);
+  Type DestTy = Dest->getType();
+  Asm->vzip(typeElementType(DestTy), Dest, Src0, Src1);
+  assert(!Asm->needsTextFixup());
+}
+
 template <> void InstARM32Vmul::emitIAS(const Cfg *Func) const {
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   const Variable *Dest = getDest();
@@ -1288,6 +1502,20 @@
   addSource(Mem);
 }
 
+InstARM32Vstr1::InstARM32Vstr1(Cfg *Func, Variable *Value, OperandARM32Mem *Mem,
+                               CondARM32::Cond Predicate, SizeT Size)
+    : InstARM32Pred(Func, InstARM32::Vstr1, 2, nullptr, Predicate) {
+  addSource(Value);
+  addSource(Mem);
+  this->Size = Size;
+}
+
+InstARM32Vdup::InstARM32Vdup(Cfg *Func, Variable *Dest, Variable *Src,
+                             IValueT Idx)
+    : InstARM32Pred(Func, InstARM32::Vdup, 1, Dest, CondARM32::AL), Idx(Idx) {
+  addSource(Src);
+}
+
 InstARM32Trap::InstARM32Trap(Cfg *Func)
     : InstARM32(Func, InstARM32::Trap, 0, nullptr) {}
 
@@ -1606,6 +1834,8 @@
 // Mov-like ops
 template <> const char *InstARM32Ldr::Opcode = "ldr";
 template <> const char *InstARM32Ldrex::Opcode = "ldrex";
+template <> const char *InstARM32Vldr1d::Opcode = "vldr1d";
+template <> const char *InstARM32Vldr1q::Opcode = "vldr1q";
 // Three-addr ops
 template <> const char *InstARM32Adc::Opcode = "adc";
 template <> const char *InstARM32Add::Opcode = "add";
@@ -1636,11 +1866,26 @@
 template <> const char *InstARM32Vmls::Opcode = "vmls";
 template <> const char *InstARM32Vmul::Opcode = "vmul";
 template <> const char *InstARM32Vmvn::Opcode = "vmvn";
+template <> const char *InstARM32Vmovl::Opcode = "vmovl";
+template <> const char *InstARM32Vmovh::Opcode = "vmovh";
+template <> const char *InstARM32Vmovhl::Opcode = "vmovhl";
+template <> const char *InstARM32Vmovlh::Opcode = "vmovlh";
 template <> const char *InstARM32Vorr::Opcode = "vorr";
 template <> const char *InstARM32UnaryopFP<InstARM32::Vneg>::Opcode = "vneg";
 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vshl>::Opcode = "vshl";
 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vshr>::Opcode = "vshr";
 template <> const char *InstARM32Vsub::Opcode = "vsub";
+template <>
+const char *InstARM32ThreeAddrFP<InstARM32::Vqadd>::Opcode = "vqadd";
+template <>
+const char *InstARM32ThreeAddrFP<InstARM32::Vqsub>::Opcode = "vqsub";
+template <>
+const char *InstARM32ThreeAddrFP<InstARM32::Vqmovn2>::Opcode = "vqmovn2";
+template <>
+const char *InstARM32ThreeAddrFP<InstARM32::Vmulh>::Opcode = "vmulh";
+template <>
+const char *InstARM32ThreeAddrFP<InstARM32::Vmlap>::Opcode = "vmlap";
+template <> const char *InstARM32ThreeAddrFP<InstARM32::Vzip>::Opcode = "vzip";
 // Four-addr ops
 template <> const char *InstARM32Mla::Opcode = "mla";
 template <> const char *InstARM32Mls::Opcode = "mls";
@@ -2102,6 +2347,62 @@
   getSrc(0)->emit(Func);
 }
 
+template <> void InstARM32Vldr1d::emit(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrEmit();
+  assert(getSrcSize() == 1);
+  assert(getDest()->hasReg());
+  Variable *Dest = getDest();
+  Type Ty = Dest->getType();
+  const bool IsVector = isVectorType(Ty);
+  const bool IsScalarFloat = isScalarFloatingType(Ty);
+  const char *ActualOpcode =
+      IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr");
+  const char *WidthString = IsVector ? "" : getWidthString(Ty);
+  Str << "\t" << ActualOpcode;
+  const bool IsVInst = IsVector || IsScalarFloat;
+  if (IsVInst) {
+    Str << getPredicate() << WidthString;
+  } else {
+    Str << WidthString << getPredicate();
+  }
+  if (IsVector)
+    Str << "." << getVecElmtBitsize(Ty);
+  Str << "\t";
+  getDest()->emit(Func);
+  Str << ", ";
+  getSrc(0)->emit(Func);
+}
+
+template <> void InstARM32Vldr1q::emit(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrEmit();
+  assert(getSrcSize() == 1);
+  assert(getDest()->hasReg());
+  Variable *Dest = getDest();
+  Type Ty = Dest->getType();
+  const bool IsVector = isVectorType(Ty);
+  const bool IsScalarFloat = isScalarFloatingType(Ty);
+  const char *ActualOpcode =
+      IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr");
+  const char *WidthString = IsVector ? "" : getWidthString(Ty);
+  Str << "\t" << ActualOpcode;
+  const bool IsVInst = IsVector || IsScalarFloat;
+  if (IsVInst) {
+    Str << getPredicate() << WidthString;
+  } else {
+    Str << WidthString << getPredicate();
+  }
+  if (IsVector)
+    Str << "." << getVecElmtBitsize(Ty);
+  Str << "\t";
+  getDest()->emit(Func);
+  Str << ", ";
+  getSrc(0)->emit(Func);
+}
+
 template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const {
   assert(getSrcSize() == 1);
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
@@ -2135,6 +2436,20 @@
   }
 }
 
+template <> void InstARM32Vldr1d::emitIAS(const Cfg *Func) const {
+  assert(getSrcSize() == 1);
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  Variable *Dest = getDest();
+  Asm->vld1(32, Dest, getSrc(0), Func->getTarget());
+}
+
+template <> void InstARM32Vldr1q::emitIAS(const Cfg *Func) const {
+  assert(getSrcSize() == 1);
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  Variable *Dest = getDest();
+  Asm->vld1(64, Dest, getSrc(0), Func->getTarget());
+}
+
 template <> void InstARM32Ldrex::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
@@ -2541,6 +2856,88 @@
   getSrc(0)->dump(Func);
 }
 
+void InstARM32Vstr1::emit(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrEmit();
+  assert(getSrcSize() == 2);
+  Type Ty = getSrc(0)->getType();
+  const bool IsVectorStore = isVectorType(Ty);
+  const bool IsScalarFloat = isScalarFloatingType(Ty);
+  const char *Opcode =
+      IsVectorStore ? "vst1" : (IsScalarFloat ? "vstr" : "str");
+  Str << "\t" << Opcode;
+  const bool IsVInst = IsVectorStore || IsScalarFloat;
+  if (IsVInst) {
+    Str << getPredicate() << getWidthString(Ty);
+  } else {
+    Str << getWidthString(Ty) << getPredicate();
+  }
+  if (IsVectorStore)
+    Str << "." << getVecElmtBitsize(Ty);
+  Str << "\t";
+  getSrc(0)->emit(Func);
+  Str << ", ";
+  getSrc(1)->emit(Func);
+}
+
+void InstARM32Vstr1::emitIAS(const Cfg *Func) const {
+  assert(getSrcSize() == 2);
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Operand *Src0 = getSrc(0);
+  const Operand *Src1 = getSrc(1);
+  Asm->vst1(Size, Src0, Src1, Func->getTarget());
+}
+
+void InstARM32Vstr1::dump(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrDump();
+  Type Ty = getSrc(0)->getType();
+  dumpOpcodePred(Str, "str", Ty);
+  Str << " ";
+  getSrc(1)->dump(Func);
+  Str << ", ";
+  getSrc(0)->dump(Func);
+}
+
+void InstARM32Vdup::emit(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrEmit();
+  assert(getSrcSize() == 2);
+  Type Ty = getSrc(0)->getType();
+  const char *Opcode = "vdup";
+  Str << "\t" << Opcode;
+  Str << getPredicate() << "." << getWidthString(Ty) << getVecElmtBitsize(Ty);
+  Str << "\t";
+  getSrc(0)->emit(Func);
+  Str << ", ";
+  getSrc(1)->emit(Func);
+  Str << ", " << Idx;
+}
+
+void InstARM32Vdup::emitIAS(const Cfg *Func) const {
+  assert(getSrcSize() == 1);
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Operand *Dest = getDest();
+  const Operand *Src = getSrc(0);
+  Type DestTy = Dest->getType();
+  Asm->vdup(typeElementType(DestTy), Dest, Src, Idx);
+}
+
+void InstARM32Vdup::dump(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrDump();
+  dumpDest(Func);
+  Str << " = ";
+  dumpOpcodePred(Str, "vdup", getDest()->getType());
+  Str << " ";
+  dumpSources(Func);
+  Str << ", " << Idx;
+}
+
 void InstARM32Trap::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
@@ -3112,10 +3509,17 @@
 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshl>;
 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshr>;
 template class InstARM32ThreeAddrFP<InstARM32::Vsub>;
+template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqadd>;
+template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqsub>;
+template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqmovn2>;
+template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vmulh>;
+template class InstARM32ThreeAddrFP<InstARM32::Vmlap>;
 
 template class InstARM32LoadBase<InstARM32::Ldr>;
 template class InstARM32LoadBase<InstARM32::Ldrex>;
-
+template class InstARM32LoadBase<InstARM32::Vldr1d>;
+template class InstARM32LoadBase<InstARM32::Vldr1q>;
+template class InstARM32ThreeAddrFP<InstARM32::Vzip>;
 template class InstARM32TwoAddrGPR<InstARM32::Movt>;
 
 template class InstARM32UnaryopGPR<InstARM32::Movw, false>;
diff --git a/third_party/subzero/src/IceInstARM32.h b/third_party/subzero/src/IceInstARM32.h
index 89f894d..e31aabc 100644
--- a/third_party/subzero/src/IceInstARM32.h
+++ b/third_party/subzero/src/IceInstARM32.h
@@ -434,18 +434,32 @@
     Vcmp,
     Vcvt,
     Vdiv,
+    Vdup,
     Veor,
+    Vldr1d,
+    Vldr1q,
     Vmla,
+    Vmlap,
     Vmls,
+    Vmovl,
+    Vmovh,
+    Vmovhl,
+    Vmovlh,
     Vmrs,
     Vmul,
+    Vmulh,
     Vmvn,
     Vneg,
     Vorr,
+    Vqadd,
+    Vqmovn2,
+    Vqsub,
     Vshl,
     Vshr,
     Vsqrt,
-    Vsub
+    Vstr1,
+    Vsub,
+    Vzip
   };
 
   static constexpr size_t InstSize = sizeof(uint32_t);
@@ -1012,15 +1026,27 @@
 using InstARM32Veor = InstARM32ThreeAddrFP<InstARM32::Veor>;
 using InstARM32Vmla = InstARM32FourAddrFP<InstARM32::Vmla>;
 using InstARM32Vmls = InstARM32FourAddrFP<InstARM32::Vmls>;
+using InstARM32Vmovl = InstARM32ThreeAddrFP<InstARM32::Vmovl>;
+using InstARM32Vmovh = InstARM32ThreeAddrFP<InstARM32::Vmovh>;
+using InstARM32Vmovhl = InstARM32ThreeAddrFP<InstARM32::Vmovhl>;
+using InstARM32Vmovlh = InstARM32ThreeAddrFP<InstARM32::Vmovlh>;
 using InstARM32Vmul = InstARM32ThreeAddrFP<InstARM32::Vmul>;
 using InstARM32Vmvn = InstARM32UnaryopFP<InstARM32::Vmvn>;
 using InstARM32Vneg = InstARM32UnaryopSignAwareFP<InstARM32::Vneg>;
 using InstARM32Vorr = InstARM32ThreeAddrFP<InstARM32::Vorr>;
+using InstARM32Vqadd = InstARM32ThreeAddrSignAwareFP<InstARM32::Vqadd>;
+using InstARM32Vqsub = InstARM32ThreeAddrSignAwareFP<InstARM32::Vqsub>;
+using InstARM32Vqmovn2 = InstARM32ThreeAddrSignAwareFP<InstARM32::Vqmovn2>;
+using InstARM32Vmulh = InstARM32ThreeAddrSignAwareFP<InstARM32::Vmulh>;
+using InstARM32Vmlap = InstARM32ThreeAddrFP<InstARM32::Vmlap>;
 using InstARM32Vshl = InstARM32ThreeAddrSignAwareFP<InstARM32::Vshl>;
 using InstARM32Vshr = InstARM32ThreeAddrSignAwareFP<InstARM32::Vshr>;
 using InstARM32Vsub = InstARM32ThreeAddrFP<InstARM32::Vsub>;
 using InstARM32Ldr = InstARM32LoadBase<InstARM32::Ldr>;
 using InstARM32Ldrex = InstARM32LoadBase<InstARM32::Ldrex>;
+using InstARM32Vldr1d = InstARM32LoadBase<InstARM32::Vldr1d>;
+using InstARM32Vldr1q = InstARM32LoadBase<InstARM32::Vldr1q>;
+using InstARM32Vzip = InstARM32ThreeAddrFP<InstARM32::Vzip>;
 /// MovT leaves the bottom bits alone so dest is also a source. This helps
 /// indicate that a previous MovW setting dest is not dead code.
 using InstARM32Movt = InstARM32TwoAddrGPR<InstARM32::Movt>;
@@ -1332,6 +1358,57 @@
                  OperandARM32Mem *Mem, CondARM32::Cond Predicate);
 };
 
+/// Sub-vector store instruction. It's important for liveness that there is no
+///  Dest operand (OperandARM32Mem instead of Dest Variable).
+class InstARM32Vstr1 final : public InstARM32Pred {
+  InstARM32Vstr1() = delete;
+  InstARM32Vstr1(const InstARM32Vstr1 &) = delete;
+  InstARM32Vstr1 &operator=(const InstARM32Vstr1 &) = delete;
+
+public:
+  /// Value must be a register.
+  static InstARM32Vstr1 *create(Cfg *Func, Variable *Value,
+                                OperandARM32Mem *Mem, CondARM32::Cond Predicate,
+                                SizeT Size) {
+    return new (Func->allocate<InstARM32Vstr1>())
+        InstARM32Vstr1(Func, Value, Mem, Predicate, Size);
+  }
+  void emit(const Cfg *Func) const override;
+  void emitIAS(const Cfg *Func) const override;
+  void dump(const Cfg *Func) const override;
+  static bool classof(const Inst *Instr) { return isClassof(Instr, Vstr1); }
+
+private:
+  InstARM32Vstr1(Cfg *Func, Variable *Value, OperandARM32Mem *Mem,
+                 CondARM32::Cond Predicate, SizeT Size);
+
+  SizeT Size;
+};
+
+/// Vector element duplication/replication instruction.
+class InstARM32Vdup final : public InstARM32Pred {
+  InstARM32Vdup() = delete;
+  InstARM32Vdup(const InstARM32Vdup &) = delete;
+  InstARM32Vdup &operator=(const InstARM32Vdup &) = delete;
+
+public:
+  /// Value must be a register.
+  static InstARM32Vdup *create(Cfg *Func, Variable *Dest, Variable *Src,
+                               IValueT Idx) {
+    return new (Func->allocate<InstARM32Vdup>())
+        InstARM32Vdup(Func, Dest, Src, Idx);
+  }
+  void emit(const Cfg *Func) const override;
+  void emitIAS(const Cfg *Func) const override;
+  void dump(const Cfg *Func) const override;
+  static bool classof(const Inst *Instr) { return isClassof(Instr, Vdup); }
+
+private:
+  InstARM32Vdup(Cfg *Func, Variable *Dest, Variable *Src, IValueT Idx);
+
+  const IValueT Idx;
+};
+
 class InstARM32Trap : public InstARM32 {
   InstARM32Trap() = delete;
   InstARM32Trap(const InstARM32Trap &) = delete;
@@ -1626,6 +1703,8 @@
 template <> void InstARM32Ldr::emit(const Cfg *Func) const;
 template <> void InstARM32Movw::emit(const Cfg *Func) const;
 template <> void InstARM32Movt::emit(const Cfg *Func) const;
+template <> void InstARM32Vldr1d::emit(const Cfg *Func) const;
+template <> void InstARM32Vldr1q::emit(const Cfg *Func) const;
 
 } // end of namespace ARM32
 } // end of namespace Ice
diff --git a/third_party/subzero/src/IceTargetLoweringARM32.cpp b/third_party/subzero/src/IceTargetLoweringARM32.cpp
index 3271271..d820bca 100644
--- a/third_party/subzero/src/IceTargetLoweringARM32.cpp
+++ b/third_party/subzero/src/IceTargetLoweringARM32.cpp
@@ -2442,6 +2442,8 @@
     return legalizeToReg(Target, Swapped ? Src0 : Src1);
   }
 
+  Operand *src1() const { return Src1; }
+
 protected:
   Operand *const Src0;
   Operand *const Src1;
@@ -3436,8 +3438,13 @@
         _lsl(T, Src0R, Src1R);
       }
     } else {
-      auto *Src1R = Srcs.unswappedSrc1R(this);
-      _vshl(T, Src0R, Src1R)->setSignType(InstARM32::FS_Unsigned);
+      if (Srcs.hasConstOperand()) {
+        ConstantInteger32 *ShAmt = llvm::cast<ConstantInteger32>(Srcs.src1());
+        _vshl(T, Src0R, ShAmt);
+      } else {
+        auto *Src1R = Srcs.unswappedSrc1R(this);
+        _vshl(T, Src0R, Src1R)->setSignType(InstARM32::FS_Unsigned);
+      }
     }
     _mov(Dest, T);
     return;
@@ -3455,10 +3462,15 @@
         _lsr(T, Src0R, Src1R);
       }
     } else {
-      auto *Src1R = Srcs.unswappedSrc1R(this);
-      auto *Src1RNeg = makeReg(Src1R->getType());
-      _vneg(Src1RNeg, Src1R);
-      _vshl(T, Src0R, Src1RNeg)->setSignType(InstARM32::FS_Unsigned);
+      if (Srcs.hasConstOperand()) {
+        ConstantInteger32 *ShAmt = llvm::cast<ConstantInteger32>(Srcs.src1());
+        _vshr(T, Src0R, ShAmt)->setSignType(InstARM32::FS_Unsigned);
+      } else {
+        auto *Src1R = Srcs.unswappedSrc1R(this);
+        auto *Src1RNeg = makeReg(Src1R->getType());
+        _vneg(Src1RNeg, Src1R);
+        _vshl(T, Src0R, Src1RNeg)->setSignType(InstARM32::FS_Unsigned);
+      }
     }
     _mov(Dest, T);
     return;
@@ -3475,10 +3487,15 @@
         _asr(T, Src0R, Srcs.unswappedSrc1RShAmtImm(this));
       }
     } else {
-      auto *Src1R = Srcs.unswappedSrc1R(this);
-      auto *Src1RNeg = makeReg(Src1R->getType());
-      _vneg(Src1RNeg, Src1R);
-      _vshl(T, Src0R, Src1RNeg)->setSignType(InstARM32::FS_Signed);
+      if (Srcs.hasConstOperand()) {
+        ConstantInteger32 *ShAmt = llvm::cast<ConstantInteger32>(Srcs.src1());
+        _vshr(T, Src0R, ShAmt)->setSignType(InstARM32::FS_Signed);
+      } else {
+        auto *Src1R = Srcs.unswappedSrc1R(this);
+        auto *Src1RNeg = makeReg(Src1R->getType());
+        _vneg(Src1RNeg, Src1R);
+        _vshl(T, Src0R, Src1RNeg)->setSignType(InstARM32::FS_Signed);
+      }
     }
     _mov(Dest, T);
     return;
@@ -5251,7 +5268,6 @@
     return;
   }
   case Intrinsics::Fabs: {
-    Type DestTy = Dest->getType();
     Variable *T = makeReg(DestTy);
     _vabs(T, legalizeToReg(Instr->getArg(0)));
     _mov(Dest, T);
@@ -5286,7 +5302,7 @@
     assert(isScalarFloatingType(Dest->getType()) ||
            getFlags().getApplicationBinaryInterface() != ::Ice::ABI_PNaCl);
     Variable *Src = legalizeToReg(Instr->getArg(0));
-    Variable *T = makeReg(Dest->getType());
+    Variable *T = makeReg(DestTy);
     _vsqrt(T, Src);
     _mov(Dest, T);
     return;
@@ -5304,14 +5320,121 @@
   case Intrinsics::Trap:
     _trap();
     return;
+  case Intrinsics::AddSaturateSigned:
+  case Intrinsics::AddSaturateUnsigned: {
+    bool Unsigned = (ID == Intrinsics::AddSaturateUnsigned);
+    Variable *Src0 = legalizeToReg(Instr->getArg(0));
+    Variable *Src1 = legalizeToReg(Instr->getArg(1));
+    Variable *T = makeReg(DestTy);
+    _vqadd(T, Src0, Src1, Unsigned);
+    _mov(Dest, T);
+    return;
+  }
   case Intrinsics::LoadSubVector: {
-    UnimplementedLoweringError(this, Instr);
+    assert(llvm::isa<ConstantInteger32>(Instr->getArg(1)) &&
+           "LoadSubVector second argument must be a constant");
+    Variable *Dest = Instr->getDest();
+    Type Ty = Dest->getType();
+    auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(1));
+    Operand *Addr = Instr->getArg(0);
+    OperandARM32Mem *Src = formMemoryOperand(Addr, Ty);
+    doMockBoundsCheck(Src);
+
+    if (Dest->isRematerializable()) {
+      Context.insert<InstFakeDef>(Dest);
+      return;
+    }
+
+    auto *T = makeReg(Ty);
+    switch (SubVectorSize->getValue()) {
+    case 4:
+      _vldr1d(T, Src);
+      break;
+    case 8:
+      _vldr1q(T, Src);
+      break;
+    default:
+      Func->setError("Unexpected size for LoadSubVector");
+      return;
+    }
+    _mov(Dest, T);
     return;
   }
   case Intrinsics::StoreSubVector: {
+    assert(llvm::isa<ConstantInteger32>(Instr->getArg(2)) &&
+           "StoreSubVector third argument must be a constant");
+    auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(2));
+    Variable *Value = legalizeToReg(Instr->getArg(0));
+    Operand *Addr = Instr->getArg(1);
+    OperandARM32Mem *NewAddr = formMemoryOperand(Addr, Value->getType());
+    doMockBoundsCheck(NewAddr);
+
+    Value = legalizeToReg(Value);
+
+    switch (SubVectorSize->getValue()) {
+    case 4:
+      _vstr1d(Value, NewAddr);
+      break;
+    case 8:
+      _vstr1q(Value, NewAddr);
+      break;
+    default:
+      Func->setError("Unexpected size for StoreSubVector");
+      return;
+    }
+    return;
+  }
+  case Intrinsics::MultiplyAddPairs: {
+    Variable *Src0 = legalizeToReg(Instr->getArg(0));
+    Variable *Src1 = legalizeToReg(Instr->getArg(1));
+    Variable *T = makeReg(DestTy);
+    _vmlap(T, Src0, Src1);
+    _mov(Dest, T);
+    return;
+  }
+  case Intrinsics::MultiplyHighSigned:
+  case Intrinsics::MultiplyHighUnsigned: {
+    bool Unsigned = (ID == Intrinsics::MultiplyHighUnsigned);
+    Variable *Src0 = legalizeToReg(Instr->getArg(0));
+    Variable *Src1 = legalizeToReg(Instr->getArg(1));
+    Variable *T = makeReg(DestTy);
+    _vmulh(T, Src0, Src1, Unsigned);
+    _mov(Dest, T);
+    return;
+  }
+  case Intrinsics::Nearbyint: {
     UnimplementedLoweringError(this, Instr);
     return;
   }
+  case Intrinsics::Round: {
+    UnimplementedLoweringError(this, Instr);
+    return;
+  }
+  case Intrinsics::SignMask: {
+    UnimplementedLoweringError(this, Instr);
+    return;
+  }
+  case Intrinsics::SubtractSaturateSigned:
+  case Intrinsics::SubtractSaturateUnsigned: {
+    bool Unsigned = (ID == Intrinsics::SubtractSaturateUnsigned);
+    Variable *Src0 = legalizeToReg(Instr->getArg(0));
+    Variable *Src1 = legalizeToReg(Instr->getArg(1));
+    Variable *T = makeReg(DestTy);
+    _vqsub(T, Src0, Src1, Unsigned);
+    _mov(Dest, T);
+    return;
+  }
+  case Intrinsics::VectorPackSigned:
+  case Intrinsics::VectorPackUnsigned: {
+    bool Unsigned = (ID == Intrinsics::VectorPackUnsigned);
+    bool Saturating = true;
+    Variable *Src0 = legalizeToReg(Instr->getArg(0));
+    Variable *Src1 = legalizeToReg(Instr->getArg(1));
+    Variable *T = makeReg(DestTy);
+    _vqmovn2(T, Src0, Src1, Unsigned, Saturating);
+    _mov(Dest, T);
+    return;
+  }
   default: // UnknownIntrinsic
     Func->setError("Unexpected intrinsic");
     return;
@@ -5852,8 +5975,121 @@
   const Type DestTy = Dest->getType();
 
   auto *T = makeReg(DestTy);
+  auto *Src0 = Instr->getSrc(0);
+  auto *Src1 = Instr->getSrc(1);
+  const SizeT NumElements = typeNumElements(DestTy);
+  const Type ElementType = typeElementType(DestTy);
+
+  bool Replicate = true;
+  for (SizeT I = 1; Replicate && I < Instr->getNumIndexes(); ++I) {
+    if (Instr->getIndexValue(I) != Instr->getIndexValue(0)) {
+      Replicate = false;
+    }
+  }
+
+  if (Replicate) {
+    Variable *Src0Var = legalizeToReg(Src0);
+    _vdup(T, Src0Var, Instr->getIndexValue(0));
+    _mov(Dest, T);
+    return;
+  }
 
   switch (DestTy) {
+  case IceType_v8i1:
+  case IceType_v8i16: {
+    static constexpr SizeT ExpectedNumElements = 8;
+    assert(ExpectedNumElements == Instr->getNumIndexes());
+    (void)ExpectedNumElements;
+
+    if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      _vzip(T, Src0R, Src0R);
+      _mov(Dest, T);
+      return;
+    }
+
+    if (Instr->indexesAre(0, 8, 1, 9, 2, 10, 3, 11)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      Variable *Src1R = legalizeToReg(Src1);
+      _vzip(T, Src0R, Src1R);
+      _mov(Dest, T);
+      return;
+    }
+
+    if (Instr->indexesAre(0, 2, 4, 6, 0, 2, 4, 6)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      _vqmovn2(T, Src0R, Src0R, false, false);
+      _mov(Dest, T);
+      return;
+    }
+  } break;
+  case IceType_v16i1:
+  case IceType_v16i8: {
+    static constexpr SizeT ExpectedNumElements = 16;
+    assert(ExpectedNumElements == Instr->getNumIndexes());
+    (void)ExpectedNumElements;
+
+    if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      _vzip(T, Src0R, Src0R);
+      _mov(Dest, T);
+      return;
+    }
+
+    if (Instr->indexesAre(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7,
+                          23)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      Variable *Src1R = legalizeToReg(Src1);
+      _vzip(T, Src0R, Src1R);
+      _mov(Dest, T);
+      return;
+    }
+  } break;
+  case IceType_v4i1:
+  case IceType_v4i32:
+  case IceType_v4f32: {
+    static constexpr SizeT ExpectedNumElements = 4;
+    assert(ExpectedNumElements == Instr->getNumIndexes());
+    (void)ExpectedNumElements;
+
+    if (Instr->indexesAre(0, 0, 1, 1)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      _vzip(T, Src0R, Src0R);
+      _mov(Dest, T);
+      return;
+    }
+
+    if (Instr->indexesAre(0, 4, 1, 5)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      Variable *Src1R = legalizeToReg(Src1);
+      _vzip(T, Src0R, Src1R);
+      _mov(Dest, T);
+      return;
+    }
+
+    if (Instr->indexesAre(0, 1, 4, 5)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      Variable *Src1R = legalizeToReg(Src1);
+      _vmovlh(T, Src0R, Src1R);
+      _mov(Dest, T);
+      return;
+    }
+
+    if (Instr->indexesAre(2, 3, 2, 3)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      _vmovhl(T, Src0R, Src0R);
+      _mov(Dest, T);
+      return;
+    }
+
+    if (Instr->indexesAre(2, 3, 6, 7)) {
+      Variable *Src0R = legalizeToReg(Src0);
+      Variable *Src1R = legalizeToReg(Src1);
+      _vmovhl(T, Src1R, Src0R);
+      _mov(Dest, T);
+      return;
+    }
+  } break;
   default:
     break;
     // TODO(jpp): figure out how to properly lower this without scalarization.
@@ -5861,10 +6097,6 @@
 
   // Unoptimized shuffle. Perform a series of inserts and extracts.
   Context.insert<InstFakeDef>(T);
-  auto *Src0 = Instr->getSrc(0);
-  auto *Src1 = Instr->getSrc(1);
-  const SizeT NumElements = typeNumElements(DestTy);
-  const Type ElementType = typeElementType(DestTy);
   for (SizeT I = 0; I < Instr->getNumIndexes(); ++I) {
     auto *Index = Instr->getIndex(I);
     const SizeT Elem = Index->getValue();
diff --git a/third_party/subzero/src/IceTargetLoweringARM32.h b/third_party/subzero/src/IceTargetLoweringARM32.h
index f6cd66b..a629627 100644
--- a/third_party/subzero/src/IceTargetLoweringARM32.h
+++ b/third_party/subzero/src/IceTargetLoweringARM32.h
@@ -885,21 +885,51 @@
              CondARM32::Cond Pred = CondARM32::AL) {
     Context.insert<InstARM32Vcmp>(Src0, FpZero, Pred);
   }
+  void _vdup(Variable *Dest, Variable *Src, int Idx) {
+    Context.insert<InstARM32Vdup>(Dest, Src, Idx);
+  }
   void _veor(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstARM32Veor>(Dest, Src0, Src1);
   }
+  void _vldr1d(Variable *Dest, OperandARM32Mem *Addr,
+               CondARM32::Cond Pred = CondARM32::AL) {
+    Context.insert<InstARM32Vldr1d>(Dest, Addr, Pred);
+  }
+  void _vldr1q(Variable *Dest, OperandARM32Mem *Addr,
+               CondARM32::Cond Pred = CondARM32::AL) {
+    Context.insert<InstARM32Vldr1q>(Dest, Addr, Pred);
+  }
   void _vmrs(CondARM32::Cond Pred = CondARM32::AL) {
     Context.insert<InstARM32Vmrs>(Pred);
   }
   void _vmla(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstARM32Vmla>(Dest, Src0, Src1);
   }
+  void _vmlap(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstARM32Vmlap>(Dest, Src0, Src1);
+  }
   void _vmls(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstARM32Vmls>(Dest, Src0, Src1);
   }
+  void _vmovl(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstARM32Vmovl>(Dest, Src0, Src1);
+  }
+  void _vmovh(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstARM32Vmovh>(Dest, Src0, Src1);
+  }
+  void _vmovhl(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstARM32Vmovhl>(Dest, Src0, Src1);
+  }
+  void _vmovlh(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstARM32Vmovlh>(Dest, Src0, Src1);
+  }
   void _vmul(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstARM32Vmul>(Dest, Src0, Src1);
   }
+  void _vmulh(Variable *Dest, Variable *Src0, Variable *Src1, bool Unsigned) {
+    Context.insert<InstARM32Vmulh>(Dest, Src0, Src1)
+        ->setSignType(Unsigned ? InstARM32::FS_Unsigned : InstARM32::FS_Signed);
+  }
   void _vmvn(Variable *Dest, Variable *Src0) {
     Context.insert<InstARM32Vmvn>(Dest, Src0, CondARM32::AL);
   }
@@ -910,6 +940,21 @@
   void _vorr(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstARM32Vorr>(Dest, Src0, Src1);
   }
+  void _vqadd(Variable *Dest, Variable *Src0, Variable *Src1, bool Unsigned) {
+    Context.insert<InstARM32Vqadd>(Dest, Src0, Src1)
+        ->setSignType(Unsigned ? InstARM32::FS_Unsigned : InstARM32::FS_Signed);
+  }
+  void _vqmovn2(Variable *Dest, Variable *Src0, Variable *Src1, bool Unsigned,
+                bool Saturating) {
+    Context.insert<InstARM32Vqmovn2>(Dest, Src0, Src1)
+        ->setSignType(Saturating ? (Unsigned ? InstARM32::FS_Unsigned
+                                             : InstARM32::FS_Signed)
+                                 : InstARM32::FS_None);
+  }
+  void _vqsub(Variable *Dest, Variable *Src0, Variable *Src1, bool Unsigned) {
+    Context.insert<InstARM32Vqsub>(Dest, Src0, Src1)
+        ->setSignType(Unsigned ? InstARM32::FS_Unsigned : InstARM32::FS_Signed);
+  }
   InstARM32Vshl *_vshl(Variable *Dest, Variable *Src0, Variable *Src1) {
     return Context.insert<InstARM32Vshl>(Dest, Src0, Src1);
   }
@@ -925,9 +970,20 @@
               CondARM32::Cond Pred = CondARM32::AL) {
     Context.insert<InstARM32Vsqrt>(Dest, Src, Pred);
   }
+  void _vstr1d(Variable *Value, OperandARM32Mem *Addr,
+               CondARM32::Cond Pred = CondARM32::AL) {
+    Context.insert<InstARM32Vstr1>(Value, Addr, Pred, 32);
+  }
+  void _vstr1q(Variable *Value, OperandARM32Mem *Addr,
+               CondARM32::Cond Pred = CondARM32::AL) {
+    Context.insert<InstARM32Vstr1>(Value, Addr, Pred, 64);
+  }
   void _vsub(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstARM32Vsub>(Dest, Src0, Src1);
   }
+  void _vzip(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstARM32Vzip>(Dest, Src0, Src1);
+  }
 
   // Iterates over the CFG and determines the maximum outgoing stack arguments
   // bytes. This information is later used during addProlog() to pre-allocate
diff --git a/third_party/subzero/src/IceTargetLoweringX86BaseImpl.h b/third_party/subzero/src/IceTargetLoweringX86BaseImpl.h
index c5eac33..f2fd83e 100644
--- a/third_party/subzero/src/IceTargetLoweringX86BaseImpl.h
+++ b/third_party/subzero/src/IceTargetLoweringX86BaseImpl.h
@@ -6304,22 +6304,22 @@
       break;
     }
 
-    const SizeT Index0 = Instr->getIndex(0)->getValue();
-    const SizeT Index1 = Instr->getIndex(1)->getValue();
-    const SizeT Index2 = Instr->getIndex(2)->getValue();
-    const SizeT Index3 = Instr->getIndex(3)->getValue();
-    const SizeT Index4 = Instr->getIndex(4)->getValue();
-    const SizeT Index5 = Instr->getIndex(5)->getValue();
-    const SizeT Index6 = Instr->getIndex(6)->getValue();
-    const SizeT Index7 = Instr->getIndex(7)->getValue();
-    const SizeT Index8 = Instr->getIndex(8)->getValue();
-    const SizeT Index9 = Instr->getIndex(9)->getValue();
-    const SizeT Index10 = Instr->getIndex(10)->getValue();
-    const SizeT Index11 = Instr->getIndex(11)->getValue();
-    const SizeT Index12 = Instr->getIndex(12)->getValue();
-    const SizeT Index13 = Instr->getIndex(13)->getValue();
-    const SizeT Index14 = Instr->getIndex(14)->getValue();
-    const SizeT Index15 = Instr->getIndex(15)->getValue();
+    const SizeT Index0 = Instr->getIndexValue(0);
+    const SizeT Index1 = Instr->getIndexValue(1);
+    const SizeT Index2 = Instr->getIndexValue(2);
+    const SizeT Index3 = Instr->getIndexValue(3);
+    const SizeT Index4 = Instr->getIndexValue(4);
+    const SizeT Index5 = Instr->getIndexValue(5);
+    const SizeT Index6 = Instr->getIndexValue(6);
+    const SizeT Index7 = Instr->getIndexValue(7);
+    const SizeT Index8 = Instr->getIndexValue(8);
+    const SizeT Index9 = Instr->getIndexValue(9);
+    const SizeT Index10 = Instr->getIndexValue(10);
+    const SizeT Index11 = Instr->getIndexValue(11);
+    const SizeT Index12 = Instr->getIndexValue(12);
+    const SizeT Index13 = Instr->getIndexValue(13);
+    const SizeT Index14 = Instr->getIndexValue(14);
+    const SizeT Index15 = Instr->getIndexValue(15);
 
     lowerShuffleVector_UsingPshufb(Dest, Src0, Src1, Index0, Index1, Index2,
                                    Index3, Index4, Index5, Index6, Index7,
@@ -6376,14 +6376,14 @@
       break;
     }
 
-    const SizeT Index0 = Instr->getIndex(0)->getValue();
-    const SizeT Index1 = Instr->getIndex(1)->getValue();
-    const SizeT Index2 = Instr->getIndex(2)->getValue();
-    const SizeT Index3 = Instr->getIndex(3)->getValue();
-    const SizeT Index4 = Instr->getIndex(4)->getValue();
-    const SizeT Index5 = Instr->getIndex(5)->getValue();
-    const SizeT Index6 = Instr->getIndex(6)->getValue();
-    const SizeT Index7 = Instr->getIndex(7)->getValue();
+    const SizeT Index0 = Instr->getIndexValue(0);
+    const SizeT Index1 = Instr->getIndexValue(1);
+    const SizeT Index2 = Instr->getIndexValue(2);
+    const SizeT Index3 = Instr->getIndexValue(3);
+    const SizeT Index4 = Instr->getIndexValue(4);
+    const SizeT Index5 = Instr->getIndexValue(5);
+    const SizeT Index6 = Instr->getIndexValue(6);
+    const SizeT Index7 = Instr->getIndexValue(7);
 
 #define TO_BYTE_INDEX(I) ((I) << 1)
     lowerShuffleVector_UsingPshufb(
@@ -6403,10 +6403,10 @@
   case IceType_v4f32: {
     static constexpr SizeT ExpectedNumElements = 4;
     assert(ExpectedNumElements == Instr->getNumIndexes());
-    const SizeT Index0 = Instr->getIndex(0)->getValue();
-    const SizeT Index1 = Instr->getIndex(1)->getValue();
-    const SizeT Index2 = Instr->getIndex(2)->getValue();
-    const SizeT Index3 = Instr->getIndex(3)->getValue();
+    const SizeT Index0 = Instr->getIndexValue(0);
+    const SizeT Index1 = Instr->getIndexValue(1);
+    const SizeT Index2 = Instr->getIndexValue(2);
+    const SizeT Index3 = Instr->getIndexValue(3);
     Variable *T = nullptr;
     switch (makeSrcSwitchMask(Index0, Index1, Index2, Index3)) {
 #define CASE_SRCS_IN(S0, S1, S2, S3)                                           \
@@ -6611,8 +6611,7 @@
           InstExtractElement::create(Func, ExtElmt, Src0, Index));
     } else {
       lowerExtractElement(InstExtractElement::create(
-          Func, ExtElmt, Src1,
-          Ctx->getConstantInt32(Index->getValue() - NumElements)));
+          Func, ExtElmt, Src1, Ctx->getConstantInt32(Elem - NumElements)));
     }
     auto *NewT = makeReg(DestTy);
     lowerInsertElement(InstInsertElement::create(Func, NewT, T, ExtElmt,
diff --git a/third_party/subzero/src/IceTypes.def b/third_party/subzero/src/IceTypes.def
index da0c7ec..0c9e491 100644
--- a/third_party/subzero/src/IceTypes.def
+++ b/third_party/subzero/src/IceTypes.def
@@ -79,7 +79,7 @@
   X(v8i16,         1, 1, 0, 1, 0, 1, v8i1)                                     \
   X(v4i32,         1, 1, 0, 1, 0, 1, v4i1)                                     \
   X(v4f32,         1, 0, 1, 0, 0, 1, v4i1)                                     \
-//#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsBoolean, IsParam,        \
+//#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsBoolean, IsParam,
 //          CompareResult)
 
 #endif // SUBZERO_SRC_ICETYPES_DEF