Edit

kc3-lang/angle/src/libGLESv2/geometry/IndexDataManager.cpp

Branch :

  • Show log

    Commit

  • Author : apatrick@chromium.org
    Date : 2010-11-16 01:57:05
    Hash : f99fbb77
    Message : Check that IDirect3DVertexBuffer9 and IDirect3DIndexBuffer9::Lock succeed. I've been seeing crashes like this on Windows XP: 0x013319aa [libglesv2.dll - memcpy.asm:188] memcpy 0x0130989a [libglesv2.dll - vertexdatamanager.cpp:164] gl::VertexDataManager::preRenderValidate(int,int,gl::TranslatedAttribute *) 0x01304f66 [libglesv2.dll - context.cpp:1996] gl::Context::applyVertexBuffer(unsigned int,int,int,bool *,gl::TranslatedIndexData *) 0x013061a7 [libglesv2.dll - context.cpp:2648] gl::Context::drawArrays(unsigned int,int,int) 0x012f7721 [libglesv2.dll - libglesv2.cpp:1741] glDrawArrays 0x01c54f1e [chrome.dll - gles2_cmd_decoder.cc:3179] gpu::gles2::GLES2DecoderImpl::DoDrawArrays(unsigned int,int,int) 0x01c59122 [chrome.dll - gles2_cmd_decoder_autogen.h:640] gpu::gles2::GLES2DecoderImpl::HandleDrawArrays(unsigned int,gpu::gles2::DrawArrays const &) Review URL: http://codereview.appspot.com/3043042 git-svn-id: https://angleproject.googlecode.com/svn/trunk@480 736b8ea6-26fd-11df-bfd4-992fa37f6226

  • src/libGLESv2/geometry/IndexDataManager.cpp
  • //
    // Copyright (c) 2002-2010 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.
    //
    
    // geometry/IndexDataManager.cpp: Defines the IndexDataManager, a class that
    // runs the Buffer translation process for index buffers.
    
    #include "libGLESv2/geometry/IndexDataManager.h"
    
    #include "common/debug.h"
    
    #include "libGLESv2/Buffer.h"
    #include "libGLESv2/mathutil.h"
    #include "libGLESv2/geometry/backend.h"
    
    namespace
    {
        enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
    }
    
    namespace gl
    {
    
    IndexDataManager::IndexDataManager(Context *context, BufferBackEnd *backend)
      : mContext(context), mBackend(backend), mIntIndicesSupported(backend->supportIntIndices())
    {
        mCountingBuffer = NULL;
        mCountingBufferSize = 0;
    
        mLineLoopBuffer = NULL;
    
        mStreamBufferShort = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
    
        if (mIntIndicesSupported)
        {
            mStreamBufferInt = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
        }
        else
        {
            mStreamBufferInt = NULL;
        }
    }
    
    IndexDataManager::~IndexDataManager()
    {
        delete mStreamBufferShort;
        delete mStreamBufferInt;
        delete mCountingBuffer;
        delete mLineLoopBuffer;
    }
    
    namespace
    {
    
    template <class InputIndexType, class OutputIndexType>
    void copyIndices(const InputIndexType *in, GLsizei count, OutputIndexType *out, GLuint *minIndex, GLuint *maxIndex)
    {
        InputIndexType first = *in;
        GLuint minIndexSoFar = first;
        GLuint maxIndexSoFar = first;
    
        for (GLsizei i = 0; i < count; i++)
        {
            if (minIndexSoFar > *in) minIndexSoFar = *in;
            if (maxIndexSoFar < *in) maxIndexSoFar = *in;
    
            *out++ = *in++;
        }
    
        // It might be a line loop, so copy the loop index.
        *out = first;
    
        *minIndex = minIndexSoFar;
        *maxIndex = maxIndexSoFar;
    }
    
    }
    
    GLenum IndexDataManager::preRenderValidate(GLenum mode, GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated)
    {
        ASSERT(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT);
        ASSERT(count > 0);
    
        if (arrayElementBuffer != NULL)
        {
            GLsizei offset = reinterpret_cast<GLsizei>(indices);
    
            if (typeSize(type) * count + offset > static_cast<std::size_t>(arrayElementBuffer->size()))
            {
                return GL_INVALID_OPERATION;
            }
    
            indices = static_cast<const GLubyte*>(arrayElementBuffer->data()) + offset;
        }
    
        translated->count = count;
    
        std::size_t requiredSpace = spaceRequired(type, count);
    
        TranslatedIndexBuffer *streamIb = prepareIndexBuffer(type, requiredSpace);
    
        size_t offset;
        void *output = streamIb->map(requiredSpace, &offset);
        if (output == NULL)
        {
            ERR(" failed to map index buffer.");
            return GL_OUT_OF_MEMORY;
        }
    
        translated->buffer = streamIb;
        translated->offset = offset;
        translated->indexSize = indexSize(type);
    
        if (type == GL_UNSIGNED_BYTE)
        {
            const GLubyte *in = static_cast<const GLubyte*>(indices);
            GLushort *out = static_cast<GLushort*>(output);
    
            copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
        }
        else if (type == GL_UNSIGNED_INT)
        {
            const GLuint *in = static_cast<const GLuint*>(indices);
    
            if (mIntIndicesSupported)
            {
                GLuint *out = static_cast<GLuint*>(output);
    
                copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
            }
            else
            {
                // When 32-bit indices are unsupported, fake them by truncating to 16-bit.
    
                GLushort *out = static_cast<GLushort*>(output);
    
                copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
            }
        }
        else
        {
            const GLushort *in = static_cast<const GLushort*>(indices);
            GLushort *out = static_cast<GLushort*>(output);
    
            copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
        }
    
        streamIb->unmap();
    
        return GL_NO_ERROR;
    }
    
    std::size_t IndexDataManager::indexSize(GLenum type) const
    {
        return (type == GL_UNSIGNED_INT && mIntIndicesSupported) ? sizeof(GLuint) : sizeof(GLushort);
    }
    
    std::size_t IndexDataManager::typeSize(GLenum type) const
    {
        switch (type)
        {
          case GL_UNSIGNED_INT: return sizeof(GLuint);
          case GL_UNSIGNED_SHORT: return sizeof(GLushort);
          default: UNREACHABLE();
          case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
        }
    }
    
    std::size_t IndexDataManager::spaceRequired(GLenum type, GLsizei count) const
    {
        return (count + 1) * indexSize(type); // +1 because we always leave an extra for line loops
    }
    
    TranslatedIndexBuffer *IndexDataManager::prepareIndexBuffer(GLenum type, std::size_t requiredSpace)
    {
        bool use32 = (type == GL_UNSIGNED_INT && mIntIndicesSupported);
    
        TranslatedIndexBuffer *streamIb = use32 ? mStreamBufferInt : mStreamBufferShort;
    
        if (requiredSpace > streamIb->size())
        {
            std::size_t newSize = std::max(requiredSpace, 2 * streamIb->size());
    
            TranslatedIndexBuffer *newStreamBuffer = mBackend->createIndexBuffer(newSize, use32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT);
    
            delete streamIb;
    
            streamIb = newStreamBuffer;
    
            if (use32)
            {
                mStreamBufferInt = streamIb;
            }
            else
            {
                mStreamBufferShort = streamIb;
            }
        }
    
        streamIb->reserveSpace(requiredSpace);
    
        return streamIb;
    }
    
    GLenum IndexDataManager::preRenderValidateUnindexed(GLenum mode, GLsizei count, TranslatedIndexData *indexInfo)
    {
        if (count >= 65535) return GL_OUT_OF_MEMORY;
    
        if (mode == GL_LINE_LOOP)
        {
            // For line loops, create a single-use buffer that runs 0 - count-1, 0.
            delete mLineLoopBuffer;
            mLineLoopBuffer = mBackend->createIndexBuffer((count+1) * sizeof(unsigned short), GL_UNSIGNED_SHORT);
    
            unsigned short *indices = static_cast<unsigned short *>(mLineLoopBuffer->map());
            if (indices == NULL)
            {
                ERR(" failed to map index buffer.");
                return GL_OUT_OF_MEMORY;
            }
    
            for (int i = 0; i < count; i++)
            {
                indices[i] = i;
            }
    
            indices[count] = 0;
    
            mLineLoopBuffer->unmap();
    
            indexInfo->buffer = mLineLoopBuffer;
            indexInfo->count = count + 1;
            indexInfo->maxIndex = count - 1;
        }
        else if (mCountingBufferSize < count)
        {
            mCountingBufferSize = std::max(static_cast<GLsizei>(ceilPow2(count)), mCountingBufferSize*2);
    
            delete mCountingBuffer;
            mCountingBuffer = mBackend->createIndexBuffer(count * sizeof(unsigned short), GL_UNSIGNED_SHORT);
    
            unsigned short *indices = static_cast<unsigned short *>(mCountingBuffer->map());
            if (indices == NULL)
            {
                ERR(" failed to map index buffer.");
                return GL_OUT_OF_MEMORY;
            }
    
            for (int i = 0; i < count; i++)
            {
                indices[i] = i;
            }
    
            mCountingBuffer->unmap();
    
            indexInfo->buffer = mCountingBuffer;
            indexInfo->count = count;
            indexInfo->maxIndex = count - 1;
        }
        else
        {
            indexInfo->buffer = mCountingBuffer;
            indexInfo->count = count;
            indexInfo->maxIndex = count - 1;
        }
    
        indexInfo->indexSize = sizeof(unsigned short);
        indexInfo->minIndex = 0;
        indexInfo->offset = 0;
    
        return GL_NO_ERROR;
    }
    
    }