Edit

kc3-lang/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp

Branch :

  • Show log

    Commit

  • Author : Jiawei-Shao
    Date : 2016-12-09 16:38:02
    Hash : 2597fb64
    Message : ES31: Refactor VertexArray for Vertex Attrib Binding OpenGL ES3.1 feature Vertex Attrib Binding requires vertex arrays should be split into two arrays: 1. an array of vertex buffer binding points, each of which specifies: - a bound buffer object, - a starting offset for vertex attribute data in that buffer object, - a stride used by all attributes using that binding point, - a frequency divisor used by all attributes using that binding point. 2. an array of generic vertex attribute format information records, each of which specifies: - a reference to one of the new buffer binding points above, - a component count and format, and a normalization flag for the attribute data, - the offset of the attribute data relative to the base offset of each vertex found at the associated binding point. Current ANGLE implementation simply uses a struct to represent a vertex attribute object, which does not meet the requirements above. This patch aims to be the the basis of the implementation of all ES3.1 Vertex Attrib Binding APIs by refactoring the struct VertexAttribute and the class VertexArray to fit the new data layout and ensuring all current functionality is retained. BUG=angleproject:1593 TEST=angle_unittests, angle_end2end_tests, gpu_unittests Change-Id: Ieb41f1bf503f815fd0476d2ea045dcb863465254 Reviewed-on: https://chromium-review.googlesource.com/418880 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/renderer/d3d/BufferD3D.cpp
  • //
    // Copyright 2014 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // BufferD3D.cpp Defines common functionality between the Buffer9 and Buffer11 classes.
    
    #include "libANGLE/renderer/d3d/BufferD3D.h"
    
    #include "common/mathutil.h"
    #include "common/utilities.h"
    #include "libANGLE/renderer/d3d/IndexBuffer.h"
    #include "libANGLE/renderer/d3d/VertexBuffer.h"
    #include "libANGLE/renderer/d3d/RendererD3D.h"
    
    namespace rx
    {
    
    unsigned int BufferD3D::mNextSerial = 1;
    
    BufferD3D::BufferD3D(const gl::BufferState &state, BufferFactoryD3D *factory)
        : BufferImpl(state),
          mFactory(factory),
          mStaticIndexBuffer(nullptr),
          mStaticBufferCacheTotalSize(0),
          mStaticVertexBufferOutOfDate(false),
          mUnmodifiedDataUse(0),
          mUsage(D3DBufferUsage::STATIC)
    {
        updateSerial();
    }
    
    BufferD3D::~BufferD3D()
    {
        SafeDelete(mStaticIndexBuffer);
    }
    
    void BufferD3D::emptyStaticBufferCache()
    {
        mStaticVertexBuffers.clear();
        mStaticBufferCacheTotalSize = 0;
    }
    
    void BufferD3D::updateSerial()
    {
        mSerial = mNextSerial++;
    }
    
    void BufferD3D::updateD3DBufferUsage(GLenum usage)
    {
        switch (usage)
        {
            case GL_STATIC_DRAW:
            case GL_STATIC_READ:
            case GL_STATIC_COPY:
                mUsage = D3DBufferUsage::STATIC;
                initializeStaticData();
                break;
    
            case GL_STREAM_DRAW:
            case GL_STREAM_READ:
            case GL_STREAM_COPY:
            case GL_DYNAMIC_READ:
            case GL_DYNAMIC_COPY:
            case GL_DYNAMIC_DRAW:
                mUsage = D3DBufferUsage::DYNAMIC;
                break;
            default:
                UNREACHABLE();
        }
    }
    
    void BufferD3D::initializeStaticData()
    {
        if (mStaticVertexBuffers.empty())
        {
            auto newStaticBuffer = new StaticVertexBufferInterface(mFactory);
            mStaticVertexBuffers.push_back(
                std::unique_ptr<StaticVertexBufferInterface>(newStaticBuffer));
        }
        if (!mStaticIndexBuffer)
        {
            mStaticIndexBuffer = new StaticIndexBufferInterface(mFactory);
        }
    }
    
    StaticIndexBufferInterface *BufferD3D::getStaticIndexBuffer()
    {
        return mStaticIndexBuffer;
    }
    
    StaticVertexBufferInterface *BufferD3D::getStaticVertexBuffer(const gl::VertexAttribute &attribute,
                                                                  const gl::VertexBinding &binding)
    {
        if (mStaticVertexBuffers.empty())
        {
            // Early out if there aren't any static buffers at all
            return nullptr;
        }
    
        // Early out, the attribute can be added to mStaticVertexBuffer.
        if (mStaticVertexBuffers.size() == 1 && mStaticVertexBuffers[0]->empty())
        {
            return mStaticVertexBuffers[0].get();
        }
    
        // Cache size limiting: track the total allocated buffer sizes.
        size_t currentTotalSize = 0;
    
        // At this point, see if any of the existing static buffers contains the attribute data
        // If there is a cached static buffer that already contains the attribute, then return it
        for (const auto &staticBuffer : mStaticVertexBuffers)
        {
            if (staticBuffer->matchesAttribute(attribute, binding))
            {
                return staticBuffer.get();
            }
    
            currentTotalSize += staticBuffer->getBufferSize();
        }
    
        // Cache size limiting: Clean-up threshold is four times the base buffer size, with a minimum.
        ASSERT(getSize() < std::numeric_limits<size_t>::max() / 4u);
        size_t sizeThreshold = std::max(getSize() * 4u, static_cast<size_t>(0x1000u));
    
        // If we're past the threshold, clear the buffer cache. Note that this will release buffers
        // that are currenly bound, and in an edge case can even translate the same attribute twice
        // in the same draw call. It will not delete currently bound buffers, however, because they
        // are ref counted.
        if (currentTotalSize > sizeThreshold)
        {
            emptyStaticBufferCache();
        }
    
        // At this point, we must create a new static buffer for the attribute data.
        auto newStaticBuffer = new StaticVertexBufferInterface(mFactory);
        newStaticBuffer->setAttribute(attribute, binding);
        mStaticVertexBuffers.push_back(std::unique_ptr<StaticVertexBufferInterface>(newStaticBuffer));
        return newStaticBuffer;
    }
    
    void BufferD3D::invalidateStaticData()
    {
        emptyStaticBufferCache();
    
        if (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0)
        {
            SafeDelete(mStaticIndexBuffer);
        }
    
        // If the buffer was created with a static usage then we recreate the static
        // buffers so that they are populated the next time we use this buffer.
        if (mUsage == D3DBufferUsage::STATIC)
        {
            initializeStaticData();
        }
    
        mUnmodifiedDataUse = 0;
    }
    
    // Creates static buffers if sufficient used data has been left unmodified
    void BufferD3D::promoteStaticUsage(int dataSize)
    {
        if (mUsage == D3DBufferUsage::DYNAMIC)
        {
            mUnmodifiedDataUse += dataSize;
    
            if (mUnmodifiedDataUse > 3 * getSize())
            {
                updateD3DBufferUsage(GL_STATIC_DRAW);
            }
        }
    }
    
    gl::Error BufferD3D::getIndexRange(GLenum type,
                                       size_t offset,
                                       size_t count,
                                       bool primitiveRestartEnabled,
                                       gl::IndexRange *outRange)
    {
        const uint8_t *data = nullptr;
        ANGLE_TRY(getData(&data));
    
        *outRange = gl::ComputeIndexRange(type, data + offset, count, primitiveRestartEnabled);
        return gl::NoError();
    }
    
    }  // namespace rx