Esempio n. 1
0
void Clear11::clearFramebuffer(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer)
{
    // First determine if a scissored clear is needed, this will always require drawing a quad.
    //
    // Otherwise, iterate over the color buffers which require clearing and determine if they can be
    // cleared with ID3D11DeviceContext::ClearRenderTargetView... This requires:
    // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer
    //    render targets as expected but does not work the other way around)
    // 2) The format of the render target has no color channels that are currently masked out.
    // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work.
    //
    // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView
    // by checking if the stencil write mask covers the entire stencil.
    //
    // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color
    // attribute.

    gl::Extents framebufferSize;
    if (frameBuffer->getFirstColorbuffer() != NULL)
    {
        gl::Renderbuffer *renderBuffer = frameBuffer->getFirstColorbuffer();
        framebufferSize.width = renderBuffer->getWidth();
        framebufferSize.height = renderBuffer->getHeight();
        framebufferSize.depth = 1;
    }
    else if (frameBuffer->getDepthOrStencilbuffer() != NULL)
    {
        gl::Renderbuffer *renderBuffer = frameBuffer->getDepthOrStencilbuffer();
        framebufferSize.width = renderBuffer->getWidth();
        framebufferSize.height = renderBuffer->getHeight();
        framebufferSize.depth = 1;
    }
    else
    {
        UNREACHABLE();
        return;
    }

    if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || 
                                       clearParams.scissor.y >= framebufferSize.height ||
                                       clearParams.scissor.x + clearParams.scissor.width <= 0 ||
                                       clearParams.scissor.y + clearParams.scissor.height <= 0))
    {
        // Scissor is enabled and the scissor rectangle is outside the renderbuffer
        return;
    }

    bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 ||
                                                             clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
                                                             clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height);

    GLuint clientVersion = mRenderer->getCurrentClientVersion();

    std::vector<RenderTarget11*> maskedClearRenderTargets;
    RenderTarget11* maskedClearDepthStencil = NULL;

    ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();

    for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
    {
        if (clearParams.clearColor[colorAttachment] && frameBuffer->isEnabledColorAttachment(colorAttachment))
        {
            gl::Renderbuffer *renderbuffer = frameBuffer->getColorbuffer(colorAttachment);
            if (renderbuffer)
            {
                RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbuffer->getRenderTarget());
                if (!renderTarget)
                {
                    ERR("Render target pointer unexpectedly null.");
                    return;
                }

                GLenum internalFormat = renderbuffer->getInternalFormat();
                GLenum actualFormat = renderbuffer->getActualFormat();
                GLenum componentType = gl::GetComponentType(internalFormat, clientVersion);
                if (clearParams.colorClearType == GL_FLOAT &&
                    !(componentType == GL_FLOAT || componentType == GL_UNSIGNED_NORMALIZED || componentType == GL_SIGNED_NORMALIZED))
                {
                    ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-"
                        "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment, internalFormat);
                }

                GLuint internalRedBits = gl::GetRedBits(internalFormat, clientVersion);
                GLuint internalGreenBits = gl::GetGreenBits(internalFormat, clientVersion);
                GLuint internalBlueBits = gl::GetBlueBits(internalFormat, clientVersion);
                GLuint internalAlphaBits = gl::GetAlphaBits(internalFormat, clientVersion);

                if ((internalRedBits   == 0 || !clearParams.colorMaskRed) &&
                    (internalGreenBits == 0 || !clearParams.colorMaskGreen) &&
                    (internalBlueBits  == 0 || !clearParams.colorMaskBlue) &&
                    (internalAlphaBits == 0 || !clearParams.colorMaskAlpha))
                {
                    // Every channel either does not exist in the render target or is masked out
                    continue;
                }
                else if (needScissoredClear || clearParams.colorClearType != GL_FLOAT ||
                         (internalRedBits   > 0 && !clearParams.colorMaskRed)   ||
                         (internalGreenBits > 0 && !clearParams.colorMaskGreen) ||
                         (internalBlueBits  > 0 && !clearParams.colorMaskBlue)  ||
                         (internalAlphaBits > 0 && !clearParams.colorMaskAlpha))
                {
                    // A scissored or masked clear is required
                    maskedClearRenderTargets.push_back(renderTarget);
                }
                else
                {
                    // ID3D11DeviceContext::ClearRenderTargetView is possible

                    ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView();
                    if (!framebufferRTV)
                    {
                        ERR("Render target view pointer unexpectedly null.");
                        return;
                    }

                    // Check if the actual format has a channel that the internal format does not and set them to the
                    // default values
                    GLuint actualRedBits   = gl::GetRedBits(actualFormat, clientVersion);
                    GLuint actualGreenBits = gl::GetGreenBits(actualFormat, clientVersion);
                    GLuint actualBlueBits  = gl::GetBlueBits(actualFormat, clientVersion);
                    GLuint actualAlphaBits = gl::GetAlphaBits(actualFormat, clientVersion);

                    const float clearValues[4] =
                    {
                        ((internalRedBits   == 0 && actualRedBits   > 0) ? 0.0f : clearParams.colorFClearValue.red),
                        ((internalGreenBits == 0 && actualGreenBits > 0) ? 0.0f : clearParams.colorFClearValue.green),
                        ((internalBlueBits  == 0 && actualBlueBits  > 0) ? 0.0f : clearParams.colorFClearValue.blue),
                        ((internalAlphaBits == 0 && actualAlphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha),
                    };

                    deviceContext->ClearRenderTargetView(framebufferRTV, clearValues);
                }
            }
        }
    }

    if (clearParams.clearDepth || clearParams.clearStencil)
    {
        gl::Renderbuffer *renderbuffer = frameBuffer->getDepthOrStencilbuffer();
        if (renderbuffer)
        {
            RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbuffer->getDepthStencil());
            if (!renderTarget)
            {
                ERR("Depth stencil render target pointer unexpectedly null.");
                return;
            }

            GLenum actualFormat = renderbuffer->getActualFormat();

            unsigned int stencilUnmasked = frameBuffer->hasStencil() ? (1 << gl::GetStencilBits(actualFormat, clientVersion)) - 1 : 0;
            bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;

            if (needScissoredClear || needMaskedStencilClear)
            {
                maskedClearDepthStencil = renderTarget;
            }
            else
            {
                ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView();
                if (!framebufferDSV)
                {
                    ERR("Depth stencil view pointer unexpectedly null.");
                    return;
                }

                UINT clearFlags = (clearParams.clearDepth   ? D3D11_CLEAR_DEPTH   : 0) |
                                  (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0);
                FLOAT depthClear = gl::clamp01(clearParams.depthClearValue);
                UINT8 stencilClear = clearParams.stencilClearValue & 0xFF;

                deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear);
            }
        }
    }

    if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil)
    {
        // To clear the render targets and depth stencil in one pass:
        //
        // Render a quad clipped to the scissor rectangle which draws the clear color and a blend
        // state that will perform the required color masking.
        //
        // The quad's depth is equal to the depth clear value with a depth stencil state that
        // will enable or disable depth test/writes if the depth buffer should be cleared or not.
        //
        // The rasterizer state's stencil is set to always pass or fail based on if the stencil
        // should be cleared or not with a stencil write mask of the stencil clear value.
        //
        // ======================================================================================
        //
        // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render-
        // buffer that is not normalized fixed point or floating point with floating point values
        // are undefined so we can just write floats to them and D3D11 will bit cast them to
        // integers.
        //
        // Also, we don't have to worry about attempting to clear a normalized fixed/floating point
        // buffer with integer values because there is no gl API call which would allow it,
        // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to
        // be a compatible clear type.

        // Bind all the render targets which need clearing
        ASSERT(maskedClearRenderTargets.size() <= mRenderer->getMaxRenderTargets());
        std::vector<ID3D11RenderTargetView*> rtvs(maskedClearRenderTargets.size());
        for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++)
        {
            ID3D11RenderTargetView *renderTarget = maskedClearRenderTargets[i]->getRenderTargetView();
            if (!renderTarget)
            {
                ERR("Render target pointer unexpectedly null.");
                return;
            }

            rtvs[i] = renderTarget;
        }
        ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL;

        ID3D11BlendState *blendState = getBlendState(clearParams, maskedClearRenderTargets);
        const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
        const UINT sampleMask = 0xFFFFFFFF;

        ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams);
        const UINT stencilClear = clearParams.stencilClearValue & 0xFF;

        // Set the vertices
        UINT vertexStride = 0;
        const UINT startIdx = 0;
        const ClearShader* shader = NULL;
        D3D11_MAPPED_SUBRESOURCE mappedResource;
        HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
        if (FAILED(result))
        {
            ERR("Failed to map masked clear vertex buffer, HRESULT: 0x%X.", result);
            return;
        }

        const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL;
        switch (clearParams.colorClearType)
        {
          case GL_FLOAT:
            ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData);
            vertexStride = sizeof(d3d11::PositionDepthColorVertex<float>);
            shader = &mFloatClearShader;
            break;

          case GL_UNSIGNED_INT:
            ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData);
            vertexStride = sizeof(d3d11::PositionDepthColorVertex<unsigned int>);
            shader = &mUintClearShader;
            break;

          case GL_INT:
            ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData);
            vertexStride = sizeof(d3d11::PositionDepthColorVertex<int>);
            shader = &mIntClearShader;
            break;

          default:
            UNREACHABLE();
            break;
        }

        deviceContext->Unmap(mVertexBuffer, 0);

        // Set the viewport to be the same size as the framebuffer
        D3D11_VIEWPORT viewport;
        viewport.TopLeftX = 0;
        viewport.TopLeftY = 0;
        viewport.Width = framebufferSize.width;
        viewport.Height = framebufferSize.height;
        viewport.MinDepth = 0;
        viewport.MaxDepth = 1;
        deviceContext->RSSetViewports(1, &viewport);

        // Apply state
        deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask);
        deviceContext->OMSetDepthStencilState(dsState, stencilClear);
        deviceContext->RSSetState(mRasterizerState);

        // Apply shaders
        deviceContext->IASetInputLayout(shader->inputLayout);
        deviceContext->VSSetShader(shader->vertexShader, NULL, 0);
        deviceContext->PSSetShader(shader->pixelShader, NULL, 0);
        deviceContext->GSSetShader(NULL, NULL, 0);

        // Apply vertex buffer
        deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx);
        deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

        // Apply render targets
        deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv);

        // Draw the clear quad
        deviceContext->Draw(4, 0);

        // Clean up
        mRenderer->markAllStateDirty();
    }
}
Esempio n. 2
0
gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData)
{
    const auto &colorAttachments = fboData.mColorAttachments;
    const auto &drawBufferStates = fboData.mDrawBufferStates;
    const auto *depthAttachment = fboData.mDepthAttachment;
    const auto *stencilAttachment = fboData.mStencilAttachment;

    ASSERT(colorAttachments.size() == drawBufferStates.size());

    // Iterate over the color buffers which require clearing and determine if they can be
    // cleared with ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView.
    // This requires:
    // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer
    //    render targets as expected but does not work the other way around)
    // 2) The format of the render target has no color channels that are currently masked out.
    // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work.
    //
    // If these conditions are met, and:
    // - No scissored clear is needed, then clear using ID3D11DeviceContext::ClearRenderTargetView.
    // - A scissored clear is needed then clear using ID3D11DeviceContext1::ClearView if available.
    //   Otherwise draw a quad.
    //
    // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView
    // by checking if the stencil write mask covers the entire stencil.
    //
    // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color
    // attribute.

    gl::Extents framebufferSize;

    auto iter = std::find_if(colorAttachments.begin(), colorAttachments.end(), [](const gl::FramebufferAttachment *attachment) { return attachment != nullptr; });
    if (iter != colorAttachments.end())
    {
        framebufferSize.width = (*iter)->getWidth();
        framebufferSize.height = (*iter)->getHeight();
        framebufferSize.depth = 1;
    }
    else if (depthAttachment != nullptr)
    {
        framebufferSize.width = depthAttachment->getWidth();
        framebufferSize.height = depthAttachment->getHeight();
        framebufferSize.depth = 1;
    }
    else if (stencilAttachment != nullptr)
    {
        framebufferSize.width = stencilAttachment->getWidth();
        framebufferSize.height = stencilAttachment->getHeight();
        framebufferSize.depth = 1;
    }
    else
    {
        UNREACHABLE();
        return gl::Error(GL_INVALID_OPERATION);
    }

    if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || 
                                       clearParams.scissor.y >= framebufferSize.height ||
                                       clearParams.scissor.x + clearParams.scissor.width <= 0 ||
                                       clearParams.scissor.y + clearParams.scissor.height <= 0))
    {
        // Scissor is enabled and the scissor rectangle is outside the renderbuffer
        return gl::Error(GL_NO_ERROR);
    }

    bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 ||
                                                             clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
                                                             clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height);

    std::vector<MaskedRenderTarget> maskedClearRenderTargets;
    RenderTarget11* maskedClearDepthStencil = NULL;

    ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
    ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();

    for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++)
    {
        if (clearParams.clearColor[colorAttachment] &&
            colorAttachments[colorAttachment] != nullptr &&
            drawBufferStates[colorAttachment] != GL_NONE)
        {
            const gl::FramebufferAttachment *attachment = colorAttachments[colorAttachment];

            RenderTarget11 *renderTarget = NULL;
            gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget);
            if (error.isError())
            {
                return error;
            }

            const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat());

            if (clearParams.colorClearType == GL_FLOAT &&
                !(formatInfo.componentType == GL_FLOAT || formatInfo.componentType == GL_UNSIGNED_NORMALIZED || formatInfo.componentType == GL_SIGNED_NORMALIZED))
            {
                ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-"
                    "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment,
                    attachment->getInternalFormat());
            }

            if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) &&
                (formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) &&
                (formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) &&
                (formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha))
            {
                // Every channel either does not exist in the render target or is masked out
                continue;
            }
            else if ((!mSupportsClearView && needScissoredClear) || clearParams.colorClearType != GL_FLOAT ||
                     (formatInfo.redBits   > 0 && !clearParams.colorMaskRed)   ||
                     (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) ||
                     (formatInfo.blueBits  > 0 && !clearParams.colorMaskBlue) ||
                     (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha))
            {
                // A masked clear is required, or a scissored clear is required and ID3D11DeviceContext1::ClearView is unavailable
                MaskedRenderTarget maskAndRt;
                bool clearColor = clearParams.clearColor[colorAttachment];
                maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed);
                maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen);
                maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue);
                maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha);
                maskAndRt.renderTarget = renderTarget;
                maskedClearRenderTargets.push_back(maskAndRt);
            }
            else
            {
                 // ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is possible

                ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView();
                if (!framebufferRTV)
                {
                    return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null.");
                }

                const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat());

                // Check if the actual format has a channel that the internal format does not and set them to the
                // default values
                const float clearValues[4] =
                {
                    ((formatInfo.redBits   == 0 && dxgiFormatInfo.redBits   > 0) ? 0.0f : clearParams.colorFClearValue.red),
                    ((formatInfo.greenBits == 0 && dxgiFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green),
                    ((formatInfo.blueBits  == 0 && dxgiFormatInfo.blueBits  > 0) ? 0.0f : clearParams.colorFClearValue.blue),
                    ((formatInfo.alphaBits == 0 && dxgiFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha),
                };

                if (needScissoredClear)
                {
                    // We shouldn't reach here if deviceContext1 is unavailable.
                    ASSERT(deviceContext1);

                    D3D11_RECT rect;
                    rect.left = clearParams.scissor.x;
                    rect.right = clearParams.scissor.x + clearParams.scissor.width;
                    rect.top = clearParams.scissor.y;
                    rect.bottom = clearParams.scissor.y + clearParams.scissor.height;

                    deviceContext1->ClearView(framebufferRTV, clearValues, &rect, 1);
                }
                else
                {
                    deviceContext->ClearRenderTargetView(framebufferRTV, clearValues);
                }
            }
        }
    }

    if (clearParams.clearDepth || clearParams.clearStencil)
    {
        const gl::FramebufferAttachment *attachment = (depthAttachment != nullptr) ? depthAttachment : stencilAttachment;
        ASSERT(attachment != nullptr);

        RenderTarget11 *renderTarget = NULL;
        gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget);
        if (error.isError())
        {
            return error;
        }

        const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat());

        unsigned int stencilUnmasked = (stencilAttachment != nullptr) ? (1 << dxgiFormatInfo.stencilBits) - 1 : 0;
        bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;

        if (needScissoredClear || needMaskedStencilClear)
        {
            maskedClearDepthStencil = renderTarget;
        }
        else
        {
            ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView();
            if (!framebufferDSV)
            {
                return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null.");
            }

            UINT clearFlags = (clearParams.clearDepth   ? D3D11_CLEAR_DEPTH   : 0) |
                                (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0);
            FLOAT depthClear = gl::clamp01(clearParams.depthClearValue);
            UINT8 stencilClear = clearParams.stencilClearValue & 0xFF;

            deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear);
        }
    }

    if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil)
    {
        // To clear the render targets and depth stencil in one pass:
        //
        // Render a quad clipped to the scissor rectangle which draws the clear color and a blend
        // state that will perform the required color masking.
        //
        // The quad's depth is equal to the depth clear value with a depth stencil state that
        // will enable or disable depth test/writes if the depth buffer should be cleared or not.
        //
        // The rasterizer state's stencil is set to always pass or fail based on if the stencil
        // should be cleared or not with a stencil write mask of the stencil clear value.
        //
        // ======================================================================================
        //
        // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render-
        // buffer that is not normalized fixed point or floating point with floating point values
        // are undefined so we can just write floats to them and D3D11 will bit cast them to
        // integers.
        //
        // Also, we don't have to worry about attempting to clear a normalized fixed/floating point
        // buffer with integer values because there is no gl API call which would allow it,
        // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to
        // be a compatible clear type.

        // Bind all the render targets which need clearing
        ASSERT(maskedClearRenderTargets.size() <= mRenderer->getRendererCaps().maxDrawBuffers);
        std::vector<ID3D11RenderTargetView*> rtvs(maskedClearRenderTargets.size());
        for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++)
        {
            RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget;
            ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView();
            if (!rtv)
            {
                return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null.");
            }

            rtvs[i] = rtv;
        }
        ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL;

        ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets);
        const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
        const UINT sampleMask = 0xFFFFFFFF;

        ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams);
        const UINT stencilClear = clearParams.stencilClearValue & 0xFF;

        // Set the vertices
        UINT vertexStride = 0;
        const UINT startIdx = 0;
        const ClearShader* shader = NULL;
        D3D11_MAPPED_SUBRESOURCE mappedResource;
        HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
        if (FAILED(result))
        {
            return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal masked clear vertex buffer, HRESULT: 0x%X.", result);
        }

        const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL;
        switch (clearParams.colorClearType)
        {
          case GL_FLOAT:
            ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData);
            vertexStride = sizeof(d3d11::PositionDepthColorVertex<float>);
            shader = &mFloatClearShader;
            break;

          case GL_UNSIGNED_INT:
            ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData);
            vertexStride = sizeof(d3d11::PositionDepthColorVertex<unsigned int>);
            shader = &mUintClearShader;
            break;

          case GL_INT:
            ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData);
            vertexStride = sizeof(d3d11::PositionDepthColorVertex<int>);
            shader = &mIntClearShader;
            break;

          default:
            UNREACHABLE();
            break;
        }

        deviceContext->Unmap(mVertexBuffer, 0);

        // Set the viewport to be the same size as the framebuffer
        D3D11_VIEWPORT viewport;
        viewport.TopLeftX = 0;
        viewport.TopLeftY = 0;
        viewport.Width = framebufferSize.width;
        viewport.Height = framebufferSize.height;
        viewport.MinDepth = 0;
        viewport.MaxDepth = 1;
        deviceContext->RSSetViewports(1, &viewport);

        // Apply state
        deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask);
        deviceContext->OMSetDepthStencilState(dsState, stencilClear);
        deviceContext->RSSetState(mRasterizerState);

        // Apply shaders
        deviceContext->IASetInputLayout(shader->inputLayout);
        deviceContext->VSSetShader(shader->vertexShader, NULL, 0);
        deviceContext->PSSetShader(shader->pixelShader, NULL, 0);
        deviceContext->GSSetShader(NULL, NULL, 0);

        // Apply vertex buffer
        deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx);
        deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

        // Apply render targets
        deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv);

        // Draw the clear quad
        deviceContext->Draw(4, 0);

        // Clean up
        mRenderer->markAllStateDirty();
    }

    return gl::Error(GL_NO_ERROR);
}