<commit_before>
/*
 * Copyright 2010 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "GrBufferAllocPool.h"
#include "GrTypes.h"
#include "GrVertexBuffer.h"
#include "GrIndexBuffer.h"
#include "GrGpu.h"

#if GR_DEBUG
    #define VALIDATE validate
#else
    static void VALIDATE(bool x = false) {}
#endif

// page size
#define GrBufferAllocPool_MIN_BLOCK_SIZE ((size_t)1 << 12)

GrBufferAllocPool::GrBufferAllocPool(GrGpu* gpu,
                                     BufferType bufferType,
                                     bool frequentResetHint,
                                     size_t blockSize,
                                     int preallocBufferCnt) :
        fBlocks(GrMax(8, 2*preallocBufferCnt)) {

    GrAssert(NULL != gpu);
    fGpu = gpu;
    fGpu->ref();
    fGpuIsReffed = true;

    fBufferType = bufferType;
    fFrequentResetHint = frequentResetHint;
    fBufferPtr = NULL;
    fMinBlockSize = GrMax(GrBufferAllocPool_MIN_BLOCK_SIZE, blockSize);

    fBytesInUse = 0;
            
    fPreallocBuffersInUse = 0;
    fFirstPreallocBuffer = 0;
    for (int i = 0; i < preallocBufferCnt; ++i) {
        GrGeometryBuffer* buffer = this->createBuffer(fMinBlockSize);
        if (NULL != buffer) {
            *fPreallocBuffers.append() = buffer;
            buffer->ref();
        }
    }
}

GrBufferAllocPool::~GrBufferAllocPool() {
    VALIDATE();
    if (fBlocks.count()) {
        GrGeometryBuffer* buffer = fBlocks.back().fBuffer;
        if (buffer->isLocked()) {
            buffer->unlock();
        }
    }
    while (!fBlocks.empty()) {
        destroyBlock();
    }
    fPreallocBuffers.unrefAll();
    releaseGpuRef();
}

void GrBufferAllocPool::releaseGpuRef() {
    if (fGpuIsReffed) {
        fGpu->unref();
        fGpuIsReffed = false;
    }
}

void GrBufferAllocPool::reset() {
    VALIDATE();
    fBytesInUse = 0;
    if (fBlocks.count()) {
        GrGeometryBuffer* buffer = fBlocks.back().fBuffer;
        if (buffer->isLocked()) {
            buffer->unlock();
        }
    }
    while (!fBlocks.empty()) {
        destroyBlock();
    }
    if (fPreallocBuffers.count()) {
        // must set this after above loop.
        fFirstPreallocBuffer = (fFirstPreallocBuffer + fPreallocBuffersInUse) %
                               fPreallocBuffers.count();
    }
    fCpuData.reset(fGpu->getCaps().fBufferLockSupport ? 0 : fMinBlockSize);
    GrAssert(0 == fPreallocBuffersInUse);
    VALIDATE();
}

void GrBufferAllocPool::unlock() {
    VALIDATE();

    if (NULL != fBufferPtr) {
        BufferBlock& block = fBlocks.back();
        if (block.fBuffer->isLocked()) {
            block.fBuffer->unlock();
        } else {
            size_t flushSize = block.fBuffer->sizeInBytes() - block.fBytesFree;
            flushCpuData(fBlocks.back().fBuffer, flushSize);
        }
        fBufferPtr = NULL;
    }
    VALIDATE();
}

#if GR_DEBUG
void GrBufferAllocPool::validate(bool unusedBlockAllowed) const {
    if (NULL != fBufferPtr) {
        GrAssert(!fBlocks.empty());
        if (fBlocks.back().fBuffer->isLocked()) {
            GrGeometryBuffer* buf = fBlocks.back().fBuffer;
            GrAssert(buf->lockPtr() == fBufferPtr);
        } else {
            GrAssert(fCpuData.get() == fBufferPtr);
        }
    } else {
        GrAssert(fBlocks.empty() || !fBlocks.back().fBuffer->isLocked());
    }
    size_t bytesInUse = 0;
    for (int i = 0; i < fBlocks.count() - 1; ++i) {
        GrAssert(!fBlocks[i].fBuffer->isLocked());
    }
    for (int i = 0; i < fBlocks.count(); ++i) {
        size_t bytes = fBlocks[i].fBuffer->sizeInBytes() - fBlocks[i].fBytesFree; 
        bytesInUse += bytes;
        GrAssert(bytes || unusedBlockAllowed);
    }
    
    GrAssert(bytesInUse == fBytesInUse);
    if (unusedBlockAllowed) {
        GrAssert((fBytesInUse && !fBlocks.empty()) ||
                 (!fBytesInUse && (fBlocks.count() < 2)));
    } else {
        GrAssert((0 == fBytesInUse) == fBlocks.empty());
    }
}
#endif

void* GrBufferAllocPool::makeSpace(size_t size,
                                   size_t alignment,
                                   const GrGeometryBuffer** buffer,
                                   size_t* offset) {
    VALIDATE();

    GrAssert(NULL != buffer);
    GrAssert(NULL != offset);

    if (NULL != fBufferPtr) {
        BufferBlock& back = fBlocks.back();
        size_t usedBytes = back.fBuffer->sizeInBytes() - back.fBytesFree;
        size_t pad = GrSizeAlignUpPad(usedBytes,
                                      alignment);
        if ((size + pad) <= back.fBytesFree) {
            usedBytes += pad;
            *offset = usedBytes;
            *buffer = back.fBuffer;
            back.fBytesFree -= size + pad;
            fBytesInUse += size;
            return (void*)(reinterpret_cast<intptr_t>(fBufferPtr) + usedBytes);
        }
    }

    // We could honor the space request using by a partial update of the current
    // VB (if there is room). But we don't currently use draw calls to GL that
    // allow the driver to know that previously issued draws won't read from
    // the part of the buffer we update. Also, the GL buffer implementation
    // may be cheating on the actual buffer size by shrinking the buffer on
    // updateData() if the amount of data passed is less than the full buffer
    // size.
    
    if (!createBlock(size)) {
        return NULL;
    }
    GrAssert(NULL != fBufferPtr);

    *offset = 0;
    BufferBlock& back = fBlocks.back();
    *buffer = back.fBuffer;
    back.fBytesFree -= size;
    fBytesInUse += size;
    VALIDATE();
    return fBufferPtr;
}

int GrBufferAllocPool::currentBufferItems(size_t itemSize) const {
    VALIDATE();
    if (NULL != fBufferPtr) {
        const BufferBlock& back = fBlocks.back();
        size_t usedBytes = back.fBuffer->sizeInBytes() - back.fBytesFree;
        size_t pad = GrSizeAlignUpPad(usedBytes, itemSize);
        return (back.fBytesFree - pad) / itemSize;
    } else if (fPreallocBuffersInUse < fPreallocBuffers.count()) {
        return fMinBlockSize / itemSize;
    }
    return 0;
}

int GrBufferAllocPool::preallocatedBuffersRemaining() const {
    return fPreallocBuffers.count() - fPreallocBuffersInUse;
}

int GrBufferAllocPool::preallocatedBufferCount() const {
    return fPreallocBuffers.count();
}

void GrBufferAllocPool::putBack(size_t bytes) {
    VALIDATE();

    while (bytes) {
        // caller shouldnt try to put back more than they've taken
        GrAssert(!fBlocks.empty());
        BufferBlock& block = fBlocks.back();
        size_t bytesUsed = block.fBuffer->sizeInBytes() - block.fBytesFree;
        if (bytes >= bytesUsed) {
            bytes -= bytesUsed;
            fBytesInUse -= bytesUsed;
            // if we locked a vb to satisfy the make space and we're releasing
            // beyond it, then unlock it.
            if (block.fBuffer->isLocked()) {
                block.fBuffer->unlock();
            }
            this->destroyBlock();
        } else {
            block.fBytesFree += bytes;
            fBytesInUse -= bytes;
            bytes = 0;
            break;
        }
    }
    VALIDATE();
}

bool GrBufferAllocPool::createBlock(size_t requestSize) {

    size_t size = GrMax(requestSize, fMinBlockSize);
    GrAssert(size >= GrBufferAllocPool_MIN_BLOCK_SIZE);

    VALIDATE();

    BufferBlock& block = fBlocks.push_back();

    if (size == fMinBlockSize &&
        fPreallocBuffersInUse < fPreallocBuffers.count()) {

        uint32_t nextBuffer = (fPreallocBuffersInUse + fFirstPreallocBuffer) %
                               fPreallocBuffers.count();
        block.fBuffer = fPreallocBuffers[nextBuffer];
        block.fBuffer->ref();
        ++fPreallocBuffersInUse;
    } else {
        block.fBuffer = this->createBuffer(size);
        if (NULL == block.fBuffer) {
            fBlocks.pop_back();
            return false;
        }
    }

    block.fBytesFree = size;
    if (NULL != fBufferPtr) {
        GrAssert(fBlocks.count() > 1);
        BufferBlock& prev = fBlocks.fromBack(1);
        if (prev.fBuffer->isLocked()) {
            prev.fBuffer->unlock();
        } else {
            flushCpuData(prev.fBuffer,
                         prev.fBuffer->sizeInBytes() - prev.fBytesFree);
        }
        fBufferPtr = NULL;
    }

    GrAssert(NULL == fBufferPtr);

    if (fGpu->getCaps().fBufferLockSupport &&
        size > GR_GEOM_BUFFER_LOCK_THRESHOLD &&
        (!fFrequentResetHint || requestSize > GR_GEOM_BUFFER_LOCK_THRESHOLD)) {
        fBufferPtr = block.fBuffer->lock();
    }

    if (NULL == fBufferPtr) {
        fBufferPtr = fCpuData.reset(size);
    }

    VALIDATE(true);

    return true;
}

void GrBufferAllocPool::destroyBlock() {
    GrAssert(!fBlocks.empty());

    BufferBlock& block = fBlocks.back();
    if (fPreallocBuffersInUse > 0) {
        uint32_t prevPreallocBuffer = (fPreallocBuffersInUse +
                                       fFirstPreallocBuffer +
                                       (fPreallocBuffers.count() - 1)) %
                                      fPreallocBuffers.count();
        if (block.fBuffer == fPreallocBuffers[prevPreallocBuffer]) {
            --fPreallocBuffersInUse;
        }
    }
    GrAssert(!block.fBuffer->isLocked());
    block.fBuffer->unref();
    fBlocks.pop_back();
    fBufferPtr = NULL;
}

void GrBufferAllocPool::flushCpuData(GrGeometryBuffer* buffer,
                                     size_t flushSize) {
    GrAssert(NULL != buffer);
    GrAssert(!buffer->isLocked());
    GrAssert(fCpuData.get() == fBufferPtr);
    GrAssert(flushSize <= buffer->sizeInBytes());

    bool updated = false;
    if (fGpu->getCaps().fBufferLockSupport &&
        flushSize > GR_GEOM_BUFFER_LOCK_THRESHOLD) {
        void* data = buffer->lock();
        if (NULL != data) {
            memcpy(data, fBufferPtr, flushSize);
            buffer->unlock();
            updated = true;
        }
    }<commit_msg>Don't update vertex/index buffer twice! <commit_after>
/*
 * Copyright 2010 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "GrBufferAllocPool.h"
#include "GrTypes.h"
#include "GrVertexBuffer.h"
#include "GrIndexBuffer.h"
#include "GrGpu.h"

#if GR_DEBUG
    #define VALIDATE validate
#else
    static void VALIDATE(bool x = false) {}
#endif

// page size
#define GrBufferAllocPool_MIN_BLOCK_SIZE ((size_t)1 << 12)

GrBufferAllocPool::GrBufferAllocPool(GrGpu* gpu,
                                     BufferType bufferType,
                                     bool frequentResetHint,
                                     size_t blockSize,
                                     int preallocBufferCnt) :
        fBlocks(GrMax(8, 2*preallocBufferCnt)) {

    GrAssert(NULL != gpu);
    fGpu = gpu;
    fGpu->ref();
    fGpuIsReffed = true;

    fBufferType = bufferType;
    fFrequentResetHint = frequentResetHint;
    fBufferPtr = NULL;
    fMinBlockSize = GrMax(GrBufferAllocPool_MIN_BLOCK_SIZE, blockSize);

    fBytesInUse = 0;
            
    fPreallocBuffersInUse = 0;
    fFirstPreallocBuffer = 0;
    for (int i = 0; i < preallocBufferCnt; ++i) {
        GrGeometryBuffer* buffer = this->createBuffer(fMinBlockSize);
        if (NULL != buffer) {
            *fPreallocBuffers.append() = buffer;
            buffer->ref();
        }
    }
}

GrBufferAllocPool::~GrBufferAllocPool() {
    VALIDATE();
    if (fBlocks.count()) {
        GrGeometryBuffer* buffer = fBlocks.back().fBuffer;
        if (buffer->isLocked()) {
            buffer->unlock();
        }
    }
    while (!fBlocks.empty()) {
        destroyBlock();
    }
    fPreallocBuffers.unrefAll();
    releaseGpuRef();
}

void GrBufferAllocPool::releaseGpuRef() {
    if (fGpuIsReffed) {
        fGpu->unref();
        fGpuIsReffed = false;
    }
}

void GrBufferAllocPool::reset() {
    VALIDATE();
    fBytesInUse = 0;
    if (fBlocks.count()) {
        GrGeometryBuffer* buffer = fBlocks.back().fBuffer;
        if (buffer->isLocked()) {
            buffer->unlock();
        }
    }
    while (!fBlocks.empty()) {
        destroyBlock();
    }
    if (fPreallocBuffers.count()) {
        // must set this after above loop.
        fFirstPreallocBuffer = (fFirstPreallocBuffer + fPreallocBuffersInUse) %
                               fPreallocBuffers.count();
    }
    fCpuData.reset(fGpu->getCaps().fBufferLockSupport ? 0 : fMinBlockSize);
    GrAssert(0 == fPreallocBuffersInUse);
    VALIDATE();
}

void GrBufferAllocPool::unlock() {
    VALIDATE();

    if (NULL != fBufferPtr) {
        BufferBlock& block = fBlocks.back();
        if (block.fBuffer->isLocked()) {
            block.fBuffer->unlock();
        } else {
            size_t flushSize = block.fBuffer->sizeInBytes() - block.fBytesFree;
            flushCpuData(fBlocks.back().fBuffer, flushSize);
        }
        fBufferPtr = NULL;
    }
    VALIDATE();
}

#if GR_DEBUG
void GrBufferAllocPool::validate(bool unusedBlockAllowed) const {
    if (NULL != fBufferPtr) {
        GrAssert(!fBlocks.empty());
        if (fBlocks.back().fBuffer->isLocked()) {
            GrGeometryBuffer* buf = fBlocks.back().fBuffer;
            GrAssert(buf->lockPtr() == fBufferPtr);
        } else {
            GrAssert(fCpuData.get() == fBufferPtr);
        }
    } else {
        GrAssert(fBlocks.empty() || !fBlocks.back().fBuffer->isLocked());
    }
    size_t bytesInUse = 0;
    for (int i = 0; i < fBlocks.count() - 1; ++i) {
        GrAssert(!fBlocks[i].fBuffer->isLocked());
    }
    for (int i = 0; i < fBlocks.count(); ++i) {
        size_t bytes = fBlocks[i].fBuffer->sizeInBytes() - fBlocks[i].fBytesFree; 
        bytesInUse += bytes;
        GrAssert(bytes || unusedBlockAllowed);
    }
    
    GrAssert(bytesInUse == fBytesInUse);
    if (unusedBlockAllowed) {
        GrAssert((fBytesInUse && !fBlocks.empty()) ||
                 (!fBytesInUse && (fBlocks.count() < 2)));
    } else {
        GrAssert((0 == fBytesInUse) == fBlocks.empty());
    }
}
#endif

void* GrBufferAllocPool::makeSpace(size_t size,
                                   size_t alignment,
                                   const GrGeometryBuffer** buffer,
                                   size_t* offset) {
    VALIDATE();

    GrAssert(NULL != buffer);
    GrAssert(NULL != offset);

    if (NULL != fBufferPtr) {
        BufferBlock& back = fBlocks.back();
        size_t usedBytes = back.fBuffer->sizeInBytes() - back.fBytesFree;
        size_t pad = GrSizeAlignUpPad(usedBytes,
                                      alignment);
        if ((size + pad) <= back.fBytesFree) {
            usedBytes += pad;
            *offset = usedBytes;
            *buffer = back.fBuffer;
            back.fBytesFree -= size + pad;
            fBytesInUse += size;
            return (void*)(reinterpret_cast<intptr_t>(fBufferPtr) + usedBytes);
        }
    }

    // We could honor the space request using by a partial update of the current
    // VB (if there is room). But we don't currently use draw calls to GL that
    // allow the driver to know that previously issued draws won't read from
    // the part of the buffer we update. Also, the GL buffer implementation
    // may be cheating on the actual buffer size by shrinking the buffer on
    // updateData() if the amount of data passed is less than the full buffer
    // size.
    
    if (!createBlock(size)) {
        return NULL;
    }
    GrAssert(NULL != fBufferPtr);

    *offset = 0;
    BufferBlock& back = fBlocks.back();
    *buffer = back.fBuffer;
    back.fBytesFree -= size;
    fBytesInUse += size;
    VALIDATE();
    return fBufferPtr;
}

int GrBufferAllocPool::currentBufferItems(size_t itemSize) const {
    VALIDATE();
    if (NULL != fBufferPtr) {
        const BufferBlock& back = fBlocks.back();
        size_t usedBytes = back.fBuffer->sizeInBytes() - back.fBytesFree;
        size_t pad = GrSizeAlignUpPad(usedBytes, itemSize);
        return (back.fBytesFree - pad) / itemSize;
    } else if (fPreallocBuffersInUse < fPreallocBuffers.count()) {
        return fMinBlockSize / itemSize;
    }
    return 0;
}

int GrBufferAllocPool::preallocatedBuffersRemaining() const {
    return fPreallocBuffers.count() - fPreallocBuffersInUse;
}

int GrBufferAllocPool::preallocatedBufferCount() const {
    return fPreallocBuffers.count();
}

void GrBufferAllocPool::putBack(size_t bytes) {
    VALIDATE();

    while (bytes) {
        // caller shouldnt try to put back more than they've taken
        GrAssert(!fBlocks.empty());
        BufferBlock& block = fBlocks.back();
        size_t bytesUsed = block.fBuffer->sizeInBytes() - block.fBytesFree;
        if (bytes >= bytesUsed) {
            bytes -= bytesUsed;
            fBytesInUse -= bytesUsed;
            // if we locked a vb to satisfy the make space and we're releasing
            // beyond it, then unlock it.
            if (block.fBuffer->isLocked()) {
                block.fBuffer->unlock();
            }
            this->destroyBlock();
        } else {
            block.fBytesFree += bytes;
            fBytesInUse -= bytes;
            bytes = 0;
            break;
        }
    }
    VALIDATE();
}

bool GrBufferAllocPool::createBlock(size_t requestSize) {

    size_t size = GrMax(requestSize, fMinBlockSize);
    GrAssert(size >= GrBufferAllocPool_MIN_BLOCK_SIZE);

    VALIDATE();

    BufferBlock& block = fBlocks.push_back();

    if (size == fMinBlockSize &&
        fPreallocBuffersInUse < fPreallocBuffers.count()) {

        uint32_t nextBuffer = (fPreallocBuffersInUse + fFirstPreallocBuffer) %
                               fPreallocBuffers.count();
        block.fBuffer = fPreallocBuffers[nextBuffer];
        block.fBuffer->ref();
        ++fPreallocBuffersInUse;
    } else {
        block.fBuffer = this->createBuffer(size);
        if (NULL == block.fBuffer) {
            fBlocks.pop_back();
            return false;
        }
    }

    block.fBytesFree = size;
    if (NULL != fBufferPtr) {
        GrAssert(fBlocks.count() > 1);
        BufferBlock& prev = fBlocks.fromBack(1);
        if (prev.fBuffer->isLocked()) {
            prev.fBuffer->unlock();
        } else {
            flushCpuData(prev.fBuffer,
                         prev.fBuffer->sizeInBytes() - prev.fBytesFree);
        }
        fBufferPtr = NULL;
    }

    GrAssert(NULL == fBufferPtr);

    if (fGpu->getCaps().fBufferLockSupport &&
        size > GR_GEOM_BUFFER_LOCK_THRESHOLD &&
        (!fFrequentResetHint || requestSize > GR_GEOM_BUFFER_LOCK_THRESHOLD)) {
        fBufferPtr = block.fBuffer->lock();
    }

    if (NULL == fBufferPtr) {
        fBufferPtr = fCpuData.reset(size);
    }

    VALIDATE(true);

    return true;
}

void GrBufferAllocPool::destroyBlock() {
    GrAssert(!fBlocks.empty());

    BufferBlock& block = fBlocks.back();
    if (fPreallocBuffersInUse > 0) {
        uint32_t prevPreallocBuffer = (fPreallocBuffersInUse +
                                       fFirstPreallocBuffer +
                                       (fPreallocBuffers.count() - 1)) %
                                      fPreallocBuffers.count();
        if (block.fBuffer == fPreallocBuffers[prevPreallocBuffer]) {
            --fPreallocBuffersInUse;
        }
    }
    GrAssert(!block.fBuffer->isLocked());
    block.fBuffer->unref();
    fBlocks.pop_back();
    fBufferPtr = NULL;
}

void GrBufferAllocPool::flushCpuData(GrGeometryBuffer* buffer,
                                     size_t flushSize) {
    GrAssert(NULL != buffer);
    GrAssert(!buffer->isLocked());
    GrAssert(fCpuData.get() == fBufferPtr);
    GrAssert(flushSize <= buffer->sizeInBytes());

    if (fGpu->getCaps().fBufferLockSupport &&
        flushSize > GR_GEOM_BUFFER_LOCK_THRESHOLD) {
        void* data = buffer->lock();
        if (NULL != data) {
            memcpy(data, fBufferPtr, flushSize);
            buffer->unlock();
            return;
        }
    }
{'fraction_non_alphanumeric': 0.11869406529673517, 'fraction_numerical': 0.0032998350082495873, 'mean_word_length': 2.127756059421423, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6249014', 'n_tokens_mistral': 6163, 'n_tokens_neox': 6026, 'n_words': 1255}