tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FramebufferD3D.cpp (15645B)


      1 //
      2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 // FramebufferD3D.cpp: Implements the DefaultAttachmentD3D and FramebufferD3D classes.
      8 
      9 #include "libANGLE/renderer/d3d/FramebufferD3D.h"
     10 
     11 #include "common/bitset_utils.h"
     12 #include "libANGLE/Context.h"
     13 #include "libANGLE/ErrorStrings.h"
     14 #include "libANGLE/Framebuffer.h"
     15 #include "libANGLE/FramebufferAttachment.h"
     16 #include "libANGLE/Surface.h"
     17 #include "libANGLE/formatutils.h"
     18 #include "libANGLE/renderer/ContextImpl.h"
     19 #include "libANGLE/renderer/d3d/ContextD3D.h"
     20 #include "libANGLE/renderer/d3d/RenderTargetD3D.h"
     21 #include "libANGLE/renderer/d3d/RenderbufferD3D.h"
     22 #include "libANGLE/renderer/d3d/RendererD3D.h"
     23 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
     24 #include "libANGLE/renderer/d3d/SwapChainD3D.h"
     25 #include "libANGLE/renderer/d3d/TextureD3D.h"
     26 
     27 namespace rx
     28 {
     29 
     30 namespace
     31 {
     32 
     33 ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask)
     34 {
     35    ClearParameters clearParams;
     36    memset(&clearParams, 0, sizeof(ClearParameters));
     37 
     38    clearParams.colorF           = state.getColorClearValue();
     39    clearParams.colorType        = GL_FLOAT;
     40    clearParams.clearDepth       = false;
     41    clearParams.depthValue       = state.getDepthClearValue();
     42    clearParams.clearStencil     = false;
     43    clearParams.stencilValue     = state.getStencilClearValue();
     44    clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask;
     45 
     46    const auto *framebufferObject      = state.getDrawFramebuffer();
     47    const gl::Extents &framebufferSize = framebufferObject->getFirstNonNullAttachment()->getSize();
     48    const gl::Offset &surfaceTextureOffset = framebufferObject->getSurfaceTextureOffset();
     49    if (state.isScissorTestEnabled())
     50    {
     51        clearParams.scissorEnabled = true;
     52        clearParams.scissor        = state.getScissor();
     53        clearParams.scissor.x      = clearParams.scissor.x + surfaceTextureOffset.x;
     54        clearParams.scissor.y      = clearParams.scissor.y + surfaceTextureOffset.y;
     55    }
     56    else if (surfaceTextureOffset != gl::kOffsetZero)
     57    {
     58        clearParams.scissorEnabled = true;
     59        clearParams.scissor        = gl::Rectangle(surfaceTextureOffset.x, surfaceTextureOffset.y,
     60                                            framebufferSize.width, framebufferSize.height);
     61    }
     62 
     63    const bool clearColor =
     64        (mask & GL_COLOR_BUFFER_BIT) && framebufferObject->hasEnabledDrawBuffer();
     65    if (clearColor)
     66    {
     67        clearParams.clearColor.set();
     68    }
     69    else
     70    {
     71        clearParams.clearColor.reset();
     72    }
     73    clearParams.colorMask = state.getBlendStateExt().getColorMaskBits();
     74 
     75    if (mask & GL_DEPTH_BUFFER_BIT)
     76    {
     77        if (state.getDepthStencilState().depthMask &&
     78            framebufferObject->getDepthAttachment() != nullptr)
     79        {
     80            clearParams.clearDepth = true;
     81        }
     82    }
     83 
     84    if (mask & GL_STENCIL_BUFFER_BIT)
     85    {
     86        if (framebufferObject->getStencilAttachment() != nullptr &&
     87            framebufferObject->getStencilAttachment()->getStencilSize() > 0)
     88        {
     89            clearParams.clearStencil = true;
     90        }
     91    }
     92 
     93    return clearParams;
     94 }
     95 }  // namespace
     96 
     97 ClearParameters::ClearParameters() = default;
     98 
     99 ClearParameters::ClearParameters(const ClearParameters &other) = default;
    100 
    101 FramebufferD3D::FramebufferD3D(const gl::FramebufferState &data, RendererD3D *renderer)
    102    : FramebufferImpl(data), mRenderer(renderer), mMockAttachment()
    103 {}
    104 
    105 FramebufferD3D::~FramebufferD3D() {}
    106 
    107 angle::Result FramebufferD3D::clear(const gl::Context *context, GLbitfield mask)
    108 {
    109    ClearParameters clearParams = GetClearParameters(context->getState(), mask);
    110    return clearImpl(context, clearParams);
    111 }
    112 
    113 angle::Result FramebufferD3D::clearBufferfv(const gl::Context *context,
    114                                            GLenum buffer,
    115                                            GLint drawbuffer,
    116                                            const GLfloat *values)
    117 {
    118    // glClearBufferfv can be called to clear the color buffer or depth buffer
    119    ClearParameters clearParams = GetClearParameters(context->getState(), 0);
    120 
    121    if (buffer == GL_COLOR)
    122    {
    123        for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
    124        {
    125            clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
    126        }
    127        clearParams.colorF    = gl::ColorF(values[0], values[1], values[2], values[3]);
    128        clearParams.colorType = GL_FLOAT;
    129    }
    130 
    131    if (buffer == GL_DEPTH)
    132    {
    133        clearParams.clearDepth = true;
    134        clearParams.depthValue = values[0];
    135    }
    136 
    137    return clearImpl(context, clearParams);
    138 }
    139 
    140 angle::Result FramebufferD3D::clearBufferuiv(const gl::Context *context,
    141                                             GLenum buffer,
    142                                             GLint drawbuffer,
    143                                             const GLuint *values)
    144 {
    145    // glClearBufferuiv can only be called to clear a color buffer
    146    ClearParameters clearParams = GetClearParameters(context->getState(), 0);
    147    for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
    148    {
    149        clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
    150    }
    151    clearParams.colorUI   = gl::ColorUI(values[0], values[1], values[2], values[3]);
    152    clearParams.colorType = GL_UNSIGNED_INT;
    153 
    154    return clearImpl(context, clearParams);
    155 }
    156 
    157 angle::Result FramebufferD3D::clearBufferiv(const gl::Context *context,
    158                                            GLenum buffer,
    159                                            GLint drawbuffer,
    160                                            const GLint *values)
    161 {
    162    // glClearBufferiv can be called to clear the color buffer or stencil buffer
    163    ClearParameters clearParams = GetClearParameters(context->getState(), 0);
    164 
    165    if (buffer == GL_COLOR)
    166    {
    167        for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
    168        {
    169            clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
    170        }
    171        clearParams.colorI    = gl::ColorI(values[0], values[1], values[2], values[3]);
    172        clearParams.colorType = GL_INT;
    173    }
    174 
    175    if (buffer == GL_STENCIL)
    176    {
    177        clearParams.clearStencil = true;
    178        clearParams.stencilValue = values[0];
    179    }
    180 
    181    return clearImpl(context, clearParams);
    182 }
    183 
    184 angle::Result FramebufferD3D::clearBufferfi(const gl::Context *context,
    185                                            GLenum buffer,
    186                                            GLint drawbuffer,
    187                                            GLfloat depth,
    188                                            GLint stencil)
    189 {
    190    // glClearBufferfi can only be called to clear a depth stencil buffer
    191    ClearParameters clearParams = GetClearParameters(context->getState(), 0);
    192    clearParams.clearDepth      = true;
    193    clearParams.depthValue      = depth;
    194    clearParams.clearStencil    = true;
    195    clearParams.stencilValue    = stencil;
    196 
    197    return clearImpl(context, clearParams);
    198 }
    199 
    200 angle::Result FramebufferD3D::readPixels(const gl::Context *context,
    201                                         const gl::Rectangle &area,
    202                                         GLenum format,
    203                                         GLenum type,
    204                                         const gl::PixelPackState &pack,
    205                                         gl::Buffer *packBuffer,
    206                                         void *pixels)
    207 {
    208    // Clip read area to framebuffer.
    209    const gl::Extents fbSize = getState().getReadPixelsAttachment(format)->getSize();
    210    const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
    211    gl::Rectangle clippedArea;
    212    if (!ClipRectangle(area, fbRect, &clippedArea))
    213    {
    214        // nothing to read
    215        return angle::Result::Continue;
    216    }
    217 
    218    const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
    219 
    220    ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
    221 
    222    GLuint outputPitch = 0;
    223    ANGLE_CHECK_GL_MATH(contextD3D,
    224                        sizedFormatInfo.computeRowPitch(type, area.width, pack.alignment,
    225                                                        pack.rowLength, &outputPitch));
    226 
    227    GLuint outputSkipBytes = 0;
    228    ANGLE_CHECK_GL_MATH(contextD3D, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, pack,
    229                                                                     false, &outputSkipBytes));
    230    outputSkipBytes += (clippedArea.x - area.x) * sizedFormatInfo.pixelBytes +
    231                       (clippedArea.y - area.y) * outputPitch;
    232 
    233    return readPixelsImpl(context, clippedArea, format, type, outputPitch, pack, packBuffer,
    234                          static_cast<uint8_t *>(pixels) + outputSkipBytes);
    235 }
    236 
    237 angle::Result FramebufferD3D::blit(const gl::Context *context,
    238                                   const gl::Rectangle &sourceArea,
    239                                   const gl::Rectangle &destArea,
    240                                   GLbitfield mask,
    241                                   GLenum filter)
    242 {
    243    const auto &glState                      = context->getState();
    244    const gl::Framebuffer *sourceFramebuffer = glState.getReadFramebuffer();
    245    const gl::Rectangle *scissor = glState.isScissorTestEnabled() ? &glState.getScissor() : nullptr;
    246    ANGLE_TRY(blitImpl(context, sourceArea, destArea, scissor, (mask & GL_COLOR_BUFFER_BIT) != 0,
    247                       (mask & GL_DEPTH_BUFFER_BIT) != 0, (mask & GL_STENCIL_BUFFER_BIT) != 0,
    248                       filter, sourceFramebuffer));
    249 
    250    return angle::Result::Continue;
    251 }
    252 
    253 gl::FramebufferStatus FramebufferD3D::checkStatus(const gl::Context *context) const
    254 {
    255    // if we have both a depth and stencil buffer, they must refer to the same object
    256    // since we only support packed_depth_stencil and not separate depth and stencil
    257    if (mState.hasSeparateDepthAndStencilAttachments())
    258    {
    259        return gl::FramebufferStatus::Incomplete(
    260            GL_FRAMEBUFFER_UNSUPPORTED,
    261            gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
    262    }
    263 
    264    // D3D11 does not allow for overlapping RenderTargetViews.
    265    // If WebGL compatibility is enabled, this has already been checked at a higher level.
    266    ASSERT(!context->isWebGL() || mState.colorAttachmentsAreUniqueImages());
    267    if (!context->isWebGL())
    268    {
    269        if (!mState.colorAttachmentsAreUniqueImages())
    270        {
    271            return gl::FramebufferStatus::Incomplete(
    272                GL_FRAMEBUFFER_UNSUPPORTED,
    273                gl::err::kFramebufferIncompleteUnsupportedNonUniqueAttachments);
    274        }
    275    }
    276 
    277    // D3D requires all render targets to have the same dimensions.
    278    if (!mState.attachmentsHaveSameDimensions())
    279    {
    280        return gl::FramebufferStatus::Incomplete(
    281            GL_FRAMEBUFFER_UNSUPPORTED,
    282            gl::err::kFramebufferIncompleteUnsupportedMissmatchedDimensions);
    283    }
    284 
    285    return gl::FramebufferStatus::Complete();
    286 }
    287 
    288 angle::Result FramebufferD3D::syncState(const gl::Context *context,
    289                                        GLenum binding,
    290                                        const gl::Framebuffer::DirtyBits &dirtyBits,
    291                                        gl::Command command)
    292 {
    293    if (!mColorAttachmentsForRender.valid())
    294    {
    295        return angle::Result::Continue;
    296    }
    297 
    298    for (auto dirtyBit : dirtyBits)
    299    {
    300        if ((dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 &&
    301             dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) ||
    302            dirtyBit == gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS)
    303        {
    304            mColorAttachmentsForRender.reset();
    305        }
    306    }
    307 
    308    return angle::Result::Continue;
    309 }
    310 
    311 const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const gl::Context *context)
    312 {
    313    gl::DrawBufferMask activeProgramOutputs =
    314        context->getState().getProgram()->getExecutable().getActiveOutputVariablesMask();
    315 
    316    if (mColorAttachmentsForRender.valid() && mCurrentActiveProgramOutputs == activeProgramOutputs)
    317    {
    318        return mColorAttachmentsForRender.value();
    319    }
    320 
    321    // Does not actually free memory
    322    gl::AttachmentList colorAttachmentsForRender;
    323    mColorAttachmentsForRenderMask.reset();
    324 
    325    const auto &colorAttachments = mState.getColorAttachments();
    326    const auto &drawBufferStates = mState.getDrawBufferStates();
    327    const auto &features         = mRenderer->getFeatures();
    328 
    329    for (size_t attachmentIndex = 0; attachmentIndex < colorAttachments.size(); ++attachmentIndex)
    330    {
    331        GLenum drawBufferState                           = drawBufferStates[attachmentIndex];
    332        const gl::FramebufferAttachment &colorAttachment = colorAttachments[attachmentIndex];
    333 
    334        if (colorAttachment.isAttached() && drawBufferState != GL_NONE &&
    335            activeProgramOutputs[attachmentIndex])
    336        {
    337            ASSERT(drawBufferState == GL_BACK ||
    338                   drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex));
    339            colorAttachmentsForRender.push_back(&colorAttachment);
    340            mColorAttachmentsForRenderMask.set(attachmentIndex);
    341        }
    342        else if (!features.mrtPerfWorkaround.enabled)
    343        {
    344            colorAttachmentsForRender.push_back(nullptr);
    345            mColorAttachmentsForRenderMask.set(attachmentIndex);
    346        }
    347    }
    348 
    349    // When rendering with no render target on D3D, two bugs lead to incorrect behavior on Intel
    350    // drivers < 4815. The rendering samples always pass neglecting discard statements in pixel
    351    // shader. We add a mock texture as render target in such case.
    352    if (mRenderer->getFeatures().addMockTextureNoRenderTarget.enabled &&
    353        colorAttachmentsForRender.empty() && activeProgramOutputs.any())
    354    {
    355        static_assert(static_cast<size_t>(activeProgramOutputs.size()) <= 32,
    356                      "Size of active program outputs should less or equal than 32.");
    357        const GLuint activeProgramLocation = static_cast<GLuint>(
    358            gl::ScanForward(static_cast<uint32_t>(activeProgramOutputs.bits())));
    359 
    360        if (mMockAttachment.isAttached() &&
    361            (mMockAttachment.getBinding() - GL_COLOR_ATTACHMENT0) == activeProgramLocation)
    362        {
    363            colorAttachmentsForRender.push_back(&mMockAttachment);
    364        }
    365        else
    366        {
    367            // Remove mock attachment to prevents us from leaking it, and the program may require
    368            // it to be attached to a new binding point.
    369            if (mMockAttachment.isAttached())
    370            {
    371                mMockAttachment.detach(context, Serial());
    372            }
    373 
    374            gl::Texture *mockTex = nullptr;
    375            // TODO(jmadill): Handle error if mock texture can't be created.
    376            (void)mRenderer->getIncompleteTexture(context, gl::TextureType::_2D, &mockTex);
    377            if (mockTex)
    378            {
    379                gl::ImageIndex index = gl::ImageIndex::Make2D(0);
    380                mMockAttachment      = gl::FramebufferAttachment(
    381                    context, GL_TEXTURE, GL_COLOR_ATTACHMENT0_EXT + activeProgramLocation, index,
    382                    mockTex, Serial());
    383                colorAttachmentsForRender.push_back(&mMockAttachment);
    384            }
    385        }
    386    }
    387 
    388    mColorAttachmentsForRender   = std::move(colorAttachmentsForRender);
    389    mCurrentActiveProgramOutputs = activeProgramOutputs;
    390 
    391    return mColorAttachmentsForRender.value();
    392 }
    393 
    394 void FramebufferD3D::destroy(const gl::Context *context)
    395 {
    396    if (mMockAttachment.isAttached())
    397    {
    398        mMockAttachment.detach(context, Serial());
    399    }
    400 }
    401 
    402 }  // namespace rx