Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / d3d9 / Renderer9.cpp
index 08e3824..7d6dd7a 100644 (file)
@@ -1,12 +1,14 @@
 #include "precompiled.h"
 //
-// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
 
 // Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer.
 
+#include "common/utilities.h"
+
 #include "libGLESv2/main.h"
 #include "libGLESv2/Buffer.h"
 #include "libGLESv2/Texture.h"
 #include "libGLESv2/renderer/IndexDataManager.h"
 #include "libGLESv2/renderer/d3d9/Renderer9.h"
 #include "libGLESv2/renderer/d3d9/renderer9_utils.h"
+#include "libGLESv2/renderer/d3d9/formatutils9.h"
 #include "libGLESv2/renderer/d3d9/ShaderExecutable9.h"
 #include "libGLESv2/renderer/d3d9/SwapChain9.h"
 #include "libGLESv2/renderer/d3d9/TextureStorage9.h"
 #include "libGLESv2/renderer/d3d9/Image9.h"
-#include "libGLESv2/renderer/d3d9/Blit.h"
+#include "libGLESv2/renderer/d3d9/Blit9.h"
 #include "libGLESv2/renderer/d3d9/RenderTarget9.h"
 #include "libGLESv2/renderer/d3d9/VertexBuffer9.h"
 #include "libGLESv2/renderer/d3d9/IndexBuffer9.h"
 #include "libGLESv2/renderer/d3d9/BufferStorage9.h"
 #include "libGLESv2/renderer/d3d9/Query9.h"
 #include "libGLESv2/renderer/d3d9/Fence9.h"
+#include "libGLESv2/angletypes.h"
 
 #include "libEGL/Display.h"
 
 #include "third_party/trace_event/trace_event.h"
+#include "third_party/systeminfo/SystemInfo.h"
 
 // Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
 #define REF_RAST 0
 #define ANGLE_ENABLE_D3D9EX 1
 #endif // !defined(ANGLE_ENABLE_D3D9EX)
 
+#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
+#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
+#endif
+
+const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z')));
+const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N','U','L','L')));
+
 namespace rx
 {
 static const D3DFORMAT RenderTargetFormats[] =
@@ -80,7 +92,7 @@ enum
     MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4
 };
 
-Renderer9::Renderer9(egl::Display *display, HDC hDc, bool softwareDevice) : Renderer(display), mDc(hDc), mSoftwareDevice(softwareDevice)
+Renderer9::Renderer9(egl::Display *display, HDC hDc) : Renderer(display), mDc(hDc)
 {
     mD3d9Module = NULL;
 
@@ -117,6 +129,10 @@ Renderer9::Renderer9(egl::Display *display, HDC hDc, bool softwareDevice) : Rend
         mNullColorbufferCache[i].height = 0;
         mNullColorbufferCache[i].buffer = NULL;
     }
+
+    mAppliedVertexShader = NULL;
+    mAppliedPixelShader = NULL;
+    mAppliedProgramSerial = 0;
 }
 
 Renderer9::~Renderer9()
@@ -142,22 +158,15 @@ void Renderer9::deinitialize()
     SafeRelease(mD3d9);
     SafeRelease(mD3d9Ex);
 
+    mCompiler.release();
+
     if (mDeviceWindow)
     {
         DestroyWindow(mDeviceWindow);
         mDeviceWindow = NULL;
     }
 
-    if (mD3d9Module)
-    {
-        mD3d9Module = NULL;
-    }
-
-    while (!mMultiSampleSupport.empty())
-    {
-        delete [] mMultiSampleSupport.begin()->second;
-        mMultiSampleSupport.erase(mMultiSampleSupport.begin());
-    }
+    mD3d9Module = NULL;
 }
 
 Renderer9 *Renderer9::makeRenderer9(Renderer *renderer)
@@ -168,21 +177,13 @@ Renderer9 *Renderer9::makeRenderer9(Renderer *renderer)
 
 EGLint Renderer9::initialize()
 {
-    if (!initializeCompiler())
+    if (!mCompiler.initialize())
     {
         return EGL_NOT_INITIALIZED;
     }
 
-    if (mSoftwareDevice)
-    {
-        TRACE_EVENT0("gpu", "GetModuleHandle_swiftshader");
-        mD3d9Module = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
-    }
-    else
-    {
-        TRACE_EVENT0("gpu", "GetModuleHandle_d3d9");
-        mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
-    }
+    TRACE_EVENT0("gpu", "GetModuleHandle_d3d9");
+    mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
 
     if (mD3d9Module == NULL)
     {
@@ -200,7 +201,7 @@ EGLint Renderer9::initialize()
     {
         TRACE_EVENT0("gpu", "D3d9Ex_QueryInterface");
         ASSERT(mD3d9Ex);
-        mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
+        mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast<void**>(&mD3d9));
         ASSERT(mD3d9);
     }
     else
@@ -251,7 +252,7 @@ EGLint Renderer9::initialize()
     }
 
     // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
-    // This is required by Texture2D::convertToRenderTarget.
+    // This is required by Texture2D::ensureRenderTarget.
     if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
     {
         ERR("Renderer does not support stretctrect from textures!\n");
@@ -267,7 +268,7 @@ EGLint Renderer9::initialize()
     mSupportsNonPower2Textures = !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
         !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
         !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) &&
-        !(getComparableOSVersion() < versionWindowsVista && mAdapterIdentifier.VendorId == VENDOR_ID_AMD);
+        !(!isWindowsVistaOrGreater() && mAdapterIdentifier.VendorId == VENDOR_ID_AMD);
 
     // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec
     mSupportsTextureFilterAnisotropy = ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2));
@@ -301,48 +302,17 @@ EGLint Renderer9::initialize()
         mMaxSwapInterval = std::max(mMaxSwapInterval, 4);
     }
 
-    int max = 0;
-    {
-        TRACE_EVENT0("gpu", "getMultiSampleSupport");
-        for (unsigned int i = 0; i < ArraySize(RenderTargetFormats); ++i)
-        {
-            bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
-            getMultiSampleSupport(RenderTargetFormats[i], multisampleArray);
-            mMultiSampleSupport[RenderTargetFormats[i]] = multisampleArray;
-
-            for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
-            {
-                if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
-                {
-                    max = j;
-                }
-            }
-        }
-    }
+    mMaxSupportedSamples = 0;
 
+    const d3d9::D3DFormatSet &d3d9Formats = d3d9::GetAllUsedD3DFormats();
+    for (d3d9::D3DFormatSet::const_iterator i = d3d9Formats.begin(); i != d3d9Formats.end(); ++i)
     {
-        TRACE_EVENT0("gpu", "getMultiSampleSupport2");
-        for (unsigned int i = 0; i < ArraySize(DepthStencilFormats); ++i)
-        {
-            if (DepthStencilFormats[i] == D3DFMT_UNKNOWN)
-                continue;
-
-            bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
-            getMultiSampleSupport(DepthStencilFormats[i], multisampleArray);
-            mMultiSampleSupport[DepthStencilFormats[i]] = multisampleArray;
-
-            for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
-            {
-                if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
-                {
-                    max = j;
-                }
-            }
-        }
+        TRACE_EVENT0("gpu", "getMultiSampleSupport");
+        MultisampleSupportInfo support = getMultiSampleSupport(*i);
+        mMultiSampleSupport[*i] = support;
+        mMaxSupportedSamples = std::max(mMaxSupportedSamples, support.maxSupportedSamples);
     }
 
-    mMaxSupportedSamples = max;
-
     static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
     static const TCHAR className[] = TEXT("STATIC");
 
@@ -378,7 +348,7 @@ EGLint Renderer9::initialize()
     if (mD3d9Ex)
     {
         TRACE_EVENT0("gpu", "mDevice_QueryInterface");
-        result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
+        result = mDevice->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void**)&mDeviceEx);
         ASSERT(SUCCEEDED(result));
     }
 
@@ -394,7 +364,7 @@ EGLint Renderer9::initialize()
         TRACE_EVENT0("gpu", "device_CreateQuery");
         if (SUCCEEDED(mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery)
         {
-            occlusionQuery->Release();
+            SafeRelease(occlusionQuery);
             mOcclusionQuerySupport = true;
         }
         else
@@ -409,7 +379,7 @@ EGLint Renderer9::initialize()
         TRACE_EVENT0("gpu", "device_CreateQuery2");
         if (SUCCEEDED(mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery)
         {
-            eventQuery->Release();
+            SafeRelease(eventQuery);
             mEventQuerySupport = true;
         }
         else
@@ -428,6 +398,10 @@ EGLint Renderer9::initialize()
                             SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
                                                                D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F));
 
+    // Check RGB565 texture support
+    mRGB565TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
+                                                               D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_R5G6B5));
+
     // Check depth texture support
     // we use INTZ for depth textures in Direct3D9
     // we also want NULL texture support to ensure the we can make depth-only FBOs
@@ -483,6 +457,25 @@ EGLint Renderer9::initialize()
         mFloat16TextureSupport = true;
     }
 
+    D3DFORMAT rgTextureFormats[] =
+    {
+        D3DFMT_R16F,
+        D3DFMT_G16R16F,
+        D3DFMT_R32F,
+        D3DFMT_G32R32F,
+    };
+
+    mRGTextureSupport = true;
+    for (unsigned int i = 0; i < ArraySize(rgTextureFormats); i++)
+    {
+        D3DFORMAT fmt = rgTextureFormats[i];
+        mRGTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, fmt)) &&
+                            SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, fmt)) &&
+                            SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, D3DRTYPE_CUBETEXTURE, fmt)) &&
+                            SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_CUBETEXTURE, fmt));
+    }
+
+
     // Check DXT texture support
     mDXT1TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
     mDXT3TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3));
@@ -494,6 +487,8 @@ EGLint Renderer9::initialize()
 
     initializeDevice();
 
+    d3d9::InitializeVertexTranslations(this);
+
     return EGL_SUCCESS;
 }
 
@@ -520,7 +515,7 @@ void Renderer9::initializeDevice()
     mSceneStarted = false;
 
     ASSERT(!mBlit && !mVertexDataManager && !mIndexDataManager);
-    mBlit = new Blit(this);
+    mBlit = new Blit9(this);
     mVertexDataManager = new rx::VertexDataManager(this);
     mIndexDataManager = new rx::IndexDataManager(this);
 }
@@ -585,10 +580,11 @@ int Renderer9::generateConfigs(ConfigDesc **configDescList)
                     if (SUCCEEDED(result))
                     {
                         ConfigDesc newConfig;
-                        newConfig.renderTargetFormat = d3d9_gl::ConvertBackBufferFormat(renderTargetFormat);
-                        newConfig.depthStencilFormat = d3d9_gl::ConvertDepthStencilFormat(depthStencilFormat);
+                        newConfig.renderTargetFormat = d3d9_gl::GetInternalFormat(renderTargetFormat);
+                        newConfig.depthStencilFormat = d3d9_gl::GetInternalFormat(depthStencilFormat);
                         newConfig.multiSample = 0; // FIXME: enumerate multi-sampling
                         newConfig.fastConfig = (currentDisplayMode.Format == renderTargetFormat);
+                        newConfig.es3Capable = false;
 
                         (*configDescList)[numConfigs++] = newConfig;
                     }
@@ -681,6 +677,7 @@ IDirect3DQuery9* Renderer9::allocateEventQuery()
     if (mEventQueryPool.empty())
     {
         HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
+        UNUSED_ASSERTION_VARIABLE(result);
         ASSERT(SUCCEEDED(result));
     }
     else
@@ -696,7 +693,7 @@ void Renderer9::freeEventQuery(IDirect3DQuery9* query)
 {
     if (mEventQueryPool.size() > 1000)
     {
-        query->Release();
+        SafeRelease(query);
     }
     else
     {
@@ -751,6 +748,26 @@ FenceImpl *Renderer9::createFence()
     return new Fence9(this);
 }
 
+bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const
+{
+    // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3.
+    return false;
+}
+
+bool Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget,
+                                        GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea)
+{
+    // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3.
+    UNREACHABLE();
+    return false;
+}
+
+void Renderer9::generateSwizzle(gl::Texture *texture)
+{
+    // Swizzled textures are not available in ES2 or D3D9
+    UNREACHABLE();
+}
+
 void Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState)
 {
     bool *forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates;
@@ -769,7 +786,7 @@ void Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::Sampl
         gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy);
         mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
         mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
-        mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.lodOffset);
+        mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.baseLevel);
         if (mSupportsTextureFilterAnisotropy)
         {
             mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy);
@@ -814,6 +831,12 @@ void Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture
     appliedSerials[index] = serial;
 }
 
+bool Renderer9::setUniformBuffers(const gl::Buffer* /*vertexUniformBuffers*/[], const gl::Buffer* /*fragmentUniformBuffers*/[])
+{
+    // No effect in ES2/D3D9
+    return true;
+}
+
 void Renderer9::setRasterizerState(const gl::RasterizerState &rasterState)
 {
     bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0;
@@ -852,10 +875,11 @@ void Renderer9::setRasterizerState(const gl::RasterizerState &rasterState)
     mForceSetRasterState = false;
 }
 
-void Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::Color &blendColor, unsigned int sampleMask)
+void Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
+                              unsigned int sampleMask)
 {
     bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0;
-    bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::Color)) != 0;
+    bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0;
     bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask;
 
     if (blendStateChanged || blendColorChanged)
@@ -906,6 +930,10 @@ void Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState
             FIXME("Sample alpha to coverage is unimplemented.");
         }
 
+        gl::FramebufferAttachment *attachment = framebuffer->getFirstColorbuffer();
+        GLenum internalFormat = attachment ? attachment->getInternalFormat() : GL_NONE;
+        GLuint clientVersion = getCurrentClientVersion();
+
         // Set the color mask
         bool zeroColorMaskAllowed = getAdapterVendor() != VENDOR_ID_AMD;
         // Apparently some ATI cards have a bug where a draw with a zero color
@@ -914,8 +942,10 @@ void Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState
         // drawing is done.
         // http://code.google.com/p/angleproject/issues/detail?id=169
 
-        DWORD colorMask = gl_d3d9::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen,
-                                                    blendState.colorMaskBlue, blendState.colorMaskAlpha);
+        DWORD colorMask = gl_d3d9::ConvertColorMask(gl::GetRedBits(internalFormat, clientVersion) > 0 && blendState.colorMaskRed,
+                                                    gl::GetGreenBits(internalFormat, clientVersion) > 0 && blendState.colorMaskGreen,
+                                                    gl::GetBlueBits(internalFormat, clientVersion) > 0 && blendState.colorMaskBlue,
+                                                    gl::GetAlphaBits(internalFormat, clientVersion) > 0 && blendState.colorMaskAlpha);
         if (colorMask == 0 && !zeroColorMaskAllowed)
         {
             // Enable green channel, but set blending so nothing will be drawn.
@@ -1195,7 +1225,7 @@ bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count)
 }
 
 
-gl::Renderbuffer *Renderer9::getNullColorbuffer(gl::Renderbuffer *depthbuffer)
+gl::FramebufferAttachment *Renderer9::getNullColorbuffer(gl::FramebufferAttachment *depthbuffer)
 {
     if (!depthbuffer)
     {
@@ -1218,7 +1248,7 @@ gl::Renderbuffer *Renderer9::getNullColorbuffer(gl::Renderbuffer *depthbuffer)
         }
     }
 
-    gl::Renderbuffer *nullbuffer = new gl::Renderbuffer(this, 0, new gl::Colorbuffer(this, width, height, GL_NONE, 0));
+    gl::FramebufferAttachment *nullbuffer = new gl::FramebufferAttachment(this, 0, new gl::Colorbuffer(this, width, height, GL_NONE, 0));
 
     // add nullbuffer to the cache
     NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0];
@@ -1243,7 +1273,7 @@ bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer)
 {
     // if there is no color attachment we must synthesize a NULL colorattachment
     // to keep the D3D runtime happy.  This should only be possible if depth texturing.
-    gl::Renderbuffer *renderbufferObject = NULL;
+    gl::FramebufferAttachment *renderbufferObject = NULL;
     if (framebuffer->getColorbufferType(0) != GL_NONE)
     {
         renderbufferObject = framebuffer->getColorbuffer(0);
@@ -1278,13 +1308,13 @@ bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer)
         }
 
         mDevice->SetRenderTarget(0, renderTargetSurface);
-        renderTargetSurface->Release();
+        SafeRelease(renderTargetSurface);
 
         mAppliedRenderTargetSerial = renderTargetSerial;
         renderTargetChanged = true;
     }
 
-    gl::Renderbuffer *depthStencil = NULL;
+    gl::FramebufferAttachment *depthStencil = NULL;
     unsigned int depthbufferSerial = 0;
     unsigned int stencilbufferSerial = 0;
     if (framebuffer->getDepthbufferType() != GL_NONE)
@@ -1335,7 +1365,7 @@ bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer)
             }
 
             mDevice->SetDepthStencilSurface(depthStencilSurface);
-            depthStencilSurface->Release();
+            SafeRelease(depthStencilSurface);
 
             depthSize = depthStencil->getDepthSize();
             stencilSize = depthStencil->getStencilSize();
@@ -1366,6 +1396,7 @@ bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer)
     {
         mForceSetScissor = true;
         mForceSetViewport = true;
+        mForceSetBlendState = true;
 
         mRenderTargetDesc.width = renderbufferObject->getWidth();
         mRenderTargetDesc.height = renderbufferObject->getHeight();
@@ -1376,15 +1407,16 @@ bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer)
     return true;
 }
 
-GLenum Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances)
+GLenum Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], gl::VertexAttribCurrentValueData currentValues[],
+                                    GLint first, GLsizei count, GLsizei instances)
 {
     TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS];
-    GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, programBinary, first, count, attributes, instances);
+    GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances);
     if (err != GL_NO_ERROR)
     {
         return err;
     }
-    
+
     return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, &mRepeatDraw);
 }
 
@@ -1410,10 +1442,17 @@ GLenum Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArr
     return err;
 }
 
-void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances)
+void Renderer9::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[])
+{
+    UNREACHABLE();
+}
+
+void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive)
 {
+    ASSERT(!transformFeedbackActive);
+
     startScene();
-        
+
     if (mode == GL_LINE_LOOP)
     {
         drawLineLoop(count, GL_NONE, NULL, 0, NULL);
@@ -1448,7 +1487,8 @@ void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances)
     }
 }
 
-void Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/)
+void Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
+                             gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/)
 {
     startScene();
 
@@ -1498,15 +1538,15 @@ void Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices,
             }
         }
 
+        // Checked by Renderer9::applyPrimitiveType
+        ASSERT(count >= 0);
+
         if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int)))
         {
             ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required.");
             return gl::error(GL_OUT_OF_MEMORY);
         }
 
-        // Checked by Renderer9::applyPrimitiveType
-        ASSERT(count >= 0);
-
         const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int);
         if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT))
         {
@@ -1688,34 +1728,50 @@ void Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indi
     }
 }
 
-void Renderer9::applyShaders(gl::ProgramBinary *programBinary)
+void Renderer9::applyShaders(gl::ProgramBinary *programBinary, bool rasterizerDiscard, bool transformFeedbackActive, const gl::VertexFormat inputLayout[])
 {
-    unsigned int programBinarySerial = programBinary->getSerial();
-    if (programBinarySerial != mAppliedProgramBinarySerial)
-    {
-        ShaderExecutable *vertexExe = programBinary->getVertexExecutable();
-        ShaderExecutable *pixelExe = programBinary->getPixelExecutable();
+    ASSERT(!transformFeedbackActive);
+    ASSERT(!rasterizerDiscard);
 
-        IDirect3DVertexShader9 *vertexShader = NULL;
-        if (vertexExe) vertexShader = ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader();
+    ShaderExecutable *vertexExe = programBinary->getVertexExecutableForInputLayout(inputLayout);
+    ShaderExecutable *pixelExe = programBinary->getPixelExecutable();
 
-        IDirect3DPixelShader9 *pixelShader = NULL;
-        if (pixelExe) pixelShader = ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader();
+    IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL);
+    IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL);
 
-        mDevice->SetPixelShader(pixelShader);
+    if (vertexShader != mAppliedVertexShader)
+    {
         mDevice->SetVertexShader(vertexShader);
+        mAppliedVertexShader = vertexShader;
+    }
+
+    if (pixelShader != mAppliedPixelShader)
+    {
+        mDevice->SetPixelShader(pixelShader);
+        mAppliedPixelShader = pixelShader;
+    }
+
+    // D3D9 has a quirk where creating multiple shaders with the same content
+    // can return the same shader pointer. Because GL programs store different data
+    // per-program, checking the program serial guarantees we upload fresh
+    // uniform data even if our shader pointers are the same.
+    // https://code.google.com/p/angleproject/issues/detail?id=661
+    unsigned int programSerial = programBinary->getSerial();
+    if (programSerial != mAppliedProgramSerial)
+    {
         programBinary->dirtyAllUniforms();
         mDxUniformsDirty = true;
-
-        mAppliedProgramBinarySerial = programBinarySerial;
+        mAppliedProgramSerial = programSerial;
     }
 }
 
-void Renderer9::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray)
+void Renderer9::applyUniforms(const gl::ProgramBinary &programBinary)
 {
-    for (std::vector<gl::Uniform*>::const_iterator ub = uniformArray->begin(), ue = uniformArray->end(); ub != ue; ++ub)
+    const std::vector<gl::LinkedUniform*> &uniformArray = programBinary.getUniforms();
+
+    for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
     {
-        gl::Uniform *targetUniform = *ub;
+        gl::LinkedUniform *targetUniform = uniformArray[uniformIndex];
 
         if (targetUniform->dirty)
         {
@@ -1751,8 +1807,6 @@ void Renderer9::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray
               default:
                 UNREACHABLE();
             }
-
-            targetUniform->dirty = false;
         }
     }
 
@@ -1765,20 +1819,20 @@ void Renderer9::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray
     }
 }
 
-void Renderer9::applyUniformnfv(gl::Uniform *targetUniform, const GLfloat *v)
+void Renderer9::applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v)
 {
-    if (targetUniform->psRegisterIndex >= 0)
+    if (targetUniform->isReferencedByFragmentShader())
     {
         mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount);
     }
 
-    if (targetUniform->vsRegisterIndex >= 0)
+    if (targetUniform->isReferencedByVertexShader())
     {
         mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount);
     }
 }
 
-void Renderer9::applyUniformniv(gl::Uniform *targetUniform, const GLint *v)
+void Renderer9::applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v)
 {
     ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
     GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
@@ -1794,7 +1848,7 @@ void Renderer9::applyUniformniv(gl::Uniform *targetUniform, const GLint *v)
     applyUniformnfv(targetUniform, (GLfloat*)vector);
 }
 
-void Renderer9::applyUniformnbv(gl::Uniform *targetUniform, const GLint *v)
+void Renderer9::applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v)
 {
     ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
     GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
@@ -1812,27 +1866,70 @@ void Renderer9::applyUniformnbv(gl::Uniform *targetUniform, const GLint *v)
 
 void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer)
 {
-    D3DCOLOR color = D3DCOLOR_ARGB(gl::unorm<8>(clearParams.colorClearValue.alpha),
-                                   gl::unorm<8>(clearParams.colorClearValue.red),
-                                   gl::unorm<8>(clearParams.colorClearValue.green),
-                                   gl::unorm<8>(clearParams.colorClearValue.blue));
+    if (clearParams.colorClearType != GL_FLOAT)
+    {
+        // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0
+        UNREACHABLE();
+        return;
+    }
+
+    bool clearColor = clearParams.clearColor[0];
+    for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
+    {
+        if (clearParams.clearColor[i] != clearColor)
+        {
+            // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0
+            UNREACHABLE();
+            return;
+        }
+    }
+
     float depth = gl::clamp01(clearParams.depthClearValue);
-    int stencil = clearParams.stencilClearValue & 0x000000FF;
+    DWORD stencil = clearParams.stencilClearValue & 0x000000FF;
 
     unsigned int stencilUnmasked = 0x0;
-    if ((clearParams.mask & GL_STENCIL_BUFFER_BIT) && frameBuffer->hasStencil())
+    if (clearParams.clearStencil && frameBuffer->hasStencil())
     {
-        unsigned int stencilSize = gl::GetStencilSize(frameBuffer->getStencilbuffer()->getActualFormat());
+        unsigned int stencilSize = gl::GetStencilBits(frameBuffer->getStencilbuffer()->getActualFormat(),
+                                                      getCurrentClientVersion());
         stencilUnmasked = (0x1 << stencilSize) - 1;
     }
 
-    bool alphaUnmasked = (gl::GetAlphaSize(mRenderTargetDesc.format) == 0) || clearParams.colorMaskAlpha;
-
-    const bool needMaskedStencilClear = (clearParams.mask & GL_STENCIL_BUFFER_BIT) &&
+    const bool needMaskedStencilClear = clearParams.clearStencil &&
                                         (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
-    const bool needMaskedColorClear = (clearParams.mask & GL_COLOR_BUFFER_BIT) &&
-                                      !(clearParams.colorMaskRed && clearParams.colorMaskGreen &&
-                                        clearParams.colorMaskBlue && alphaUnmasked);
+
+    bool needMaskedColorClear = false;
+    D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0);
+    if (clearColor)
+    {
+        gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer();
+        GLenum internalFormat = attachment->getInternalFormat();
+        GLenum actualFormat = attachment->getActualFormat();
+
+        GLuint clientVersion = getCurrentClientVersion();
+        GLuint internalRedBits = gl::GetRedBits(internalFormat, clientVersion);
+        GLuint internalGreenBits = gl::GetGreenBits(internalFormat, clientVersion);
+        GLuint internalBlueBits = gl::GetBlueBits(internalFormat, clientVersion);
+        GLuint internalAlphaBits = gl::GetAlphaBits(internalFormat, clientVersion);
+
+        GLuint actualRedBits = gl::GetRedBits(actualFormat, clientVersion);
+        GLuint actualGreenBits = gl::GetGreenBits(actualFormat, clientVersion);
+        GLuint actualBlueBits = gl::GetBlueBits(actualFormat, clientVersion);
+        GLuint actualAlphaBits = gl::GetAlphaBits(actualFormat, clientVersion);
+
+        color = D3DCOLOR_ARGB(gl::unorm<8>((internalAlphaBits == 0 && actualAlphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha),
+                              gl::unorm<8>((internalRedBits   == 0 && actualRedBits   > 0) ? 0.0f : clearParams.colorFClearValue.red),
+                              gl::unorm<8>((internalGreenBits == 0 && actualGreenBits > 0) ? 0.0f : clearParams.colorFClearValue.green),
+                              gl::unorm<8>((internalBlueBits  == 0 && actualBlueBits  > 0) ? 0.0f : clearParams.colorFClearValue.blue));
+
+        if ((internalRedBits   > 0 && !clearParams.colorMaskRed) ||
+            (internalGreenBits > 0 && !clearParams.colorMaskGreen) ||
+            (internalBlueBits  > 0 && !clearParams.colorMaskBlue) ||
+            (internalAlphaBits > 0 && !clearParams.colorMaskAlpha))
+        {
+            needMaskedColorClear = true;
+        }
+    }
 
     if (needMaskedColorClear || needMaskedStencilClear)
     {
@@ -1893,7 +1990,7 @@ void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *f
         mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
         mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
 
-        if (clearParams.mask & GL_COLOR_BUFFER_BIT)
+        if (clearColor)
         {
             mDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
                                     gl_d3d9::ConvertColorMask(clearParams.colorMaskRed,
@@ -1906,7 +2003,7 @@ void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *f
             mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
         }
 
-        if (stencilUnmasked != 0x0 && (clearParams.mask & GL_STENCIL_BUFFER_BIT))
+        if (stencilUnmasked != 0x0 && clearParams.clearStencil)
         {
             mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
             mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
@@ -1962,7 +2059,7 @@ void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *f
         startScene();
         mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4]));
 
-        if (clearParams.mask & GL_DEPTH_BUFFER_BIT)
+        if (clearParams.clearDepth)
         {
             mDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
             mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
@@ -1974,18 +2071,18 @@ void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *f
             mMaskedClearSavedState->Apply();
         }
     }
-    else if (clearParams.mask)
+    else if (clearColor || clearParams.clearDepth || clearParams.clearStencil)
     {
         DWORD dxClearFlags = 0;
-        if (clearParams.mask & GL_COLOR_BUFFER_BIT)
+        if (clearColor)
         {
             dxClearFlags |= D3DCLEAR_TARGET;
         }
-        if (clearParams.mask & GL_DEPTH_BUFFER_BIT)
+        if (clearParams.clearDepth)
         {
             dxClearFlags |= D3DCLEAR_ZBUFFER;
         }
-        if (clearParams.mask & GL_STENCIL_BUFFER_BIT)
+        if (clearParams.clearStencil)
         {
             dxClearFlags |= D3DCLEAR_STENCIL;
         }
@@ -2020,7 +2117,9 @@ void Renderer9::markAllStateDirty()
     }
 
     mAppliedIBSerial = 0;
-    mAppliedProgramBinarySerial = 0;
+    mAppliedVertexShader = NULL;
+    mAppliedPixelShader = NULL;
+    mAppliedProgramSerial = 0;
     mDxUniformsDirty = true;
 
     mVertexDeclarationCache.markStateDirty();
@@ -2028,11 +2127,11 @@ void Renderer9::markAllStateDirty()
 
 void Renderer9::releaseDeviceResources()
 {
-    while (!mEventQueryPool.empty())
+    for (size_t i = 0; i < mEventQueryPool.size(); i++)
     {
-        mEventQueryPool.back()->Release();
-        mEventQueryPool.pop_back();
+        SafeRelease(mEventQueryPool[i]);
     }
+    mEventQueryPool.clear();
 
     SafeRelease(mMaskedClearSavedState);
 
@@ -2048,10 +2147,8 @@ void Renderer9::releaseDeviceResources()
     {
         SafeDelete(mNullColorbufferCache[i].buffer);
     }
-
 }
 
-
 void Renderer9::notifyDeviceLost()
 {
     mDeviceLost = true;
@@ -2255,15 +2352,30 @@ GUID Renderer9::getAdapterIdentifier() const
     return mAdapterIdentifier.DeviceIdentifier;
 }
 
-void Renderer9::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
+Renderer9::MultisampleSupportInfo Renderer9::getMultiSampleSupport(D3DFORMAT format)
 {
-    for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
+    MultisampleSupportInfo support = { 0 };
+
+    for (unsigned int multiSampleIndex = 0; multiSampleIndex < ArraySize(support.supportedSamples); multiSampleIndex++)
     {
-        HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
-                                                           TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
+        HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format, TRUE,
+                                                           (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
 
-        multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
+        if (SUCCEEDED(result))
+        {
+             support.supportedSamples[multiSampleIndex] = true;
+             if (multiSampleIndex != D3DMULTISAMPLE_NONMASKABLE)
+             {
+                 support.maxSupportedSamples = std::max(support.maxSupportedSamples, multiSampleIndex);
+             }
+        }
+        else
+        {
+            support.supportedSamples[multiSampleIndex] = false;
+        }
     }
+
+    return support;
 }
 
 bool Renderer9::getBGRATextureSupport() const
@@ -2272,17 +2384,17 @@ bool Renderer9::getBGRATextureSupport() const
     return true;
 }
 
-bool Renderer9::getDXT1TextureSupport()
+bool Renderer9::getDXT1TextureSupport() const
 {
     return mDXT1TextureSupport;
 }
 
-bool Renderer9::getDXT3TextureSupport()
+bool Renderer9::getDXT3TextureSupport() const
 {
     return mDXT3TextureSupport;
 }
 
-bool Renderer9::getDXT5TextureSupport()
+bool Renderer9::getDXT5TextureSupport() const
 {
     return mDXT5TextureSupport;
 }
@@ -2292,35 +2404,67 @@ bool Renderer9::getDepthTextureSupport() const
     return mDepthTextureSupport;
 }
 
-bool Renderer9::getFloat32TextureSupport(bool *filtering, bool *renderable)
+bool Renderer9::getFloat32TextureSupport() const
 {
-    *filtering = mFloat32FilterSupport;
-    *renderable = mFloat32RenderSupport;
     return mFloat32TextureSupport;
 }
 
-bool Renderer9::getFloat16TextureSupport(bool *filtering, bool *renderable)
+bool Renderer9::getFloat32TextureFilteringSupport() const
+{
+    return mFloat32FilterSupport;
+}
+
+bool Renderer9::getFloat32TextureRenderingSupport() const
+{
+    return mFloat32RenderSupport;
+}
+
+bool Renderer9::getFloat16TextureSupport() const
 {
-    *filtering = mFloat16FilterSupport;
-    *renderable = mFloat16RenderSupport;
     return mFloat16TextureSupport;
 }
 
-bool Renderer9::getLuminanceTextureSupport()
+bool Renderer9::getFloat16TextureFilteringSupport() const
+{
+    return mFloat16FilterSupport;
+}
+
+bool Renderer9::getFloat16TextureRenderingSupport() const
+{
+    return mFloat16RenderSupport;
+}
+
+bool Renderer9::getRGB565TextureSupport() const
+{
+    return mRGB565TextureSupport;
+}
+
+bool Renderer9::getLuminanceTextureSupport() const
 {
     return mLuminanceTextureSupport;
 }
 
-bool Renderer9::getLuminanceAlphaTextureSupport()
+bool Renderer9::getLuminanceAlphaTextureSupport() const
 {
     return mLuminanceAlphaTextureSupport;
 }
 
+bool Renderer9::getRGTextureSupport() const
+{
+    return mRGTextureSupport;
+}
+
 bool Renderer9::getTextureFilterAnisotropySupport() const
 {
     return mSupportsTextureFilterAnisotropy;
 }
 
+bool Renderer9::getPBOSupport() const
+{
+    // D3D9 cannot support PBOs
+    return false;
+}
+
 float Renderer9::getTextureMaxAnisotropy() const
 {
     if (mSupportsTextureFilterAnisotropy)
@@ -2330,7 +2474,7 @@ float Renderer9::getTextureMaxAnisotropy() const
     return 1.0f;
 }
 
-bool Renderer9::getEventQuerySupport()
+bool Renderer9::getEventQuerySupport() const
 {
     return mEventQuerySupport;
 }
@@ -2373,6 +2517,46 @@ unsigned int Renderer9::getMaxVaryingVectors() const
     return (getMajorShaderModel() >= 3) ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2;
 }
 
+unsigned int Renderer9::getMaxVertexShaderUniformBuffers() const
+{
+    return 0;
+}
+
+unsigned int Renderer9::getMaxFragmentShaderUniformBuffers() const
+{
+    return 0;
+}
+
+unsigned int Renderer9::getReservedVertexUniformBuffers() const
+{
+    return 0;
+}
+
+unsigned int Renderer9::getReservedFragmentUniformBuffers() const
+{
+    return 0;
+}
+
+unsigned int Renderer9::getMaxTransformFeedbackBuffers() const
+{
+    return 0;
+}
+
+unsigned int Renderer9::getMaxTransformFeedbackSeparateComponents() const
+{
+    return 0;
+}
+
+unsigned int Renderer9::getMaxTransformFeedbackInterleavedComponents() const
+{
+    return 0;
+}
+
+unsigned int Renderer9::getMaxUniformBufferSize() const
+{
+    return 0;
+}
+
 bool Renderer9::getNonPower2TextureSupport() const
 {
     return mSupportsNonPower2Textures;
@@ -2404,6 +2588,20 @@ bool Renderer9::getPostSubBufferSupport() const
     return true;
 }
 
+int Renderer9::getMaxRecommendedElementsIndices() const
+{
+    // ES3 only
+    UNREACHABLE();
+    return 0;
+}
+
+int Renderer9::getMaxRecommendedElementsVertices() const
+{
+    // ES3 only
+    UNREACHABLE();
+    return 0;
+}
+
 int Renderer9::getMajorShaderModel() const
 {
     return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion);
@@ -2418,7 +2616,7 @@ float Renderer9::getMaxPointSize() const
 int Renderer9::getMaxViewportDimension() const
 {
     int maxTextureDimension = std::min(std::min(getMaxTextureWidth(), getMaxTextureHeight()),
-                                       (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE);
+                                       (int)gl::IMPLEMENTATION_MAX_2D_TEXTURE_SIZE);
     return maxTextureDimension;
 }
 
@@ -2432,6 +2630,18 @@ int Renderer9::getMaxTextureHeight() const
     return (int)mDeviceCaps.MaxTextureHeight;
 }
 
+int Renderer9::getMaxTextureDepth() const
+{
+    // 3D textures are not available in the D3D9 backend.
+    return 1;
+}
+
+int Renderer9::getMaxTextureArrayLayers() const
+{
+    // 2D array textures are not available in the D3D9 backend.
+    return 1;
+}
+
 bool Renderer9::get32BitIndexSupport() const
 {
     return mDeviceCaps.MaxVertexIndex >= (1 << 16);
@@ -2457,6 +2667,53 @@ int Renderer9::getMaxSupportedSamples() const
     return mMaxSupportedSamples;
 }
 
+GLsizei Renderer9::getMaxSupportedFormatSamples(GLenum internalFormat) const
+{
+    D3DFORMAT format = gl_d3d9::GetTextureFormat(internalFormat, this);
+    MultisampleSupportMap::const_iterator itr = mMultiSampleSupport.find(format);
+    return (itr != mMultiSampleSupport.end()) ? mMaxSupportedSamples : 0;
+}
+
+GLsizei Renderer9::getNumSampleCounts(GLenum internalFormat) const
+{
+    D3DFORMAT format = gl_d3d9::GetTextureFormat(internalFormat, this);
+    MultisampleSupportMap::const_iterator iter = mMultiSampleSupport.find(format);
+
+    unsigned int numCounts = 0;
+    if (iter != mMultiSampleSupport.end())
+    {
+        const MultisampleSupportInfo& info = iter->second;
+        for (int i = 0; i < D3DMULTISAMPLE_16_SAMPLES; i++)
+        {
+            if (i != D3DMULTISAMPLE_NONMASKABLE && info.supportedSamples[i])
+            {
+                numCounts++;
+            }
+        }
+    }
+
+    return numCounts;
+}
+
+void Renderer9::getSampleCounts(GLenum internalFormat, GLsizei bufSize, GLint *params) const
+{
+    D3DFORMAT format = gl_d3d9::GetTextureFormat(internalFormat, this);
+    MultisampleSupportMap::const_iterator iter = mMultiSampleSupport.find(format);
+
+    if (iter != mMultiSampleSupport.end())
+    {
+        const MultisampleSupportInfo& info = iter->second;
+        int bufPos = 0;
+        for (int i = D3DMULTISAMPLE_16_SAMPLES; i >= 0 && bufPos < bufSize; i--)
+        {
+            if (i != D3DMULTISAMPLE_NONMASKABLE && info.supportedSamples[i])
+            {
+                params[bufPos++] = i;
+            }
+        }
+    }
+}
+
 int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const
 {
     if (requested == 0)
@@ -2464,7 +2721,7 @@ int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const
         return requested;
     }
 
-    std::map<D3DFORMAT, bool *>::const_iterator itr = mMultiSampleSupport.find(format);
+    MultisampleSupportMap::const_iterator itr = mMultiSampleSupport.find(format);
     if (itr == mMultiSampleSupport.end())
     {
         if (format == D3DFMT_UNKNOWN)
@@ -2472,9 +2729,9 @@ int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const
         return -1;
     }
 
-    for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i)
+    for (unsigned int i = requested; i < ArraySize(itr->second.supportedSamples); ++i)
     {
-        if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE)
+        if (itr->second.supportedSamples[i] && i != D3DMULTISAMPLE_NONMASKABLE)
         {
             return i;
         }
@@ -2489,7 +2746,7 @@ unsigned int Renderer9::getMaxRenderTargets() const
     return 1;
 }
 
-D3DFORMAT Renderer9::ConvertTextureInternalFormat(GLint internalformat)
+D3DFORMAT Renderer9::ConvertTextureInternalFormat(GLenum internalformat)
 {
     switch (internalformat)
     {
@@ -2545,19 +2802,21 @@ bool Renderer9::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStora
         TextureStorage9_2D *source9 = TextureStorage9_2D::makeTextureStorage9_2D(source->getStorageInstance());
         TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(dest->getStorageInstance());
 
-        int levels = source9->levelCount();
+        int levels = source9->getLevelCount();
         for (int i = 0; i < levels; ++i)
         {
             IDirect3DSurface9 *srcSurf = source9->getSurfaceLevel(i, false);
             IDirect3DSurface9 *dstSurf = dest9->getSurfaceLevel(i, false);
-            
+
             result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged());
 
-            if (srcSurf) srcSurf->Release();
-            if (dstSurf) dstSurf->Release();
+            SafeRelease(srcSurf);
+            SafeRelease(dstSurf);
 
             if (!result)
+            {
                 return false;
+            }
         }
     }
 
@@ -2572,7 +2831,7 @@ bool Renderer9::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureSto
     {
         TextureStorage9_Cube *source9 = TextureStorage9_Cube::makeTextureStorage9_Cube(source->getStorageInstance());
         TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(dest->getStorageInstance());
-        int levels = source9->levelCount();
+        int levels = source9->getLevelCount();
         for (int f = 0; f < 6; f++)
         {
             for (int i = 0; i < levels; i++)
@@ -2582,11 +2841,13 @@ bool Renderer9::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureSto
 
                 result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged());
 
-                if (srcSurf) srcSurf->Release();
-                if (dstSurf) dstSurf->Release();
+                SafeRelease(srcSurf);
+                SafeRelease(dstSurf);
 
                 if (!result)
+                {
                     return false;
+                }
             }
         }
     }
@@ -2594,6 +2855,20 @@ bool Renderer9::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureSto
     return result;
 }
 
+bool Renderer9::copyToRenderTarget(TextureStorageInterface3D *dest, TextureStorageInterface3D *source)
+{
+    // 3D textures are not available in the D3D9 backend.
+    UNREACHABLE();
+    return false;
+}
+
+bool Renderer9::copyToRenderTarget(TextureStorageInterface2DArray *dest, TextureStorageInterface2DArray *source)
+{
+    // 2D array textures are not supported by the D3D9 backend.
+    UNREACHABLE();
+    return false;
+}
+
 D3DPOOL Renderer9::getBufferPool(DWORD usage) const
 {
     if (mD3d9Ex != NULL)
@@ -2635,15 +2910,33 @@ bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sou
     return mBlit->copy(framebuffer, rect, destFormat, xoffset, yoffset, storage, target, level);
 }
 
+bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+                          GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface3D *storage, GLint level)
+{
+    // 3D textures are not available in the D3D9 backend.
+    UNREACHABLE();
+    return false;
+}
+
+bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+                          GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level)
+{
+    // 2D array textures are not available in the D3D9 backend.
+    UNREACHABLE();
+    return false;
+}
+
 bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &readRect, gl::Framebuffer *drawFramebuffer, const gl::Rectangle &drawRect,
-                         bool blitRenderTarget, bool blitDepthStencil)
+                         const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter)
 {
+    ASSERT(filter == GL_NEAREST);
+
     endScene();
 
     if (blitRenderTarget)
     {
-        gl::Renderbuffer *readBuffer = readFramebuffer->getColorbuffer(0);
-        gl::Renderbuffer *drawBuffer = drawFramebuffer->getColorbuffer(0);
+        gl::FramebufferAttachment *readBuffer = readFramebuffer->getColorbuffer(0);
+        gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getColorbuffer(0);
         RenderTarget9 *readRenderTarget = NULL;
         RenderTarget9 *drawRenderTarget = NULL;
         IDirect3DSurface9* readSurface = NULL;
@@ -2673,6 +2966,9 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &
             return gl::error(GL_OUT_OF_MEMORY, false);
         }
 
+        gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1);
+        gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1);
+
         RECT srcRect;
         srcRect.left = readRect.x;
         srcRect.right = readRect.x + readRect.width;
@@ -2685,10 +2981,79 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &
         dstRect.top = drawRect.y;
         dstRect.bottom = drawRect.y + drawRect.height;
 
+        // Clip the rectangles to the scissor rectangle
+        if (scissor)
+        {
+            if (dstRect.left < scissor->x)
+            {
+                srcRect.left += (scissor->x - dstRect.left);
+                dstRect.left = scissor->x;
+            }
+            if (dstRect.top < scissor->y)
+            {
+                srcRect.top += (scissor->y - dstRect.top);
+                dstRect.top = scissor->y;
+            }
+            if (dstRect.right > scissor->x + scissor->width)
+            {
+                srcRect.right -= (dstRect.right - (scissor->x + scissor->width));
+                dstRect.right = scissor->x + scissor->width;
+            }
+            if (dstRect.bottom > scissor->y + scissor->height)
+            {
+                srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height));
+                dstRect.bottom = scissor->y + scissor->height;
+            }
+        }
+
+        // Clip the rectangles to the destination size
+        if (dstRect.left < 0)
+        {
+            srcRect.left += -dstRect.left;
+            dstRect.left = 0;
+        }
+        if (dstRect.right > dstSize.width)
+        {
+            srcRect.right -= (dstRect.right - dstSize.width);
+            dstRect.right = dstSize.width;
+        }
+        if (dstRect.top < 0)
+        {
+            srcRect.top += -dstRect.top;
+            dstRect.top = 0;
+        }
+        if (dstRect.bottom > dstSize.height)
+        {
+            srcRect.bottom -= (dstRect.bottom - dstSize.height);
+            dstRect.bottom = dstSize.height;
+        }
+
+        // Clip the rectangles to the source size
+        if (srcRect.left < 0)
+        {
+            dstRect.left += -srcRect.left;
+            srcRect.left = 0;
+        }
+        if (srcRect.right > srcSize.width)
+        {
+            dstRect.right -= (srcRect.right - srcSize.width);
+            srcRect.right = srcSize.width;
+        }
+        if (srcRect.top < 0)
+        {
+            dstRect.top += -srcRect.top;
+            srcRect.top = 0;
+        }
+        if (srcRect.bottom > srcSize.height)
+        {
+            dstRect.bottom -= (srcRect.bottom - srcSize.height);
+            srcRect.bottom = srcSize.height;
+        }
+
         HRESULT result = mDevice->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE);
 
-        readSurface->Release();
-        drawSurface->Release();
+        SafeRelease(readSurface);
+        SafeRelease(drawSurface);
 
         if (FAILED(result))
         {
@@ -2697,10 +3062,10 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &
         }
     }
 
-    if (blitDepthStencil)
+    if (blitDepth || blitStencil)
     {
-        gl::Renderbuffer *readBuffer = readFramebuffer->getDepthOrStencilbuffer();
-        gl::Renderbuffer *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer();
+        gl::FramebufferAttachment *readBuffer = readFramebuffer->getDepthOrStencilbuffer();
+        gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer();
         RenderTarget9 *readDepthStencil = NULL;
         RenderTarget9 *drawDepthStencil = NULL;
         IDirect3DSurface9* readSurface = NULL;
@@ -2732,8 +3097,8 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &
 
         HRESULT result = mDevice->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE);
 
-        readSurface->Release();
-        drawSurface->Release();
+        SafeRelease(readSurface);
+        SafeRelease(drawSurface);
 
         if (FAILED(result))
         {
@@ -2745,18 +3110,20 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &
     return true;
 }
 
-void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, 
-                           GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels)
+void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+                           GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, void* pixels)
 {
+    ASSERT(pack.pixelBuffer.get() == NULL);
+
     RenderTarget9 *renderTarget = NULL;
     IDirect3DSurface9 *surface = NULL;
-    gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0);
+    gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
 
     if (colorbuffer)
     {
         renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget());
     }
-    
+
     if (renderTarget)
     {
         surface = renderTarget->getSurface();
@@ -2774,13 +3141,13 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz
     if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
     {
         UNIMPLEMENTED();   // FIXME: Requires resolve using StretchRect into non-multisampled render target
-        surface->Release();
+        SafeRelease(surface);
         return gl::error(GL_OUT_OF_MEMORY);
     }
 
     HRESULT result;
     IDirect3DSurface9 *systemSurface = NULL;
-    bool directToPixels = !packReverseRowOrder && packAlignment <= 4 && getShareHandleSupport() &&
+    bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && getShareHandleSupport() &&
                           x == 0 && y == 0 && UINT(width) == desc.Width && UINT(height) == desc.Height &&
                           desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
     if (directToPixels)
@@ -2802,18 +3169,17 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz
         if (FAILED(result))
         {
             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-            surface->Release();
+            SafeRelease(surface);
             return gl::error(GL_OUT_OF_MEMORY);
         }
     }
 
     result = mDevice->GetRenderTargetData(surface, systemSurface);
-    surface->Release();
-    surface = NULL;
+    SafeRelease(surface);
 
     if (FAILED(result))
     {
-        systemSurface->Release();
+        SafeRelease(systemSurface);
 
         // It turns out that D3D will sometimes produce more error
         // codes than those documented.
@@ -2832,7 +3198,7 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz
 
     if (directToPixels)
     {
-        systemSurface->Release();
+        SafeRelease(systemSurface);
         return;
     }
 
@@ -2848,17 +3214,14 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz
     if (FAILED(result))
     {
         UNREACHABLE();
-        systemSurface->Release();
+        SafeRelease(systemSurface);
 
         return;   // No sensible error to generate
     }
 
-    unsigned char *dest = (unsigned char*)pixels;
-    unsigned short *dest16 = (unsigned short*)pixels;
-
     unsigned char *source;
     int inputPitch;
-    if (packReverseRowOrder)
+    if (pack.reverseRowOrder)
     {
         source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1);
         inputPitch = -lock.Pitch;
@@ -2869,231 +3232,69 @@ void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsiz
         inputPitch = lock.Pitch;
     }
 
-    unsigned int fastPixelSize = 0;
+    GLuint clientVersion = getCurrentClientVersion();
 
-    if (desc.Format == D3DFMT_A8R8G8B8 &&
-        format == GL_BGRA_EXT &&
-        type == GL_UNSIGNED_BYTE)
-    {
-        fastPixelSize = 4;
-    }
-    else if ((desc.Format == D3DFMT_A4R4G4B4 &&
-             format == GL_BGRA_EXT &&
-             type == GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT) ||
-             (desc.Format == D3DFMT_A1R5G5B5 &&
-             format == GL_BGRA_EXT &&
-             type == GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT))
-    {
-        fastPixelSize = 2;
-    }
-    else if (desc.Format == D3DFMT_A16B16G16R16F &&
-             format == GL_RGBA &&
-             type == GL_HALF_FLOAT_OES)
-    {
-        fastPixelSize = 8;
-    }
-    else if (desc.Format == D3DFMT_A32B32G32R32F &&
-             format == GL_RGBA &&
-             type == GL_FLOAT)
-    {
-        fastPixelSize = 16;
-    }
+    GLenum sourceInternalFormat = d3d9_gl::GetInternalFormat(desc.Format);
+    GLenum sourceFormat = gl::GetFormat(sourceInternalFormat, clientVersion);
+    GLenum sourceType = gl::GetType(sourceInternalFormat, clientVersion);
+
+    GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat, clientVersion);
 
-    for (int j = 0; j < rect.bottom - rect.top; j++)
+    if (sourceFormat == format && sourceType == type)
     {
-        if (fastPixelSize != 0)
+        // Direct copy possible
+        unsigned char *dest = static_cast<unsigned char*>(pixels);
+        for (int y = 0; y < rect.bottom - rect.top; y++)
         {
-            // Fast path for formats which require no translation:
-            // D3DFMT_A8R8G8B8 to BGRA/UNSIGNED_BYTE
-            // D3DFMT_A4R4G4B4 to BGRA/UNSIGNED_SHORT_4_4_4_4_REV_EXT
-            // D3DFMT_A1R5G5B5 to BGRA/UNSIGNED_SHORT_1_5_5_5_REV_EXT
-            // D3DFMT_A16B16G16R16F to RGBA/HALF_FLOAT_OES
-            // D3DFMT_A32B32G32R32F to RGBA/FLOAT
-            // 
-            // Note that buffers with no alpha go through the slow path below.
-            memcpy(dest + j * outputPitch,
-                   source + j * inputPitch,
-                   (rect.right - rect.left) * fastPixelSize);
-            continue;
-        }
-        else if (desc.Format == D3DFMT_A8R8G8B8 &&
-                 format == GL_RGBA &&
-                 type == GL_UNSIGNED_BYTE)
-        {
-            // Fast path for swapping red with blue
-            for (int i = 0; i < rect.right - rect.left; i++)
-            {
-                unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
-                *(unsigned int*)(dest + 4 * i + j * outputPitch) =
-                    (argb & 0xFF00FF00) |       // Keep alpha and green
-                    (argb & 0x00FF0000) >> 16 | // Move red to blue
-                    (argb & 0x000000FF) << 16;  // Move blue to red
-            }
-            continue;
+            memcpy(dest + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourcePixelSize);
         }
+    }
+    else
+    {
+        GLenum destInternalFormat = gl::GetSizedInternalFormat(format, type, clientVersion);
+        GLuint destPixelSize = gl::GetPixelBytes(destInternalFormat, clientVersion);
+        GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat, clientVersion);
 
-        for (int i = 0; i < rect.right - rect.left; i++)
+        ColorCopyFunction fastCopyFunc = d3d9::GetFastCopyFunction(desc.Format, format, type, getCurrentClientVersion());
+        if (fastCopyFunc)
         {
-            float r;
-            float g;
-            float b;
-            float a;
-
-            switch (desc.Format)
+            // Fast copy is possible through some special function
+            for (int y = 0; y < rect.bottom - rect.top; y++)
             {
-              case D3DFMT_R5G6B5:
-                {
-                    unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch);
-
-                    a = 1.0f;
-                    b = (rgb & 0x001F) * (1.0f / 0x001F);
-                    g = (rgb & 0x07E0) * (1.0f / 0x07E0);
-                    r = (rgb & 0xF800) * (1.0f / 0xF800);
-                }
-                break;
-              case D3DFMT_A1R5G5B5:
-                {
-                    unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch);
-
-                    a = (argb & 0x8000) ? 1.0f : 0.0f;
-                    b = (argb & 0x001F) * (1.0f / 0x001F);
-                    g = (argb & 0x03E0) * (1.0f / 0x03E0);
-                    r = (argb & 0x7C00) * (1.0f / 0x7C00);
-                }
-                break;
-              case D3DFMT_A8R8G8B8:
-                {
-                    unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
-
-                    a = (argb & 0xFF000000) * (1.0f / 0xFF000000);
-                    b = (argb & 0x000000FF) * (1.0f / 0x000000FF);
-                    g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00);
-                    r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000);
-                }
-                break;
-              case D3DFMT_X8R8G8B8:
+                for (int x = 0; x < rect.right - rect.left; x++)
                 {
-                    unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch);
+                    void *dest = static_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize;
+                    void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize;
 
-                    a = 1.0f;
-                    b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF);
-                    g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00);
-                    r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000);
-                }
-                break;
-              case D3DFMT_A2R10G10B10:
-                {
-                    unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
-
-                    a = (argb & 0xC0000000) * (1.0f / 0xC0000000);
-                    b = (argb & 0x000003FF) * (1.0f / 0x000003FF);
-                    g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00);
-                    r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000);
-                }
-                break;
-              case D3DFMT_A32B32G32R32F:
-                {
-                    // float formats in D3D are stored rgba, rather than the other way round
-                    r = *((float*)(source + 16 * i + j * inputPitch) + 0);
-                    g = *((float*)(source + 16 * i + j * inputPitch) + 1);
-                    b = *((float*)(source + 16 * i + j * inputPitch) + 2);
-                    a = *((float*)(source + 16 * i + j * inputPitch) + 3);
-                }
-                break;
-              case D3DFMT_A16B16G16R16F:
-                {
-                    // float formats in D3D are stored rgba, rather than the other way round
-                    r = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 0));
-                    g = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 1));
-                    b = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 2));
-                    a = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 3));
+                    fastCopyFunc(src, dest);
                 }
-                break;
-              default:
-                UNIMPLEMENTED();   // FIXME
-                UNREACHABLE();
-                return;
             }
+        }
+        else
+        {
+            ColorReadFunction readFunc = d3d9::GetColorReadFunction(desc.Format);
+            ColorWriteFunction writeFunc = gl::GetColorWriteFunction(format, type, clientVersion);
+
+            gl::ColorF temp;
 
-            switch (format)
+            for (int y = 0; y < rect.bottom - rect.top; y++)
             {
-              case GL_RGBA:
-                switch (type)
-                {
-                  case GL_UNSIGNED_BYTE:
-                    dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f);
-                    dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);
-                    dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f);
-                    dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f);
-                    break;
-                  default: UNREACHABLE();
-                }
-                break;
-              case GL_BGRA_EXT:
-                switch (type)
-                {
-                  case GL_UNSIGNED_BYTE:
-                    dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * b + 0.5f);
-                    dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);
-                    dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * r + 0.5f);
-                    dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f);
-                    break;
-                  case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
-                    // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
-                    // this type is packed as follows:
-                    //   15   14   13   12   11   10    9    8    7    6    5    4    3    2    1    0
-                    //  --------------------------------------------------------------------------------
-                    // |       4th         |        3rd         |        2nd        |   1st component   |
-                    //  --------------------------------------------------------------------------------
-                    // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
-                    dest16[i + j * outputPitch / sizeof(unsigned short)] =
-                        ((unsigned short)(15 * a + 0.5f) << 12)|
-                        ((unsigned short)(15 * r + 0.5f) << 8) |
-                        ((unsigned short)(15 * g + 0.5f) << 4) |
-                        ((unsigned short)(15 * b + 0.5f) << 0);
-                    break;
-                  case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
-                    // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
-                    // this type is packed as follows:
-                    //   15   14   13   12   11   10    9    8    7    6    5    4    3    2    1    0
-                    //  --------------------------------------------------------------------------------
-                    // | 4th |          3rd           |           2nd          |      1st component     |
-                    //  --------------------------------------------------------------------------------
-                    // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
-                    dest16[i + j * outputPitch / sizeof(unsigned short)] =
-                        ((unsigned short)(     a + 0.5f) << 15) |
-                        ((unsigned short)(31 * r + 0.5f) << 10) |
-                        ((unsigned short)(31 * g + 0.5f) << 5) |
-                        ((unsigned short)(31 * b + 0.5f) << 0);
-                    break;
-                  default: UNREACHABLE();
-                }
-                break;
-              case GL_RGB:
-                switch (type)
+                for (int x = 0; x < rect.right - rect.left; x++)
                 {
-                  case GL_UNSIGNED_SHORT_5_6_5:
-                    dest16[i + j * outputPitch / sizeof(unsigned short)] = 
-                        ((unsigned short)(31 * b + 0.5f) << 0) |
-                        ((unsigned short)(63 * g + 0.5f) << 5) |
-                        ((unsigned short)(31 * r + 0.5f) << 11);
-                    break;
-                  case GL_UNSIGNED_BYTE:
-                    dest[3 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f);
-                    dest[3 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);
-                    dest[3 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f);
-                    break;
-                  default: UNREACHABLE();
+                    void *dest = reinterpret_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize;
+                    void *src = source + y * inputPitch + x * sourcePixelSize;
+
+                    // readFunc and writeFunc will be using the same type of color, CopyTexImage
+                    // will not allow the copy otherwise.
+                    readFunc(src, &temp);
+                    writeFunc(&temp, dest);
                 }
-                break;
-              default: UNREACHABLE();
             }
         }
     }
 
     systemSurface->UnlockRect();
-
-    systemSurface->Release();
+    SafeRelease(systemSurface);
 }
 
 RenderTarget *Renderer9::createRenderTarget(SwapChain *swapChain, bool depth)
@@ -3114,14 +3315,19 @@ RenderTarget *Renderer9::createRenderTarget(SwapChain *swapChain, bool depth)
     return renderTarget;
 }
 
-RenderTarget *Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth)
+RenderTarget *Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples)
 {
     RenderTarget9 *renderTarget = new RenderTarget9(this, width, height, format, samples);
     return renderTarget;
 }
 
-ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type)
+ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type,
+                                            const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                            bool separatedOutputBuffers)
 {
+    // Transform feedback is not supported in ES2 or D3D9
+    ASSERT(transformFeedbackVaryings.size() == 0);
+
     ShaderExecutable9 *executable = NULL;
 
     switch (type)
@@ -3152,8 +3358,13 @@ ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length,
     return executable;
 }
 
-ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround)
+ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type,
+                                                 const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                                 bool separatedOutputBuffers, D3DWorkaroundType workaround)
 {
+    // Transform feedback is not supported in ES2 or D3D9
+    ASSERT(transformFeedbackVaryings.size() == 0);
+
     const char *profile = NULL;
 
     switch (type)
@@ -3169,28 +3380,67 @@ ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const cha
         return NULL;
     }
 
-    UINT optimizationFlags = ANGLE_COMPILE_OPTIMIZATION_LEVEL;
+    UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL;
 
     if (workaround == ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION)
     {
-        optimizationFlags = D3DCOMPILE_SKIP_OPTIMIZATION;
+        flags = D3DCOMPILE_SKIP_OPTIMIZATION;
     }
     else if (workaround == ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION)
     {
-        optimizationFlags = D3DCOMPILE_OPTIMIZATION_LEVEL3;
+        flags = D3DCOMPILE_OPTIMIZATION_LEVEL3;
     }
     else ASSERT(workaround == ANGLE_D3D_WORKAROUND_NONE);
 
-    ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, optimizationFlags, true);
+    if (gl::perfActive())
+    {
+#ifndef NDEBUG
+        flags = D3DCOMPILE_SKIP_OPTIMIZATION;
+#endif
+
+        flags |= D3DCOMPILE_DEBUG;
+
+        std::string sourcePath = getTempPath();
+        std::string sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(shaderHLSL);
+        writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
+    }
+
+    // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options.
+    // Try the default flags first and if compilation fails, try some alternatives.
+    const UINT extraFlags[] =
+    {
+        flags,
+        flags | D3DCOMPILE_AVOID_FLOW_CONTROL,
+        flags | D3DCOMPILE_PREFER_FLOW_CONTROL
+    };
+
+    const static char *extraFlagNames[] =
+    {
+        "default",
+        "avoid flow control",
+        "prefer flow control"
+    };
+
+    int attempts = ArraySize(extraFlags);
+
+    ID3DBlob *binary = (ID3DBlob*)mCompiler.compileToBinary(infoLog, shaderHLSL, profile, extraFlags, extraFlagNames, attempts);
     if (!binary)
+    {
         return NULL;
+    }
 
-    ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type);
-    binary->Release();
+    ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
+                                                  transformFeedbackVaryings, separatedOutputBuffers);
+    SafeRelease(binary);
 
     return executable;
 }
 
+rx::UniformStorage *Renderer9::createUniformStorage(size_t storageSize)
+{
+    return new UniformStorage(storageSize);
+}
+
 bool Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
 {
     return mBlit->boxFilter(source, dest);
@@ -3231,7 +3481,7 @@ bool Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *s
             {
                 Image9::copyLockableSurfaces(surf, source);
                 result = mDevice->UpdateSurface(surf, NULL, dest, NULL);
-                surf->Release();
+                SafeRelease(surf);
             }
         }
         else
@@ -3268,14 +3518,30 @@ TextureStorage *Renderer9::createTextureStorage2D(SwapChain *swapChain)
     return new TextureStorage9_2D(this, swapChain9);
 }
 
-TextureStorage *Renderer9::createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
+TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels)
+{
+    return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels);
+}
+
+TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels)
+{
+    return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels);
+}
+
+TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels)
 {
-    return new TextureStorage9_2D(this, levels, internalformat, usage, forceRenderable, width, height);
+    // 3D textures are not supported by the D3D9 backend.
+    UNREACHABLE();
+
+    return NULL;
 }
 
-TextureStorage *Renderer9::createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
+TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels)
 {
-    return new TextureStorage9_Cube(this, levels, internalformat, usage, forceRenderable, size);
+    // 2D array textures are not supported by the D3D9 backend.
+    UNREACHABLE();
+
+    return NULL;
 }
 
 bool Renderer9::getLUID(LUID *adapterLuid) const
@@ -3292,4 +3558,20 @@ bool Renderer9::getLUID(LUID *adapterLuid) const
     return false;
 }
 
+GLenum Renderer9::getNativeTextureFormat(GLenum internalFormat) const
+{
+    return d3d9_gl::GetInternalFormat(gl_d3d9::GetTextureFormat(internalFormat, this));
+}
+
+rx::VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const
+{
+    return d3d9::GetVertexConversionType(vertexFormat);
+}
+
+GLenum Renderer9::getVertexComponentType(const gl::VertexFormat &vertexFormat) const
+{
+    D3DDECLTYPE declType = d3d9::GetNativeVertexFormat(vertexFormat);
+    return d3d9::GetDeclTypeComponentType(declType);
+}
+
 }