Move Context draw call logic into RendererD3D.

Also move a lot of supporting code.

BUG=angle:789

Change-Id: I098bf7d072ece1f414605783c32ec5354ba63e19
Reviewed-on: https://chromium-review.googlesource.com/226061
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index 558d3ce..8ada58c 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -35,7 +35,6 @@
 #include <iterator>
 
 // TODO(jmadill): phase these out
-#include "libGLESv2/renderer/d3d/IndexDataManager.h"
 #include "libGLESv2/renderer/d3d/RendererD3D.h"
 
 namespace gl
@@ -1301,324 +1300,6 @@
     return false;
 }
 
-// Applies the render target surface, depth stencil surface, viewport rectangle and
-// scissor rectangle to the renderer
-Error Context::applyRenderTarget(GLenum drawMode, bool ignoreViewport)
-{
-    Framebuffer *framebufferObject = mState.getDrawFramebuffer();
-    ASSERT(framebufferObject && framebufferObject->completeness(getData()) == GL_FRAMEBUFFER_COMPLETE);
-
-    //TODO(jmadill): MANGLE refactor
-    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
-
-    gl::Error error = rendererD3D->applyRenderTarget(framebufferObject);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    float nearZ, farZ;
-    mState.getDepthRange(&nearZ, &farZ);
-    rendererD3D->setViewport(mState.getViewport(), nearZ, farZ, drawMode,
-                             mState.getRasterizerState().frontFace, ignoreViewport);
-
-    rendererD3D->setScissorRectangle(mState.getScissor(), mState.isScissorTestEnabled());
-
-    return gl::Error(GL_NO_ERROR);
-}
-
-// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device
-Error Context::applyState(GLenum drawMode)
-{
-    Framebuffer *framebufferObject = mState.getDrawFramebuffer();
-    int samples = framebufferObject->getSamples(getData());
-
-    RasterizerState rasterizer = mState.getRasterizerState();
-    rasterizer.pointDrawMode = (drawMode == GL_POINTS);
-    rasterizer.multiSample = (samples != 0);
-
-    //TODO(jmadill): MANGLE refactor
-    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
-
-    Error error = rendererD3D->setRasterizerState(rasterizer);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    unsigned int mask = 0;
-    if (mState.isSampleCoverageEnabled())
-    {
-        GLclampf coverageValue;
-        bool coverageInvert = false;
-        mState.getSampleCoverageParams(&coverageValue, &coverageInvert);
-        if (coverageValue != 0)
-        {
-            float threshold = 0.5f;
-
-            for (int i = 0; i < samples; ++i)
-            {
-                mask <<= 1;
-
-                if ((i + 1) * coverageValue >= threshold)
-                {
-                    threshold += 1.0f;
-                    mask |= 1;
-                }
-            }
-        }
-
-        if (coverageInvert)
-        {
-            mask = ~mask;
-        }
-    }
-    else
-    {
-        mask = 0xFFFFFFFF;
-    }
-    error = rendererD3D->setBlendState(framebufferObject, mState.getBlendState(), mState.getBlendColor(), mask);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = rendererD3D->setDepthStencilState(mState.getDepthStencilState(), mState.getStencilRef(),
-                                              mState.getStencilBackRef(), rasterizer.frontFace == GL_CCW);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    return Error(GL_NO_ERROR);
-}
-
-// Applies the shaders and shader constants to the Direct3D 9 device
-Error Context::applyShaders(ProgramBinary *programBinary, bool transformFeedbackActive)
-{
-    VertexFormat inputLayout[MAX_VERTEX_ATTRIBS];
-    VertexFormat::GetInputLayout(inputLayout, programBinary, mState);
-
-    const Framebuffer *fbo = mState.getDrawFramebuffer();
-
-    //TODO(jmadill): MANGLE refactor
-    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
-
-    Error error = rendererD3D->applyShaders(programBinary, inputLayout, fbo,
-                                            mState.getRasterizerState().rasterizerDiscard,
-                                            transformFeedbackActive);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    return programBinary->applyUniforms();
-}
-
-Error Context::generateSwizzles(ProgramBinary *programBinary, SamplerType type)
-{
-    size_t samplerRange = programBinary->getUsedSamplerRange(type);
-
-    for (size_t i = 0; i < samplerRange; i++)
-    {
-        GLenum textureType = programBinary->getSamplerTextureType(type, i);
-        GLint textureUnit = programBinary->getSamplerMapping(type, i, getCaps());
-        if (textureUnit != -1)
-        {
-            Texture *texture = getSamplerTexture(textureUnit, textureType);
-            ASSERT(texture);
-            if (texture->getSamplerState().swizzleRequired())
-            {
-                //TODO(jmadill): MANGLE refactor
-                rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
-
-                Error error = rendererD3D->generateSwizzle(texture);
-                if (error.isError())
-                {
-                    return error;
-                }
-            }
-        }
-    }
-
-    return Error(GL_NO_ERROR);
-}
-
-Error Context::generateSwizzles(ProgramBinary *programBinary)
-{
-    Error error = generateSwizzles(programBinary, SAMPLER_VERTEX);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = generateSwizzles(programBinary, SAMPLER_PIXEL);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    return Error(GL_NO_ERROR);
-}
-
-// For each Direct3D sampler of either the pixel or vertex stage,
-// looks up the corresponding OpenGL texture image unit and texture type,
-// and sets the texture and its addressing/filtering state (or NULL when inactive).
-Error Context::applyTextures(ProgramBinary *programBinary, SamplerType shaderType,
-                             const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount)
-{
-    //TODO(jmadill): MANGLE refactor
-    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
-
-    size_t samplerRange = programBinary->getUsedSamplerRange(shaderType);
-    for (size_t samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
-    {
-        GLenum textureType = programBinary->getSamplerTextureType(shaderType, samplerIndex);
-        GLint textureUnit = programBinary->getSamplerMapping(shaderType, samplerIndex, getCaps());
-        if (textureUnit != -1)
-        {
-            Texture *texture = getSamplerTexture(textureUnit, textureType);
-            ASSERT(texture);
-            SamplerState sampler = texture->getSamplerState();
-
-            Sampler *samplerObject = mState.getSampler(textureUnit);
-            if (samplerObject)
-            {
-                samplerObject->getState(&sampler);
-            }
-
-            // TODO: std::binary_search may become unavailable using older versions of GCC
-            if (texture->isSamplerComplete(sampler, mTextureCaps, mExtensions, mClientVersion) &&
-                !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial()))
-            {
-                Error error = rendererD3D->setSamplerState(shaderType, samplerIndex, texture, sampler);
-                if (error.isError())
-                {
-                    return error;
-                }
-
-                error = rendererD3D->setTexture(shaderType, samplerIndex, texture);
-                if (error.isError())
-                {
-                    return error;
-                }
-            }
-            else
-            {
-                // Texture is not sampler complete or it is in use by the framebuffer.  Bind the incomplete texture.
-                Texture *incompleteTexture = getIncompleteTexture(textureType);
-                gl::Error error = rendererD3D->setTexture(shaderType, samplerIndex, incompleteTexture);
-                if (error.isError())
-                {
-                    return error;
-                }
-            }
-        }
-        else
-        {
-            // No texture bound to this slot even though it is used by the shader, bind a NULL texture
-            Error error = rendererD3D->setTexture(shaderType, samplerIndex, NULL);
-            if (error.isError())
-            {
-                return error;
-            }
-        }
-    }
-
-    // Set all the remaining textures to NULL
-    size_t samplerCount = (shaderType == SAMPLER_PIXEL) ? mCaps.maxTextureImageUnits
-                                                        : mCaps.maxVertexTextureImageUnits;
-    for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++)
-    {
-        //TODO(jmadill): MANGLE refactor
-        rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
-
-        Error error = rendererD3D->setTexture(shaderType, samplerIndex, NULL);
-        if (error.isError())
-        {
-            return error;
-        }
-    }
-
-    return Error(GL_NO_ERROR);
-}
-
-Error Context::applyTextures(ProgramBinary *programBinary)
-{
-    FramebufferTextureSerialArray framebufferSerials;
-    size_t framebufferSerialCount = getBoundFramebufferTextureSerials(&framebufferSerials);
-
-    Error error = applyTextures(programBinary, SAMPLER_VERTEX, framebufferSerials, framebufferSerialCount);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = applyTextures(programBinary, SAMPLER_PIXEL, framebufferSerials, framebufferSerialCount);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    return Error(GL_NO_ERROR);
-}
-
-Error Context::applyUniformBuffers()
-{
-    Program *programObject = getProgram(mState.getCurrentProgramId());
-    ProgramBinary *programBinary = programObject->getProgramBinary();
-
-    std::vector<Buffer*> boundBuffers;
-
-    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < programBinary->getActiveUniformBlockCount(); uniformBlockIndex++)
-    {
-        GLuint blockBinding = programObject->getUniformBlockBinding(uniformBlockIndex);
-
-        if (mState.getIndexedUniformBuffer(blockBinding)->id() == 0)
-        {
-            // undefined behaviour
-            return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer.");
-        }
-        else
-        {
-            Buffer *uniformBuffer = mState.getIndexedUniformBuffer(blockBinding);
-            ASSERT(uniformBuffer);
-            boundBuffers.push_back(uniformBuffer);
-        }
-    }
-
-    return programBinary->applyUniformBuffers(boundBuffers, getCaps());
-}
-
-bool Context::applyTransformFeedbackBuffers()
-{
-    //TODO(jmadill): MANGLE refactor
-    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
-
-    TransformFeedback *curTransformFeedback = mState.getCurrentTransformFeedback();
-    if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
-    {
-        rendererD3D->applyTransformFeedbackBuffers(mState);
-        return true;
-    }
-    else
-    {
-        return false;
-    }
-}
-
-void Context::markTransformFeedbackUsage()
-{
-    for (size_t i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++)
-    {
-        Buffer *buffer = mState.getIndexedTransformFeedbackBuffer(i);
-        if (buffer)
-        {
-            buffer->markTransformFeedbackUsage();
-        }
-    }
-}
-
 Error Context::clear(GLbitfield mask)
 {
     if (mState.isRasterizerDiscardEnabled())
@@ -1628,7 +1309,11 @@
 
     ClearParameters clearParams = mState.getClearParameters(mask);
 
-    Error error = applyRenderTarget(GL_TRIANGLES, true);   // Clips the clear to the scissor rectangle but not the viewport
+    //TODO(jmadill): Renderer refactor
+    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
+
+    // Clips the clear to the scissor rectangle but not the viewport
+    Error error = rendererD3D->applyRenderTarget(getData(), GL_TRIANGLES, true);
     if (error.isError())
     {
         return error;
@@ -1663,7 +1348,11 @@
         clearParams.depthClearValue = values[0];
     }
 
-    Error error = applyRenderTarget(GL_TRIANGLES, true);   // Clips the clear to the scissor rectangle but not the viewport
+    //TODO(jmadill): Renderer refactor
+    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
+
+    // Clips the clear to the scissor rectangle but not the viewport
+    Error error = rendererD3D->applyRenderTarget(getData(), GL_TRIANGLES, true);
     if (error.isError())
     {
         return error;
@@ -1688,7 +1377,11 @@
     clearParams.colorUIClearValue = ColorUI(values[0], values[1], values[2], values[3]);
     clearParams.colorClearType = GL_UNSIGNED_INT;
 
-    Error error = applyRenderTarget(GL_TRIANGLES, true);   // Clips the clear to the scissor rectangle but not the viewport
+    //TODO(jmadill): Renderer refactor
+    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
+
+    // Clips the clear to the scissor rectangle but not the viewport
+    Error error = rendererD3D->applyRenderTarget(getData(), GL_TRIANGLES, true);
     if (error.isError())
     {
         return error;
@@ -1723,7 +1416,11 @@
         clearParams.stencilClearValue = values[1];
     }
 
-    Error error = applyRenderTarget(GL_TRIANGLES, true);   // Clips the clear to the scissor rectangle but not the viewport
+    //TODO(jmadill): Renderer refactor
+    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
+
+    // Clips the clear to the scissor rectangle but not the viewport
+    Error error = rendererD3D->applyRenderTarget(getData(), GL_TRIANGLES, true);
     if (error.isError())
     {
         return error;
@@ -1746,7 +1443,11 @@
     clearParams.clearStencil = true;
     clearParams.stencilClearValue = stencil;
 
-    Error error = applyRenderTarget(GL_TRIANGLES, true);   // Clips the clear to the scissor rectangle but not the viewport
+    //TODO(jmadill): Renderer refactor
+    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
+
+    // Clips the clear to the scissor rectangle but not the viewport
+    Error error = rendererD3D->applyRenderTarget(getData(), GL_TRIANGLES, true);
     if (error.isError())
     {
         return error;
@@ -1770,164 +1471,14 @@
 
 Error Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances)
 {
-    ASSERT(mState.getCurrentProgramId() != 0);
-
-    ProgramBinary *programBinary = mState.getCurrentProgramBinary();
-    programBinary->updateSamplerMapping();
-
-    Error error = generateSwizzles(programBinary);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    //TODO(jmadill): MANGLE refactor
-    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
-
-    if (!rendererD3D->applyPrimitiveType(mode, count))
-    {
-        return Error(GL_NO_ERROR);
-    }
-
-    error = applyRenderTarget(mode, false);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = applyState(mode);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = rendererD3D->applyVertexBuffer(mState, first, count, instances);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    bool transformFeedbackActive = applyTransformFeedbackBuffers();
-
-    error = applyShaders(programBinary, transformFeedbackActive);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = applyTextures(programBinary);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = applyUniformBuffers();
-    if (error.isError())
-    {
-        return error;
-    }
-
-    if (!skipDraw(mode))
-    {
-        error = mRenderer->drawArrays(mode, count, instances, transformFeedbackActive);
-        if (error.isError())
-        {
-            return error;
-        }
-
-        if (transformFeedbackActive)
-        {
-            markTransformFeedbackUsage();
-        }
-    }
-
-    return gl::Error(GL_NO_ERROR);
+    return mRenderer->drawArrays(getData(), mode, first, count, instances);
 }
 
 Error Context::drawElements(GLenum mode, GLsizei count, GLenum type,
                             const GLvoid *indices, GLsizei instances,
                             const rx::RangeUI &indexRange)
 {
-    ASSERT(mState.getCurrentProgramId() != 0);
-
-    ProgramBinary *programBinary = mState.getCurrentProgramBinary();
-    programBinary->updateSamplerMapping();
-
-    Error error = generateSwizzles(programBinary);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    //TODO(jmadill): MANGLE refactor
-    rx::RendererD3D *rendererD3D = rx::RendererD3D::makeRendererD3D(mRenderer);
-
-    if (!rendererD3D->applyPrimitiveType(mode, count))
-    {
-        return Error(GL_NO_ERROR);
-    }
-
-    error = applyRenderTarget(mode, false);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = applyState(mode);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    VertexArray *vao = mState.getVertexArray();
-    rx::TranslatedIndexData indexInfo;
-    indexInfo.indexRange = indexRange;
-    error = rendererD3D->applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    GLsizei vertexCount = indexInfo.indexRange.length() + 1;
-    error = rendererD3D->applyVertexBuffer(mState, indexInfo.indexRange.start, vertexCount, instances);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    bool transformFeedbackActive = applyTransformFeedbackBuffers();
-    // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation
-    // layer.
-    ASSERT(!transformFeedbackActive);
-
-    error = applyShaders(programBinary, transformFeedbackActive);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = applyTextures(programBinary);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = applyUniformBuffers();
-    if (error.isError())
-    {
-        return error;
-    }
-
-    if (!skipDraw(mode))
-    {
-        error = mRenderer->drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances);
-        if (error.isError())
-        {
-            return error;
-        }
-    }
-
-    return Error(GL_NO_ERROR);
+    return mRenderer->drawElements(getData(), mode, count, type, indices, instances, indexRange);
 }
 
 // Implements glFlush when block is false, glFinish when block is true
@@ -2104,95 +1655,6 @@
     mState.detachSampler(sampler);
 }
 
-Texture *Context::getIncompleteTexture(GLenum type)
-{
-    if (mIncompleteTextures.find(type) == mIncompleteTextures.end())
-    {
-        const GLubyte color[] = { 0, 0, 0, 255 };
-        const PixelUnpackState incompleteUnpackState(1);
-
-        Texture* t = NULL;
-        switch (type)
-        {
-          default:
-            UNREACHABLE();
-            // default falls through to TEXTURE_2D
-
-          case GL_TEXTURE_2D:
-            {
-                Texture2D *incomplete2d = new Texture2D(mRenderer->createTexture(GL_TEXTURE_2D), Texture::INCOMPLETE_TEXTURE_ID);
-                incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
-                t = incomplete2d;
-            }
-            break;
-
-          case GL_TEXTURE_CUBE_MAP:
-            {
-              TextureCubeMap *incompleteCube = new TextureCubeMap(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), Texture::INCOMPLETE_TEXTURE_ID);
-
-              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
-              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
-              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
-              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
-              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
-              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
-
-              t = incompleteCube;
-            }
-            break;
-
-          case GL_TEXTURE_3D:
-            {
-                Texture3D *incomplete3d = new Texture3D(mRenderer->createTexture(GL_TEXTURE_3D), Texture::INCOMPLETE_TEXTURE_ID);
-                incomplete3d->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
-
-                t = incomplete3d;
-            }
-            break;
-
-          case GL_TEXTURE_2D_ARRAY:
-            {
-                Texture2DArray *incomplete2darray = new Texture2DArray(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), Texture::INCOMPLETE_TEXTURE_ID);
-                incomplete2darray->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
-
-                t = incomplete2darray;
-            }
-            break;
-        }
-
-        mIncompleteTextures[type].set(t);
-    }
-
-    return mIncompleteTextures[type].get();
-}
-
-bool Context::skipDraw(GLenum drawMode)
-{
-    if (drawMode == GL_POINTS)
-    {
-        // ProgramBinary assumes non-point rendering if gl_PointSize isn't written,
-        // which affects varying interpolation. Since the value of gl_PointSize is
-        // undefined when not written, just skip drawing to avoid unexpected results.
-        if (!mState.getCurrentProgramBinary()->usesPointSize())
-        {
-            // This is stictly speaking not an error, but developers should be
-            // notified of risking undefined behavior.
-            ERR("Point rendering without writing to gl_PointSize.");
-
-            return true;
-        }
-    }
-    else if (IsTriangleMode(drawMode))
-    {
-        if (mState.getRasterizerState().cullFace && mState.getRasterizerState().cullMode == GL_FRONT_AND_BACK)
-        {
-            return true;
-        }
-    }
-
-    return false;
-}
-
 void Context::setVertexAttribDivisor(GLuint index, GLuint divisor)
 {
     mState.getVertexArray()->setVertexAttribDivisor(index, divisor);
@@ -2325,33 +1787,6 @@
     return mExtensionStrings.size();
 }
 
-size_t Context::getBoundFramebufferTextureSerials(FramebufferTextureSerialArray *outSerialArray)
-{
-    size_t serialCount = 0;
-
-    Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
-    for (unsigned int i = 0; i < IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
-    {
-        FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i);
-        if (attachment && attachment->isTexture())
-        {
-            Texture *texture = attachment->getTexture();
-            (*outSerialArray)[serialCount++] = texture->getTextureSerial();
-        }
-    }
-
-    FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer();
-    if (depthStencilAttachment && depthStencilAttachment->isTexture())
-    {
-        Texture *depthStencilTexture = depthStencilAttachment->getTexture();
-        (*outSerialArray)[serialCount++] = depthStencilTexture->getTextureSerial();
-    }
-
-    std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount);
-
-    return serialCount;
-}
-
 Error Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                                GLbitfield mask, GLenum filter)
 {
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
index 96b0089..fa971b4 100644
--- a/src/libGLESv2/Context.h
+++ b/src/libGLESv2/Context.h
@@ -223,19 +223,6 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(Context);
 
-    // TODO: std::array may become unavailable using older versions of GCC
-    typedef std::array<unsigned int, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS> FramebufferTextureSerialArray;
-
-    Error applyRenderTarget(GLenum drawMode, bool ignoreViewport);
-    Error applyState(GLenum drawMode);
-    Error applyShaders(ProgramBinary *programBinary, bool transformFeedbackActive);
-    Error applyTextures(ProgramBinary *programBinary, SamplerType shaderType, const FramebufferTextureSerialArray &framebufferSerials,
-                        size_t framebufferSerialCount);
-    Error applyTextures(ProgramBinary *programBinary);
-    Error applyUniformBuffers();
-    bool applyTransformFeedbackBuffers();
-    void markTransformFeedbackUsage();
-
     void detachBuffer(GLuint buffer);
     void detachTexture(GLuint texture);
     void detachFramebuffer(GLuint framebuffer);
@@ -244,18 +231,9 @@
     void detachTransformFeedback(GLuint transformFeedback);
     void detachSampler(GLuint sampler);
 
-    Error generateSwizzles(ProgramBinary *programBinary, SamplerType type);
-    Error generateSwizzles(ProgramBinary *programBinary);
-
-    Texture *getIncompleteTexture(GLenum type);
-
-    bool skipDraw(GLenum drawMode);
-
     void initRendererString();
     void initExtensionStrings();
 
-    size_t getBoundFramebufferTextureSerials(FramebufferTextureSerialArray *outSerialArray);
-
     void initCaps(GLuint clientVersion);
 
     // Caps to use for validation
diff --git a/src/libGLESv2/ResourceManager.cpp b/src/libGLESv2/ResourceManager.cpp
index 0a9c3d3..ac6a0a2 100644
--- a/src/libGLESv2/ResourceManager.cpp
+++ b/src/libGLESv2/ResourceManager.cpp
@@ -295,9 +295,9 @@
     }
 }
 
-Program *ResourceManager::getProgram(unsigned int handle)
+Program *ResourceManager::getProgram(unsigned int handle) const
 {
-    ProgramMap::iterator program = mProgramMap.find(handle);
+    ProgramMap::const_iterator program = mProgramMap.find(handle);
 
     if (program == mProgramMap.end())
     {
diff --git a/src/libGLESv2/ResourceManager.h b/src/libGLESv2/ResourceManager.h
index 5421eaf..d75f3d2 100644
--- a/src/libGLESv2/ResourceManager.h
+++ b/src/libGLESv2/ResourceManager.h
@@ -60,7 +60,7 @@
 
     Buffer *getBuffer(GLuint handle);
     Shader *getShader(GLuint handle);
-    Program *getProgram(GLuint handle);
+    Program *getProgram(GLuint handle) const;
     Texture *getTexture(GLuint handle);
     Renderbuffer *getRenderbuffer(GLuint handle);
     Sampler *getSampler(GLuint handle);
diff --git a/src/libGLESv2/State.cpp b/src/libGLESv2/State.cpp
index fa3bbd6..e7acda2 100644
--- a/src/libGLESv2/State.cpp
+++ b/src/libGLESv2/State.cpp
@@ -486,7 +486,7 @@
     mSampleCoverageInvert = invert;
 }
 
-void State::getSampleCoverageParams(GLclampf *value, bool *invert)
+void State::getSampleCoverageParams(GLclampf *value, bool *invert) const
 {
     ASSERT(value != NULL && invert != NULL);
 
diff --git a/src/libGLESv2/State.h b/src/libGLESv2/State.h
index 85c96a9..c3e6106 100644
--- a/src/libGLESv2/State.h
+++ b/src/libGLESv2/State.h
@@ -101,7 +101,7 @@
     bool isSampleCoverageEnabled() const;
     void setSampleCoverage(bool enabled);
     void setSampleCoverageParams(GLclampf value, bool invert);
-    void getSampleCoverageParams(GLclampf *value, bool *invert);
+    void getSampleCoverageParams(GLclampf *value, bool *invert) const;
 
     // Scissor test state toggle & query
     bool isScissorTestEnabled() const;
diff --git a/src/libGLESv2/renderer/Renderer.h b/src/libGLESv2/renderer/Renderer.h
index 902c241..13738f2 100644
--- a/src/libGLESv2/renderer/Renderer.h
+++ b/src/libGLESv2/renderer/Renderer.h
@@ -16,6 +16,7 @@
 #include "libGLESv2/angletypes.h"
 #include "libGLESv2/renderer/Workarounds.h"
 #include "common/NativeWindow.h"
+#include "common/mathutil.h"
 
 #include <cstdint>
 
@@ -36,6 +37,7 @@
 {
 class Buffer;
 class Framebuffer;
+struct Data;
 }
 
 namespace rx
@@ -77,15 +79,18 @@
 
     virtual gl::Error sync(bool block) = 0;
 
+    virtual gl::Error drawArrays(const gl::Data &data, GLenum mode,
+                                 GLint first, GLsizei count, GLsizei instances) = 0;
+    virtual gl::Error drawElements(const gl::Data &data, GLenum mode, GLsizei count, GLenum type,
+                                   const GLvoid *indices, GLsizei instances,
+                                   const RangeUI &indexRange) = 0;
+
     // TODO(jmadill): pass state and essetial params only
-    virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0;
-    virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
-                                   gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0;
     virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) = 0;
     virtual gl::Error readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
                                  GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) = 0;
 
-    // TODO(jmadill): caps?
+    // TODO(jmadill): caps? and virtual for egl::Display
     virtual bool getShareHandleSupport() const = 0;
     virtual bool getPostSubBufferSupport() const = 0;
 
diff --git a/src/libGLESv2/renderer/d3d/RendererD3D.cpp b/src/libGLESv2/renderer/d3d/RendererD3D.cpp
index 39c9072..6253f21 100644
--- a/src/libGLESv2/renderer/d3d/RendererD3D.cpp
+++ b/src/libGLESv2/renderer/d3d/RendererD3D.cpp
@@ -8,6 +8,14 @@
 
 #include "libGLESv2/renderer/d3d/RendererD3D.h"
 
+#include "libGLESv2/renderer/d3d/IndexDataManager.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/FramebufferAttachment.h"
+#include "libGLESv2/ResourceManager.h"
+#include "libGLESv2/State.h"
+#include "libGLESv2/VertexArray.h"
+#include "common/utilities.h"
+
 namespace rx
 {
 
@@ -19,6 +27,11 @@
 
 RendererD3D::~RendererD3D()
 {
+    for (auto &incompleteTexture : mIncompleteTextures)
+    {
+        incompleteTexture.second.set(NULL);
+    }
+    mIncompleteTextures.clear();
 }
 
 // static
@@ -28,4 +41,581 @@
     return static_cast<RendererD3D*>(renderer);
 }
 
+gl::Error RendererD3D::drawElements(const gl::Data &data,
+                                    GLenum mode, GLsizei count, GLenum type,
+                                    const GLvoid *indices, GLsizei instances,
+                                    const RangeUI &indexRange)
+{
+    ASSERT(data.state->getCurrentProgramId() != 0);
+
+    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
+    programBinary->updateSamplerMapping();
+
+    gl::Error error = generateSwizzles(data);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    if (!applyPrimitiveType(mode, count))
+    {
+        return gl::Error(GL_NO_ERROR);
+    }
+
+    error = applyRenderTarget(data, mode, false);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = applyState(data, mode);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    gl::VertexArray *vao = data.state->getVertexArray();
+    rx::TranslatedIndexData indexInfo;
+    indexInfo.indexRange = indexRange;
+    error = applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    GLsizei vertexCount = indexInfo.indexRange.length() + 1;
+    error = applyVertexBuffer(*data.state, indexInfo.indexRange.start, vertexCount, instances);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    bool transformFeedbackActive = applyTransformFeedbackBuffers(data);
+    // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation
+    // layer.
+    ASSERT(!transformFeedbackActive);
+
+    error = applyShaders(data, transformFeedbackActive);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = applyTextures(data);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = applyUniformBuffers(data);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    if (!skipDraw(data, mode))
+    {
+        error = drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances);
+        if (error.isError())
+        {
+            return error;
+        }
+    }
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error RendererD3D::drawArrays(const gl::Data &data,
+                                  GLenum mode, GLint first,
+                                  GLsizei count, GLsizei instances)
+{
+    ASSERT(data.state->getCurrentProgramId() != 0);
+
+    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
+    programBinary->updateSamplerMapping();
+
+    gl::Error error = generateSwizzles(data);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    if (!applyPrimitiveType(mode, count))
+    {
+        return gl::Error(GL_NO_ERROR);
+    }
+
+    error = applyRenderTarget(data, mode, false);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = applyState(data, mode);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = applyVertexBuffer(*data.state, first, count, instances);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    bool transformFeedbackActive = applyTransformFeedbackBuffers(data);
+
+    error = applyShaders(data, transformFeedbackActive);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = applyTextures(data);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = applyUniformBuffers(data);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    if (!skipDraw(data, mode))
+    {
+        error = drawArrays(mode, count, instances, transformFeedbackActive);
+        if (error.isError())
+        {
+            return error;
+        }
+
+        if (transformFeedbackActive)
+        {
+            markTransformFeedbackUsage(data);
+        }
+    }
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error RendererD3D::generateSwizzles(const gl::Data &data, gl::SamplerType type)
+{
+    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
+
+    size_t samplerRange = programBinary->getUsedSamplerRange(type);
+
+    for (size_t i = 0; i < samplerRange; i++)
+    {
+        GLenum textureType = programBinary->getSamplerTextureType(type, i);
+        GLint textureUnit = programBinary->getSamplerMapping(type, i, *data.caps);
+        if (textureUnit != -1)
+        {
+            gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType);
+            ASSERT(texture);
+            if (texture->getSamplerState().swizzleRequired())
+            {
+                gl::Error error = generateSwizzle(texture);
+                if (error.isError())
+                {
+                    return error;
+                }
+            }
+        }
+    }
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error RendererD3D::generateSwizzles(const gl::Data &data)
+{
+    gl::Error error = generateSwizzles(data, gl::SAMPLER_VERTEX);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = generateSwizzles(data, gl::SAMPLER_PIXEL);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+// Applies the render target surface, depth stencil surface, viewport rectangle and
+// scissor rectangle to the renderer
+gl::Error RendererD3D::applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport)
+{
+    const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer();
+    ASSERT(framebufferObject && framebufferObject->completeness(data) == GL_FRAMEBUFFER_COMPLETE);
+
+    gl::Error error = applyRenderTarget(framebufferObject);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    float nearZ, farZ;
+    data.state->getDepthRange(&nearZ, &farZ);
+    setViewport(data.state->getViewport(), nearZ, farZ, drawMode,
+                data.state->getRasterizerState().frontFace, ignoreViewport);
+
+    setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled());
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D device
+gl::Error RendererD3D::applyState(const gl::Data &data, GLenum drawMode)
+{
+    const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer();
+    int samples = framebufferObject->getSamples(data);
+
+    gl::RasterizerState rasterizer = data.state->getRasterizerState();
+    rasterizer.pointDrawMode = (drawMode == GL_POINTS);
+    rasterizer.multiSample = (samples != 0);
+
+    gl::Error error = setRasterizerState(rasterizer);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    unsigned int mask = 0;
+    if (data.state->isSampleCoverageEnabled())
+    {
+        GLclampf coverageValue;
+        bool coverageInvert = false;
+        data.state->getSampleCoverageParams(&coverageValue, &coverageInvert);
+        if (coverageValue != 0)
+        {
+            float threshold = 0.5f;
+
+            for (int i = 0; i < samples; ++i)
+            {
+                mask <<= 1;
+
+                if ((i + 1) * coverageValue >= threshold)
+                {
+                    threshold += 1.0f;
+                    mask |= 1;
+                }
+            }
+        }
+
+        if (coverageInvert)
+        {
+            mask = ~mask;
+        }
+    }
+    else
+    {
+        mask = 0xFFFFFFFF;
+    }
+    error = setBlendState(framebufferObject, data.state->getBlendState(), data.state->getBlendColor(), mask);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = setDepthStencilState(data.state->getDepthStencilState(), data.state->getStencilRef(),
+                                 data.state->getStencilBackRef(), rasterizer.frontFace == GL_CCW);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+bool RendererD3D::applyTransformFeedbackBuffers(const gl::Data &data)
+{
+    gl::TransformFeedback *curTransformFeedback = data.state->getCurrentTransformFeedback();
+    if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
+    {
+        applyTransformFeedbackBuffers(*data.state);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+// Applies the shaders and shader constants to the Direct3D device
+gl::Error RendererD3D::applyShaders(const gl::Data &data, bool transformFeedbackActive)
+{
+    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
+
+    gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS];
+    gl::VertexFormat::GetInputLayout(inputLayout, programBinary, *data.state);
+
+    const gl::Framebuffer *fbo = data.state->getDrawFramebuffer();
+
+    gl::Error error = applyShaders(programBinary, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, transformFeedbackActive);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return programBinary->applyUniforms();
+}
+
+// For each Direct3D sampler of either the pixel or vertex stage,
+// looks up the corresponding OpenGL texture image unit and texture type,
+// and sets the texture and its addressing/filtering state (or NULL when inactive).
+gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shaderType,
+                                     const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount)
+{
+    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
+
+    size_t samplerRange = programBinary->getUsedSamplerRange(shaderType);
+    for (size_t samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
+    {
+        GLenum textureType = programBinary->getSamplerTextureType(shaderType, samplerIndex);
+        GLint textureUnit = programBinary->getSamplerMapping(shaderType, samplerIndex, *data.caps);
+        if (textureUnit != -1)
+        {
+            gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType);
+            ASSERT(texture);
+            gl::SamplerState sampler = texture->getSamplerState();
+
+            gl::Sampler *samplerObject = data.state->getSampler(textureUnit);
+            if (samplerObject)
+            {
+                samplerObject->getState(&sampler);
+            }
+
+            // TODO: std::binary_search may become unavailable using older versions of GCC
+            if (texture->isSamplerComplete(sampler, *data.textureCaps, *data.extensions, data.clientVersion) &&
+                !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial()))
+            {
+                gl::Error error = setSamplerState(shaderType, samplerIndex, texture, sampler);
+                if (error.isError())
+                {
+                    return error;
+                }
+
+                error = setTexture(shaderType, samplerIndex, texture);
+                if (error.isError())
+                {
+                    return error;
+                }
+            }
+            else
+            {
+                // Texture is not sampler complete or it is in use by the framebuffer.  Bind the incomplete texture.
+                gl::Texture *incompleteTexture = getIncompleteTexture(textureType);
+                gl::Error error = setTexture(shaderType, samplerIndex, incompleteTexture);
+                if (error.isError())
+                {
+                    return error;
+                }
+            }
+        }
+        else
+        {
+            // No texture bound to this slot even though it is used by the shader, bind a NULL texture
+            gl::Error error = setTexture(shaderType, samplerIndex, NULL);
+            if (error.isError())
+            {
+                return error;
+            }
+        }
+    }
+
+    // Set all the remaining textures to NULL
+    size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? data.caps->maxTextureImageUnits
+                                                            : data.caps->maxVertexTextureImageUnits;
+    for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++)
+    {
+        gl::Error error = setTexture(shaderType, samplerIndex, NULL);
+        if (error.isError())
+        {
+            return error;
+        }
+    }
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error RendererD3D::applyTextures(const gl::Data &data)
+{
+    FramebufferTextureSerialArray framebufferSerials;
+    size_t framebufferSerialCount = getBoundFramebufferTextureSerials(data, &framebufferSerials);
+
+    gl::Error error = applyTextures(data, gl::SAMPLER_VERTEX, framebufferSerials, framebufferSerialCount);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    error = applyTextures(data, gl::SAMPLER_PIXEL, framebufferSerials, framebufferSerialCount);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error RendererD3D::applyUniformBuffers(const gl::Data &data)
+{
+    gl::Program *programObject = data.resourceManager->getProgram(data.state->getCurrentProgramId());
+    gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+
+    std::vector<gl::Buffer*> boundBuffers;
+
+    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < programBinary->getActiveUniformBlockCount(); uniformBlockIndex++)
+    {
+        GLuint blockBinding = programObject->getUniformBlockBinding(uniformBlockIndex);
+
+        if (data.state->getIndexedUniformBuffer(blockBinding)->id() == 0)
+        {
+            // undefined behaviour
+            return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer.");
+        }
+        else
+        {
+            gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(blockBinding);
+            ASSERT(uniformBuffer);
+            boundBuffers.push_back(uniformBuffer);
+        }
+    }
+
+    return programBinary->applyUniformBuffers(boundBuffers, *data.caps);
+}
+
+bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode)
+{
+    if (drawMode == GL_POINTS)
+    {
+        // ProgramBinary assumes non-point rendering if gl_PointSize isn't written,
+        // which affects varying interpolation. Since the value of gl_PointSize is
+        // undefined when not written, just skip drawing to avoid unexpected results.
+        if (!data.state->getCurrentProgramBinary()->usesPointSize())
+        {
+            // This is stictly speaking not an error, but developers should be
+            // notified of risking undefined behavior.
+            ERR("Point rendering without writing to gl_PointSize.");
+
+            return true;
+        }
+    }
+    else if (gl::IsTriangleMode(drawMode))
+    {
+        if (data.state->getRasterizerState().cullFace && data.state->getRasterizerState().cullMode == GL_FRONT_AND_BACK)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void RendererD3D::markTransformFeedbackUsage(const gl::Data &data)
+{
+    for (size_t i = 0; i < data.caps->maxTransformFeedbackSeparateAttributes; i++)
+    {
+        gl::Buffer *buffer = data.state->getIndexedTransformFeedbackBuffer(i);
+        if (buffer)
+        {
+            buffer->markTransformFeedbackUsage();
+        }
+    }
+}
+
+size_t RendererD3D::getBoundFramebufferTextureSerials(const gl::Data &data,
+                                                      FramebufferTextureSerialArray *outSerialArray)
+{
+    size_t serialCount = 0;
+
+    const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer();
+    for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
+    {
+        gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i);
+        if (attachment && attachment->isTexture())
+        {
+            gl::Texture *texture = attachment->getTexture();
+            (*outSerialArray)[serialCount++] = texture->getTextureSerial();
+        }
+    }
+
+    gl::FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer();
+    if (depthStencilAttachment && depthStencilAttachment->isTexture())
+    {
+        gl::Texture *depthStencilTexture = depthStencilAttachment->getTexture();
+        (*outSerialArray)[serialCount++] = depthStencilTexture->getTextureSerial();
+    }
+
+    std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount);
+
+    return serialCount;
+}
+
+gl::Texture *RendererD3D::getIncompleteTexture(GLenum type)
+{
+    if (mIncompleteTextures.find(type) == mIncompleteTextures.end())
+    {
+        const GLubyte color[] = { 0, 0, 0, 255 };
+        const gl::PixelUnpackState incompleteUnpackState(1);
+
+        gl::Texture* t = NULL;
+        switch (type)
+        {
+          default:
+            UNREACHABLE();
+            // default falls through to TEXTURE_2D
+
+          case GL_TEXTURE_2D:
+            {
+                gl::Texture2D *incomplete2d = new gl::Texture2D(createTexture(GL_TEXTURE_2D), gl::Texture::INCOMPLETE_TEXTURE_ID);
+                incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+                t = incomplete2d;
+            }
+            break;
+
+          case GL_TEXTURE_CUBE_MAP:
+            {
+              gl::TextureCubeMap *incompleteCube = new gl::TextureCubeMap(createTexture(GL_TEXTURE_CUBE_MAP), gl::Texture::INCOMPLETE_TEXTURE_ID);
+
+              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+              incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+
+              t = incompleteCube;
+            }
+            break;
+
+          case GL_TEXTURE_3D:
+            {
+                gl::Texture3D *incomplete3d = new gl::Texture3D(createTexture(GL_TEXTURE_3D), gl::Texture::INCOMPLETE_TEXTURE_ID);
+                incomplete3d->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+
+                t = incomplete3d;
+            }
+            break;
+
+          case GL_TEXTURE_2D_ARRAY:
+            {
+                gl::Texture2DArray *incomplete2darray = new gl::Texture2DArray(createTexture(GL_TEXTURE_2D_ARRAY), gl::Texture::INCOMPLETE_TEXTURE_ID);
+                incomplete2darray->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+
+                t = incomplete2darray;
+            }
+            break;
+        }
+
+        mIncompleteTextures[type].set(t);
+    }
+
+    return mIncompleteTextures[type].get();
+}
+
 }
diff --git a/src/libGLESv2/renderer/d3d/RendererD3D.h b/src/libGLESv2/renderer/d3d/RendererD3D.h
index 2fb237d..91773f4 100644
--- a/src/libGLESv2/renderer/d3d/RendererD3D.h
+++ b/src/libGLESv2/renderer/d3d/RendererD3D.h
@@ -10,6 +10,10 @@
 #define LIBGLESV2_RENDERER_RENDERERD3D_H_
 
 #include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/Data.h"
+
+//FIXME(jmadill): std::array is currently prohibited by Chromium style guide
+#include <array>
 
 namespace gl
 {
@@ -38,6 +42,15 @@
 
     static RendererD3D *makeRendererD3D(Renderer *renderer);
 
+    gl::Error drawArrays(const gl::Data &data,
+                         GLenum mode, GLint first,
+                         GLsizei count, GLsizei instances) override;
+
+    gl::Error drawElements(const gl::Data &data,
+                           GLenum mode, GLsizei count, GLenum type,
+                           const GLvoid *indices, GLsizei instances,
+                           const RangeUI &indexRange) override;
+
     // Direct3D Specific methods
     virtual SwapChain *createSwapChain(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0;
 
@@ -48,7 +61,7 @@
     virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]) = 0;
 
     virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState) = 0;
-    virtual gl::Error setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
+    virtual gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
                                     unsigned int sampleMask) = 0;
     virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
                                            int stencilBackRef, bool frontFaceCCW) = 0;
@@ -57,7 +70,7 @@
     virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
                              bool ignoreViewport) = 0;
 
-    virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer) = 0;
+    virtual gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) = 0;
     virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive) = 0;
     virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) = 0;
@@ -130,13 +143,42 @@
     virtual VertexBuffer *createVertexBuffer() = 0;
     virtual IndexBuffer *createIndexBuffer() = 0;
 
+    //TODO(jmadill): Should be private or protected
+    gl::Error applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport);
+
   protected:
+    virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0;
+    virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
+                                   gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0;
+
     egl::Display *mDisplay;
 
   private:
     DISALLOW_COPY_AND_ASSIGN(RendererD3D);
 
+    //FIXME(jmadill): std::array is currently prohibited by Chromium style guide
+    typedef std::array<unsigned int, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS> FramebufferTextureSerialArray;
+
+    gl::Error generateSwizzles(const gl::Data &data, gl::SamplerType type);
+    gl::Error generateSwizzles(const gl::Data &data);
+
+    gl::Error applyState(const gl::Data &data, GLenum drawMode);
+    bool applyTransformFeedbackBuffers(const gl::Data &data);
+    gl::Error applyShaders(const gl::Data &data, bool transformFeedbackActive);
+    gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType,
+                            const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount);
+    gl::Error applyTextures(const gl::Data &data);
+    gl::Error applyUniformBuffers(const gl::Data &data);
+
+    bool skipDraw(const gl::Data &data, GLenum drawMode);
+    void markTransformFeedbackUsage(const gl::Data &data);
+
+    size_t getBoundFramebufferTextureSerials(const gl::Data &data,
+                                             FramebufferTextureSerialArray *outSerialArray);
+    gl::Texture *getIncompleteTexture(GLenum type);
+
     int mCurrentClientVersion;
+    gl::TextureMap mIncompleteTextures;
 };
 
 }
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
index 75b5f5e..772bc18 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
@@ -643,7 +643,7 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error Renderer11::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
+gl::Error Renderer11::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
                                     unsigned int sampleMask)
 {
     if (mForceSetBlendState ||
@@ -858,7 +858,7 @@
     }
 }
 
-gl::Error Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer)
+gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer)
 {
     // Get the color render buffer and serial
     // Also extract the render target dimensions and view
@@ -3275,7 +3275,7 @@
     }
 }
 
-void Renderer11::invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer)
+void Renderer11::invalidateFramebufferSwizzles(const gl::Framebuffer *framebuffer)
 {
     for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
     {
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
index 0dfd4e3..dbfc90d 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
@@ -69,8 +69,8 @@
     virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]);
 
     virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState);
-    virtual gl::Error setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
-                                    unsigned int sampleMask);
+    gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
+                            unsigned int sampleMask) override;
     virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
                                            int stencilBackRef, bool frontFaceCCW);
 
@@ -79,7 +79,7 @@
                              bool ignoreViewport);
 
     virtual bool applyPrimitiveType(GLenum mode, GLsizei count);
-    virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer);
+    gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override;
     virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive);
 
@@ -227,7 +227,7 @@
     void unsetSRVsWithResource(gl::SamplerType shaderType, const ID3D11Resource *resource);
 
     static void invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel);
-    static void invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer);
+    static void invalidateFramebufferSwizzles(const gl::Framebuffer *framebuffer);
 
     HMODULE mD3d11Module;
     HMODULE mDxgiModule;
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
index ecfaacb..61ca443 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
@@ -797,7 +797,7 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
+gl::Error Renderer9::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
                                    unsigned int sampleMask)
 {
     bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0;
@@ -1193,7 +1193,7 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer)
+gl::Error Renderer9::applyRenderTarget(const 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.
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h
index 333b57f..c22c9d5 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h
+++ b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h
@@ -72,8 +72,8 @@
     virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]);
 
     virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState);
-    virtual gl::Error setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
-                                    unsigned int sampleMask);
+    gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
+                            unsigned int sampleMask) override;
     virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
                                            int stencilBackRef, bool frontFaceCCW);
 
@@ -81,7 +81,7 @@
     virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
                              bool ignoreViewport);
 
-    virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer);
+    gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override;
     virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive);
     virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);