⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 276569 in webkit


Ignore:
Timestamp:
Apr 25, 2021, 12:17:10 PM (5 years ago)
Author:
commit-queue@webkit.org
Message:

[Metal ANGLE] support primitive restart behavior with simple data types
https://bugs.webkit.org/show_bug.cgi?id=225011

Primitive restart behavior for simple data types is not defined in Metal. Add a pre-draw pass to
create a set of restart indices, rather than re-write the index buffer. This pass avoids
storing more copies of the index buffer: instead, we cache the location of restart indices, and
use them to build draw lists.

Patch by Kyle Piddington <Kyle Piddington> on 2021-04-25
Reviewed by Dean Jackson.

  • src/libANGLE/renderer/metal/BufferMtl.h:
  • src/libANGLE/renderer/metal/BufferMtl.mm:

(rx::IndexConversionBufferMtl::IndexConversionBufferMtl):
(rx::BufferMtl::markConversionBuffersDirty):
(rx::calculateRestartRanges):
(rx::BufferMtl::getRestartIndices):

  • src/libANGLE/renderer/metal/ContextMtl.h:
  • src/libANGLE/renderer/metal/ContextMtl.mm:

(rx::ContextMtl::drawLineLoopElements):
(rx::ContextMtl::drawElementsImpl):
(rx::ContextMtl::drawElementsSimpleTypesPrimitiveRestart): Deleted.

  • src/libANGLE/renderer/metal/VertexArrayMtl.h:
  • src/libANGLE/renderer/metal/VertexArrayMtl.mm:

(rx::VertexArrayMtl::getIndexBuffer):
(rx::VertexArrayMtl::getDrawIndices):
(rx::VertexArrayMtl::convertIndexBuffer):
(rx::VertexArrayMtl::streamIndexBufferFromClient):

Location:
trunk/Source/ThirdParty/ANGLE
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/ThirdParty/ANGLE/ChangeLog

    r276568 r276569  
     12021-04-25  Kyle Piddington  <kpiddington@apple.com>
     2
     3        [Metal ANGLE] support primitive restart behavior with simple data types
     4        https://bugs.webkit.org/show_bug.cgi?id=225011
     5
     6        Primitive restart behavior for simple data types is not defined in Metal. Add a pre-draw pass to
     7        create a set of restart indices, rather than re-write the index buffer. This pass avoids
     8        storing more copies of the index buffer: instead, we cache the location of restart indices, and
     9        use them to build draw lists.
     10 
     11        Reviewed by Dean Jackson.
     12
     13        * src/libANGLE/renderer/metal/BufferMtl.h:
     14        * src/libANGLE/renderer/metal/BufferMtl.mm:
     15        (rx::IndexConversionBufferMtl::IndexConversionBufferMtl):
     16        (rx::BufferMtl::markConversionBuffersDirty):
     17        (rx::calculateRestartRanges):
     18        (rx::BufferMtl::getRestartIndices):
     19        * src/libANGLE/renderer/metal/ContextMtl.h:
     20        * src/libANGLE/renderer/metal/ContextMtl.mm:
     21        (rx::ContextMtl::drawLineLoopElements):
     22        (rx::ContextMtl::drawElementsImpl):
     23        (rx::ContextMtl::drawElementsSimpleTypesPrimitiveRestart): Deleted.
     24        * src/libANGLE/renderer/metal/VertexArrayMtl.h:
     25        * src/libANGLE/renderer/metal/VertexArrayMtl.mm:
     26        (rx::VertexArrayMtl::getIndexBuffer):
     27        (rx::VertexArrayMtl::getDrawIndices):
     28        (rx::VertexArrayMtl::convertIndexBuffer):
     29        (rx::VertexArrayMtl::streamIndexBufferFromClient):
     30
    1312021-04-25  John Cunningham  <johncunningham@apple.com>
    232
  • trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.h

    r274547 r276569  
    2525namespace rx
    2626{
     27
     28struct DrawCommandRange
     29{
     30    uint32_t count;
     31    size_t offset;
     32};
    2733struct IndexRange
    2834{
     
    6470                             gl::DrawElementsType elemType,
    6571                             bool primitiveRestartEnabled,
    66                              size_t offsetIn,
    67                              std::vector<IndexRange> restartRangesIn = std::vector<IndexRange>());
     72                             size_t offsetIn);
    6873    const gl::DrawElementsType elemType;
    6974    const size_t offset;
    7075    bool primitiveRestartEnabled;
    71     std::vector<IndexRange> restartRanges;
    7276    IndexRange getRangeForConvertedBuffer(size_t count);
    7377
     
    164168
    165169    size_t size() const { return static_cast<size_t>(mState.getSize()); }
    166 
     170   
     171    const std::vector<IndexRange> & getRestartIndices(ContextMtl * ctx, gl::DrawElementsType indexType);
     172   
    167173  private:
    168174    angle::Result setDataImpl(const gl::Context *context,
     
    200206
    201207    std::vector<IndexConversionBufferMtl> mIndexConversionBuffers;
    202 
     208   
    203209    std::vector<UniformConversionBufferMtl> mUniformConversionBuffers;
     210   
     211    bool mRestartIndicesDirty;
     212    std::vector<IndexRange> mRestartIndices;
     213   
    204214};
    205215
  • trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/BufferMtl.mm

    r274547 r276569  
    6161                                                   gl::DrawElementsType elemTypeIn,
    6262                                                   bool primitiveRestartEnabledIn,
    63                                                    size_t offsetIn,
    64                                                    std::vector<IndexRange> restartRangesIn)
     63                                                   size_t offsetIn)
    6564    : ConversionBufferMtl(context,
    6665                          kConvertedElementArrayBufferInitialSize,
     
    6867      elemType(elemTypeIn),
    6968      offset(offsetIn),
    70       primitiveRestartEnabled(primitiveRestartEnabledIn),
    71       restartRanges(restartRangesIn)
    72 
    73 {}
     69      primitiveRestartEnabled(primitiveRestartEnabledIn)
     70{
     71}
    7472
    7573IndexRange IndexConversionBufferMtl::getRangeForConvertedBuffer(size_t count)
     
    404402        buffer.convertedOffset = 0;
    405403    }
     404    mRestartIndicesDirty = true;
    406405}
    407406
     
    413412}
    414413
     414template<typename T>
     415static void calculateRestartRanges(ContextMtl* ctx, mtl::BufferRef idxBuffer, std::vector<IndexRange> * ranges)
     416{
     417    ranges->clear();
     418    T *bufferData = (T*)(idxBuffer->mapReadOnly(ctx));
     419    for(int i = 0; i < idxBuffer->size()/sizeof(T); i++)
     420    {
     421        T value = bufferData[i];
     422        if(value == std::numeric_limits<T>::max())
     423        {
     424            IndexRange newRange;
     425            newRange.restartBegin = i;
     426            //Find the end of the restart range.
     427            do
     428            {
     429                ++i;
     430                value = bufferData[i];
     431            }while (i < idxBuffer->size() && value == std::numeric_limits<T>::max());
     432            newRange.restartEnd = i-1;
     433            ranges->push_back(newRange);
     434        }
     435    }
     436}
     437
     438const std::vector<IndexRange> & BufferMtl::getRestartIndices(ContextMtl * ctx, gl::DrawElementsType indexType)
     439{
     440    if(mRestartIndicesDirty)
     441    {
     442        switch(indexType)
     443        {
     444            case gl::DrawElementsType::UnsignedByte:
     445                calculateRestartRanges<uint8_t>(ctx, getCurrentBuffer(),&mRestartIndices);
     446                break;
     447            case gl::DrawElementsType::UnsignedShort:
     448                calculateRestartRanges<uint16_t>(ctx, getCurrentBuffer(),&mRestartIndices);
     449                break;
     450            case gl::DrawElementsType::UnsignedInt:
     451                calculateRestartRanges<uint32_t>(ctx, getCurrentBuffer(),&mRestartIndices);
     452                break;
     453            default:
     454                ASSERT(false);
     455               
     456        }
     457        mRestartIndicesDirty = false;
     458    }
     459    return mRestartIndices;
     460}
    415461angle::Result BufferMtl::setDataImpl(const gl::Context *context,
    416462                                     gl::BufferBinding target,
  • trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.h

    r274547 r276569  
    158158                                                                   const GLuint *baseInstances,
    159159                                                                   GLsizei drawcount) override;
    160     angle::Result drawElementsSimpleTypesPrimitiveRestart(const gl::Context *context,
    161                                                           gl::PrimitiveMode mode,
    162                                                           GLsizei count,
    163                                                           gl::DrawElementsType type,
    164                                                           const void *indices,
    165                                                           GLsizei instances);
    166 
    167160    // Device loss
    168161    gl::GraphicsResetStatus getResetStatus() override;
  • trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/ContextMtl.mm

    r275476 r276569  
    580580                                 instances);
    581581}
    582 angle::Result ContextMtl::drawElementsSimpleTypesPrimitiveRestart(const gl::Context *context,
    583                                                                   gl::PrimitiveMode mode,
    584                                                                   GLsizei count,
    585                                                                   gl::DrawElementsType type,
    586                                                                   const void *indices,
    587                                                                   GLsizei instances)
    588 {
    589 
    590     mtl::BufferRef genIdxBuffer;
    591     uint32_t genIdxBufferOffset;
    592     uint32_t reservedIndices = count;
    593     size_t genIndicesCount;
    594     ANGLE_TRY(AllocateBufferFromPool(this, reservedIndices, &mPrimitiveRestartBuffer, &genIdxBuffer,
    595                                      &genIdxBufferOffset));
    596     switch (mode)
    597     {
    598         case gl::PrimitiveMode::Points:
    599             ANGLE_TRY(getDisplay()->getUtils().generatePrimitiveRestartPointsBuffer(
    600                 this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, true},
    601                 &genIndicesCount));
    602             break;
    603         case gl::PrimitiveMode::Lines:
    604             ANGLE_TRY(getDisplay()->getUtils().generatePrimitiveRestartLinesBuffer(
    605                 this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, true},
    606                 &genIndicesCount));
    607             break;
    608         case gl::PrimitiveMode::Triangles:
    609             ANGLE_TRY(getDisplay()->getUtils().generatePrimitiveRestartTrianglesBuffer(
    610                 this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, true},
    611                 &genIndicesCount));
    612             break;
    613         default:
    614             UNREACHABLE();
    615             return angle::Result::Stop;
    616     }
    617     ANGLE_TRY(mPrimitiveRestartBuffer.commit(this));
    618     MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
    619     if (mState.isTransformFeedbackActiveUnpaused())
    620     {
    621         ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type,
    622                             reinterpret_cast<const void *>(0), true));
    623 
    624         execDrawIndexedInstanced(mtlType, (uint32_t)genIndicesCount, MTLIndexTypeUInt32,
    625                                  genIdxBuffer, genIdxBufferOffset, instances);
    626     }
    627     ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type, indices, false));
    628 
    629     execDrawIndexedInstanced(mtlType, (uint32_t)genIndicesCount, MTLIndexTypeUInt32, genIdxBuffer,
    630                              genIdxBufferOffset, instances);
    631 
    632     return angle::Result::Continue;
    633 }
    634582
    635583angle::Result ContextMtl::drawElementsImpl(const gl::Context *context,
     
    658606    size_t convertedOffset             = 0;
    659607    gl::DrawElementsType convertedType = type;
    660     ANGLE_TRY(mVertexArray->getIndexBuffer(context, type, mode, count, indices, &idxBuffer,
     608    ANGLE_TRY(mVertexArray->getIndexBuffer(context, type, count, indices, &idxBuffer,
    661609                                           &convertedOffset, &convertedType));
    662610
     
    664612    ASSERT((convertedOffset % mtl::kIndexBufferOffsetAlignment) == 0);
    665613    uint32_t convertedCounti32 = (uint32_t)count;
     614   
     615    //Draw commands will only be broken up if transform feedback is enabled,
     616    //if the mode is a simple type, and if the buffer contained any restart
     617    //indices.
     618    const std::vector<DrawCommandRange> drawCommands = mVertexArray->getDrawIndices(context, type, convertedType, mode, convertedCounti32, convertedOffset);
     619   
    666620    if (mState.isTransformFeedbackActiveUnpaused())
    667621    {
     
    674628        {
    675629            // Normal draw
    676             mRenderEncoder.drawIndexed(mtlType, convertedCounti32, mtlIdxType, idxBuffer,
    677                                        convertedOffset);
     630            for(auto & command : drawCommands)
     631            {
     632                mRenderEncoder.drawIndexed(mtlType, command.count, mtlIdxType, idxBuffer,
     633                                           command.offset);
     634
     635            }
    678636        }
    679637        else
    680638        {
    681639            // Instanced draw
    682             execDrawIndexedInstanced(mtlType, convertedCounti32, mtlIdxType, idxBuffer,
    683                                      convertedOffset, instanceCount);
     640            for(auto & command : drawCommands)
     641            {
     642                execDrawIndexedInstanced(mtlType, command.count, mtlIdxType, idxBuffer,
     643                                     command.offset, instanceCount);
     644            }
    684645        }
    685646    }
     
    694655    {
    695656        // Normal draw
    696         mRenderEncoder.drawIndexed(mtlType, convertedCounti32, mtlIdxType, idxBuffer,
    697                                    convertedOffset);
     657        for(auto & command : drawCommands)
     658        {
     659            mRenderEncoder.drawIndexed(mtlType, command.count, mtlIdxType, idxBuffer,
     660                                   command.offset);
     661        }
    698662    }
    699663    else
    700664    {
    701665        // Instanced draw
    702         execDrawIndexedInstanced(mtlType, convertedCounti32, mtlIdxType, idxBuffer, convertedOffset,
     666        for(auto & command : drawCommands)
     667        {
     668            execDrawIndexedInstanced(mtlType, command.count, mtlIdxType, idxBuffer, command.offset,
    703669                                 instanceCount);
     670        }
    704671    }
    705672
  • trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.h

    r273200 r276569  
    5454    angle::Result getIndexBuffer(const gl::Context *glContext,
    5555                                 gl::DrawElementsType indexType,
    56                                  gl::PrimitiveMode primitiveMode,
    5756                                 size_t indexCount,
    5857                                 const void *sourcePointer,
     
    6059                                 size_t *idxBufferOffsetOut,
    6160                                 gl::DrawElementsType *indexTypeOut);
    62 
     61   
     62   
     63    std::vector<DrawCommandRange> getDrawIndices(const gl::Context *glContext,
     64                                                 gl::DrawElementsType originalIndexType,
     65                                                 gl::DrawElementsType indexType,
     66                                                 gl::PrimitiveMode primitiveMode,
     67                                                 uint32_t indexCount,
     68                                                 size_t offset);
     69   
    6370    // Use to emulate instanced draw for instance <instanceId>.
    6471    // The typical call sequence for emulated instance draw is:
     
    8693    angle::Result convertIndexBuffer(const gl::Context *glContext,
    8794                                     gl::DrawElementsType indexType,
    88                                      gl::PrimitiveMode mode,
    8995                                     size_t offset,
    9096                                     mtl::BufferRef *idxBufferOut,
     
    9298    angle::Result streamIndexBufferFromClient(const gl::Context *glContext,
    9399                                              gl::DrawElementsType indexType,
    94                                               gl::PrimitiveMode primitiveType,
    95100                                              size_t indexCount,
    96101                                              const void *sourcePointer,
     
    128133                                         bool isExpandingComponents,
    129134                                         ConversionBufferMtl *conversion);
    130 
     135   
    131136    // These can point to real BufferMtl or converted buffer in mConvertedArrayBufferHolders
    132137    gl::AttribArray<BufferHolderMtl *> mCurrentArrayBuffers;
  • trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/VertexArrayMtl.mm

    r274547 r276569  
    8080                              gl::DrawElementsType indexType,
    8181                              size_t indexCount,
    82                               gl::PrimitiveMode mode,
    8382                              bool primitiveRestartEnabled,
    8483                              mtl::BufferRef *bufferOut,
     
    697696angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context,
    698697                                             gl::DrawElementsType type,
    699                                              gl::PrimitiveMode mode,
    700698                                             size_t count,
    701699                                             const void *indices,
     
    709707    if (!glElementArrayBuffer)
    710708    {
    711         ANGLE_TRY(streamIndexBufferFromClient(context, type, mode, count, indices, idxBufferOut,
     709        ANGLE_TRY(streamIndexBufferFromClient(context, type, count, indices, idxBufferOut,
    712710                                              idxBufferOffsetOut));
    713711    }
     
    718716        if (needConversion)
    719717        {
    720             ANGLE_TRY(convertIndexBuffer(context, type, mode, convertedOffset, idxBufferOut,
     718            ANGLE_TRY(convertIndexBuffer(context, type, convertedOffset, idxBufferOut,
    721719                                         idxBufferOffsetOut));
    722720        }
     
    740738}
    741739
     740std::vector<DrawCommandRange> VertexArrayMtl::getDrawIndices(const gl::Context *glContext,
     741                             gl::DrawElementsType originalIndexType,
     742                             gl::DrawElementsType indexType,
     743                             gl::PrimitiveMode primitiveMode,
     744                             uint32_t indexCount,
     745                             size_t offset)
     746{
     747    ContextMtl *contextMtl   = mtl::GetImpl(glContext);
     748    std::vector<DrawCommandRange> drawCommands;
     749   
     750    BufferMtl *idxBuffer     = mtl::GetImpl(getState().getElementArrayBuffer());
     751    const std::vector<IndexRange> restartIndices = idxBuffer->getRestartIndices(contextMtl, originalIndexType);
     752    bool isSimpleType =
     753        primitiveMode == gl::PrimitiveMode::Points ||
     754        primitiveMode == gl::PrimitiveMode::Lines ||
     755        primitiveMode == gl::PrimitiveMode::Triangles;
     756    //If prim restart isn't enabled, or we're drawing a restartable type, or there's no restarts, skip breaking up draw commands.
     757    if(restartIndices.size() == 0 || !isSimpleType || !glContext->getState().isPrimitiveRestartEnabled())
     758    {
     759        drawCommands.push_back({indexCount, offset});
     760        return drawCommands;
     761    }
     762    else
     763    {
     764        //Reminder, offset is in bytes, not elements.
     765        //Slice draw commands based off of indices.
     766        int nIndicesPerPrimitive;
     767        switch(primitiveMode)
     768        {
     769            case gl::PrimitiveMode::Points:
     770                nIndicesPerPrimitive = 1;
     771                break;
     772            case gl::PrimitiveMode::Lines:
     773                nIndicesPerPrimitive = 2;
     774                break;
     775            case gl::PrimitiveMode::Triangles:
     776                nIndicesPerPrimitive = 3;
     777                break;
     778            default:
     779                //Unreachable
     780                ASSERT(FALSE);
     781                return drawCommands;
     782        }
     783        const GLuint indexTypeBytes        = gl::GetDrawElementsTypeSize(indexType);
     784        uint32_t indicesLeft = indexCount;
     785        size_t currentIndexOffset = offset / indexTypeBytes;
     786       
     787        for(auto & range : restartIndices)
     788        {
     789            if(range.restartBegin > currentIndexOffset)
     790            {
     791                int64_t nIndicesInSlice = ((int64_t)range.restartBegin - currentIndexOffset) - ((int64_t) range.restartBegin - currentIndexOffset) % nIndicesPerPrimitive;
     792                size_t restartSize = (range.restartEnd - range.restartBegin) + 1;
     793                if(nIndicesInSlice > nIndicesPerPrimitive)
     794                    drawCommands.push_back({(uint32_t)nIndicesInSlice, currentIndexOffset * indexTypeBytes});
     795                //Account for dropped indices due to incomplete primitives.
     796                size_t indicesUsed = ( (range.restartBegin + restartSize) - currentIndexOffset);
     797                if(indicesLeft <= indicesUsed)
     798                {
     799                    indicesLeft = 0;
     800                }
     801                else
     802                {
     803                    indicesLeft -= indicesUsed;
     804                }
     805                currentIndexOffset = (size_t)(range.restartBegin + restartSize);
     806            }
     807            //If the initial offset into the index buffer is within a restart zone, move to the end of the restart zone.
     808            else if(range.restartEnd >= currentIndexOffset)
     809            {
     810                size_t restartSize = (range.restartEnd - currentIndexOffset) + 1;
     811                if(indicesLeft <= restartSize)
     812                {
     813                    indicesLeft = 0;
     814                }
     815                else
     816                {
     817                    indicesLeft -= restartSize;
     818                }
     819                currentIndexOffset = (size_t)(currentIndexOffset + restartSize);
     820            }
     821           
     822        }
     823        if(indicesLeft >= nIndicesPerPrimitive)
     824            drawCommands.push_back({indicesLeft, currentIndexOffset * indexTypeBytes});
     825        return drawCommands;
     826    }
     827   
     828}
     829
     830
    742831angle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext,
    743832                                                 gl::DrawElementsType indexType,
    744                                                  gl::PrimitiveMode mode,
    745833                                                 size_t offset,
    746834                                                 mtl::BufferRef *idxBufferOut,
     
    780868        ANGLE_TRY(StreamIndexData(contextMtl, &conversion->data,
    781869                                  idxBuffer->getClientShadowCopyData(contextMtl) + offsetModulo,
    782                                   indexType, indexCount, mode, glState.isPrimitiveRestartEnabled(),
     870                                  indexType, indexCount, glState.isPrimitiveRestartEnabled(),
    783871                                  &conversion->convertedBuffer, &conversion->convertedOffset));
    784872    }
     
    788876                                        conversion));
    789877    }
    790 
     878    //Calculate ranges for prim restart simple types.
    791879    *idxBufferOut       = conversion->convertedBuffer;
    792880    *idxBufferOffsetOut = conversion->convertedOffset + alignedOffset;
     
    830918angle::Result VertexArrayMtl::streamIndexBufferFromClient(const gl::Context *context,
    831919                                                          gl::DrawElementsType indexType,
    832                                                           gl::PrimitiveMode mode,
    833920                                                          size_t indexCount,
    834921                                                          const void *sourcePointer,
     
    840927
    841928    auto srcData = static_cast<const uint8_t *>(sourcePointer);
    842     ANGLE_TRY(StreamIndexData(contextMtl, &mDynamicIndexData, srcData, indexType, indexCount, mode,
     929    ANGLE_TRY(StreamIndexData(contextMtl, &mDynamicIndexData, srcData, indexType, indexCount,
    843930                              context->getState().isPrimitiveRestartEnabled(), idxBufferOut,
    844931                              idxBufferOffsetOut));
Note: See TracChangeset for help on using the changeset viewer.