Add an EGL_ANGLE_surface_orientation extension.

BUG=angleproject:1262

Change-Id: Ifbb0f5302311a68a0c6f02baaea706cbb7055a52
Reviewed-on: https://chromium-review.googlesource.com/320011
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index a7c7a0b..ca291a2 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -609,6 +609,7 @@
       querySurfacePointer(false),
       windowFixedSize(false),
       keyedMutex(false),
+      surfaceOrientation(false),
       postSubBuffer(false),
       createContext(false),
       deviceQuery(false),
@@ -636,6 +637,7 @@
     InsertExtensionString("EGL_ANGLE_query_surface_pointer",               querySurfacePointer,            &extensionStrings);
     InsertExtensionString("EGL_ANGLE_window_fixed_size",                   windowFixedSize,                &extensionStrings);
     InsertExtensionString("EGL_ANGLE_keyed_mutex",                         keyedMutex,                     &extensionStrings);
+    InsertExtensionString("EGL_ANGLE_surface_orientation",                 surfaceOrientation,             &extensionStrings);
     InsertExtensionString("EGL_NV_post_sub_buffer",                        postSubBuffer,                  &extensionStrings);
     InsertExtensionString("EGL_KHR_create_context",                        createContext,                  &extensionStrings);
     InsertExtensionString("EGL_EXT_device_query",                          deviceQuery,                    &extensionStrings);
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index 537f964..ecae714 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -427,6 +427,9 @@
     // EGL_ANGLE_keyed_mutex
     bool keyedMutex;
 
+    // EGL_ANGLE_surface_orientation
+    bool surfaceOrientation;
+
     // EGL_NV_post_sub_buffer
     bool postSubBuffer;
 
diff --git a/src/libANGLE/Config.cpp b/src/libANGLE/Config.cpp
index c558b31..d511df3 100644
--- a/src/libANGLE/Config.cpp
+++ b/src/libANGLE/Config.cpp
@@ -57,7 +57,8 @@
       transparentType(EGL_NONE),
       transparentRedValue(0),
       transparentGreenValue(0),
-      transparentBlueValue(0)
+      transparentBlueValue(0),
+      optimalOrientation(0)
 {
 }
 
@@ -251,6 +252,9 @@
               case EGL_MAX_PBUFFER_WIDTH:         match = config.maxPBufferWidth >= attributeValue;                   break;
               case EGL_MAX_PBUFFER_HEIGHT:        match = config.maxPBufferHeight >= attributeValue;                  break;
               case EGL_MAX_PBUFFER_PIXELS:        match = config.maxPBufferPixels >= attributeValue;                  break;
+              case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE:
+                  match = config.optimalOrientation == attributeValue;
+                  break;
               default: UNREACHABLE();
             }
 
diff --git a/src/libANGLE/Config.h b/src/libANGLE/Config.h
index aed8aed..00f5673 100644
--- a/src/libANGLE/Config.h
+++ b/src/libANGLE/Config.h
@@ -64,6 +64,7 @@
     EGLint transparentRedValue;     // Transparent red value
     EGLint transparentGreenValue;   // Transparent green value
     EGLint transparentBlueValue;    // Transparent blue value
+    EGLint optimalOrientation;      // Optimal window surface orientation
 };
 
 class ConfigSet
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
index 5e71a90..439e433 100644
--- a/src/libANGLE/Display.cpp
+++ b/src/libANGLE/Display.cpp
@@ -483,6 +483,15 @@
       case EGL_MAX_PBUFFER_WIDTH:         *value = configuration->maxPBufferWidth;        break;
       case EGL_MAX_PBUFFER_HEIGHT:        *value = configuration->maxPBufferHeight;       break;
       case EGL_MAX_PBUFFER_PIXELS:        *value = configuration->maxPBufferPixels;       break;
+
+      case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE:
+          if (!getExtensions().surfaceOrientation)
+          {
+              return false;
+          }
+          *value = configuration->optimalOrientation;
+          break;
+
       default:
         return false;
     }
diff --git a/src/libANGLE/Surface.cpp b/src/libANGLE/Surface.cpp
index e5c3aee..dc754ff 100644
--- a/src/libANGLE/Surface.cpp
+++ b/src/libANGLE/Surface.cpp
@@ -41,7 +41,9 @@
       // FIXME: Determine actual pixel aspect ratio
       mPixelAspectRatio(static_cast<EGLint>(1.0 * EGL_DISPLAY_SCALING)),
       mRenderBuffer(EGL_BACK_BUFFER),
-      mSwapBehavior(impl->getSwapBehavior())
+      mSwapBehavior(impl->getSwapBehavior()),
+      mOrientation(0),
+      mTexture()
 {
     mPostSubBufferRequested = (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE);
     mFlexibleSurfaceCompatibilityRequested =
@@ -60,6 +62,8 @@
         mTextureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE);
     }
 
+    mOrientation = attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0);
+
     mDefaultFramebuffer = createDefaultFramebuffer();
     ASSERT(mDefaultFramebuffer != nullptr);
 }
diff --git a/src/libANGLE/Surface.h b/src/libANGLE/Surface.h
index c7a3d78..813f2ef 100644
--- a/src/libANGLE/Surface.h
+++ b/src/libANGLE/Surface.h
@@ -82,6 +82,7 @@
     {
         return mFlexibleSurfaceCompatibilityRequested;
     }
+    EGLint getOrientation() const { return mOrientation; }
 
   private:
     virtual ~Surface();
@@ -116,6 +117,8 @@
     EGLenum mRenderBuffer;         // Render buffer
     EGLenum mSwapBehavior;         // Buffer swap behavior
 
+    EGLint mOrientation;
+
     BindingPointer<gl::Texture> mTexture;
 };
 
diff --git a/src/libANGLE/renderer/d3d/DisplayD3D.cpp b/src/libANGLE/renderer/d3d/DisplayD3D.cpp
index 3aced4f..7c53c81 100644
--- a/src/libANGLE/renderer/d3d/DisplayD3D.cpp
+++ b/src/libANGLE/renderer/d3d/DisplayD3D.cpp
@@ -172,6 +172,7 @@
     EGLint width = attribs.get(EGL_WIDTH, 0);
     EGLint height = attribs.get(EGL_HEIGHT, 0);
     EGLint fixedSize = attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE);
+    EGLint orientation = attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0);
 
     if (!fixedSize)
     {
@@ -179,8 +180,8 @@
         height = -1;
     }
 
-    return SurfaceD3D::createFromWindow(
-        mRenderer, mDisplay, configuration, window, fixedSize, width, height);
+    return SurfaceD3D::createFromWindow(mRenderer, mDisplay, configuration, window, fixedSize,
+                                        width, height, orientation);
 }
 
 SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::Config *configuration,
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.h b/src/libANGLE/renderer/d3d/RendererD3D.h
index f6c5be6..4a90fd1 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -143,7 +143,11 @@
     // Direct3D Specific methods
     virtual DeviceIdentifier getAdapterIdentifier() const = 0;
 
-    virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0;
+    virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow,
+                                          HANDLE shareHandle,
+                                          GLenum backBufferFormat,
+                                          GLenum depthBufferFormat,
+                                          EGLint orientation) = 0;
 
     virtual gl::Error generateSwizzle(gl::Texture *texture) = 0;
     virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler) = 0;
diff --git a/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
index 613b9df..44c525b 100644
--- a/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
+++ b/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
@@ -24,13 +24,20 @@
 SurfaceD3D *SurfaceD3D::createOffscreen(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLClientBuffer shareHandle,
                                         EGLint width, EGLint height)
 {
-    return new SurfaceD3D(renderer, display, config, width, height, EGL_TRUE, shareHandle, NULL);
+    return new SurfaceD3D(renderer, display, config, width, height, EGL_TRUE, 0, shareHandle, NULL);
 }
 
-SurfaceD3D *SurfaceD3D::createFromWindow(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLNativeWindowType window,
-                                         EGLint fixedSize, EGLint width, EGLint height)
+SurfaceD3D *SurfaceD3D::createFromWindow(RendererD3D *renderer,
+                                         egl::Display *display,
+                                         const egl::Config *config,
+                                         EGLNativeWindowType window,
+                                         EGLint fixedSize,
+                                         EGLint width,
+                                         EGLint height,
+                                         EGLint orientation)
 {
-    return new SurfaceD3D(renderer, display, config, width, height, fixedSize, static_cast<EGLClientBuffer>(0), window);
+    return new SurfaceD3D(renderer, display, config, width, height, fixedSize, orientation,
+                          static_cast<EGLClientBuffer>(0), window);
 }
 
 SurfaceD3D::SurfaceD3D(RendererD3D *renderer,
@@ -39,12 +46,14 @@
                        EGLint width,
                        EGLint height,
                        EGLint fixedSize,
+                       EGLint orientation,
                        EGLClientBuffer shareHandle,
                        EGLNativeWindowType window)
     : SurfaceImpl(),
       mRenderer(renderer),
       mDisplay(display),
       mFixedSize(fixedSize == EGL_TRUE),
+      mOrientation(orientation),
       mRenderTargetFormat(config->renderTargetFormat),
       mDepthStencilFormat(config->depthStencilFormat),
       mSwapChain(nullptr),
@@ -128,7 +137,8 @@
         height = mHeight;
     }
 
-    mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, mRenderTargetFormat, mDepthStencilFormat);
+    mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, mRenderTargetFormat,
+                                            mDepthStencilFormat, mOrientation);
     if (!mSwapChain)
     {
         return egl::Error(EGL_BAD_ALLOC);
diff --git a/src/libANGLE/renderer/d3d/SurfaceD3D.h b/src/libANGLE/renderer/d3d/SurfaceD3D.h
index ed259de..a2929dc 100644
--- a/src/libANGLE/renderer/d3d/SurfaceD3D.h
+++ b/src/libANGLE/renderer/d3d/SurfaceD3D.h
@@ -25,8 +25,14 @@
 class SurfaceD3D : public SurfaceImpl
 {
   public:
-    static SurfaceD3D *createFromWindow(RendererD3D *renderer, egl::Display *display, const egl::Config *config,
-                                        EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height);
+    static SurfaceD3D *createFromWindow(RendererD3D *renderer,
+                                        egl::Display *display,
+                                        const egl::Config *config,
+                                        EGLNativeWindowType window,
+                                        EGLint fixedSize,
+                                        EGLint width,
+                                        EGLint height,
+                                        EGLint orientation);
     static SurfaceD3D *createOffscreen(RendererD3D *renderer, egl::Display *display, const egl::Config *config,
                                        EGLClientBuffer shareHandle, EGLint width, EGLint height);
     ~SurfaceD3D() override;
@@ -60,8 +66,15 @@
                                         FramebufferAttachmentRenderTarget **rtOut) override;
 
   private:
-    SurfaceD3D(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLint width, EGLint height,
-               EGLint fixedSize, EGLClientBuffer shareHandle, EGLNativeWindowType window);
+    SurfaceD3D(RendererD3D *renderer,
+               egl::Display *display,
+               const egl::Config *config,
+               EGLint width,
+               EGLint height,
+               EGLint fixedSize,
+               EGLint orientation,
+               EGLClientBuffer shareHandle,
+               EGLNativeWindowType window);
 
     egl::Error swapRect(EGLint x, EGLint y, EGLint width, EGLint height);
     egl::Error resetSwapChain(int backbufferWidth, int backbufferHeight);
@@ -71,6 +84,7 @@
     egl::Display *mDisplay;
 
     bool mFixedSize;
+    GLint mOrientation;
 
     GLenum mRenderTargetFormat;
     GLenum mDepthStencilFormat;
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index a808bb2..2db242c 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -989,6 +989,8 @@
     const gl::Caps &rendererCaps = getRendererCaps();
     const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps();
 
+    const EGLint optimalSurfaceOrientation = EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE;
+
     egl::ConfigSet configs;
     for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++)
     {
@@ -1043,6 +1045,7 @@
                     config.transparentRedValue = 0;
                     config.transparentGreenValue = 0;
                     config.transparentBlueValue = 0;
+                    config.optimalOrientation    = optimalSurfaceOrientation;
 
                     configs.add(config);
                 }
@@ -1070,6 +1073,7 @@
 
     outExtensions->querySurfacePointer = true;
     outExtensions->windowFixedSize     = true;
+    outExtensions->surfaceOrientation  = true;
 
     // D3D11 does not support present with dirty rectangles until DXGI 1.2.
     outExtensions->postSubBuffer = mRenderer11DeviceCaps.supportsDXGI1_2;
@@ -1136,9 +1140,14 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat)
+SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow,
+                                          HANDLE shareHandle,
+                                          GLenum backBufferFormat,
+                                          GLenum depthBufferFormat,
+                                          EGLint orientation)
 {
-    return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat);
+    return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat,
+                           orientation);
 }
 
 void *Renderer11::getD3DDevice()
@@ -2399,12 +2408,7 @@
 {
     TRACE_EVENT0("gpu.angle", "Renderer11::markAllStateDirty");
 
-    for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++)
-    {
-        mAppliedRTVs[rtIndex] = DirtyPointer;
-    }
-    mAppliedDSV = DirtyPointer;
-    mDepthStencilInitialized = false;
+    markRenderTargetStateDirty();
 
     // We reset the current SRV data because it might not be in sync with D3D's state
     // anymore. For example when a currently used SRV is used as an RTV, D3D silently
@@ -2468,6 +2472,16 @@
     mCurrentPrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
 }
 
+void Renderer11::markRenderTargetStateDirty()
+{
+    for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++)
+    {
+        mAppliedRTVs[rtIndex] = DirtyPointer;
+    }
+    mAppliedDSV              = DirtyPointer;
+    mDepthStencilInitialized = false;
+}
+
 void Renderer11::releaseDeviceResources()
 {
     mStateCache.clear();
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index 7f80186..4bfcbf3 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -111,7 +111,11 @@
     gl::Error flush() override;
     gl::Error finish() override;
 
-    virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat);
+    SwapChainD3D *createSwapChain(NativeWindow nativeWindow,
+                                  HANDLE shareHandle,
+                                  GLenum backBufferFormat,
+                                  GLenum depthBufferFormat,
+                                  EGLint orientation) override;
 
     virtual gl::Error generateSwizzle(gl::Texture *texture);
     virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler);
@@ -139,6 +143,7 @@
     void applyTransformFeedbackBuffers(const gl::State &state) override;
 
     virtual void markAllStateDirty();
+    void markRenderTargetStateDirty();
 
     // lost device
     bool testDeviceLost() override;
diff --git a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
index 8a4b619..21ce8bb 100644
--- a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
@@ -8,6 +8,8 @@
 
 #include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
 
+#include <EGL/eglext.h>
+
 #include "libANGLE/features.h"
 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
 #include "libANGLE/renderer/d3d/d3d11/NativeWindow.h"
@@ -29,40 +31,43 @@
 namespace rx
 {
 
-SwapChain11::SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle,
-                         GLenum backBufferFormat, GLenum depthBufferFormat)
+SwapChain11::SwapChain11(Renderer11 *renderer,
+                         NativeWindow nativeWindow,
+                         HANDLE shareHandle,
+                         GLenum backBufferFormat,
+                         GLenum depthBufferFormat,
+                         EGLint orientation)
     : SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat),
       mRenderer(renderer),
+      mWidth(-1),
+      mHeight(-1),
+      mOrientation(orientation),
+      mAppCreatedShareHandle(mShareHandle != nullptr),
+      mSwapInterval(0),
       mPassThroughResourcesInit(false),
+      mFirstSwap(true),
+      mSwapChain(nullptr),
+      mSwapChain1(nullptr),
+      mKeyedMutex(nullptr),
+      mNeedsOffscreenTexture(orientation != EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE),
+      mBackBufferTexture(nullptr),
+      mBackBufferRTView(nullptr),
+      mBackBufferSRView(nullptr),
+      mOffscreenTexture(nullptr),
+      mOffscreenRTView(nullptr),
+      mOffscreenSRView(nullptr),
+      mDepthStencilTexture(nullptr),
+      mDepthStencilDSView(nullptr),
+      mDepthStencilSRView(nullptr),
+      mQuadVB(nullptr),
+      mPassThroughSampler(nullptr),
+      mPassThroughIL(nullptr),
+      mPassThroughVS(nullptr),
+      mPassThroughPS(nullptr),
+      mPassThroughRS(nullptr),
       mColorRenderTarget(this, renderer, false),
       mDepthStencilRenderTarget(this, renderer, true)
 {
-    mHeight = -1;
-    mWidth = -1;
-    mAppCreatedShareHandle = mShareHandle != NULL;
-    mSwapInterval = 0;
-
-    mSwapChain = NULL;
-    mSwapChain1 = nullptr;
-
-    mKeyedMutex = nullptr;
-
-    mBackBufferTexture = NULL;
-    mBackBufferRTView = NULL;
-
-    mOffscreenTexture = NULL;
-    mOffscreenRTView = NULL;
-    mOffscreenSRView = NULL;
-
-    mDepthStencilTexture = NULL;
-    mDepthStencilDSView = NULL;
-    mDepthStencilSRView = NULL;
-
-    mQuadVB = NULL;
-    mPassThroughSampler = NULL;
-    mPassThroughIL = NULL;
-    mPassThroughVS = NULL;
-    mPassThroughPS = NULL;
 }
 
 SwapChain11::~SwapChain11()
@@ -77,6 +82,7 @@
     SafeRelease(mKeyedMutex);
     SafeRelease(mBackBufferTexture);
     SafeRelease(mBackBufferRTView);
+    SafeRelease(mBackBufferSRView);
     SafeRelease(mOffscreenTexture);
     SafeRelease(mOffscreenRTView);
     SafeRelease(mOffscreenSRView);
@@ -88,6 +94,7 @@
     SafeRelease(mPassThroughIL);
     SafeRelease(mPassThroughVS);
     SafeRelease(mPassThroughPS);
+    SafeRelease(mPassThroughRS);
 
     if (!mAppCreatedShareHandle)
     {
@@ -95,18 +102,47 @@
     }
 }
 
-void SwapChain11::releaseOffscreenTexture()
+void SwapChain11::releaseOffscreenColorBuffer()
 {
     SafeRelease(mOffscreenTexture);
     SafeRelease(mOffscreenRTView);
     SafeRelease(mOffscreenSRView);
+}
+
+void SwapChain11::releaseOffscreenDepthBuffer()
+{
     SafeRelease(mDepthStencilTexture);
     SafeRelease(mDepthStencilDSView);
     SafeRelease(mDepthStencilSRView);
 }
 
-EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHeight)
+EGLint SwapChain11::resetOffscreenBuffers(int backbufferWidth, int backbufferHeight)
 {
+    if (mNeedsOffscreenTexture)
+    {
+        EGLint result = resetOffscreenColorBuffer(backbufferWidth, backbufferHeight);
+        if (result != EGL_SUCCESS)
+        {
+            return result;
+        }
+    }
+
+    EGLint result = resetOffscreenDepthBuffer(backbufferWidth, backbufferHeight);
+    if (result != EGL_SUCCESS)
+    {
+        return result;
+    }
+
+    mWidth  = backbufferWidth;
+    mHeight = backbufferHeight;
+
+    return EGL_SUCCESS;
+}
+
+EGLint SwapChain11::resetOffscreenColorBuffer(int backbufferWidth, int backbufferHeight)
+{
+    ASSERT(mNeedsOffscreenTexture);
+
     TRACE_EVENT0("gpu.angle", "SwapChain11::resetOffscreenTexture");
     ID3D11Device *device = mRenderer->getDevice();
 
@@ -125,7 +161,7 @@
     const int previousWidth = mWidth;
     const int previousHeight = mHeight;
 
-    releaseOffscreenTexture();
+    releaseOffscreenColorBuffer();
 
     const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps());
 
@@ -230,7 +266,6 @@
         mKeyedMutex = d3d11::DynamicCastComObject<IDXGIKeyedMutex>(mOffscreenTexture);
     }
 
-
     D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc;
     offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat;
     offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
@@ -250,10 +285,41 @@
     ASSERT(SUCCEEDED(result));
     d3d11::SetDebugName(mOffscreenSRView, "Offscreen back buffer shader resource");
 
-    const d3d11::TextureFormat &depthBufferFormatInfo = d3d11::GetTextureFormatInfo(mDepthBufferFormat, mRenderer->getRenderer11DeviceCaps());
+    if (previousOffscreenTexture != nullptr)
+    {
+        D3D11_BOX sourceBox = {0};
+        sourceBox.left      = 0;
+        sourceBox.right     = std::min(previousWidth, backbufferWidth);
+        sourceBox.top       = std::max(previousHeight - backbufferHeight, 0);
+        sourceBox.bottom    = previousHeight;
+        sourceBox.front     = 0;
+        sourceBox.back      = 1;
+
+        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+        const int yoffset = std::max(backbufferHeight - previousHeight, 0);
+        deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0,
+                                             previousOffscreenTexture, 0, &sourceBox);
+
+        SafeRelease(previousOffscreenTexture);
+
+        if (mSwapChain)
+        {
+            swapRect(0, 0, backbufferWidth, backbufferHeight);
+        }
+    }
+
+    return EGL_SUCCESS;
+}
+
+EGLint SwapChain11::resetOffscreenDepthBuffer(int backbufferWidth, int backbufferHeight)
+{
+    releaseOffscreenDepthBuffer();
 
     if (mDepthBufferFormat != GL_NONE)
     {
+        const d3d11::TextureFormat &depthBufferFormatInfo =
+            d3d11::GetTextureFormatInfo(mDepthBufferFormat, mRenderer->getRenderer11DeviceCaps());
+
         D3D11_TEXTURE2D_DESC depthStencilTextureDesc;
         depthStencilTextureDesc.Width = backbufferWidth;
         depthStencilTextureDesc.Height = backbufferHeight;
@@ -273,7 +339,9 @@
         depthStencilTextureDesc.CPUAccessFlags = 0;
         depthStencilTextureDesc.MiscFlags = 0;
 
-        result = device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture);
+        ID3D11Device *device = mRenderer->getDevice();
+        HRESULT result =
+            device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture);
         if (FAILED(result))
         {
             ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
@@ -314,31 +382,6 @@
         }
     }
 
-    mWidth = backbufferWidth;
-    mHeight = backbufferHeight;
-
-    if (previousOffscreenTexture != NULL)
-    {
-        D3D11_BOX sourceBox = {0};
-        sourceBox.left = 0;
-        sourceBox.right = std::min(previousWidth, mWidth);
-        sourceBox.top = std::max(previousHeight - mHeight, 0);
-        sourceBox.bottom = previousHeight;
-        sourceBox.front = 0;
-        sourceBox.back = 1;
-
-        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
-        const int yoffset = std::max(mHeight - previousHeight, 0);
-        deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, previousOffscreenTexture, 0, &sourceBox);
-
-        SafeRelease(previousOffscreenTexture);
-
-        if (mSwapChain)
-        {
-            swapRect(0, 0, mWidth, mHeight);
-        }
-    }
-
     return EGL_SUCCESS;
 }
 
@@ -358,11 +401,18 @@
         return EGL_SUCCESS;
     }
 
+    // Don't resize unnecessarily
+    if (mWidth == backbufferWidth && mHeight == backbufferHeight)
+    {
+        return EGL_SUCCESS;
+    }
+
     // Can only call resize if we have already created our swap buffer and resources
-    ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView);
+    ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView && mBackBufferSRView);
 
     SafeRelease(mBackBufferTexture);
     SafeRelease(mBackBufferRTView);
+    SafeRelease(mBackBufferSRView);
 
     // Resize swap chain
     DXGI_SWAP_CHAIN_DESC desc;
@@ -398,14 +448,22 @@
         d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture");
         result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView);
         ASSERT(SUCCEEDED(result));
+        if (SUCCEEDED(result))
+        {
+            d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target");
+        }
+
+        result = device->CreateShaderResourceView(mBackBufferTexture, nullptr, &mBackBufferSRView);
+        ASSERT(SUCCEEDED(result));
+        if (SUCCEEDED(result))
+        {
+            d3d11::SetDebugName(mBackBufferSRView, "Back buffer shader resource");
+        }
     }
 
-    if (SUCCEEDED(result))
-    {
-        d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target");
-    }
+    mFirstSwap = true;
 
-    return resetOffscreenTexture(backbufferWidth, backbufferHeight);
+    return resetOffscreenBuffers(backbufferWidth, backbufferHeight);
 }
 
 DXGI_FORMAT SwapChain11::getSwapChainNativeFormat() const
@@ -417,6 +475,20 @@
 
 EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
 {
+    mSwapInterval = static_cast<unsigned int>(swapInterval);
+    if (mSwapInterval > 4)
+    {
+        // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4]
+        // range
+        return EGL_BAD_PARAMETER;
+    }
+
+    // If the swap chain already exists, just resize
+    if (mSwapChain != nullptr)
+    {
+        return resize(backbufferWidth, backbufferHeight);
+    }
+
     TRACE_EVENT0("gpu.angle", "SwapChain11::reset");
     ID3D11Device *device = mRenderer->getDevice();
 
@@ -432,17 +504,10 @@
     SafeRelease(mBackBufferTexture);
     SafeRelease(mBackBufferRTView);
 
-    mSwapInterval = static_cast<unsigned int>(swapInterval);
-    if (mSwapInterval > 4)
-    {
-        // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4] range
-        return EGL_BAD_PARAMETER;
-    }
-
     // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains
     if (backbufferWidth < 1 || backbufferHeight < 1)
     {
-        releaseOffscreenTexture();
+        releaseOffscreenColorBuffer();
         return EGL_SUCCESS;
     }
 
@@ -479,9 +544,15 @@
         result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView);
         ASSERT(SUCCEEDED(result));
         d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target");
+
+        result = device->CreateShaderResourceView(mBackBufferTexture, nullptr, &mBackBufferSRView);
+        ASSERT(SUCCEEDED(result));
+        d3d11::SetDebugName(mBackBufferSRView, "Back buffer shader resource view");
     }
 
-    return resetOffscreenTexture(backbufferWidth, backbufferHeight);
+    mFirstSwap = true;
+
+    return resetOffscreenBuffers(backbufferWidth, backbufferHeight);
 }
 
 void SwapChain11::initPassThroughResources()
@@ -549,12 +620,50 @@
     ASSERT(SUCCEEDED(result));
     d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader");
 
+    // Use the default rasterizer state but without culling
+    D3D11_RASTERIZER_DESC rasterizerDesc;
+    rasterizerDesc.FillMode              = D3D11_FILL_SOLID;
+    rasterizerDesc.CullMode              = D3D11_CULL_NONE;
+    rasterizerDesc.FrontCounterClockwise = FALSE;
+    rasterizerDesc.DepthBias             = 0;
+    rasterizerDesc.SlopeScaledDepthBias  = 0.0f;
+    rasterizerDesc.DepthBiasClamp        = 0.0f;
+    rasterizerDesc.DepthClipEnable       = TRUE;
+    rasterizerDesc.ScissorEnable         = FALSE;
+    rasterizerDesc.MultisampleEnable     = FALSE;
+    rasterizerDesc.AntialiasedLineEnable = FALSE;
+    result = device->CreateRasterizerState(&rasterizerDesc, &mPassThroughRS);
+    ASSERT(SUCCEEDED(result));
+    d3d11::SetDebugName(mPassThroughRS, "Swap chain pass through rasterizer state");
+
     mPassThroughResourcesInit = true;
 }
 
 // parameters should be validated/clamped by caller
 EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
 {
+    if (mNeedsOffscreenTexture)
+    {
+        EGLint result = copyOffscreenToBackbuffer(x, y, width, height);
+        if (result != EGL_SUCCESS)
+        {
+            return result;
+        }
+    }
+
+    EGLint result = present(x, y, width, height);
+    if (result != EGL_SUCCESS)
+    {
+        return result;
+    }
+
+    mRenderer->onSwap();
+
+    return EGL_SUCCESS;
+}
+
+EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, EGLint height)
+{
     if (!mSwapChain)
     {
         return EGL_SUCCESS;
@@ -562,7 +671,6 @@
 
     initPassThroughResources();
 
-    ID3D11Device *device = mRenderer->getDevice();
     ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
 
     // Set vertices
@@ -586,6 +694,16 @@
     float u2 = (x + width) / float(mWidth);
     float v2 = (y + height) / float(mHeight);
 
+    // Invert the quad vertices depending on the surface orientation.
+    if ((mOrientation & EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE) != 0)
+    {
+        std::swap(x1, x2);
+    }
+    if ((mOrientation & EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE) != 0)
+    {
+        std::swap(y1, y2);
+    }
+
     d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v1);
     d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2);
     d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1);
@@ -603,7 +721,7 @@
     static const float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
     deviceContext->OMSetBlendState(NULL, blendFactor, 0xFFFFFFF);
 
-    deviceContext->RSSetState(NULL);
+    deviceContext->RSSetState(mPassThroughRS);
 
     // Apply shaders
     deviceContext->IASetInputLayout(mPassThroughIL);
@@ -640,28 +758,54 @@
     mRenderer->unapplyRenderTargets();
     mRenderer->markAllStateDirty();
 
+    return EGL_SUCCESS;
+}
+
+EGLint SwapChain11::present(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+    if (!mSwapChain)
+    {
+        return EGL_SUCCESS;
+    }
+
+    UINT swapInterval = mSwapInterval;
 #if ANGLE_VSYNC == ANGLE_DISABLED
-    result = mSwapChain->Present(0, 0);
-#else
+    swapInterval = 0;
+#endif
+
+    HRESULT result = S_OK;
+
     // Use IDXGISwapChain1::Present1 with a dirty rect if DXGI 1.2 is available.
     if (mSwapChain1 != nullptr)
     {
-        RECT rect =
+        if (mFirstSwap)
         {
-            static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height),
-            static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)
-        };
-        DXGI_PRESENT_PARAMETERS params = { 1, &rect, nullptr, nullptr };
-        result = mSwapChain1->Present1(mSwapInterval, 0, &params);
+            // Can't swap with a dirty rect if this swap chain has never swapped before
+            DXGI_PRESENT_PARAMETERS params = {0, nullptr, nullptr, nullptr};
+            result                         = mSwapChain1->Present1(swapInterval, 0, &params);
+        }
+        else
+        {
+            RECT rect = {static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height),
+                         static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)};
+            DXGI_PRESENT_PARAMETERS params = {1, &rect, nullptr, nullptr};
+            result                         = mSwapChain1->Present1(swapInterval, 0, &params);
+        }
     }
     else
     {
-        result = mSwapChain->Present(mSwapInterval, 0);
+        result = mSwapChain->Present(swapInterval, 0);
     }
-#endif
+
+    mFirstSwap = false;
+
+    // Some swapping mechanisms such as DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL unbind the current render
+    // target.  Mark it dirty.
+    mRenderer->markRenderTargetStateDirty();
 
     if (result == DXGI_ERROR_DEVICE_REMOVED)
     {
+        ID3D11Device *device  = mRenderer->getDevice();
         HRESULT removedReason = device->GetDeviceRemovedReason();
         UNUSED_TRACE_VARIABLE(removedReason);
         ERR("Present failed: the D3D11 device was removed: 0x%08X", removedReason);
@@ -677,24 +821,22 @@
         ERR("Present failed with error code 0x%08X", result);
     }
 
-    mRenderer->onSwap();
-
     return EGL_SUCCESS;
 }
 
 ID3D11Texture2D *SwapChain11::getOffscreenTexture()
 {
-    return mOffscreenTexture;
+    return mNeedsOffscreenTexture ? mOffscreenTexture : mBackBufferTexture;
 }
 
 ID3D11RenderTargetView *SwapChain11::getRenderTarget()
 {
-    return mOffscreenRTView;
+    return mNeedsOffscreenTexture ? mOffscreenRTView : mBackBufferRTView;
 }
 
 ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource()
 {
-    return mOffscreenSRView;
+    return mNeedsOffscreenTexture ? mOffscreenSRView : mBackBufferSRView;
 }
 
 ID3D11DepthStencilView *SwapChain11::getDepthStencil()
diff --git a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h
index 24c21e1..9c29cd8 100644
--- a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h
@@ -20,8 +20,12 @@
 class SwapChain11 : public SwapChainD3D
 {
   public:
-    SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle,
-                GLenum backBufferFormat, GLenum depthBufferFormat);
+    SwapChain11(Renderer11 *renderer,
+                NativeWindow nativeWindow,
+                HANDLE shareHandle,
+                GLenum backBufferFormat,
+                GLenum depthBufferFormat,
+                EGLint orientation);
     virtual ~SwapChain11();
 
     EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight);
@@ -47,24 +51,36 @@
   private:
     void release();
     void initPassThroughResources();
-    void releaseOffscreenTexture();
-    EGLint resetOffscreenTexture(int backbufferWidth, int backbufferHeight);
+
+    void releaseOffscreenColorBuffer();
+    void releaseOffscreenDepthBuffer();
+    EGLint resetOffscreenBuffers(int backbufferWidth, int backbufferHeight);
+    EGLint resetOffscreenColorBuffer(int backbufferWidth, int backbufferHeight);
+    EGLint resetOffscreenDepthBuffer(int backbufferWidth, int backbufferHeight);
+
     DXGI_FORMAT getSwapChainNativeFormat() const;
 
+    EGLint copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, EGLint height);
+    EGLint present(EGLint x, EGLint y, EGLint width, EGLint height);
+
     Renderer11 *mRenderer;
     EGLint mHeight;
     EGLint mWidth;
+    const EGLint mOrientation;
     bool mAppCreatedShareHandle;
     unsigned int mSwapInterval;
     bool mPassThroughResourcesInit;
 
+    bool mFirstSwap;
     DXGISwapChain *mSwapChain;
     IDXGISwapChain1 *mSwapChain1;
     IDXGIKeyedMutex *mKeyedMutex;
 
     ID3D11Texture2D *mBackBufferTexture;
     ID3D11RenderTargetView *mBackBufferRTView;
+    ID3D11ShaderResourceView *mBackBufferSRView;
 
+    const bool mNeedsOffscreenTexture;
     ID3D11Texture2D *mOffscreenTexture;
     ID3D11RenderTargetView *mOffscreenRTView;
     ID3D11ShaderResourceView *mOffscreenSRView;
@@ -78,6 +94,7 @@
     ID3D11InputLayout *mPassThroughIL;
     ID3D11VertexShader *mPassThroughVS;
     ID3D11PixelShader *mPassThroughPS;
+    ID3D11RasterizerState *mPassThroughRS;
 
     SurfaceRenderTarget11 mColorRenderTarget;
     SurfaceRenderTarget11 mDepthStencilRenderTarget;
diff --git a/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp b/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp
index 2b8b48c..4f773bb 100644
--- a/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp
@@ -59,7 +59,8 @@
         swapChainDesc.Stereo = FALSE;
         swapChainDesc.SampleDesc.Count = 1;
         swapChainDesc.SampleDesc.Quality = 0;
-        swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+        swapChainDesc.BufferUsage =
+            DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER;
         swapChainDesc.BufferCount = 1;
         swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
         swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
@@ -84,7 +85,8 @@
     swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
     swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
     swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
-    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+    swapChainDesc.BufferUsage =
+        DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER;
     swapChainDesc.Flags = 0;
     swapChainDesc.OutputWindow = mWindow;
     swapChainDesc.SampleDesc.Count = 1;
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index 49e4171..4718781 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -652,9 +652,14 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-SwapChainD3D *Renderer9::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat)
+SwapChainD3D *Renderer9::createSwapChain(NativeWindow nativeWindow,
+                                         HANDLE shareHandle,
+                                         GLenum backBufferFormat,
+                                         GLenum depthBufferFormat,
+                                         EGLint orientation)
 {
-    return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat);
+    return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat,
+                          orientation);
 }
 
 void *Renderer9::getD3DDevice()
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
index 6087b4e..4e3fb9c 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
@@ -79,7 +79,11 @@
     gl::Error flush() override;
     gl::Error finish() override;
 
-    virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat);
+    SwapChainD3D *createSwapChain(NativeWindow nativeWindow,
+                                  HANDLE shareHandle,
+                                  GLenum backBufferFormat,
+                                  GLenum depthBufferFormat,
+                                  EGLint orientation) override;
 
     gl::Error allocateEventQuery(IDirect3DQuery9 **outQuery);
     void freeEventQuery(IDirect3DQuery9* query);
diff --git a/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp b/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp
index 5ce76f8..76b535e 100644
--- a/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp
@@ -15,21 +15,27 @@
 namespace rx
 {
 
-SwapChain9::SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle,
-                       GLenum backBufferFormat, GLenum depthBufferFormat)
+SwapChain9::SwapChain9(Renderer9 *renderer,
+                       NativeWindow nativeWindow,
+                       HANDLE shareHandle,
+                       GLenum backBufferFormat,
+                       GLenum depthBufferFormat,
+                       EGLint orientation)
     : SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat),
       mRenderer(renderer),
+      mWidth(-1),
+      mHeight(-1),
+      mOrientation(orientation),
+      mSwapInterval(-1),
+      mSwapChain(nullptr),
+      mBackBuffer(nullptr),
+      mRenderTarget(nullptr),
+      mDepthStencil(nullptr),
+      mOffscreenTexture(nullptr),
       mColorRenderTarget(this, false),
       mDepthStencilRenderTarget(this, true)
 {
-    mSwapChain = NULL;
-    mBackBuffer = NULL;
-    mDepthStencil = NULL;
-    mRenderTarget = NULL;
-    mOffscreenTexture = NULL;
-    mWidth = -1;
-    mHeight = -1;
-    mSwapInterval = -1;
+    ASSERT(mOrientation == 0);
 }
 
 SwapChain9::~SwapChain9()
diff --git a/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h b/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h
index 9c67f71..6cee949 100644
--- a/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h
@@ -20,8 +20,12 @@
 class SwapChain9 : public SwapChainD3D
 {
   public:
-    SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle,
-               GLenum backBufferFormat, GLenum depthBufferFormat);
+    SwapChain9(Renderer9 *renderer,
+               NativeWindow nativeWindow,
+               HANDLE shareHandle,
+               GLenum backBufferFormat,
+               GLenum depthBufferFormat,
+               EGLint orientation);
     virtual ~SwapChain9();
 
     EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight);
@@ -47,6 +51,7 @@
     Renderer9 *mRenderer;
     EGLint mHeight;
     EGLint mWidth;
+    EGLint mOrientation;
     EGLint mSwapInterval;
 
     IDirect3DSwapChain9 *mSwapChain;
diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp
index 5cbb6d8..a6d2313 100644
--- a/src/libANGLE/validationEGL.cpp
+++ b/src/libANGLE/validationEGL.cpp
@@ -372,6 +372,13 @@
             }
             break;
 
+          case EGL_SURFACE_ORIENTATION_ANGLE:
+              if (!displayExtensions.surfaceOrientation)
+              {
+                  return Error(EGL_BAD_ATTRIBUTE, "EGL_ANGLE_surface_orientation is not enabled.");
+              }
+              break;
+
           case EGL_VG_COLORSPACE:
             return Error(EGL_BAD_MATCH);
 
diff --git a/src/libGLESv2/entry_points_egl.cpp b/src/libGLESv2/entry_points_egl.cpp
index 3f0f0e0..b67abe2 100644
--- a/src/libGLESv2/entry_points_egl.cpp
+++ b/src/libGLESv2/entry_points_egl.cpp
@@ -437,6 +437,16 @@
           }
           *value = eglSurface->flexibleSurfaceCompatibilityRequested();
           break;
+      case EGL_SURFACE_ORIENTATION_ANGLE:
+          if (!display->getExtensions().surfaceOrientation)
+          {
+              SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
+                                   "EGL_SURFACE_ORIENTATION_ANGLE cannot be queried without "
+                                   "EGL_ANGLE_surface_orientation support."));
+              return EGL_FALSE;
+          }
+          *value = eglSurface->getOrientation();
+          break;
       default:
         SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
         return EGL_FALSE;