/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_HWUI_PIXEL_BUFFER_H
#define ANDROID_HWUI_PIXEL_BUFFER_H

#include <GLES3/gl3.h>

#include <log/log.h>

namespace android {
namespace uirenderer {

/**
 * Represents a pixel buffer. A pixel buffer will be backed either by a
 * PBO on OpenGL ES 3.0 and higher or by an array of uint8_t on other
 * versions. If the buffer is backed by a PBO it will of type
 * GL_PIXEL_UNPACK_BUFFER.
 *
 * To read from or write into a PixelBuffer you must first map the
 * buffer using the map(AccessMode) method. This method returns a
 * pointer to the beginning of the buffer.
 *
 * Before the buffer can be used by the GPU, for instance to upload
 * a texture, you must first unmap the buffer. To do so, call the
 * unmap() method.
 *
 * Mapping and unmapping a PixelBuffer can have the side effect of
 * changing the currently active GL_PIXEL_UNPACK_BUFFER. It is
 * therefore recommended to call Caches::unbindPixelbuffer() after
 * using a PixelBuffer to upload to a texture.
 */
class PixelBuffer {
public:
    enum BufferType {
        kBufferType_Auto,
        kBufferType_CPU
    };

    enum AccessMode {
        kAccessMode_None = 0,
        kAccessMode_Read = GL_MAP_READ_BIT,
        kAccessMode_Write = GL_MAP_WRITE_BIT,
        kAccessMode_ReadWrite = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT
    };

    /**
     * Creates a new PixelBuffer object with the specified format and
     * dimensions. The buffer is immediately allocated.
     *
     * The buffer type specifies how the buffer should be allocated.
     * By default this method will automatically choose whether to allocate
     * a CPU or GPU buffer.
     */
    static PixelBuffer* create(GLenum format, uint32_t width, uint32_t height,
            BufferType type = kBufferType_Auto);

    virtual ~PixelBuffer() {
    }

    /**
     * Returns the format of this render buffer.
     */
    GLenum getFormat() const {
        return mFormat;
    }

    /**
     * Maps this before with the specified access mode. This method
     * returns a pointer to the region of memory where the buffer was
     * mapped.
     *
     * If the buffer is already mapped when this method is invoked,
     * this method will return the previously mapped pointer. The
     * access mode can only be changed by calling unmap() first.
     *
     * The specified access mode cannot be kAccessMode_None.
     */
    virtual uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) = 0;

    /**
     * Returns the current access mode for this buffer. If the buffer
     * is not mapped, this method returns kAccessMode_None.
     */
    AccessMode getAccessMode() const {
        return mAccessMode;
    }

    /**
     * Upload the specified rectangle of this pixel buffer as a
     * GL_TEXTURE_2D texture. Calling this method will trigger
     * an unmap() if necessary.
     */
    virtual void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) = 0;

    /**
     * Upload the specified rectangle of this pixel buffer as a
     * GL_TEXTURE_2D texture. Calling this method will trigger
     * an unmap() if necessary.
     *
     * This is a convenience function provided to save callers the
     * trouble of computing the offset parameter.
     */
    void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
        upload(x, y, width, height, getOffset(x, y));
    }

    /**
     * Returns the width of the render buffer in pixels.
     */
    uint32_t getWidth() const {
        return mWidth;
    }

    /**
     * Returns the height of the render buffer in pixels.
     */
    uint32_t getHeight() const {
        return mHeight;
    }

    /**
     * Returns the size of this pixel buffer in bytes.
     */
    uint32_t getSize() const {
        return mWidth * mHeight * formatSize(mFormat);
    }

    /**
     * Returns the offset of a pixel in this pixel buffer, in bytes.
     */
    uint32_t getOffset(uint32_t x, uint32_t y) const {
        return (y * mWidth + x) * formatSize(mFormat);
    }

    /**
     * Returns the number of bytes per pixel in the specified format.
     *
     * Supported formats:
     *      GL_ALPHA
     *      GL_RGBA
     */
    static uint32_t formatSize(GLenum format) {
        switch (format) {
            case GL_ALPHA:
                return 1;
            case GL_RGBA:
                return 4;
        }
        return 0;
    }

    /**
     * Returns the alpha channel offset in the specified format.
     *
     * Supported formats:
     *      GL_ALPHA
     *      GL_RGBA
     */
    static uint32_t formatAlphaOffset(GLenum format) {
        switch (format) {
            case GL_ALPHA:
                return 0;
            case GL_RGBA:
                return 3;
        }

        ALOGE("unsupported format: %d",format);
        return 0;
    }

protected:
    /**
     * Creates a new render buffer in the specified format and dimensions.
     * The format must be GL_ALPHA or GL_RGBA.
     */
    PixelBuffer(GLenum format, uint32_t width, uint32_t height):
            mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {
    }

    /**
     * Unmaps this buffer, if needed. After the buffer is unmapped,
     * the pointer previously returned by map() becomes invalid and
     * should not be used.
     */
    virtual void unmap() = 0;

    GLenum mFormat;

    uint32_t mWidth;
    uint32_t mHeight;

    AccessMode mAccessMode;

}; // class PixelBuffer

}; // namespace uirenderer
}; // namespace android

#endif // ANDROID_HWUI_PIXEL_BUFFER_H
