// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CCPrioritizedTexture_h
#define CCPrioritizedTexture_h

#include "CCPriorityCalculator.h"
#include "CCResourceProvider.h"
#include "CCTexture.h"
#include "GraphicsContext3D.h"
#include "IntRect.h"
#include "IntSize.h"

namespace WebCore {

class CCPrioritizedTextureManager;

class CCPrioritizedTexture {
    WTF_MAKE_NONCOPYABLE(CCPrioritizedTexture);
public:
    static PassOwnPtr<CCPrioritizedTexture> create(CCPrioritizedTextureManager* manager, IntSize size, GC3Denum format)
    {
        return adoptPtr(new CCPrioritizedTexture(manager, size, format));
    }
    static PassOwnPtr<CCPrioritizedTexture> create(CCPrioritizedTextureManager* manager)
    {
        return adoptPtr(new CCPrioritizedTexture(manager, IntSize(), 0));
    }
    ~CCPrioritizedTexture();

    // Texture properties. Changing these causes the backing texture to be lost.
    // Setting these to the same value is a no-op.
    void setTextureManager(CCPrioritizedTextureManager*);
    CCPrioritizedTextureManager* textureManager() { return m_manager; }
    void setDimensions(IntSize, GC3Denum format);
    GC3Denum format() const { return m_format; }
    IntSize size() const { return m_size; }
    size_t bytes() const { return m_bytes; }

    // Set priority for the requested texture. 
    void setRequestPriority(int priority) { m_priority = priority; }
    int requestPriority() const { return m_priority; }

    // After CCPrioritizedTexture::prioritizeTextures() is called, this returns
    // if the the request succeeded and this texture can be acquired for use.
    bool canAcquireBackingTexture() const { return m_isAbovePriorityCutoff; }

    // This returns whether we still have a backing texture. This can continue
    // to be true even after canAcquireBackingTexture() becomes false. In this
    // case the texture can be used but shouldn't be updated since it will get
    // taken away "soon".
    bool haveBackingTexture() const { return !!backing(); }

    // If canAcquireBackingTexture() is true acquireBackingTexture() will acquire
    // a backing texture for use. Call this whenever the texture is actually needed.
    void acquireBackingTexture(CCResourceProvider*);

    // FIXME: Request late is really a hack for when we are totally out of memory
    //        (all textures are visible) but we can still squeeze into the limit
    //        by not painting occluded textures. In this case the manager
    //        refuses all visible textures and requestLate() will enable
    //        canAcquireBackingTexture() on a call-order basis. We might want to
    //        just remove this in the future (carefully) and just make sure we don't
    //        regress OOMs situations.
    bool requestLate();

    // Uploads pixels into the backing resource. This functions will aquire the backing if needed.
    void upload(CCResourceProvider*, const uint8_t* image, const IntRect& imageRect, const IntRect& sourceRect, const IntSize& destOffset);

    CCResourceProvider::ResourceId resourceId() const;

    // Self-managed textures are accounted for when prioritizing other textures,
    // but they are not allocated/recycled/deleted, so this needs to be done
    // externally. canAcquireBackingTexture() indicates if the texture would have
    // been allowed given its priority.
    void setIsSelfManaged(bool isSelfManaged) { m_isSelfManaged = isSelfManaged; }
    bool isSelfManaged() { return m_isSelfManaged; }
    void setToSelfManagedMemoryPlaceholder(size_t bytes);

private:
    friend class CCPrioritizedTextureManager;

    class Backing : public CCTexture {
        WTF_MAKE_NONCOPYABLE(Backing);
    public:
        Backing(unsigned id, IntSize size, GC3Denum format)
            : CCTexture(id, size, format), m_owner(0) { }
        ~Backing() { ASSERT(!m_owner); }

        CCPrioritizedTexture* owner() { return m_owner; }
    private:
        friend class CCPrioritizedTexture;
        CCPrioritizedTexture* m_owner;
    };

    CCPrioritizedTexture(CCPrioritizedTextureManager*, IntSize, GC3Denum format);

    bool isAbovePriorityCutoff() { return m_isAbovePriorityCutoff; }
    void setAbovePriorityCutoff(bool isAbovePriorityCutoff) { m_isAbovePriorityCutoff = isAbovePriorityCutoff; }
    void setManagerInternal(CCPrioritizedTextureManager* manager) { m_manager = manager; }

    Backing* backing() const { return m_backing; }
    void link(Backing*);
    void unlink();

    IntSize m_size;
    GC3Denum m_format;
    size_t m_bytes;

    size_t m_priority;
    bool m_isAbovePriorityCutoff;
    bool m_isSelfManaged;

    Backing* m_backing;
    CCPrioritizedTextureManager* m_manager;
};

} // WebCore

#endif