tor-browser

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

IndexDataManager.cpp (13015B)


      1 //
      2 // Copyright 2002 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 // IndexDataManager.cpp: Defines the IndexDataManager, a class that
      8 // runs the Buffer translation process for index buffers.
      9 
     10 #include "libANGLE/renderer/d3d/IndexDataManager.h"
     11 
     12 #include "common/utilities.h"
     13 #include "libANGLE/Buffer.h"
     14 #include "libANGLE/Context.h"
     15 #include "libANGLE/VertexArray.h"
     16 #include "libANGLE/formatutils.h"
     17 #include "libANGLE/renderer/d3d/BufferD3D.h"
     18 #include "libANGLE/renderer/d3d/ContextD3D.h"
     19 #include "libANGLE/renderer/d3d/IndexBuffer.h"
     20 
     21 namespace rx
     22 {
     23 
     24 namespace
     25 {
     26 
     27 template <typename InputT, typename DestT>
     28 void ConvertIndexArray(const void *input,
     29                       gl::DrawElementsType sourceType,
     30                       void *output,
     31                       gl::DrawElementsType destinationType,
     32                       GLsizei count,
     33                       bool usePrimitiveRestartFixedIndex)
     34 {
     35    const InputT *in = static_cast<const InputT *>(input);
     36    DestT *out       = static_cast<DestT *>(output);
     37 
     38    if (usePrimitiveRestartFixedIndex)
     39    {
     40        InputT srcRestartIndex = static_cast<InputT>(gl::GetPrimitiveRestartIndex(sourceType));
     41        DestT destRestartIndex = static_cast<DestT>(gl::GetPrimitiveRestartIndex(destinationType));
     42        for (GLsizei i = 0; i < count; i++)
     43        {
     44            out[i] = (in[i] == srcRestartIndex ? destRestartIndex : static_cast<DestT>(in[i]));
     45        }
     46    }
     47    else
     48    {
     49        for (GLsizei i = 0; i < count; i++)
     50        {
     51            out[i] = static_cast<DestT>(in[i]);
     52        }
     53    }
     54 }
     55 
     56 void ConvertIndices(gl::DrawElementsType sourceType,
     57                    gl::DrawElementsType destinationType,
     58                    const void *input,
     59                    GLsizei count,
     60                    void *output,
     61                    bool usePrimitiveRestartFixedIndex)
     62 {
     63    if (sourceType == destinationType)
     64    {
     65        const GLuint dstTypeSize = gl::GetDrawElementsTypeSize(destinationType);
     66        memcpy(output, input, count * dstTypeSize);
     67        return;
     68    }
     69 
     70    if (sourceType == gl::DrawElementsType::UnsignedByte)
     71    {
     72        ASSERT(destinationType == gl::DrawElementsType::UnsignedShort);
     73        ConvertIndexArray<GLubyte, GLushort>(input, sourceType, output, destinationType, count,
     74                                             usePrimitiveRestartFixedIndex);
     75    }
     76    else if (sourceType == gl::DrawElementsType::UnsignedShort)
     77    {
     78        ASSERT(destinationType == gl::DrawElementsType::UnsignedInt);
     79        ConvertIndexArray<GLushort, GLuint>(input, sourceType, output, destinationType, count,
     80                                            usePrimitiveRestartFixedIndex);
     81    }
     82    else
     83        UNREACHABLE();
     84 }
     85 
     86 angle::Result StreamInIndexBuffer(const gl::Context *context,
     87                                  IndexBufferInterface *buffer,
     88                                  const void *data,
     89                                  unsigned int count,
     90                                  gl::DrawElementsType srcType,
     91                                  gl::DrawElementsType dstType,
     92                                  bool usePrimitiveRestartFixedIndex,
     93                                  unsigned int *offset)
     94 {
     95    const GLuint dstTypeBytesShift = gl::GetDrawElementsTypeShift(dstType);
     96 
     97    bool check = (count > (std::numeric_limits<unsigned int>::max() >> dstTypeBytesShift));
     98    ANGLE_CHECK(GetImplAs<ContextD3D>(context), !check,
     99                "Reserving indices exceeds the maximum buffer size.", GL_OUT_OF_MEMORY);
    100 
    101    unsigned int bufferSizeRequired = count << dstTypeBytesShift;
    102    ANGLE_TRY(buffer->reserveBufferSpace(context, bufferSizeRequired, dstType));
    103 
    104    void *output = nullptr;
    105    ANGLE_TRY(buffer->mapBuffer(context, bufferSizeRequired, &output, offset));
    106 
    107    ConvertIndices(srcType, dstType, data, count, output, usePrimitiveRestartFixedIndex);
    108 
    109    ANGLE_TRY(buffer->unmapBuffer(context));
    110    return angle::Result::Continue;
    111 }
    112 }  // anonymous namespace
    113 
    114 // IndexDataManager implementation.
    115 IndexDataManager::IndexDataManager(BufferFactoryD3D *factory)
    116    : mFactory(factory), mStreamingBufferShort(), mStreamingBufferInt()
    117 {}
    118 
    119 IndexDataManager::~IndexDataManager() {}
    120 
    121 void IndexDataManager::deinitialize()
    122 {
    123    mStreamingBufferShort.reset();
    124    mStreamingBufferInt.reset();
    125 }
    126 
    127 // This function translates a GL-style indices into DX-style indices, with their description
    128 // returned in translated.
    129 // GL can specify vertex data in immediate mode (pointer to CPU array of indices), which is not
    130 // possible in DX and requires streaming (Case 1). If the GL indices are specified with a buffer
    131 // (Case 2), in a format supported by DX (subcase a) then all is good.
    132 // When we have a buffer with an unsupported format (subcase b) then we need to do some translation:
    133 // we will start by falling back to streaming, and after a while will start using a static
    134 // translated copy of the index buffer.
    135 angle::Result IndexDataManager::prepareIndexData(const gl::Context *context,
    136                                                 gl::DrawElementsType srcType,
    137                                                 gl::DrawElementsType dstType,
    138                                                 GLsizei count,
    139                                                 gl::Buffer *glBuffer,
    140                                                 const void *indices,
    141                                                 TranslatedIndexData *translated)
    142 {
    143    GLuint srcTypeBytes = gl::GetDrawElementsTypeSize(srcType);
    144    GLuint srcTypeShift = gl::GetDrawElementsTypeShift(srcType);
    145    GLuint dstTypeShift = gl::GetDrawElementsTypeShift(dstType);
    146 
    147    BufferD3D *buffer = glBuffer ? GetImplAs<BufferD3D>(glBuffer) : nullptr;
    148 
    149    translated->indexType                 = dstType;
    150    translated->srcIndexData.srcBuffer    = buffer;
    151    translated->srcIndexData.srcIndices   = indices;
    152    translated->srcIndexData.srcIndexType = srcType;
    153    translated->srcIndexData.srcCount     = count;
    154 
    155    // Context can be nullptr in perf tests.
    156    bool primitiveRestartFixedIndexEnabled =
    157        context ? context->getState().isPrimitiveRestartEnabled() : false;
    158 
    159    // Case 1: the indices are passed by pointer, which forces the streaming of index data
    160    if (glBuffer == nullptr)
    161    {
    162        translated->storage = nullptr;
    163        return streamIndexData(context, indices, count, srcType, dstType,
    164                               primitiveRestartFixedIndexEnabled, translated);
    165    }
    166 
    167    // Case 2: the indices are already in a buffer
    168    unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
    169    ASSERT(srcTypeBytes * static_cast<unsigned int>(count) + offset <= buffer->getSize());
    170 
    171    bool offsetAligned = IsOffsetAligned(srcType, offset);
    172 
    173    // Case 2a: the buffer can be used directly
    174    if (offsetAligned && buffer->supportsDirectBinding() && dstType == srcType)
    175    {
    176        translated->storage     = buffer;
    177        translated->indexBuffer = nullptr;
    178        translated->serial      = buffer->getSerial();
    179        translated->startIndex  = (offset >> srcTypeShift);
    180        translated->startOffset = offset;
    181        return angle::Result::Continue;
    182    }
    183 
    184    translated->storage = nullptr;
    185 
    186    // Case 2b: use a static translated copy or fall back to streaming
    187    StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();
    188 
    189    bool staticBufferInitialized = staticBuffer && staticBuffer->getBufferSize() != 0;
    190    bool staticBufferUsable =
    191        staticBuffer && offsetAligned && staticBuffer->getIndexType() == dstType;
    192 
    193    if (staticBufferInitialized && !staticBufferUsable)
    194    {
    195        buffer->invalidateStaticData(context);
    196        staticBuffer = nullptr;
    197    }
    198 
    199    if (staticBuffer == nullptr || !offsetAligned)
    200    {
    201        const uint8_t *bufferData = nullptr;
    202        ANGLE_TRY(buffer->getData(context, &bufferData));
    203        ASSERT(bufferData != nullptr);
    204 
    205        ANGLE_TRY(streamIndexData(context, bufferData + offset, count, srcType, dstType,
    206                                  primitiveRestartFixedIndexEnabled, translated));
    207        buffer->promoteStaticUsage(context, count << srcTypeShift);
    208    }
    209    else
    210    {
    211        if (!staticBufferInitialized)
    212        {
    213            const uint8_t *bufferData = nullptr;
    214            ANGLE_TRY(buffer->getData(context, &bufferData));
    215            ASSERT(bufferData != nullptr);
    216 
    217            unsigned int convertCount =
    218                static_cast<unsigned int>(buffer->getSize()) >> srcTypeShift;
    219            ANGLE_TRY(StreamInIndexBuffer(context, staticBuffer, bufferData, convertCount, srcType,
    220                                          dstType, primitiveRestartFixedIndexEnabled, nullptr));
    221        }
    222        ASSERT(offsetAligned && staticBuffer->getIndexType() == dstType);
    223 
    224        translated->indexBuffer = staticBuffer->getIndexBuffer();
    225        translated->serial      = staticBuffer->getSerial();
    226        translated->startIndex  = (offset >> srcTypeShift);
    227        translated->startOffset = (offset >> srcTypeShift) << dstTypeShift;
    228    }
    229 
    230    return angle::Result::Continue;
    231 }
    232 
    233 angle::Result IndexDataManager::streamIndexData(const gl::Context *context,
    234                                                const void *data,
    235                                                unsigned int count,
    236                                                gl::DrawElementsType srcType,
    237                                                gl::DrawElementsType dstType,
    238                                                bool usePrimitiveRestartFixedIndex,
    239                                                TranslatedIndexData *translated)
    240 {
    241    const GLuint dstTypeShift = gl::GetDrawElementsTypeShift(dstType);
    242 
    243    IndexBufferInterface *indexBuffer = nullptr;
    244    ANGLE_TRY(getStreamingIndexBuffer(context, dstType, &indexBuffer));
    245    ASSERT(indexBuffer != nullptr);
    246 
    247    unsigned int offset;
    248    ANGLE_TRY(StreamInIndexBuffer(context, indexBuffer, data, count, srcType, dstType,
    249                                  usePrimitiveRestartFixedIndex, &offset));
    250 
    251    translated->indexBuffer = indexBuffer->getIndexBuffer();
    252    translated->serial      = indexBuffer->getSerial();
    253    translated->startIndex  = (offset >> dstTypeShift);
    254    translated->startOffset = offset;
    255 
    256    return angle::Result::Continue;
    257 }
    258 
    259 angle::Result IndexDataManager::getStreamingIndexBuffer(const gl::Context *context,
    260                                                        gl::DrawElementsType destinationIndexType,
    261                                                        IndexBufferInterface **outBuffer)
    262 {
    263    ASSERT(outBuffer);
    264    ASSERT(destinationIndexType == gl::DrawElementsType::UnsignedShort ||
    265           destinationIndexType == gl::DrawElementsType::UnsignedInt);
    266 
    267    auto &streamingBuffer = (destinationIndexType == gl::DrawElementsType::UnsignedInt)
    268                                ? mStreamingBufferInt
    269                                : mStreamingBufferShort;
    270 
    271    if (!streamingBuffer)
    272    {
    273        StreamingBuffer newBuffer(new StreamingIndexBufferInterface(mFactory));
    274        ANGLE_TRY(newBuffer->reserveBufferSpace(context, INITIAL_INDEX_BUFFER_SIZE,
    275                                                destinationIndexType));
    276        streamingBuffer = std::move(newBuffer);
    277    }
    278 
    279    *outBuffer = streamingBuffer.get();
    280    return angle::Result::Continue;
    281 }
    282 
    283 angle::Result GetIndexTranslationDestType(const gl::Context *context,
    284                                          GLsizei indexCount,
    285                                          gl::DrawElementsType indexType,
    286                                          const void *indices,
    287                                          bool usePrimitiveRestartWorkaround,
    288                                          gl::DrawElementsType *destTypeOut)
    289 {
    290    // Avoid D3D11's primitive restart index value
    291    // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
    292    if (usePrimitiveRestartWorkaround)
    293    {
    294        // Conservatively assume we need to translate the indices for draw indirect.
    295        // This is a bit of a trick. We assume the count for an indirect draw is zero.
    296        if (indexCount == 0)
    297        {
    298            *destTypeOut = gl::DrawElementsType::UnsignedInt;
    299            return angle::Result::Continue;
    300        }
    301 
    302        gl::IndexRange indexRange;
    303        ANGLE_TRY(context->getState().getVertexArray()->getIndexRange(
    304            context, indexType, indexCount, indices, &indexRange));
    305        if (indexRange.end == gl::GetPrimitiveRestartIndex(indexType))
    306        {
    307            *destTypeOut = gl::DrawElementsType::UnsignedInt;
    308            return angle::Result::Continue;
    309        }
    310    }
    311 
    312    *destTypeOut = (indexType == gl::DrawElementsType::UnsignedInt)
    313                       ? gl::DrawElementsType::UnsignedInt
    314                       : gl::DrawElementsType::UnsignedShort;
    315    return angle::Result::Continue;
    316 }
    317 
    318 }  // namespace rx