Edit

kc3-lang/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2015-06-30 10:04:29
    Hash : 476682e6
    Message : Use std::vector for TranslatedAttribs. This allows us to cache a std::vector between calls, and avoids us calling allocation/constructors for locals, which saves us some time. It also allows us to use the vector's size to limit the range of attribs we look at. BUG=angleproject:959 Change-Id: I799ed6c92fa8fca96e92e235b125a11d2d551aab Reviewed-on: https://chromium-review.googlesource.com/277286 Reviewed-by: Geoff Lang <geofflang@chromium.org> Tested-by: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp
  • //
    // Copyright (c) 2012 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.
    //
    
    // VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations.
    
    #include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h"
    #include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
    #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
    #include "libANGLE/Program.h"
    #include "libANGLE/VertexAttribute.h"
    
    namespace rx
    {
    
    VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
    {
        for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
        {
            mVertexDeclCache[i].vertexDeclaration = NULL;
            mVertexDeclCache[i].lruCount = 0;
        }
    
        for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
        {
            mAppliedVBs[i].serial = 0;
        }
    
        mLastSetVDecl = NULL;
        mInstancingEnabled = true;
    }
    
    VertexDeclarationCache::~VertexDeclarationCache()
    {
        for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
        {
            SafeRelease(mVertexDeclCache[i].vertexDeclaration);
        }
    }
    
    gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device,
                                                       const std::vector<TranslatedAttribute> &attributes,
                                                       gl::Program *program,
                                                       GLsizei instances,
                                                       GLsizei *repeatDraw)
    {
        ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size());
    
        *repeatDraw = 1;
    
        const size_t invalidAttribIndex = attributes.size();
        size_t indexedAttribute = invalidAttribIndex;
        size_t instancedAttribute = invalidAttribIndex;
    
        if (instances == 0)
        {
            for (size_t i = 0; i < attributes.size(); ++i)
            {
                if (attributes[i].divisor != 0)
                {
                    // If a divisor is set, it still applies even if an instanced draw was not used, so treat
                    // as a single-instance draw.
                    instances = 1;
                    break;
                }
            }
        }
    
        if (instances > 0)
        {
            // Find an indexed attribute to be mapped to D3D stream 0
            for (size_t i = 0; i < attributes.size(); i++)
            {
                if (attributes[i].active)
                {
                    if (indexedAttribute == invalidAttribIndex && attributes[i].divisor == 0)
                    {
                        indexedAttribute = i;
                    }
                    else if (instancedAttribute == invalidAttribIndex && attributes[i].divisor != 0)
                    {
                        instancedAttribute = i;
                    }
                    if (indexedAttribute != invalidAttribIndex && instancedAttribute != invalidAttribIndex)
                        break;   // Found both an indexed and instanced attribute
                }
            }
    
            // The validation layer checks that there is at least one active attribute with a zero divisor as per
            // the GL_ANGLE_instanced_arrays spec.
            ASSERT(indexedAttribute != invalidAttribIndex);
        }
    
        D3DCAPS9 caps;
        device->GetDeviceCaps(&caps);
    
        D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
        D3DVERTEXELEMENT9 *element = &elements[0];
    
        for (size_t i = 0; i < attributes.size(); i++)
        {
            if (attributes[i].active)
            {
                // Directly binding the storage buffer is not supported for d3d9
                ASSERT(attributes[i].storage == NULL);
    
                int stream = i;
    
                if (instances > 0)
                {
                    // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
                    if (instancedAttribute == invalidAttribIndex)
                    {
                        *repeatDraw = instances;
                    }
                    else
                    {
                        if (i == indexedAttribute)
                        {
                            stream = 0;
                        }
                        else if (i == 0)
                        {
                            stream = indexedAttribute;
                        }
    
                        UINT frequency = 1;
                        
                        if (attributes[i].divisor == 0)
                        {
                            frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
                        }
                        else
                        {
                            frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
                        }
                        
                        device->SetStreamSourceFreq(stream, frequency);
                        mInstancingEnabled = true;
                    }
                }
    
                VertexBuffer9 *vertexBuffer = GetAs<VertexBuffer9>(attributes[i].vertexBuffer);
    
                if (mAppliedVBs[stream].serial != attributes[i].serial ||
                    mAppliedVBs[stream].stride != attributes[i].stride ||
                    mAppliedVBs[stream].offset != attributes[i].offset)
                {
                    device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride);
                    mAppliedVBs[stream].serial = attributes[i].serial;
                    mAppliedVBs[stream].stride = attributes[i].stride;
                    mAppliedVBs[stream].offset = attributes[i].offset;
                }
    
                gl::VertexFormat vertexFormat(*attributes[i].attribute, GL_FLOAT);
                const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexFormat);
    
                element->Stream = static_cast<WORD>(stream);
                element->Offset = 0;
                element->Type = static_cast<BYTE>(d3d9VertexInfo.nativeFormat);
                element->Method = D3DDECLMETHOD_DEFAULT;
                element->Usage = D3DDECLUSAGE_TEXCOORD;
                element->UsageIndex = static_cast<BYTE>(program->getSemanticIndex(i));
                element++;
            }
        }
    
        if (instances == 0 || instancedAttribute == invalidAttribIndex)
        {
            if (mInstancingEnabled)
            {
                for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
                {
                    device->SetStreamSourceFreq(i, 1);
                }
    
                mInstancingEnabled = false;
            }
        }
    
        static const D3DVERTEXELEMENT9 end = D3DDECL_END();
        *(element++) = end;
    
        for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
        {
            VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
            if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
            {
                entry->lruCount = ++mMaxLru;
                if(entry->vertexDeclaration != mLastSetVDecl)
                {
                    device->SetVertexDeclaration(entry->vertexDeclaration);
                    mLastSetVDecl = entry->vertexDeclaration;
                }
    
                return gl::Error(GL_NO_ERROR);
            }
        }
    
        VertexDeclCacheEntry *lastCache = mVertexDeclCache;
    
        for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
        {
            if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
            {
                lastCache = &mVertexDeclCache[i];
            }
        }
    
        if (lastCache->vertexDeclaration != NULL)
        {
            SafeRelease(lastCache->vertexDeclaration);
            // mLastSetVDecl is set to the replacement, so we don't have to worry
            // about it.
        }
    
        memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
        HRESULT result = device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
        if (FAILED(result))
        {
            return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal vertex declaration, result: 0x%X.", result);
        }
    
        device->SetVertexDeclaration(lastCache->vertexDeclaration);
        mLastSetVDecl = lastCache->vertexDeclaration;
        lastCache->lruCount = ++mMaxLru;
    
        return gl::Error(GL_NO_ERROR);
    }
    
    void VertexDeclarationCache::markStateDirty()
    {
        for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
        {
            mAppliedVBs[i].serial = 0;
        }
    
        mLastSetVDecl = NULL;
        mInstancingEnabled = true;   // Forces it to be disabled when not used
    }
    
    }