Exemple #1
0
static gl::Error getRenderTargetResource(const gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut,
                                         ID3D11Texture2D **texture2DOut)
{
    ASSERT(colorbuffer);

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

    ID3D11Resource *renderTargetResource = renderTarget->getTexture();
    ASSERT(renderTargetResource);

    *subresourceIndexOut = renderTarget->getSubresourceIndex();
    *texture2DOut = d3d11::DynamicCastComObject<ID3D11Texture2D>(renderTargetResource);

    if (!(*texture2DOut))
    {
        return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the ID3D11Texture2D from a RenderTarget");
    }

    return gl::Error(GL_NO_ERROR);
}
Exemple #2
0
ID3D11BlendState *Clear11::getBlendState(const std::vector<MaskedRenderTarget>& rts)
{
    ClearBlendInfo blendKey = { 0 };
    for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
    {
        if (i < rts.size())
        {
            RenderTarget11 *rt = rts[i].renderTarget;
            const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(rt->getInternalFormat());

            blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && formatInfo.redBits   > 0);
            blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && formatInfo.greenBits > 0);
            blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && formatInfo.blueBits  > 0);
            blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && formatInfo.alphaBits > 0);
        }
        else
        {
            blendKey.maskChannels[i][0] = false;
            blendKey.maskChannels[i][1] = false;
            blendKey.maskChannels[i][2] = false;
            blendKey.maskChannels[i][3] = false;
        }
    }

    ClearBlendStateMap::const_iterator i = mClearBlendStates.find(blendKey);
    if (i != mClearBlendStates.end())
    {
        return i->second;
    }
    else
    {
        D3D11_BLEND_DESC blendDesc = { 0 };
        blendDesc.AlphaToCoverageEnable = FALSE;
        blendDesc.IndependentBlendEnable = (rts.size() > 1) ? TRUE : FALSE;

        for (unsigned int j = 0; j < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; j++)
        {
            blendDesc.RenderTarget[j].BlendEnable = FALSE;
            blendDesc.RenderTarget[j].RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendKey.maskChannels[j][0],
                                                                                         blendKey.maskChannels[j][1],
                                                                                         blendKey.maskChannels[j][2],
                                                                                         blendKey.maskChannels[j][3]);
        }

        ID3D11Device *device = mRenderer->getDevice();
        ID3D11BlendState* blendState = NULL;
        HRESULT result = device->CreateBlendState(&blendDesc, &blendState);
        if (FAILED(result) || !blendState)
        {
            ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result);
            return NULL;
        }

        mClearBlendStates[blendKey] = blendState;

        return blendState;
    }
}
Exemple #3
0
gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source)
{
    RenderTarget11 *sourceRenderTarget = GetAs<RenderTarget11>(source);
    ASSERT(sourceRenderTarget->getTexture());

    ID3D11Resource *resource = sourceRenderTarget->getTexture();
    UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex();

    gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
    gl::Error error = copy(destOffset, sourceBox, resource, subresourceIndex);

    SafeRelease(resource);

    return error;
}
gl::Error Framebuffer11::invalidateAttachment(const gl::FramebufferAttachment *attachment) const
{
    ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
    ASSERT(deviceContext1);
    ASSERT(attachment && attachment->isAttached());

    RenderTarget11 *renderTarget = nullptr;
    ANGLE_TRY(attachment->getRenderTarget(&renderTarget));
    ID3D11View *view = renderTarget->getRenderTargetView();

    if (view != nullptr)
    {
        deviceContext1->DiscardView(view);
    }

    return gl::NoError();
}
Exemple #5
0
gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
{
    RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source);
    ASSERT(sourceRenderTarget->getTexture());

    UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex();
    ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(sourceRenderTarget->getTexture());

    if (!sourceTexture2D)
    {
        return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the ID3D11Texture2D from the source RenderTarget.");
    }

    gl::Error error = copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex);

    SafeRelease(sourceTexture2D);

    return error;
}
Exemple #6
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();
    }
}
Exemple #7
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);
}
Exemple #8
0
gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, bool useEXTBehavior) const
{
    ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();

    if (!deviceContext1)
    {
        // DiscardView() is only supported on ID3D11DeviceContext1
        return gl::Error(GL_NO_ERROR);
    }

    bool foundDepth = false;
    bool foundStencil = false;

    for (size_t i = 0; i < count; ++i)
    {
        switch (attachments[i])
        {
          // Handle depth and stencil attachments. Defer discarding until later.
          case GL_DEPTH_STENCIL_ATTACHMENT:
            foundDepth = true;
            foundStencil = true;
            break;
          case GL_DEPTH_EXT:
          case GL_DEPTH_ATTACHMENT:
            foundDepth = true;
            break;
          case GL_STENCIL_EXT:
          case GL_STENCIL_ATTACHMENT:
            foundStencil = true;
            break;
          default:
            {
                // Handle color attachments
                ASSERT((attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) ||
                       (attachments[i] == GL_COLOR));

                RenderTarget11 *renderTarget = nullptr;
                ID3D11View *colorView = nullptr;
                gl::Error error(GL_NO_ERROR);
                size_t colorAttachmentID = 0;

                if (attachments[i] == GL_COLOR)
                {
                    colorAttachmentID = 0;
                }
                else
                {
                    colorAttachmentID = attachments[i] - GL_COLOR_ATTACHMENT0;
                }

                if (mData.getColorAttachment(static_cast<unsigned int>(colorAttachmentID)))
                {
                    error = mData.getColorAttachment(static_cast<unsigned int>(colorAttachmentID))
                                ->getRenderTarget(&renderTarget);
                    if (error.isError())
                    {
                        return error;
                    }

                    colorView = renderTarget->getRenderTargetView();

                    if (colorView != nullptr)
                    {
                        deviceContext1->DiscardView(colorView);
                    }
                }

                break;
            }
        }
    }

    bool discardDepth = false;
    bool discardStencil = false;

    // The D3D11 renderer uses the same view for depth and stencil buffers, so we must be careful.
    if (useEXTBehavior)
    {
        // In the extension, if the app discards only one of the depth and stencil attachments, but
        // those are backed by the same packed_depth_stencil buffer, then both images become undefined.
        discardDepth = foundDepth;

        // Don't bother discarding the stencil buffer if the depth buffer will already do it
        discardStencil = foundStencil && (!discardDepth || mData.getDepthAttachment() == nullptr);
    }
    else
    {
        // In ES 3.0.4, if a specified attachment has base internal format DEPTH_STENCIL but the
        // attachments list does not include DEPTH_STENCIL_ATTACHMENT or both DEPTH_ATTACHMENT and
        // STENCIL_ATTACHMENT, then only the specified portion of every pixel in the subregion of pixels
        // of the DEPTH_STENCIL buffer may be invalidated, and the other portion must be preserved.
        discardDepth = (foundDepth && foundStencil) || (foundDepth && (mData.getStencilAttachment() == nullptr));
        discardStencil = (foundStencil && (mData.getDepthAttachment() == nullptr));
    }

    if (discardDepth && mData.getDepthAttachment())
    {
        RenderTarget11 *renderTarget = nullptr;
        ID3D11View *depthView = nullptr;
        gl::Error error(GL_NO_ERROR);

        error = mData.getDepthAttachment()->getRenderTarget(&renderTarget);
        if (error.isError())
        {
            return error;
        }

        depthView = renderTarget->getDepthStencilView();

        if (depthView != nullptr)
        {
            deviceContext1->DiscardView(depthView);
        }
    }

    if (discardStencil && mData.getStencilAttachment())
    {
        RenderTarget11 *renderTarget = nullptr;
        ID3D11View *stencilView = nullptr;
        gl::Error error(GL_NO_ERROR);

        error = mData.getStencilAttachment()->getRenderTarget(&renderTarget);
        if (error.isError())
        {
            return error;
        }

        stencilView = renderTarget->getDepthStencilView();

        if (stencilView != nullptr)
        {
            deviceContext1->DiscardView(stencilView);
        }
    }

    return gl::Error(GL_NO_ERROR);
}
Exemple #9
0
gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer)
{
    // Get the color render buffer and serial
    // Also extract the render target dimensions and view
    unsigned int renderTargetWidth  = 0;
    unsigned int renderTargetHeight = 0;
    DXGI_FORMAT renderTargetFormat  = DXGI_FORMAT_UNKNOWN;
    RenderTargetArray framebufferRTVs;
    bool missingColorRenderTarget = true;

    framebufferRTVs.fill(nullptr);

    const Framebuffer11 *framebuffer11     = GetImplAs<Framebuffer11>(framebuffer);
    const gl::AttachmentList &colorbuffers = framebuffer11->getColorAttachmentsForRender();

    for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
    {
        const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];

        if (colorbuffer)
        {
            // the draw buffer must be either "none", "back" for the default buffer or the same
            // index as this color (in order)

            // check for zero-sized default framebuffer, which is a special case.
            // in this case we do not wish to modify any state and just silently return false.
            // this will not report any gl error but will cause the calling method to return.
            const gl::Extents &size = colorbuffer->getSize();
            if (size.width == 0 || size.height == 0)
            {
                return gl::Error(GL_NO_ERROR);
            }

            // Extract the render target dimensions and view
            RenderTarget11 *renderTarget = NULL;
            gl::Error error = colorbuffer->getRenderTarget(&renderTarget);
            if (error.isError())
            {
                return error;
            }
            ASSERT(renderTarget);

            framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView();
            ASSERT(framebufferRTVs[colorAttachment]);

            if (missingColorRenderTarget)
            {
                renderTargetWidth        = renderTarget->getWidth();
                renderTargetHeight       = renderTarget->getHeight();
                renderTargetFormat       = renderTarget->getDXGIFormat();
                missingColorRenderTarget = false;
            }

            // Unbind render target SRVs from the shader here to prevent D3D11 warnings.
            if (colorbuffer->type() == GL_TEXTURE)
            {
                uintptr_t rtResource =
                    reinterpret_cast<uintptr_t>(GetViewResource(framebufferRTVs[colorAttachment]));
                const gl::ImageIndex &index = colorbuffer->getTextureImageIndex();
                // The index doesn't need to be corrected for the small compressed texture
                // workaround
                // because a rendertarget is never compressed.
                unsetConflictingSRVs(gl::SAMPLER_VERTEX, rtResource, index);
                unsetConflictingSRVs(gl::SAMPLER_PIXEL, rtResource, index);
            }
        }
    }

    // Get the depth stencil buffers
    ID3D11DepthStencilView *framebufferDSV        = NULL;
    const gl::FramebufferAttachment *depthStencil = framebuffer->getDepthOrStencilbuffer();
    if (depthStencil)
    {
        RenderTarget11 *depthStencilRenderTarget = NULL;
        gl::Error error = depthStencil->getRenderTarget(&depthStencilRenderTarget);
        if (error.isError())
        {
            return error;
        }
        ASSERT(depthStencilRenderTarget);

        framebufferDSV = depthStencilRenderTarget->getDepthStencilView();
        ASSERT(framebufferDSV);

        // If there is no render buffer, the width, height and format values come from
        // the depth stencil
        if (missingColorRenderTarget)
        {
            renderTargetWidth  = depthStencilRenderTarget->getWidth();
            renderTargetHeight = depthStencilRenderTarget->getHeight();
        }

        // Unbind render target SRVs from the shader here to prevent D3D11 warnings.
        if (depthStencil->type() == GL_TEXTURE)
        {
            uintptr_t depthStencilResource =
                reinterpret_cast<uintptr_t>(GetViewResource(framebufferDSV));
            const gl::ImageIndex &index = depthStencil->getTextureImageIndex();
            // The index doesn't need to be corrected for the small compressed texture workaround
            // because a rendertarget is never compressed.
            unsetConflictingSRVs(gl::SAMPLER_VERTEX, depthStencilResource, index);
            unsetConflictingSRVs(gl::SAMPLER_PIXEL, depthStencilResource, index);
        }
    }

    if (setRenderTargets(framebufferRTVs, framebufferDSV))
    {
        setViewportBounds(renderTargetWidth, renderTargetHeight);
    }

    gl::Error error = framebuffer11->invalidateSwizzles();
    if (error.isError())
    {
        return error;
    }

    return gl::Error(GL_NO_ERROR);
}