gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
                                                GLint start, GLsizei count, GLsizei instances, unsigned int offset)
{
    if (!mBuffer)
    {
        return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized.");
    }

    gl::Buffer *buffer = attrib.buffer.get();
    int inputStride = ComputeVertexAttributeStride(attrib);
    ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext();

    D3D11_MAPPED_SUBRESOURCE mappedResource;
    HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource);
    if (FAILED(result))
    {
        return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer, HRESULT: 0x%08x.", result);
    }

    uint8_t *output = reinterpret_cast<uint8_t*>(mappedResource.pData) + offset;

    const uint8_t *input = NULL;
    if (attrib.enabled)
    {
        if (buffer)
        {
            BufferD3D *storage = BufferD3D::makeFromBuffer(buffer);
            gl::Error error = storage->getData(&input);
            if (error.isError())
            {
                return error;
            }
            input += static_cast<int>(attrib.offset);
        }
        else
        {
            input = static_cast<const uint8_t*>(attrib.pointer);
        }
    }
    else
    {
        input = reinterpret_cast<const uint8_t*>(currentValue.FloatValues);
    }

    if (instances == 0 || attrib.divisor == 0)
    {
        input += inputStride * start;
    }

    gl::VertexFormat vertexFormat(attrib, currentValue.Type);
    const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat);
    ASSERT(vertexFormatInfo.copyFunction != NULL);
    vertexFormatInfo.copyFunction(input, inputStride, count, output);

    dxContext->Unmap(mBuffer, 0);

    return gl::Error(GL_NO_ERROR);
}
angle::Result VertexDataManager::storeDynamicAttrib(const gl::Context *context,
                                                    TranslatedAttribute *translated,
                                                    GLint start,
                                                    size_t count,
                                                    GLsizei instances)
{
    ASSERT(translated->attribute && translated->binding);
    const auto &attrib  = *translated->attribute;
    const auto &binding = *translated->binding;

    gl::Buffer *buffer = binding.getBuffer().get();
    ASSERT(buffer || attrib.pointer);
    ASSERT(attrib.enabled);

    BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;

    // Instanced vertices do not apply the 'start' offset
    GLint firstVertexIndex = (binding.getDivisor() > 0 ? 0 : start);

    // Compute source data pointer
    const uint8_t *sourceData = nullptr;

    if (buffer)
    {
        ANGLE_TRY(storage->getData(context, &sourceData));
        sourceData += static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
    }
    else
    {
        // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
        // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
        sourceData = static_cast<const uint8_t*>(attrib.pointer);
    }

    unsigned int streamOffset = 0;

    translated->storage = nullptr;
    ANGLE_TRY(
        mFactory->getVertexSpaceRequired(context, attrib, binding, 1, 0, &translated->stride));

    size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count,
                                                             static_cast<size_t>(instances));

    ANGLE_TRY(mStreamingBuffer.storeDynamicAttribute(
        context, attrib, binding, translated->currentValueType, firstVertexIndex,
        static_cast<GLsizei>(totalCount), instances, &streamOffset, sourceData));

    VertexBuffer *vertexBuffer = mStreamingBuffer.getVertexBuffer();

    translated->vertexBuffer.set(vertexBuffer);
    translated->serial = vertexBuffer->getSerial();
    translated->baseOffset            = streamOffset;
    translated->usesFirstVertexOffset = false;

    return angle::Result::Continue();
}
gl::Error VertexDataManager::storeAttribute(TranslatedAttribute *translated,
                                            GLint start,
                                            GLsizei count,
                                            GLsizei instances)
{
    const gl::VertexAttribute &attrib = *translated->attribute;

    gl::Buffer *buffer = attrib.buffer.get();
    ASSERT(buffer || attrib.pointer);
    ASSERT(attrib.enabled);

    BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : NULL;
    StaticVertexBufferInterface *staticBuffer =
        storage ? storage->getStaticVertexBuffer(attrib) : NULL;
    VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer);
    bool directStorage = vertexBuffer->directStoragePossible(attrib, translated->currentValueType);

    // Instanced vertices do not apply the 'start' offset
    GLint firstVertexIndex = (instances > 0 && attrib.divisor > 0 ? 0 : start);

    translated->vertexBuffer = vertexBuffer->getVertexBuffer();

    if (directStorage)
    {
        translated->storage = storage;
        translated->serial = storage->getSerial();
        translated->stride  = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib));
        translated->offset = static_cast<unsigned int>(attrib.offset + translated->stride * firstVertexIndex);

        return gl::Error(GL_NO_ERROR);
    }

    // Compute source data pointer
    const uint8_t *sourceData = nullptr;

    if (buffer)
    {
        gl::Error error = storage->getData(&sourceData);
        if (error.isError())
        {
            return error;
        }
        sourceData += static_cast<int>(attrib.offset);
    }
    else
    {
        sourceData = static_cast<const uint8_t*>(attrib.pointer);
    }

    unsigned int streamOffset = 0;
    unsigned int outputElementSize = 0;

    if (staticBuffer)
    {
        gl::Error error = staticBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize);
        if (error.isError())
        {
            return error;
        }

        if (!staticBuffer->lookupAttribute(attrib, &streamOffset))
        {
            // Convert the entire buffer
            int totalCount =
                ElementsInBuffer(attrib, static_cast<unsigned int>(storage->getSize()));
            int startIndex = static_cast<int>(attrib.offset) /
                             static_cast<int>(ComputeVertexAttributeStride(attrib));

            error = staticBuffer->storeVertexAttributes(attrib,
                                                        translated->currentValueType,
                                                        -startIndex,
                                                        totalCount,
                                                        0,
                                                        &streamOffset,
                                                        sourceData);
            if (error.isError())
            {
                return error;
            }
        }

        unsigned int firstElementOffset =
            (static_cast<unsigned int>(attrib.offset) /
             static_cast<unsigned int>(ComputeVertexAttributeStride(attrib))) *
            outputElementSize;
        unsigned int startOffset = (instances == 0 || attrib.divisor == 0) ? firstVertexIndex * outputElementSize : 0;
        if (streamOffset + firstElementOffset + startOffset < streamOffset)
        {
            return gl::Error(GL_OUT_OF_MEMORY);
        }

        streamOffset += firstElementOffset + startOffset;
    }
    else
    {
        size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances);
        gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize);
        if (error.isError())
        {
            return error;
        }

        error = mStreamingBuffer->storeVertexAttributes(
            attrib, translated->currentValueType, firstVertexIndex,
            static_cast<GLsizei>(totalCount), instances, &streamOffset, sourceData);
        if (error.isError())
        {
            return error;
        }
    }

    translated->storage = nullptr;
    translated->serial = vertexBuffer->getSerial();
    translated->stride = outputElementSize;
    translated->offset = streamOffset;

    return gl::Error(GL_NO_ERROR);
}
Beispiel #4
0
gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
{
    const gl::Type &typeInfo = gl::GetTypeInfo(type);

    GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;

    unsigned int offset = 0;
    bool alignedOffset = false;

    BufferD3D *storage = NULL;

    if (buffer != NULL)
    {
        offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));

        storage = GetImplAs<BufferD3D>(buffer);

        switch (type)
        {
          case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
          case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
          case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
          default: UNREACHABLE(); alignedOffset = false;
        }

        ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize());

        const uint8_t *bufferData = NULL;
        gl::Error error = storage->getData(&bufferData);
        if (error.isError())
        {
            return error;
        }

        indices = bufferData + offset;
    }

    StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
    IndexBufferInterface *indexBuffer = NULL;
    bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
                         destinationIndexType == type;
    unsigned int streamOffset = 0;

    if (directStorage)
    {
        streamOffset = offset;

        if (!buffer->getIndexRangeCache()->findRange(type, offset, count, NULL, NULL))
        {
            buffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, offset);
        }
    }
    else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
    {
        indexBuffer = staticBuffer;

        if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, NULL, &streamOffset))
        {
            streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes;
            staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
        }
    }

    // Avoid D3D11's primitive restart index value
    // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
    if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3)
    {
        destinationIndexType = GL_UNSIGNED_INT;
        directStorage = false;
        indexBuffer = NULL;
    }

    const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);

    if (!directStorage && !indexBuffer)
    {
        gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer);
        if (error.isError())
        {
            return error;
        }

        unsigned int convertCount = count;

        if (staticBuffer)
        {
            if (staticBuffer->getBufferSize() == 0 && alignedOffset)
            {
                indexBuffer = staticBuffer;
                convertCount = storage->getSize() / typeInfo.bytes;
            }
            else
            {
                storage->invalidateStaticData();
                staticBuffer = NULL;
            }
        }

        ASSERT(indexBuffer);

        if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes)
        {
            return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
                             convertCount, destTypeInfo.bytes);
        }

        unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes;
        error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
        if (error.isError())
        {
            return error;
        }

        void* output = NULL;
        error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset);
        if (error.isError())
        {
            return error;
        }

        const uint8_t *dataPointer = reinterpret_cast<const uint8_t*>(indices);
        if (staticBuffer)
        {
            error = storage->getData(&dataPointer);
            if (error.isError())
            {
                return error;
            }
        }
        ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output);

        error = indexBuffer->unmapBuffer();
        if (error.isError())
        {
            return error;
        }

        if (staticBuffer)
        {
            streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes;
            staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
        }
    }

    translated->storage = directStorage ? storage : NULL;
    translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
    translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
    translated->startIndex = streamOffset / destTypeInfo.bytes;
    translated->startOffset = streamOffset;
    translated->indexType = destinationIndexType;

    if (storage)
    {
        storage->promoteStaticUsage(count * typeInfo.bytes);
    }

    return gl::Error(GL_NO_ERROR);
}
gl::Error VertexDataManager::storeDynamicAttrib(TranslatedAttribute *translated,
                                                GLint start,
                                                GLsizei count,
                                                GLsizei instances)
{
    const gl::VertexAttribute &attrib = *translated->attribute;

    gl::Buffer *buffer = attrib.buffer.get();
    ASSERT(buffer || attrib.pointer);
    ASSERT(attrib.enabled);

    BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;

    // Instanced vertices do not apply the 'start' offset
    GLint firstVertexIndex = (attrib.divisor > 0 ? 0 : start);

    // Compute source data pointer
    const uint8_t *sourceData = nullptr;

    if (buffer)
    {
        gl::Error error = storage->getData(&sourceData);
        if (error.isError())
        {
            return error;
        }
        sourceData += static_cast<int>(attrib.offset);
    }
    else
    {
        sourceData = static_cast<const uint8_t*>(attrib.pointer);
    }

    unsigned int streamOffset = 0;

    auto errorOrOutputElementSize = mFactory->getVertexSpaceRequired(attrib, 1, 0);
    if (errorOrOutputElementSize.isError())
    {
        return errorOrOutputElementSize.getError();
    }

    translated->storage = nullptr;
    translated->stride  = errorOrOutputElementSize.getResult();

    size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances);

    gl::Error error = mStreamingBuffer->storeDynamicAttribute(
        attrib, translated->currentValueType, firstVertexIndex, static_cast<GLsizei>(totalCount),
        instances, &streamOffset, sourceData);
    if (error.isError())
    {
        return error;
    }

    VertexBuffer *vertexBuffer = mStreamingBuffer->getVertexBuffer();

    translated->vertexBuffer.set(vertexBuffer);
    translated->serial = vertexBuffer->getSerial();
    translated->offset = streamOffset;

    return gl::Error(GL_NO_ERROR);
}
GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
{
    if (!mStreamingBufferShort)
    {
        return GL_OUT_OF_MEMORY;
    }

    GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
    unsigned int offset = 0;
    bool alignedOffset = false;

    BufferD3D *storage = NULL;

    if (buffer != NULL)
    {
        if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
        {
            return GL_OUT_OF_MEMORY;
        }
        offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));

        storage = BufferD3D::makeBufferD3D(buffer->getImplementation());

        switch (type)
        {
          case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
          case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
          case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
          default: UNREACHABLE(); alignedOffset = false;
        }

        unsigned int typeSize = gl::GetTypeBytes(type);

        // check for integer overflows
        if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeSize) ||
            typeSize * static_cast<unsigned int>(count) + offset < offset)
        {
            return GL_OUT_OF_MEMORY;
        }

        if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize())
        {
            return GL_INVALID_OPERATION;
        }

        indices = static_cast<const GLubyte*>(storage->getData()) + offset;
    }

    StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;

    StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
    IndexBufferInterface *indexBuffer = streamingBuffer;
    bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
                         destinationIndexType == type;
    unsigned int streamOffset = 0;

    if (directStorage)
    {
        indexBuffer = streamingBuffer;
        streamOffset = offset;

        if (!storage->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
                                                     &translated->maxIndex, NULL))
        {
            computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
            storage->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
                                                   translated->maxIndex, offset);
        }
    }
    else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
    {
        indexBuffer = staticBuffer;

        if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
                                                           &translated->maxIndex, &streamOffset))
        {
            streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
            computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
            staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
                                                         translated->maxIndex, streamOffset);
        }
    }
    else
    {
        unsigned int convertCount = count;

        if (staticBuffer)
        {
            if (staticBuffer->getBufferSize() == 0 && alignedOffset)
            {
                indexBuffer = staticBuffer;
                convertCount = storage->getSize() / gl::GetTypeBytes(type);
            }
            else
            {
                storage->invalidateStaticData();
                staticBuffer = NULL;
            }
        }

        if (!indexBuffer)
        {
            ERR("No valid index buffer.");
            return GL_INVALID_OPERATION;
        }

        unsigned int indexTypeSize = gl::GetTypeBytes(destinationIndexType);
        if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize)
        {
            ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize);
            return GL_OUT_OF_MEMORY;
        }

        unsigned int bufferSizeRequired = convertCount * indexTypeSize;
        if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
        {
            ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
            return GL_OUT_OF_MEMORY;
        }

        void* output = NULL;
        if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
        {
            ERR("Failed to map index buffer.");
            return GL_OUT_OF_MEMORY;
        }

        convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);

        if (!indexBuffer->unmapBuffer())
        {
            ERR("Failed to unmap index buffer.");
            return GL_OUT_OF_MEMORY;
        }

        computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);

        if (staticBuffer)
        {
            streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
            staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
                                                         translated->maxIndex, streamOffset);
        }
    }

    translated->storage = directStorage ? storage : NULL;
    translated->indexBuffer = indexBuffer->getIndexBuffer();
    translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
    translated->startIndex = streamOffset / gl::GetTypeBytes(destinationIndexType);
    translated->startOffset = streamOffset;

    if (storage)
    {
        storage->promoteStaticUsage(count * gl::GetTypeBytes(type));
    }

    return GL_NO_ERROR;
}
gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
                                               GLint start, GLsizei count, GLsizei instances, unsigned int offset)
{
    if (!mVertexBuffer)
    {
        return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized.");
    }

    gl::Buffer *buffer = attrib.buffer.get();

    int inputStride = gl::ComputeVertexAttributeStride(attrib);
    int elementSize = gl::ComputeVertexAttributeTypeSize(attrib);

    DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0;

    uint8_t *mapPtr = NULL;

    unsigned int mapSize;
    gl::Error error = spaceRequired(attrib, count, instances, &mapSize);
    if (error.isError())
    {
        return error;
    }

    HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast<void**>(&mapPtr), lockFlags);
    if (FAILED(result))
    {
        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result);
    }

    const uint8_t *input = NULL;
    if (attrib.enabled)
    {
        if (buffer)
        {
            BufferD3D *storage = BufferD3D::makeFromBuffer(buffer);
            ASSERT(storage);
            gl::Error error = storage->getData(&input);
            if (error.isError())
            {
                return error;
            }
            input += static_cast<int>(attrib.offset);
        }
        else
        {
            input = static_cast<const uint8_t*>(attrib.pointer);
        }
    }
    else
    {
        input = reinterpret_cast<const uint8_t*>(currentValue.FloatValues);
    }

    if (instances == 0 || attrib.divisor == 0)
    {
        input += inputStride * start;
    }

    gl::VertexFormat vertexFormat(attrib, currentValue.Type);
    const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat);
    bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0;

    if (!needsConversion && inputStride == elementSize)
    {
        size_t copySize = static_cast<size_t>(count) * static_cast<size_t>(inputStride);
        memcpy(mapPtr, input, copySize);
    }
    else
    {
        d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr);
    }

    mVertexBuffer->Unlock();

    return gl::Error(GL_NO_ERROR);
}