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

#include "GrGLBufferImpl.h"
#include "GrGLGpu.h"

#define GL_CALL(GPU, X) GR_GL_CALL(GPU->glInterface(), X)

#ifdef SK_DEBUG
#define VALIDATE() this->validate()
#else
#define VALIDATE() do {} while(false)
#endif

GrGLBufferImpl::GrGLBufferImpl(GrGLGpu* gpu, const Desc& desc, GrGLenum bufferType)
    : fDesc(desc)
    , fBufferType(bufferType)
    , fMapPtr(nullptr) {
    if (0 == desc.fID) {
        if (gpu->caps()->mustClearUploadedBufferData()) {
            fCPUData = sk_calloc_throw(desc.fSizeInBytes);
        } else {
            fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW);
        }
        fGLSizeInBytes = 0;
    } else {
        fCPUData = nullptr;
        // We assume that the GL buffer was created at the desc's size initially.
        fGLSizeInBytes = fDesc.fSizeInBytes;
    }
    VALIDATE();
}

void GrGLBufferImpl::release(GrGLGpu* gpu) {
    VALIDATE();
    // make sure we've not been abandoned or already released
    if (fCPUData) {
        sk_free(fCPUData);
        fCPUData = nullptr;
    } else if (fDesc.fID) {
        gpu->releaseBuffer(fDesc.fID, fBufferType);
        fDesc.fID = 0;
        fGLSizeInBytes = 0;
    }
    fMapPtr = nullptr;
    VALIDATE();
}

void GrGLBufferImpl::abandon() {
    fDesc.fID = 0;
    fGLSizeInBytes = 0;
    fMapPtr = nullptr;
    sk_free(fCPUData);
    fCPUData = nullptr;
    VALIDATE();
}

void* GrGLBufferImpl::map(GrGLGpu* gpu) {
    VALIDATE();
    SkASSERT(!this->isMapped());
    if (0 == fDesc.fID) {
        fMapPtr = fCPUData;
    } else {
        fMapPtr = gpu->mapBuffer(fDesc.fID, fBufferType, fDesc.fDynamic, fGLSizeInBytes,
                                 fDesc.fSizeInBytes);
        fGLSizeInBytes = fDesc.fSizeInBytes;
    }
    VALIDATE();
    return fMapPtr;
}

void GrGLBufferImpl::unmap(GrGLGpu* gpu) {
    VALIDATE();
    SkASSERT(this->isMapped());
    if (0 != fDesc.fID) {
        gpu->unmapBuffer(fDesc.fID, fBufferType, fMapPtr);
    }
    fMapPtr = nullptr;
}

bool GrGLBufferImpl::isMapped() const {
    VALIDATE();
    return SkToBool(fMapPtr);
}

bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInBytes) {
    SkASSERT(!this->isMapped());
    VALIDATE();
    if (srcSizeInBytes > fDesc.fSizeInBytes) {
        return false;
    }
    if (0 == fDesc.fID) {
        memcpy(fCPUData, src, srcSizeInBytes);
        return true;
    }
    gpu->bufferData(fDesc.fID, fBufferType, fDesc.fDynamic, fDesc.fSizeInBytes, src,
                    srcSizeInBytes);
#if GR_GL_USE_BUFFER_DATA_NULL_HINT
    fGLSizeInBytes = fDesc.fSizeInBytes;
#else
    fGLSizeInBytes = srcSizeInBytes;
#endif
    VALIDATE();
    return true;
}

void GrGLBufferImpl::validate() const {
    SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType);
    // The following assert isn't valid when the buffer has been abandoned:
    // SkASSERT((0 == fDesc.fID) == (fCPUData));
    SkASSERT(nullptr == fCPUData || 0 == fGLSizeInBytes);
    SkASSERT(nullptr == fMapPtr || fCPUData || fGLSizeInBytes <= fDesc.fSizeInBytes);
    SkASSERT(nullptr == fCPUData || nullptr == fMapPtr || fCPUData == fMapPtr);
}
