<commit_before>//
// Copyright (c) 2002-2014 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.
//

// Texture.cpp: Implements the gl::Texture class. [OpenGL ES 2.0.24] section 3.7 page 63.

#include "libANGLE/Texture.h"
#include "libANGLE/Data.h"
#include "libANGLE/formatutils.h"

#include "libANGLE/Surface.h"

#include "common/mathutil.h"
#include "common/utilities.h"

namespace gl
{

bool IsMipmapFiltered(const gl::SamplerState &samplerState)
{
    switch (samplerState.minFilter)
    {
      case GL_NEAREST:
      case GL_LINEAR:
        return false;
      case GL_NEAREST_MIPMAP_NEAREST:
      case GL_LINEAR_MIPMAP_NEAREST:
      case GL_NEAREST_MIPMAP_LINEAR:
      case GL_LINEAR_MIPMAP_LINEAR:
        return true;
      default: UNREACHABLE();
        return false;
    }
}

bool IsPointSampled(const gl::SamplerState &samplerState)
{
    return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
}

unsigned int Texture::mCurrentTextureSerial = 1;

Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
    : RefCountObject(id),
      mTexture(impl),
      mTextureSerial(issueTextureSerial()),
      mUsage(GL_NONE),
      mImmutableLevelCount(0),
      mTarget(target),
      mBoundSurface(NULL)
{
}

Texture::~Texture()
{
    if (mBoundSurface)
    {
        mBoundSurface->releaseTexImage(EGL_BACK_BUFFER);
        mBoundSurface = NULL;
    }
    SafeDelete(mTexture);
}

GLenum Texture::getTarget() const
{
    return mTarget;
}

void Texture::setUsage(GLenum usage)
{
    mUsage = usage;
    getImplementation()->setUsage(usage);
}

GLenum Texture::getUsage() const
{
    return mUsage;
}

size_t Texture::getWidth(GLenum target, size_t level) const
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
    return getImageDesc(ImageIndex::MakeGeneric(target, level)).size.width;
}

size_t Texture::getHeight(GLenum target, size_t level) const
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
    return getImageDesc(ImageIndex::MakeGeneric(target, level)).size.height;
}

size_t Texture::getDepth(GLenum target, size_t level) const
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
    return getImageDesc(ImageIndex::MakeGeneric(target, level)).size.depth;
}

GLenum Texture::getInternalFormat(GLenum target, size_t level) const
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
    return getImageDesc(ImageIndex::MakeGeneric(target, level)).internalFormat;
}

bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
{
    GLenum baseTarget = getBaseImageTarget();
    size_t width = getWidth(baseTarget, samplerState.baseLevel);
    size_t height = getHeight(baseTarget, samplerState.baseLevel);
    size_t depth = getDepth(baseTarget, samplerState.baseLevel);
    if (width == 0 || height == 0 || depth == 0)
    {
        return false;
    }

    if (mTarget == GL_TEXTURE_CUBE_MAP && width != height)
    {
        return false;
    }

    GLenum internalFormat = getInternalFormat(baseTarget, samplerState.baseLevel);
    const TextureCaps &textureCaps = data.textureCaps->get(internalFormat);
    if (!textureCaps.filterable && !IsPointSampled(samplerState))
    {
        return false;
    }

    bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3;
    if (!npotSupport)
    {
        if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) ||
            (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height)))
        {
            return false;
        }
    }

    if (IsMipmapFiltered(samplerState))
    {
        if (!npotSupport)
        {
            if (!gl::isPow2(width) || !gl::isPow2(height))
            {
                return false;
            }
        }

        if (!isMipmapComplete(samplerState))
        {
            return false;
        }
    }
    else
    {
        if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
        {
            return false;
        }
    }

    // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
    // The internalformat specified for the texture arrays is a sized internal depth or
    // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
    // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
    // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
    if (formatInfo.depthBits > 0 && data.clientVersion > 2)
    {
        if (samplerState.compareMode == GL_NONE)
        {
            if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
                samplerState.magFilter != GL_NEAREST)
            {
                return false;
            }
        }
    }

    return true;
}

// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
bool Texture::isCubeComplete() const
{
    ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);

    GLenum baseTarget = FirstCubeMapTextureTarget;
    size_t width = getWidth(baseTarget, 0);
    size_t height = getWidth(baseTarget, 0);
    if (width == 0 || width != height)
    {
        return false;
    }

    GLenum internalFormat = getInternalFormat(baseTarget, 0);
    for (GLenum face = baseTarget + 1; face <= LastCubeMapTextureTarget; face++)
    {
        if (getWidth(face, 0) != width ||
            getHeight(face, 0) != height ||
            getInternalFormat(face, 0) != internalFormat)
        {
            return false;
        }
    }

    return true;
}

unsigned int Texture::getTextureSerial() const
{
    return mTextureSerial;
}

unsigned int Texture::issueTextureSerial()
{
    return mCurrentTextureSerial++;
}

bool Texture::isImmutable() const
{
    return (mImmutableLevelCount > 0);
}

int Texture::immutableLevelCount()
{
    return mImmutableLevelCount;
}

Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
                        const PixelUnpackState &unpack, const uint8_t *pixels)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    setImageDesc(ImageIndex::MakeGeneric(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));

    return Error(GL_NO_ERROR);
}

Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
                           const PixelUnpackState &unpack, const uint8_t *pixels)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
}

Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
                                  const PixelUnpackState &unpack, const uint8_t *pixels)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels);
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    setImageDesc(ImageIndex::MakeGeneric(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));

    return Error(GL_NO_ERROR);
}

Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
                                     const PixelUnpackState &unpack, const uint8_t *pixels)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels);
}

Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
                         const Framebuffer *source)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    setImageDesc(ImageIndex::MakeGeneric(target, level), ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
                                                                   GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));

    return Error(GL_NO_ERROR);
}

Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
                            const Framebuffer *source)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
}

Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
{
    ASSERT(target == mTarget);

    Error error = mTexture->setStorage(target, levels, internalFormat, size);
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    mImmutableLevelCount = levels;
    clearImageDescs();
    setImageDescChain(levels, size, internalFormat);

    return Error(GL_NO_ERROR);
}

Error Texture::generateMipmaps()
{
    Error error = mTexture->generateMipmaps();
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    ImageIndex baseLevel = ImageIndex::MakeGeneric(getBaseImageTarget(), 0);
    const ImageDesc &baseImageInfo = getImageDesc(baseLevel);
    size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
    setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);

    return Error(GL_NO_ERROR);
}

void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
{
    for (size_t level = 0; level < levels; level++)
    {
        Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
                          std::max<size_t>(baseSize.height >> level, 1),
                          (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
        ImageDesc levelInfo(levelSize, sizedInternalFormat);

        if (mTarget == GL_TEXTURE_CUBE_MAP)
        {
            for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
            {
                setImageDesc(ImageIndex::MakeGeneric(face, level), levelInfo);
            }
        }
        else
        {
            setImageDesc(ImageIndex::MakeGeneric(mTarget, level), levelInfo);
        }
    }
}

Texture::ImageDesc::ImageDesc()
    : ImageDesc(Extents(0, 0, 0), GL_NONE)
{
}

Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
    : size(size),
      internalFormat(internalFormat)
{
}

const Texture::ImageDesc &Texture::getImageDesc(const ImageIndex &index) const
{
    static const Texture::ImageDesc defaultDesc;
    ImageDescMap::const_iterator iter = mImageDescs.find(index);
    return (iter != mImageDescs.end()) ? iter->second : defaultDesc;
}

void Texture::setImageDesc(const ImageIndex &index, const ImageDesc &desc)
{
    mImageDescs[index] = desc;
}

void Texture::clearImageDescs()
{
    mImageDescs.clear();
}

void Texture::bindTexImage(egl::Surface *surface)
{
    releaseTexImage();
    mTexture->bindTexImage(surface);
    mBoundSurface = surface;
}

void Texture::releaseTexImage()
{
    if (mBoundSurface)
    {
        mBoundSurface = NULL;
        mTexture->releaseTexImage();
    }
}

GLenum Texture::getBaseImageTarget() const
{
    return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
}

size_t Texture::getExpectedMipLevels() const
{
    GLenum baseTarget = getBaseImageTarget();
    size_t width = getWidth(baseTarget, 0);
    size_t height = getHeight(baseTarget, 0);
    if (mTarget == GL_TEXTURE_3D)
    {
        size_t depth = getDepth(baseTarget, 0);
        return log2(std::max(std::max(width, height), depth)) + 1;
    }
    else
    {
        return log2(std::max(width, height)) + 1;
    }
}

bool Texture::isMipmapComplete(const gl::SamplerState &samplerState) const
{
    size_t expectedMipLevels = getExpectedMipLevels();

    size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1);

    for (size_t level = samplerState.baseLevel; level < maxLevel; level++)
    {
        if (mTarget == GL_TEXTURE_CUBE_MAP)
        {
            for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
            {
                if (!isLevelComplete(face, level, samplerState))
                {
                    return false;
                }
            }
        }
        else
        {
            if (!isLevelComplete(mTarget, level, samplerState))
            {
                return false;
            }
        }
    }

    return true;
}

bool Texture::isLevelComplete(GLenum target, size_t level,
                              const gl::SamplerState &samplerState) const
{
    ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);

    if (isImmutable())
    {
        return true;
    }

    size_t width = getWidth(target, samplerState.baseLevel);
    size_t height = getHeight(target, samplerState.baseLevel);
    size_t depth = getHeight(target, samplerState.baseLevel);
    if (width == 0 || height == 0 || depth == 0)
    {
        return false;
    }

    // The base image level is complete if the width and height are positive
    if (level == 0)
    {
        return true;
    }

    if (getInternalFormat(target, level) != getInternalFormat(target, samplerState.baseLevel))
    {
        return false;
    }

    if (getWidth(target, level) != std::max<size_t>(1, width >> level))
    {
        return false;
    }

    if (getHeight(target, level) != std::max<size_t>(1, height >> level))
    {
        return false;
    }

    if (mTarget == GL_TEXTURE_3D)
    {
        if (getDepth(target, level) != std::max<size_t>(1, depth >> level))
        {
            return false;
        }
    }
    else if (mTarget == GL_TEXTURE_2D_ARRAY)
    {
        if (getDepth(target, level) != depth)
        {
            return false;
        }
    }

    return true;
}

}
<commit_msg>Fix 'getDepth' in Texture::isLevelComplete.<commit_after>//
// Copyright (c) 2002-2014 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.
//

// Texture.cpp: Implements the gl::Texture class. [OpenGL ES 2.0.24] section 3.7 page 63.

#include "libANGLE/Texture.h"
#include "libANGLE/Data.h"
#include "libANGLE/formatutils.h"

#include "libANGLE/Surface.h"

#include "common/mathutil.h"
#include "common/utilities.h"

namespace gl
{

bool IsMipmapFiltered(const gl::SamplerState &samplerState)
{
    switch (samplerState.minFilter)
    {
      case GL_NEAREST:
      case GL_LINEAR:
        return false;
      case GL_NEAREST_MIPMAP_NEAREST:
      case GL_LINEAR_MIPMAP_NEAREST:
      case GL_NEAREST_MIPMAP_LINEAR:
      case GL_LINEAR_MIPMAP_LINEAR:
        return true;
      default: UNREACHABLE();
        return false;
    }
}

bool IsPointSampled(const gl::SamplerState &samplerState)
{
    return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
}

unsigned int Texture::mCurrentTextureSerial = 1;

Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
    : RefCountObject(id),
      mTexture(impl),
      mTextureSerial(issueTextureSerial()),
      mUsage(GL_NONE),
      mImmutableLevelCount(0),
      mTarget(target),
      mBoundSurface(NULL)
{
}

Texture::~Texture()
{
    if (mBoundSurface)
    {
        mBoundSurface->releaseTexImage(EGL_BACK_BUFFER);
        mBoundSurface = NULL;
    }
    SafeDelete(mTexture);
}

GLenum Texture::getTarget() const
{
    return mTarget;
}

void Texture::setUsage(GLenum usage)
{
    mUsage = usage;
    getImplementation()->setUsage(usage);
}

GLenum Texture::getUsage() const
{
    return mUsage;
}

size_t Texture::getWidth(GLenum target, size_t level) const
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
    return getImageDesc(ImageIndex::MakeGeneric(target, level)).size.width;
}

size_t Texture::getHeight(GLenum target, size_t level) const
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
    return getImageDesc(ImageIndex::MakeGeneric(target, level)).size.height;
}

size_t Texture::getDepth(GLenum target, size_t level) const
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
    return getImageDesc(ImageIndex::MakeGeneric(target, level)).size.depth;
}

GLenum Texture::getInternalFormat(GLenum target, size_t level) const
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
    return getImageDesc(ImageIndex::MakeGeneric(target, level)).internalFormat;
}

bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
{
    GLenum baseTarget = getBaseImageTarget();
    size_t width = getWidth(baseTarget, samplerState.baseLevel);
    size_t height = getHeight(baseTarget, samplerState.baseLevel);
    size_t depth = getDepth(baseTarget, samplerState.baseLevel);
    if (width == 0 || height == 0 || depth == 0)
    {
        return false;
    }

    if (mTarget == GL_TEXTURE_CUBE_MAP && width != height)
    {
        return false;
    }

    GLenum internalFormat = getInternalFormat(baseTarget, samplerState.baseLevel);
    const TextureCaps &textureCaps = data.textureCaps->get(internalFormat);
    if (!textureCaps.filterable && !IsPointSampled(samplerState))
    {
        return false;
    }

    bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3;
    if (!npotSupport)
    {
        if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) ||
            (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height)))
        {
            return false;
        }
    }

    if (IsMipmapFiltered(samplerState))
    {
        if (!npotSupport)
        {
            if (!gl::isPow2(width) || !gl::isPow2(height))
            {
                return false;
            }
        }

        if (!isMipmapComplete(samplerState))
        {
            return false;
        }
    }
    else
    {
        if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
        {
            return false;
        }
    }

    // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
    // The internalformat specified for the texture arrays is a sized internal depth or
    // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
    // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
    // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
    if (formatInfo.depthBits > 0 && data.clientVersion > 2)
    {
        if (samplerState.compareMode == GL_NONE)
        {
            if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
                samplerState.magFilter != GL_NEAREST)
            {
                return false;
            }
        }
    }

    return true;
}

// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
bool Texture::isCubeComplete() const
{
    ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);

    GLenum baseTarget = FirstCubeMapTextureTarget;
    size_t width = getWidth(baseTarget, 0);
    size_t height = getWidth(baseTarget, 0);
    if (width == 0 || width != height)
    {
        return false;
    }

    GLenum internalFormat = getInternalFormat(baseTarget, 0);
    for (GLenum face = baseTarget + 1; face <= LastCubeMapTextureTarget; face++)
    {
        if (getWidth(face, 0) != width ||
            getHeight(face, 0) != height ||
            getInternalFormat(face, 0) != internalFormat)
        {
            return false;
        }
    }

    return true;
}

unsigned int Texture::getTextureSerial() const
{
    return mTextureSerial;
}

unsigned int Texture::issueTextureSerial()
{
    return mCurrentTextureSerial++;
}

bool Texture::isImmutable() const
{
    return (mImmutableLevelCount > 0);
}

int Texture::immutableLevelCount()
{
    return mImmutableLevelCount;
}

Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
                        const PixelUnpackState &unpack, const uint8_t *pixels)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    setImageDesc(ImageIndex::MakeGeneric(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));

    return Error(GL_NO_ERROR);
}

Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
                           const PixelUnpackState &unpack, const uint8_t *pixels)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
}

Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
                                  const PixelUnpackState &unpack, const uint8_t *pixels)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels);
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    setImageDesc(ImageIndex::MakeGeneric(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));

    return Error(GL_NO_ERROR);
}

Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
                                     const PixelUnpackState &unpack, const uint8_t *pixels)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels);
}

Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
                         const Framebuffer *source)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    setImageDesc(ImageIndex::MakeGeneric(target, level), ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
                                                                   GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));

    return Error(GL_NO_ERROR);
}

Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
                            const Framebuffer *source)
{
    ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));

    return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
}

Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
{
    ASSERT(target == mTarget);

    Error error = mTexture->setStorage(target, levels, internalFormat, size);
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    mImmutableLevelCount = levels;
    clearImageDescs();
    setImageDescChain(levels, size, internalFormat);

    return Error(GL_NO_ERROR);
}

Error Texture::generateMipmaps()
{
    Error error = mTexture->generateMipmaps();
    if (error.isError())
    {
        return error;
    }

    releaseTexImage();

    ImageIndex baseLevel = ImageIndex::MakeGeneric(getBaseImageTarget(), 0);
    const ImageDesc &baseImageInfo = getImageDesc(baseLevel);
    size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
    setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);

    return Error(GL_NO_ERROR);
}

void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
{
    for (size_t level = 0; level < levels; level++)
    {
        Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
                          std::max<size_t>(baseSize.height >> level, 1),
                          (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
        ImageDesc levelInfo(levelSize, sizedInternalFormat);

        if (mTarget == GL_TEXTURE_CUBE_MAP)
        {
            for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
            {
                setImageDesc(ImageIndex::MakeGeneric(face, level), levelInfo);
            }
        }
        else
        {
            setImageDesc(ImageIndex::MakeGeneric(mTarget, level), levelInfo);
        }
    }
}

Texture::ImageDesc::ImageDesc()
    : ImageDesc(Extents(0, 0, 0), GL_NONE)
{
}

Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
    : size(size),
      internalFormat(internalFormat)
{
}

const Texture::ImageDesc &Texture::getImageDesc(const ImageIndex &index) const
{
    static const Texture::ImageDesc defaultDesc;
    ImageDescMap::const_iterator iter = mImageDescs.find(index);
    return (iter != mImageDescs.end()) ? iter->second : defaultDesc;
}

void Texture::setImageDesc(const ImageIndex &index, const ImageDesc &desc)
{
    mImageDescs[index] = desc;
}

void Texture::clearImageDescs()
{
    mImageDescs.clear();
}

void Texture::bindTexImage(egl::Surface *surface)
{
    releaseTexImage();
    mTexture->bindTexImage(surface);
    mBoundSurface = surface;
}

void Texture::releaseTexImage()
{
    if (mBoundSurface)
    {
        mBoundSurface = NULL;
        mTexture->releaseTexImage();
    }
}

GLenum Texture::getBaseImageTarget() const
{
    return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
}

size_t Texture::getExpectedMipLevels() const
{
    GLenum baseTarget = getBaseImageTarget();
    size_t width = getWidth(baseTarget, 0);
    size_t height = getHeight(baseTarget, 0);
    if (mTarget == GL_TEXTURE_3D)
    {
        size_t depth = getDepth(baseTarget, 0);
        return log2(std::max(std::max(width, height), depth)) + 1;
    }
    else
    {
        return log2(std::max(width, height)) + 1;
    }
}

bool Texture::isMipmapComplete(const gl::SamplerState &samplerState) const
{
    size_t expectedMipLevels = getExpectedMipLevels();

    size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1);

    for (size_t level = samplerState.baseLevel; level < maxLevel; level++)
    {
        if (mTarget == GL_TEXTURE_CUBE_MAP)
        {
            for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
            {
                if (!isLevelComplete(face, level, samplerState))
                {
                    return false;
                }
            }
        }
        else
        {
            if (!isLevelComplete(mTarget, level, samplerState))
            {
                return false;
            }
        }
    }

    return true;
}

bool Texture::isLevelComplete(GLenum target, size_t level,
                              const gl::SamplerState &samplerState) const
{
    ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);

    if (isImmutable())
    {
        return true;
    }

    size_t width = getWidth(target, samplerState.baseLevel);
    size_t height = getHeight(target, samplerState.baseLevel);
    size_t depth = getDepth(target, samplerState.baseLevel);
    if (width == 0 || height == 0 || depth == 0)
    {
        return false;
    }

    // The base image level is complete if the width and height are positive
    if (level == 0)
    {
        return true;
    }

    if (getInternalFormat(target, level) != getInternalFormat(target, samplerState.baseLevel))
    {
        return false;
    }

    if (getWidth(target, level) != std::max<size_t>(1, width >> level))
    {
        return false;
    }

    if (getHeight(target, level) != std::max<size_t>(1, height >> level))
    {
        return false;
    }

    if (mTarget == GL_TEXTURE_3D)
    {
        if (getDepth(target, level) != std::max<size_t>(1, depth >> level))
        {
            return false;
        }
    }
    else if (mTarget == GL_TEXTURE_2D_ARRAY)
    {
        if (getDepth(target, level) != depth)
        {
            return false;
        }
    }

    return true;
}

}
<|endoftext|>


<commit_before>/* The MIT License (MIT)
 *
 * Copyright (c) 2014 - 2015, Andreas Merkle
 * http://www.blue-andi.de
 * vscp@blue-andi.de
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

/*******************************************************************************
    DESCRIPTION
*******************************************************************************/
/**
@brief  VSCP framework class
@file   VSCP.cpp
@author Andreas Merkle, http://www.blue-andi.de

@section desc Description
@see VSCP.h

@section svn Subversion
$Author: amerkle $
$Rev: 449 $
$Date: 2015-01-05 20:23:52 +0100 (Mo, 05 Jan 2015) $
*******************************************************************************/

/*******************************************************************************
    INCLUDES
*******************************************************************************/
#include "VSCP.h"
#include "framework/vscp_core.h"
#include "framework/vscp_portable.h"
#include "framework/vscp_timer.h"
#include "framework/vscp_dev_data.h"
#include "framework/vscp_tp_adapter.h"
#include "framework/vscp_action.h"

/*******************************************************************************
    COMPILER SWITCHES
*******************************************************************************/

/*******************************************************************************
    CONSTANTS
*******************************************************************************/

/*******************************************************************************
    MACROS
*******************************************************************************/

/*******************************************************************************
    CLASSES, TYPES AND STRUCTURES
*******************************************************************************/

/*******************************************************************************
    PROTOTYPES
*******************************************************************************/

/*******************************************************************************
    LOCAL VARIABLES
*******************************************************************************/

/*******************************************************************************
    GLOBAL VARIABLES
*******************************************************************************/

/*******************************************************************************
    GLOBAL FUNCTIONS
*******************************************************************************/

VSCP::VSCP() :
    mIsInitialized(false),                  /* Call setup() later */
    mStatusLampPin(0),                      /* Status Lamp pin */
    mInitButtonPin(0),                      /* Segment initialization button pin */
    mStatusLampState(VSCP_LAMP_STATE_OFF),  /* Status lamp startup state is off */
    mStatusLampPeriod(200),                 /* 200 ms status lamp blinking period */
    mStatusLampTimer(),                     /* Status lamp timer for blinking */
    mVSCPTimerPeriod(250),                  /* 250 ms VSCP timer period */
    mVSCPTimer()                            /* Timer instance used to handle the VSCP framework timers */
{
    return;
}

VSCP::~VSCP()
{
    return;
}

void VSCP::setup(
    int             statusLampPin,
    int             initButtonPin,
    const VSCPGuid& guid,
    unsigned char   zone,
    unsigned char   subZone,
    TpRead          tpReadFunc,
    TpWrite         tpWriteFunc,
    ExecuteAction   actionExecFunc)
{
    unsigned char           index   = 0;
    vscp_dev_data_Container devData;

    /* Configure the hardware */
    pinMode(mStatusLampPin, OUTPUT);
    pinMode(initButtonPin, INPUT);

    /* Initialize the VSCP core and the user specific stuff. */
    (void)vscp_core_init();

    /* Store device data */
    for(index = 0; index < VSCP_GUID_SIZE; ++index)
    {
        devData.guid[index] = guid[index];
    }
    devData.zone    = zone;
    devData.subZone = subZone;
    vscp_dev_data_set(&devData);

    /* Setup transport layer */
    vscp_tp_adapter_set(tpReadFunc, tpWriteFunc);

    /* Setup action */
    vscp_action_set(actionExecFunc);

    /* Start VSCP timer */
    mVSCPTimer.start(mVSCPTimerPeriod, false);

    /* Framework is now ready */
    mIsInitialized = true;

    return;
}

void VSCP::restoreFactoryDefaultSettings(void)
{
    if (true == mIsInitialized)
    {
        vscp_core_restoreFactoryDefaultSettings();
    }

    return;
}

void VSCP::process(void)
{
    if (true == mIsInitialized)
    {
        /* Process the whole framework */
        vscp_core_process();

        /* Process all member timers */
        mStatusLampTimer.process();
        mVSCPTimer.process();

        /* Process all VSCP framework timers */
        if (true == mVSCPTimer.isTimeout())
        {
            vscp_timer_process(mVSCPTimerPeriod);
        }

        /* Process the status lamp */
        processStatusLamp();

        /* Handle segment initialization button */
        if (HIGH == digitalRead(mInitButtonPin))
        {
            vscp_core_startNodeSegmentInit();
        }
    }

    return;
}

uint8_t VSCP::readNicknameId(void)
{
    unsigned char   nicknameId  = VSCP_NICKNAME_NOT_INIT;

    if (true == mIsInitialized)
    {
        nicknameId = vscp_core_readNicknameId();
    }

    return nicknameId;
}

void VSCP::startNodeSegmentInit(void)
{
    if (true == mIsInitialized)
    {
        vscp_core_startNodeSegmentInit();
    }

    return;
}

void VSCP::setAlarm(unsigned char value)
{
    if (true == mIsInitialized)
    {
        vscp_core_setAlarm(value);
    }

    return;
}

bool VSCP::isActive(void)
{
    bool    status  = false;

    if (TRUE == mIsInitialized)
    {
        if (FALSE != vscp_core_isActive())
        {
            status = true;
        }
    }

    return status;
}

void VSCP::prepareTxMessage(vscp_TxMessage& txMessage, unsigned int vscpClass, unsigned char vscpType, VSCP_PRIORITY priority)
{
    vscp_core_prepareTxMessage(&txMessage, vscpClass, vscpType, priority);
    return;
}

bool VSCP::write(const vscp_TxMessage& txMessage)
{
    bool    status = false;

    if (TRUE == mIsInitialized)
    {
        status = vscp_core_sendEvent(&txMessage);
    }

    return status;
}

bool VSCP::read(vscp_RxMessage& msg)
{
    bool    status = false;

    if (TRUE == mIsInitialized)
    {
        status = vscp_portable_read(&msg);
    }

    return status;
}

/*******************************************************************************
    LOCAL FUNCTIONS
*******************************************************************************/

void VSCP::processStatusLamp(void)
{
    VSCP_LAMP_STATE     statusLampState     = vscp_portable_getLampState();

    /* Lamp state changed? */
    if (mStatusLampState != statusLampState)
    {
        mStatusLampState = statusLampState;

        switch(mStatusLampState)
        {
        case VSCP_LAMP_STATE_OFF:
            digitalWrite(mStatusLampPin, LOW);
            break;

        case VSCP_LAMP_STATE_ON:
            digitalWrite(mStatusLampPin, HIGH);
            break;

        case VSCP_LAMP_STATE_BLINK:
            mStatusLampTimer.start(mStatusLampPeriod, false);
            break;

        default:
            break;
        }
    }
    /* Shall the lamp blink? */
    else if (VSCP_LAMP_STATE_BLINK == mStatusLampState)
    {
        /* Toggle status lamp? */
        if (true == mStatusLampTimer.isTimeout())
        {
            int statusLampPinState = digitalRead(mStatusLampPin);

            if (LOW == statusLampPinState)
            {
                statusLampPinState = HIGH;
            }
            else
            {
                statusLampPinState = LOW;
            }

            digitalWrite(mStatusLampPin, statusLampPinState);
        }
    }

    return;
}
<commit_msg>Hardware configuration fixed.<commit_after>/* The MIT License (MIT)
 *
 * Copyright (c) 2014 - 2015, Andreas Merkle
 * http://www.blue-andi.de
 * vscp@blue-andi.de
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

/*******************************************************************************
    DESCRIPTION
*******************************************************************************/
/**
@brief  VSCP framework class
@file   VSCP.cpp
@author Andreas Merkle, http://www.blue-andi.de

@section desc Description
@see VSCP.h

@section svn Subversion
$Author: amerkle $
$Rev: 449 $
$Date: 2015-01-05 20:23:52 +0100 (Mo, 05 Jan 2015) $
*******************************************************************************/

/*******************************************************************************
    INCLUDES
*******************************************************************************/
#include "VSCP.h"
#include "framework/vscp_core.h"
#include "framework/vscp_portable.h"
#include "framework/vscp_timer.h"
#include "framework/vscp_dev_data.h"
#include "framework/vscp_tp_adapter.h"
#include "framework/vscp_action.h"

/*******************************************************************************
    COMPILER SWITCHES
*******************************************************************************/

/*******************************************************************************
    CONSTANTS
*******************************************************************************/

/*******************************************************************************
    MACROS
*******************************************************************************/

/*******************************************************************************
    CLASSES, TYPES AND STRUCTURES
*******************************************************************************/

/*******************************************************************************
    PROTOTYPES
*******************************************************************************/

/*******************************************************************************
    LOCAL VARIABLES
*******************************************************************************/

/*******************************************************************************
    GLOBAL VARIABLES
*******************************************************************************/

/*******************************************************************************
    GLOBAL FUNCTIONS
*******************************************************************************/

VSCP::VSCP() :
    mIsInitialized(false),                  /* Call setup() later */
    mStatusLampPin(0),                      /* Status Lamp pin */
    mInitButtonPin(0),                      /* Segment initialization button pin */
    mStatusLampState(VSCP_LAMP_STATE_OFF),  /* Status lamp startup state is off */
    mStatusLampPeriod(200),                 /* 200 ms status lamp blinking period */
    mStatusLampTimer(),                     /* Status lamp timer for blinking */
    mVSCPTimerPeriod(250),                  /* 250 ms VSCP timer period */
    mVSCPTimer()                            /* Timer instance used to handle the VSCP framework timers */
{
    return;
}

VSCP::~VSCP()
{
    return;
}

void VSCP::setup(
    int             statusLampPin,
    int             initButtonPin,
    const VSCPGuid& guid,
    unsigned char   zone,
    unsigned char   subZone,
    TpRead          tpReadFunc,
    TpWrite         tpWriteFunc,
    ExecuteAction   actionExecFunc)
{
    unsigned char           index   = 0;
    vscp_dev_data_Container devData;

    /* Configure the hardware */
    pinMode(statusLampPin, OUTPUT);
    pinMode(initButtonPin, INPUT_PULLUP);

    mStatusLampPin = statusLampPin;
    mInitButtonPin = initButtonPin;

    /* Initialize the VSCP core and the user specific stuff. */
    (void)vscp_core_init();

    /* Store device data */
    for(index = 0; index < VSCP_GUID_SIZE; ++index)
    {
        devData.guid[index] = guid[index];
    }
    devData.zone    = zone;
    devData.subZone = subZone;
    vscp_dev_data_set(&devData);

    /* Setup transport layer */
    vscp_tp_adapter_set(tpReadFunc, tpWriteFunc);

    /* Setup action */
    vscp_action_set(actionExecFunc);

    /* Start VSCP timer */
    mVSCPTimer.start(mVSCPTimerPeriod, false);

    /* Framework is now ready */
    mIsInitialized = true;

    return;
}

void VSCP::restoreFactoryDefaultSettings(void)
{
    if (true == mIsInitialized)
    {
        vscp_core_restoreFactoryDefaultSettings();
    }

    return;
}

void VSCP::process(void)
{
    if (true == mIsInitialized)
    {
        /* Process the whole framework */
        vscp_core_process();

        /* Process all member timers */
        mStatusLampTimer.process();
        mVSCPTimer.process();

        /* Process all VSCP framework timers */
        if (true == mVSCPTimer.isTimeout())
        {
            vscp_timer_process(mVSCPTimerPeriod);
        }

        /* Process the status lamp */
        processStatusLamp();

        /* Handle segment initialization button */
        if (LOW == digitalRead(mInitButtonPin))
        {
            vscp_core_startNodeSegmentInit();
        }
    }

    return;
}

uint8_t VSCP::readNicknameId(void)
{
    unsigned char   nicknameId  = VSCP_NICKNAME_NOT_INIT;

    if (true == mIsInitialized)
    {
        nicknameId = vscp_core_readNicknameId();
    }

    return nicknameId;
}

void VSCP::startNodeSegmentInit(void)
{
    if (true == mIsInitialized)
    {
        vscp_core_startNodeSegmentInit();
    }

    return;
}

void VSCP::setAlarm(unsigned char value)
{
    if (true == mIsInitialized)
    {
        vscp_core_setAlarm(value);
    }

    return;
}

bool VSCP::isActive(void)
{
    bool    status  = false;

    if (TRUE == mIsInitialized)
    {
        if (FALSE != vscp_core_isActive())
        {
            status = true;
        }
    }

    return status;
}

void VSCP::prepareTxMessage(vscp_TxMessage& txMessage, unsigned int vscpClass, unsigned char vscpType, VSCP_PRIORITY priority)
{
    vscp_core_prepareTxMessage(&txMessage, vscpClass, vscpType, priority);
    return;
}

bool VSCP::write(const vscp_TxMessage& txMessage)
{
    bool    status = false;

    if (TRUE == mIsInitialized)
    {
        status = vscp_core_sendEvent(&txMessage);
    }

    return status;
}

bool VSCP::read(vscp_RxMessage& msg)
{
    bool    status = false;

    if (TRUE == mIsInitialized)
    {
        status = vscp_portable_read(&msg);
    }

    return status;
}

/*******************************************************************************
    LOCAL FUNCTIONS
*******************************************************************************/

void VSCP::processStatusLamp(void)
{
    VSCP_LAMP_STATE     statusLampState     = vscp_portable_getLampState();

    /* Lamp state changed? */
    if (mStatusLampState != statusLampState)
    {
        mStatusLampState = statusLampState;

        switch(mStatusLampState)
        {
        case VSCP_LAMP_STATE_OFF:
            digitalWrite(mStatusLampPin, LOW);
            break;

        case VSCP_LAMP_STATE_ON:
            digitalWrite(mStatusLampPin, HIGH);
            break;

        case VSCP_LAMP_STATE_BLINK:
            mStatusLampTimer.start(mStatusLampPeriod, false);
            break;

        default:
            break;
        }
    }
    /* Shall the lamp blink? */
    else if (VSCP_LAMP_STATE_BLINK == mStatusLampState)
    {
        /* Toggle status lamp? */
        if (true == mStatusLampTimer.isTimeout())
        {
            int statusLampPinState = digitalRead(mStatusLampPin);

            if (LOW == statusLampPinState)
            {
                statusLampPinState = HIGH;
            }
            else
            {
                statusLampPinState = LOW;
            }

            digitalWrite(mStatusLampPin, statusLampPinState);
        }
    }

    return;
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_OPERATORS_ELLIPTIC_CG_HH
#define DUNE_GDT_OPERATORS_ELLIPTIC_CG_HH

#include <type_traits>

#include <dune/stuff/la/container/interfaces.hh>
#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/common/memory.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/localevaluation/elliptic.hh>
#include <dune/gdt/localoperator/codim0.hh>
#include <dune/gdt/assembler/local/codim0.hh>
#include <dune/gdt/assembler/system.hh>

#include "base.hh"

namespace Dune {
namespace GDT {
namespace Operators {

// forwards
template <class DiffusionFactorType, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp = SourceSpaceImp,
          class GridViewImp = typename SourceSpaceImp::GridViewType, class DiffusionTensorType = void>
class EllipticCG;

namespace internal {

template <class DiffusionFactorType, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp, class GridViewImp,
          class DiffusionTensorType = void>
class EllipticCGTraits
{
  static_assert(std::is_base_of<Stuff::Tags::LocalizableFunction, DiffusionFactorType>::value,
                "DiffusionFactorType has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(std::is_base_of<Stuff::Tags::LocalizableFunction, DiffusionTensorType>::value
                    || std::is_same<void, DiffusionTensorType>::value,
                "DiffusionTensorType has to be void or derived from Stuff::LocalizableFunctionInterface!");
  static_assert(
      std::is_base_of<Stuff::LA::MatrixInterface<typename MatrixImp::Traits, typename MatrixImp::Traits::ScalarType>,
                      MatrixImp>::value,
      "MatrixImp has to be derived from Stuff::LA::MatrixInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename SourceSpaceImp::Traits>, SourceSpaceImp>::value,
                "SourceSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename RangeSpaceImp::Traits>, RangeSpaceImp>::value,
                "RangeSpaceImp has to be derived from SpaceInterface!");

public:
  typedef EllipticCG<DiffusionFactorType, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp, DiffusionTensorType>
      derived_type;
  typedef MatrixImp MatrixType;
  typedef SourceSpaceImp SourceSpaceType;
  typedef RangeSpaceImp RangeSpaceType;
  typedef GridViewImp GridViewType;
}; // class EllipticCGTraits

} // namespace internal

template <class DiffusionType, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp, class GridViewImp>
class EllipticCG<DiffusionType, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp, void>
    : public Operators::MatrixBased<internal::EllipticCGTraits<DiffusionType, MatrixImp, SourceSpaceImp, RangeSpaceImp,
                                                               GridViewImp, void>>,
      public SystemAssembler<RangeSpaceImp, GridViewImp, SourceSpaceImp>
{
  typedef SystemAssembler<RangeSpaceImp, GridViewImp, SourceSpaceImp> AssemblerBaseType;
  typedef Operators::MatrixBased<internal::EllipticCGTraits<DiffusionType, MatrixImp, SourceSpaceImp, RangeSpaceImp,
                                                            GridViewImp>> OperatorBaseType;
  typedef LocalOperator::Codim0Integral<LocalEvaluation::Elliptic<DiffusionType>> LocalOperatorType;
  typedef LocalAssembler::Codim0Matrix<LocalOperatorType> LocalAssemblerType;

public:
  typedef internal::EllipticCGTraits<DiffusionType, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp, void> Traits;

  typedef typename Traits::MatrixType MatrixType;
  typedef typename Traits::SourceSpaceType SourceSpaceType;
  typedef typename Traits::RangeSpaceType RangeSpaceType;
  typedef typename Traits::GridViewType GridViewType;

  using OperatorBaseType::pattern;

  static Stuff::LA::SparsityPatternDefault pattern(const RangeSpaceType& range_space,
                                                   const SourceSpaceType& source_space, const GridViewType& grid_view)
  {
    return range_space.compute_volume_pattern(grid_view, source_space);
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& matrix, const SourceSpaceType& source_space,
             const RangeSpaceType& range_space, const GridViewType& grid_view)
    : OperatorBaseType(matrix, source_space, range_space, grid_view)
    , AssemblerBaseType(range_space, grid_view, source_space)
    , diffusion_(diffusion)
    , local_operator_(diffusion_)
    , local_assembler_(local_operator_)
  {
    this->add(local_assembler_, this->matrix());
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& mtrx, const SourceSpaceType& src_spc,
             const RangeSpaceType& rng_spc)
    : OperatorBaseType(mtrx, src_spc, rng_spc)
    , AssemblerBaseType(rng_spc, src_spc)
    , diffusion_(diffusion)
    , local_operator_(diffusion_)
    , local_assembler_(local_operator_)
  {
    this->add(local_assembler_, this->matrix());
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& mtrx, const SourceSpaceType& src_spc)
    : OperatorBaseType(mtrx, src_spc)
    , AssemblerBaseType(src_spc)
    , diffusion_(diffusion)
    , local_operator_(diffusion_)
    , local_assembler_(local_operator_)
  {
    this->add(local_assembler_, this->matrix());
  }

  virtual ~EllipticCG()
  {
  }

  virtual void assemble() override final
  {
    AssemblerBaseType::assemble();
  }

private:
  const DiffusionType& diffusion_;
  const LocalOperatorType local_operator_;
  const LocalAssemblerType local_assembler_;
}; // class EllipticCG

} // namespace Operators
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_OPERATORS_ELLIPTIC_CG_HH
<commit_msg>[operators.elliptic-cg] use storage provider<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_OPERATORS_ELLIPTIC_CG_HH
#define DUNE_GDT_OPERATORS_ELLIPTIC_CG_HH

#include <type_traits>

#include <dune/stuff/common/memory.hh>
#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/la/container/interfaces.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/localevaluation/elliptic.hh>
#include <dune/gdt/localoperator/codim0.hh>
#include <dune/gdt/assembler/local/codim0.hh>
#include <dune/gdt/assembler/system.hh>

#include "base.hh"

namespace Dune {
namespace GDT {
namespace Operators {

// forwards
template <class DiffusionFactorType, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp = SourceSpaceImp,
          class GridViewImp = typename SourceSpaceImp::GridViewType, class DiffusionTensorType = void>
class EllipticCG;

namespace internal {

template <class DiffusionFactorType, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp, class GridViewImp,
          class DiffusionTensorType = void>
class EllipticCGTraits
{
  static_assert(std::is_base_of<Stuff::Tags::LocalizableFunction, DiffusionFactorType>::value,
                "DiffusionFactorType has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(std::is_base_of<Stuff::Tags::LocalizableFunction, DiffusionTensorType>::value
                    || std::is_same<void, DiffusionTensorType>::value,
                "DiffusionTensorType has to be void or derived from Stuff::LocalizableFunctionInterface!");
  static_assert(
      std::is_base_of<Stuff::LA::MatrixInterface<typename MatrixImp::Traits, typename MatrixImp::Traits::ScalarType>,
                      MatrixImp>::value,
      "MatrixImp has to be derived from Stuff::LA::MatrixInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename SourceSpaceImp::Traits>, SourceSpaceImp>::value,
                "SourceSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename RangeSpaceImp::Traits>, RangeSpaceImp>::value,
                "RangeSpaceImp has to be derived from SpaceInterface!");

public:
  typedef EllipticCG<DiffusionFactorType, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp, DiffusionTensorType>
      derived_type;
  typedef MatrixImp MatrixType;
  typedef SourceSpaceImp SourceSpaceType;
  typedef RangeSpaceImp RangeSpaceType;
  typedef GridViewImp GridViewType;
}; // class EllipticCGTraits

} // namespace internal

template <class DiffusionType, class MatrixImp, class SourceSpaceImp, class RangeSpaceImp, class GridViewImp>
class EllipticCG<DiffusionType, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp, void>
    : Stuff::Common::StorageProvider<MatrixImp>,
      public Operators::MatrixBased<internal::EllipticCGTraits<DiffusionType, MatrixImp, SourceSpaceImp, RangeSpaceImp,
                                                               GridViewImp, void>>,
      public SystemAssembler<RangeSpaceImp, GridViewImp, SourceSpaceImp>
{
  typedef Stuff::Common::StorageProvider<MatrixImp> StorageProvider;
  typedef SystemAssembler<RangeSpaceImp, GridViewImp, SourceSpaceImp> AssemblerBaseType;
  typedef Operators::MatrixBased<internal::EllipticCGTraits<DiffusionType, MatrixImp, SourceSpaceImp, RangeSpaceImp,
                                                            GridViewImp>> OperatorBaseType;
  typedef LocalOperator::Codim0Integral<LocalEvaluation::Elliptic<DiffusionType>> LocalOperatorType;
  typedef LocalAssembler::Codim0Matrix<LocalOperatorType> LocalAssemblerType;

public:
  typedef internal::EllipticCGTraits<DiffusionType, MatrixImp, SourceSpaceImp, RangeSpaceImp, GridViewImp, void> Traits;

  typedef typename Traits::MatrixType MatrixType;
  typedef typename Traits::SourceSpaceType SourceSpaceType;
  typedef typename Traits::RangeSpaceType RangeSpaceType;
  typedef typename Traits::GridViewType GridViewType;

  using OperatorBaseType::pattern;

  static Stuff::LA::SparsityPatternDefault pattern(const RangeSpaceType& range_space,
                                                   const SourceSpaceType& source_space, const GridViewType& grid_view)
  {
    return range_space.compute_volume_pattern(grid_view, source_space);
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& mtrx, const SourceSpaceType& src_spc,
             const RangeSpaceType& rng_spc, const GridViewType& grid_view)
    : StorageProvider(mtrx)
    , OperatorBaseType(this->storage_access(), src_spc, rng_spc, grid_view)
    , AssemblerBaseType(rng_spc, grid_view, src_spc)
    , diffusion_(diffusion)
    , local_operator_(diffusion_)
    , local_assembler_(local_operator_)
    , assembled_(false)
  {
    this->add(local_assembler_, this->matrix());
  }

  EllipticCG(const DiffusionType& diffusion, const SourceSpaceType& src_spc, const RangeSpaceType& rng_spc,
             const GridViewType& grid_view)
    : StorageProvider(
          new MatrixType(rng_spc.mapper().size(), src_spc.mapper().size(), pattern(rng_spc, src_spc, grid_view)))
    , OperatorBaseType(this->storage_access(), src_spc, rng_spc, grid_view)
    , AssemblerBaseType(rng_spc, grid_view, src_spc)
    , diffusion_(diffusion)
    , local_operator_(diffusion_)
    , local_assembler_(local_operator_)
    , assembled_(false)
  {
    this->add(local_assembler_, this->matrix());
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& mtrx, const SourceSpaceType& src_spc,
             const RangeSpaceType& rng_spc)
    : StorageProvider(mtrx)
    , OperatorBaseType(this->storage_access(), src_spc, rng_spc)
    , AssemblerBaseType(rng_spc, src_spc)
    , diffusion_(diffusion)
    , local_operator_(diffusion_)
    , local_assembler_(local_operator_)
    , assembled_(false)
  {
    this->add(local_assembler_, this->matrix());
  }

  EllipticCG(const DiffusionType& diffusion, const SourceSpaceType& src_spc, const RangeSpaceType& rng_spc)
    : StorageProvider(new MatrixType(rng_spc.mapper().size(), src_spc.mapper().size(), pattern(rng_spc, src_spc)))
    , OperatorBaseType(this->storage_access(), src_spc, rng_spc)
    , AssemblerBaseType(rng_spc, src_spc)
    , diffusion_(diffusion)
    , local_operator_(diffusion_)
    , local_assembler_(local_operator_)
    , assembled_(false)
  {
    this->add(local_assembler_, this->matrix());
  }

  EllipticCG(const DiffusionType& diffusion, MatrixType& mtrx, const SourceSpaceType& src_spc)
    : StorageProvider(mtrx)
    , OperatorBaseType(this->storage_access(), src_spc)
    , AssemblerBaseType(src_spc)
    , diffusion_(diffusion)
    , local_operator_(diffusion_)
    , local_assembler_(local_operator_)
    , assembled_(false)
  {
    this->add(local_assembler_, this->matrix());
  }

  EllipticCG(const DiffusionType& diffusion, const SourceSpaceType& src_spc)
    : StorageProvider(new MatrixType(src_spc.mapper().size(), src_spc.mapper().size(), pattern(src_spc)))
    , OperatorBaseType(this->storage_access(), src_spc)
    , AssemblerBaseType(src_spc)
    , diffusion_(diffusion)
    , local_operator_(diffusion_)
    , local_assembler_(local_operator_)
    , assembled_(false)
  {
    this->add(local_assembler_, this->matrix());
  }

  virtual ~EllipticCG()
  {
  }

  virtual void assemble() override final
  {
    if (!assembled_) {
      AssemblerBaseType::assemble(true);
      assembled_ = true;
    }
  } // ... assemble(...)

private:
  const DiffusionType& diffusion_;
  const LocalOperatorType local_operator_;
  const LocalAssemblerType local_assembler_;
  bool assembled_;
}; // class EllipticCG

} // namespace Operators
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_OPERATORS_ELLIPTIC_CG_HH
<|endoftext|>


<commit_before>//===- CallGraph.cpp - Build a Module's call graph ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This interface is used to build and manipulate a call graph, which is a very
// useful tool for interprocedural optimization.
//
// Every function in a module is represented as a node in the call graph.  The
// callgraph node keeps track of which functions the are called by the function
// corresponding to the node.
//
// A call graph will contain nodes where the function that they correspond to is
// null.  This 'external' node is used to represent control flow that is not
// represented (or analyzable) in the module.  As such, the external node will
// have edges to functions with the following properties:
//   1. All functions in the module without internal linkage, since they could
//      be called by functions outside of the our analysis capability.
//   2. All functions whose address is used for something more than a direct
//      call, for example being stored into a memory location.  Since they may
//      be called by an unknown caller later, they must be tracked as such.
//
// Similarly, functions have a call edge to the external node iff:
//   1. The function is external, reflecting the fact that they could call
//      anything without internal linkage or that has its address taken.
//   2. The function contains an indirect function call.
//
// As an extension in the future, there may be multiple nodes with a null
// function.  These will be used when we can prove (through pointer analysis)
// that an indirect call site can call only a specific set of functions.
//
// Because of these properties, the CallGraph captures a conservative superset
// of all of the caller-callee relationships, which is useful for
// transformations.
//
// The CallGraph class also attempts to figure out what the root of the
// CallGraph is, which is currently does by looking for a function named 'main'.
// If no function named 'main' is found, the external node is used as the entry
// node, reflecting the fact that any function without internal linkage could
// be called into (which is common for libraries).
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/CallGraph.h"
#include "llvm/Constants.h"     // Remove when ConstantPointerRefs are gone
#include "llvm/Module.h"
#include "llvm/iOther.h"
#include "llvm/iTerminators.h"
#include "llvm/Support/CallSite.h"
#include "Support/STLExtras.h"

static RegisterAnalysis<CallGraph> X("callgraph", "Call Graph Construction");

static const char * const KnownExternalFunctions[] = {
  // Low-level system calls
  "open",
  "read",
  "write",
  "writev",
  "lseek",
  "poll",
  "ioctl",

  // Low-level stdc library functions
  "abort",
  "getenv",
  "putenv",

  // Standard IO functions
  "printf",
  "sprintf",
  "fopen",
  "freopen",
  "fclose",
  "fwrite",
  "puts",
  "fputs",
  "getc",
  "ungetc",
  "putc",
  "putchar",
  "fread",
  "fileno",
  "ftell",
  "fflush",
  "fseek",
  "fileno",
  "ferror",
  "feof",
  "fdopen",
  "__fxstat",
  "setbuf",
  "setbuffer",
  "etlinebuf",
  "setvbuf",

  // Memory functions
  "malloc",
  "free",
  "realloc",
  "calloc",
  "memalign",

  // String functions
  "atoi",
  "memmove",
  "memset",
  "memchr",
  "memcmp",
  "strchr",
  "strncpy",
  "strncmp",
  "strcmp",
  "__strcoll_l",
  "__strxfrm_l",
  "__strftime_l",
  "__strtol_l",
  "__strtoul_l",
  "__strtoll_l",
  "__strtoull_l",
  "__strtof_l",
  "__strtod_l",
  "__strtold_l",

  // Locale functions
  "__uselocale",
  "__newlocale",
  "__freelocale",
  "__duplocale",
  "__nl_langinfo_l",

  // gettext functions used by libstdc++
  "gettext",
  "dgettext",
  "dcgettext",
  "textdomain",
  "bindtextdomain",

  // Random stuff
  "__assert_fail",
  "__errno_location",
};

/// ExternalFunctionDoesntCallIntoProgram - This hack is used to indicate to the
/// call graph that the specified external function is _KNOWN_ to not call back
/// into the program.  This is important, because otherwise functions which call
/// "printf" for example, end up in a great big SCC that goes from the function
/// through main.
///
static bool ExternalFunctionDoesntCallIntoProgram(const std::string &Name) {
  static std::vector<std::string> Funcs;

  // First time this is called?
  if (Funcs.empty()) {
    // Add a whole bunch of functions which are often used...
    Funcs.insert(Funcs.end(), KnownExternalFunctions,
                 KnownExternalFunctions+
              sizeof(KnownExternalFunctions)/sizeof(KnownExternalFunctions[0]));
    // Sort the list for efficient access
    std::sort(Funcs.begin(), Funcs.end());
  }

  // Binary search for the function name...
  std::vector<std::string>::iterator I =
    std::lower_bound(Funcs.begin(), Funcs.end(), Name);

  // Found it?
  return I != Funcs.end() && *I == Name;
}

// getNodeFor - Return the node for the specified function or create one if it
// does not already exist.
//
CallGraphNode *CallGraph::getNodeFor(Function *F) {
  CallGraphNode *&CGN = FunctionMap[F];
  if (CGN) return CGN;

  assert((!F || F->getParent() == Mod) && "Function not in current module!");
  return CGN = new CallGraphNode(F);
}

static bool isOnlyADirectCall(Function *F, CallSite CS) {
  if (!CS.getInstruction()) return false;
  for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I)
    if (*I == F) return false;
  return true;
}

// addToCallGraph - Add a function to the call graph, and link the node to all
// of the functions that it calls.
//
void CallGraph::addToCallGraph(Function *F) {
  CallGraphNode *Node = getNodeFor(F);

  // If this function has external linkage, anything could call it...
  if (!F->hasInternalLinkage()) {
    ExternalNode->addCalledFunction(Node);

    // Found the entry point?
    if (F->getName() == "main") {
      if (Root)
        Root = ExternalNode;  // Found multiple external mains?  Don't pick one.
      else
        Root = Node;          // Found a main, keep track of it!
    }
  }

  // If this function is not defined in this translation unit, it could call
  // anything.
  if (F->isExternal() && !F->getIntrinsicID() &&
      !ExternalFunctionDoesntCallIntoProgram(F->getName()))
    Node->addCalledFunction(ExternalNode);

  // Loop over all of the users of the function... looking for callers...
  //
  bool isUsedExternally = false;
  for (Value::use_iterator I = F->use_begin(), E = F->use_end(); I != E; ++I) {
    if (Instruction *Inst = dyn_cast<Instruction>(*I)) {
      if (isOnlyADirectCall(F, CallSite::get(Inst)))
        getNodeFor(Inst->getParent()->getParent())->addCalledFunction(Node);
      else
        isUsedExternally = true;
    } else if (ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(*I)) {
      // THIS IS A DISGUSTING HACK.  Brought to you by the power of
      // ConstantPointerRefs!
      for (Value::use_iterator I = CPR->use_begin(), E = CPR->use_end();
           I != E; ++I)
        if (Instruction *Inst = dyn_cast<Instruction>(*I)) {
          if (isOnlyADirectCall(F, CallSite::get(Inst)))
            getNodeFor(Inst->getParent()->getParent())->addCalledFunction(Node);
          else
            isUsedExternally = true;
        } else {
          isUsedExternally = true;
        }
    } else {                        // Can't classify the user!
      isUsedExternally = true;
    }
  }
  if (isUsedExternally)
    ExternalNode->addCalledFunction(Node);

  // Look for an indirect function call...
  for (Function::iterator BB = F->begin(), BBE = F->end(); BB != BBE; ++BB)
    for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE; ++II){
      CallSite CS = CallSite::get(II);
      if (CS.getInstruction() && !CS.getCalledFunction())
        Node->addCalledFunction(ExternalNode);
    }
}

bool CallGraph::run(Module &M) {
  destroy();

  Mod = &M;
  ExternalNode = getNodeFor(0);
  Root = 0;

  // Add every function to the call graph...
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    addToCallGraph(I);

  // If we didn't find a main function, use the external call graph node
  if (Root == 0) Root = ExternalNode;

  return false;
}

void CallGraph::destroy() {
  for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
       I != E; ++I)
    delete I->second;
  FunctionMap.clear();
}

static void WriteToOutput(const CallGraphNode *CGN, std::ostream &o) {
  if (CGN->getFunction())
    o << "Call graph node for function: '"
      << CGN->getFunction()->getName() <<"'\n";
  else
    o << "Call graph node <<null function: 0x" << CGN << ">>:\n";

  for (unsigned i = 0; i < CGN->size(); ++i)
    if ((*CGN)[i]->getFunction())
      o << "  Calls function '" << (*CGN)[i]->getFunction()->getName() << "'\n";
    else
      o << "  Calls external node\n";
  o << "\n";
}

void CallGraph::print(std::ostream &o, const Module *M) const {
  o << "CallGraph Root is: ";
  if (getRoot()->getFunction())
    o << getRoot()->getFunction()->getName() << "\n";
  else
    o << "<<null function: 0x" << getRoot() << ">>\n";

  for (CallGraph::const_iterator I = begin(), E = end(); I != E; ++I)
    WriteToOutput(I->second, o);
}

//===----------------------------------------------------------------------===//
// Implementations of public modification methods
//

// Functions to keep a call graph up to date with a function that has been
// modified
//
void CallGraph::addFunctionToModule(Function *Meth) {
  assert(0 && "not implemented");
  abort();
}

// removeFunctionFromModule - Unlink the function from this module, returning
// it.  Because this removes the function from the module, the call graph node
// is destroyed.  This is only valid if the function does not call any other
// functions (ie, there are no edges in it's CGN).  The easiest way to do this
// is to dropAllReferences before calling this.
//
Function *CallGraph::removeFunctionFromModule(CallGraphNode *CGN) {
  assert(CGN->CalledFunctions.empty() && "Cannot remove function from call "
         "graph if it references other functions!");
  Function *F = CGN->getFunction(); // Get the function for the call graph node
  delete CGN;                       // Delete the call graph node for this func
  FunctionMap.erase(F);             // Remove the call graph node from the map

  Mod->getFunctionList().remove(F);
  return F;
}

void CallGraph::stub() {}
<commit_msg>None of the __llvm_* functions call into the program.  This makes the callgraph MUCH simpler for eh using program.<commit_after>//===- CallGraph.cpp - Build a Module's call graph ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This interface is used to build and manipulate a call graph, which is a very
// useful tool for interprocedural optimization.
//
// Every function in a module is represented as a node in the call graph.  The
// callgraph node keeps track of which functions the are called by the function
// corresponding to the node.
//
// A call graph will contain nodes where the function that they correspond to is
// null.  This 'external' node is used to represent control flow that is not
// represented (or analyzable) in the module.  As such, the external node will
// have edges to functions with the following properties:
//   1. All functions in the module without internal linkage, since they could
//      be called by functions outside of the our analysis capability.
//   2. All functions whose address is used for something more than a direct
//      call, for example being stored into a memory location.  Since they may
//      be called by an unknown caller later, they must be tracked as such.
//
// Similarly, functions have a call edge to the external node iff:
//   1. The function is external, reflecting the fact that they could call
//      anything without internal linkage or that has its address taken.
//   2. The function contains an indirect function call.
//
// As an extension in the future, there may be multiple nodes with a null
// function.  These will be used when we can prove (through pointer analysis)
// that an indirect call site can call only a specific set of functions.
//
// Because of these properties, the CallGraph captures a conservative superset
// of all of the caller-callee relationships, which is useful for
// transformations.
//
// The CallGraph class also attempts to figure out what the root of the
// CallGraph is, which is currently does by looking for a function named 'main'.
// If no function named 'main' is found, the external node is used as the entry
// node, reflecting the fact that any function without internal linkage could
// be called into (which is common for libraries).
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/CallGraph.h"
#include "llvm/Constants.h"     // Remove when ConstantPointerRefs are gone
#include "llvm/Module.h"
#include "llvm/iOther.h"
#include "llvm/iTerminators.h"
#include "llvm/Support/CallSite.h"
#include "Support/STLExtras.h"

static RegisterAnalysis<CallGraph> X("callgraph", "Call Graph Construction");

static const char * const KnownExternalFunctions[] = {
  // Low-level system calls
  "open",
  "read",
  "write",
  "writev",
  "lseek",
  "poll",
  "ioctl",

  // Low-level stdc library functions
  "abort",
  "getenv",
  "putenv",

  // Standard IO functions
  "printf",
  "sprintf",
  "fopen",
  "freopen",
  "fclose",
  "fwrite",
  "puts",
  "fputs",
  "getc",
  "ungetc",
  "putc",
  "putchar",
  "fread",
  "fileno",
  "ftell",
  "fflush",
  "fseek",
  "fileno",
  "ferror",
  "feof",
  "fdopen",
  "__fxstat",
  "setbuf",
  "setbuffer",
  "etlinebuf",
  "setvbuf",

  // Memory functions
  "malloc",
  "free",
  "realloc",
  "calloc",
  "memalign",

  // String functions
  "atoi",
  "memmove",
  "memset",
  "memchr",
  "memcmp",
  "strchr",
  "strncpy",
  "strncmp",
  "strcmp",
  "__strcoll_l",
  "__strxfrm_l",
  "__strftime_l",
  "__strtol_l",
  "__strtoul_l",
  "__strtoll_l",
  "__strtoull_l",
  "__strtof_l",
  "__strtod_l",
  "__strtold_l",

  // Locale functions
  "__uselocale",
  "__newlocale",
  "__freelocale",
  "__duplocale",
  "__nl_langinfo_l",

  // gettext functions used by libstdc++
  "gettext",
  "dgettext",
  "dcgettext",
  "textdomain",
  "bindtextdomain",

  // Random stuff
  "__assert_fail",
  "__errno_location",
};

/// ExternalFunctionDoesntCallIntoProgram - This hack is used to indicate to the
/// call graph that the specified external function is _KNOWN_ to not call back
/// into the program.  This is important, because otherwise functions which call
/// "printf" for example, end up in a great big SCC that goes from the function
/// through main.
///
static bool ExternalFunctionDoesntCallIntoProgram(const std::string &Name) {
  static std::vector<std::string> Funcs;

  // First time this is called?
  if (Funcs.empty()) {
    // Add a whole bunch of functions which are often used...
    Funcs.insert(Funcs.end(), KnownExternalFunctions,
                 KnownExternalFunctions+
              sizeof(KnownExternalFunctions)/sizeof(KnownExternalFunctions[0]));
    // Sort the list for efficient access
    std::sort(Funcs.begin(), Funcs.end());
  }

  if (Name.size() > 7 && !memcmp("__llvm_", Name.c_str(), 7))
    return true;

  // Binary search for the function name...
  std::vector<std::string>::iterator I =
    std::lower_bound(Funcs.begin(), Funcs.end(), Name);

  // Found it?
  return I != Funcs.end() && *I == Name;
}

// getNodeFor - Return the node for the specified function or create one if it
// does not already exist.
//
CallGraphNode *CallGraph::getNodeFor(Function *F) {
  CallGraphNode *&CGN = FunctionMap[F];
  if (CGN) return CGN;

  assert((!F || F->getParent() == Mod) && "Function not in current module!");
  return CGN = new CallGraphNode(F);
}

static bool isOnlyADirectCall(Function *F, CallSite CS) {
  if (!CS.getInstruction()) return false;
  for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I)
    if (*I == F) return false;
  return true;
}

// addToCallGraph - Add a function to the call graph, and link the node to all
// of the functions that it calls.
//
void CallGraph::addToCallGraph(Function *F) {
  CallGraphNode *Node = getNodeFor(F);

  // If this function has external linkage, anything could call it...
  if (!F->hasInternalLinkage()) {
    ExternalNode->addCalledFunction(Node);

    // Found the entry point?
    if (F->getName() == "main") {
      if (Root)
        Root = ExternalNode;  // Found multiple external mains?  Don't pick one.
      else
        Root = Node;          // Found a main, keep track of it!
    }
  }

  // If this function is not defined in this translation unit, it could call
  // anything.
  if (F->isExternal() && !F->getIntrinsicID() &&
      !ExternalFunctionDoesntCallIntoProgram(F->getName()))
    Node->addCalledFunction(ExternalNode);

  // Loop over all of the users of the function... looking for callers...
  //
  bool isUsedExternally = false;
  for (Value::use_iterator I = F->use_begin(), E = F->use_end(); I != E; ++I) {
    if (Instruction *Inst = dyn_cast<Instruction>(*I)) {
      if (isOnlyADirectCall(F, CallSite::get(Inst)))
        getNodeFor(Inst->getParent()->getParent())->addCalledFunction(Node);
      else
        isUsedExternally = true;
    } else if (ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(*I)) {
      // THIS IS A DISGUSTING HACK.  Brought to you by the power of
      // ConstantPointerRefs!
      for (Value::use_iterator I = CPR->use_begin(), E = CPR->use_end();
           I != E; ++I)
        if (Instruction *Inst = dyn_cast<Instruction>(*I)) {
          if (isOnlyADirectCall(F, CallSite::get(Inst)))
            getNodeFor(Inst->getParent()->getParent())->addCalledFunction(Node);
          else
            isUsedExternally = true;
        } else {
          isUsedExternally = true;
        }
    } else {                        // Can't classify the user!
      isUsedExternally = true;
    }
  }
  if (isUsedExternally)
    ExternalNode->addCalledFunction(Node);

  // Look for an indirect function call...
  for (Function::iterator BB = F->begin(), BBE = F->end(); BB != BBE; ++BB)
    for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE; ++II){
      CallSite CS = CallSite::get(II);
      if (CS.getInstruction() && !CS.getCalledFunction())
        Node->addCalledFunction(ExternalNode);
    }
}

bool CallGraph::run(Module &M) {
  destroy();

  Mod = &M;
  ExternalNode = getNodeFor(0);
  Root = 0;

  // Add every function to the call graph...
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    addToCallGraph(I);

  // If we didn't find a main function, use the external call graph node
  if (Root == 0) Root = ExternalNode;

  return false;
}

void CallGraph::destroy() {
  for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
       I != E; ++I)
    delete I->second;
  FunctionMap.clear();
}

static void WriteToOutput(const CallGraphNode *CGN, std::ostream &o) {
  if (CGN->getFunction())
    o << "Call graph node for function: '"
      << CGN->getFunction()->getName() <<"'\n";
  else
    o << "Call graph node <<null function: 0x" << CGN << ">>:\n";

  for (unsigned i = 0; i < CGN->size(); ++i)
    if ((*CGN)[i]->getFunction())
      o << "  Calls function '" << (*CGN)[i]->getFunction()->getName() << "'\n";
    else
      o << "  Calls external node\n";
  o << "\n";
}

void CallGraph::print(std::ostream &o, const Module *M) const {
  o << "CallGraph Root is: ";
  if (getRoot()->getFunction())
    o << getRoot()->getFunction()->getName() << "\n";
  else
    o << "<<null function: 0x" << getRoot() << ">>\n";

  for (CallGraph::const_iterator I = begin(), E = end(); I != E; ++I)
    WriteToOutput(I->second, o);
}

//===----------------------------------------------------------------------===//
// Implementations of public modification methods
//

// Functions to keep a call graph up to date with a function that has been
// modified
//
void CallGraph::addFunctionToModule(Function *Meth) {
  assert(0 && "not implemented");
  abort();
}

// removeFunctionFromModule - Unlink the function from this module, returning
// it.  Because this removes the function from the module, the call graph node
// is destroyed.  This is only valid if the function does not call any other
// functions (ie, there are no edges in it's CGN).  The easiest way to do this
// is to dropAllReferences before calling this.
//
Function *CallGraph::removeFunctionFromModule(CallGraphNode *CGN) {
  assert(CGN->CalledFunctions.empty() && "Cannot remove function from call "
         "graph if it references other functions!");
  Function *F = CGN->getFunction(); // Get the function for the call graph node
  delete CGN;                       // Delete the call graph node for this func
  FunctionMap.erase(F);             // Remove the call graph node from the map

  Mod->getFunctionList().remove(F);
  return F;
}

void CallGraph::stub() {}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2011 The QXmpp developers
 *
 * Author:
 *  Jeremy Lainé
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include <cstdlib>
#include <iostream>

#include <QCoreApplication>
#include <QFile>
#include <QProcess>
#include <QRegExp>
#include <QTextStream>

#include "QXmppGlobal.h"

static void setField(QString &code, const QString &name, const QString &value)
{
    code.replace(
        QRegExp(QString("(%1\\s*=)[^\\r\\n]*").arg(name)),
        QString("\\1 %1").arg(value));
}

static void usage() {
    QTextStream output(stderr);
    output << "Usage:" << endl;
    output << "  doxyfilter              Generate documentation" << endl;
    output << "  doxyfilter -g           Generate Doxyfile" << endl;
    output << "  doxyfilter <sourcefile> Filter the given file's code" << endl;
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    if (argc == 1)
        return QProcess::execute("doxygen");
    else if (argc != 2) {
        usage();
        return 1;
    }

    if (!strcmp(argv[1], "-g")) {
        // generate default Doxyfile
        QProcess process;
        process.start("doxygen", QStringList() << "-g" << "-");
        if (!process.waitForFinished()) {
            qWarning("Could not run doxygen");
            return 1;
        }
        QString code = QString::fromUtf8(process.readAll());

        // adjust Doxyfile
        setField(code, "ALPHABETICAL_INDEX", "NO");
        setField(code, "EXCLUDE_PATTERNS", "*/moc_* */qdnslookup*");
        setField(code, "FULL_PATH_NAMES", "NO");
        setField(code, "HIDE_UNDOC_CLASSES", "YES");
        setField(code, "GENERATE_LATEX", "NO");
        setField(code, "HTML_TIMESTAMP", "NO");
        setField(code, "INPUT", "../src");
        setField(code, "INPUT_FILTER", QString::fromLocal8Bit(argv[0]));
        setField(code, "PROJECT_NAME", "QXmpp");
        setField(code, "PROJECT_NUMBER", QString("Version: %1.%2.%3").arg(
                QString::number((QXMPP_VERSION >> 16) & 0xff),
                QString::number((QXMPP_VERSION >> 8) & 0xff),
                QString::number(QXMPP_VERSION & 0xff)));

        // write doxyfile
        QFile output("Doxyfile");
        if (!output.open(QIODevice::WriteOnly)) {
            qWarning("Could not write to %s", qPrintable(output.fileName()));
            return 1;
        }
        output.write(code.toUtf8());
        output.close();

    } else if (!strcmp(argv[1], "-h")) {
        usage();
        return 0;
    } else {
        // read source code
        QFile source(QString::fromLocal8Bit(argv[1]));
        if (!source.open(QIODevice::ReadOnly)) {
            qWarning("Could not open %s", qPrintable(source.fileName()));
            return 1;
        }
        QString code = QString::fromUtf8(source.readAll());
        source.close();

        // add links for XEPs
        QRegExp regexp("(XEP-([0-9]{4})(: [^\\s.]+( [A-Z][^\\s.]*)*)?)");
        code.replace(regexp, "\\1");

        QTextStream output(stdout);
        output << code;
    }

    return 0;
}

<commit_msg>fix doc generation<commit_after>/*
 * Copyright (C) 2008-2011 The QXmpp developers
 *
 * Author:
 *  Jeremy Lainé
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include <cstdlib>
#include <iostream>

#include <QCoreApplication>
#include <QFile>
#include <QProcess>
#include <QRegExp>
#include <QTextStream>

#include "QXmppGlobal.h"

static void setField(QString &code, const QString &name, const QString &value)
{
    code.replace(
        QRegExp(QString("(%1\\s*=)[^\\r\\n]*").arg(name)),
        QString("\\1 %1").arg(value));
}

static void usage() {
    QTextStream output(stderr);
    output << "Usage:" << endl;
    output << "  doxyfilter              Generate documentation" << endl;
    output << "  doxyfilter -g           Generate Doxyfile" << endl;
    output << "  doxyfilter <sourcefile> Filter the given file's code" << endl;
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    if (argc == 1)
        return QProcess::execute("doxygen");
    else if (argc != 2) {
        usage();
        return 1;
    }

    if (!strcmp(argv[1], "-g")) {
        // generate default Doxyfile
        QProcess process;
        process.start("doxygen", QStringList() << "-g" << "-");
        if (!process.waitForFinished()) {
            qWarning("Could not run doxygen");
            return 1;
        }
        QString code = QString::fromUtf8(process.readAll());

        // adjust Doxyfile
        setField(code, "ALPHABETICAL_INDEX", "NO");
        setField(code, "EXCLUDE_PATTERNS", "*/moc_* */mod_* */qdnslookup*");
        setField(code, "FULL_PATH_NAMES", "NO");
        setField(code, "HIDE_UNDOC_CLASSES", "YES");
        setField(code, "GENERATE_LATEX", "NO");
        setField(code, "HTML_TIMESTAMP", "NO");
        setField(code, "INPUT", "../src");
        setField(code, "INPUT_FILTER", QString::fromLocal8Bit(argv[0]));
        setField(code, "PROJECT_NAME", "QXmpp");
        setField(code, "PROJECT_NUMBER", QString("Version: %1.%2.%3").arg(
                QString::number((QXMPP_VERSION >> 16) & 0xff),
                QString::number((QXMPP_VERSION >> 8) & 0xff),
                QString::number(QXMPP_VERSION & 0xff)));
        setField(code, "RECURSIVE", "YES");

        // write doxyfile
        QFile output("Doxyfile");
        if (!output.open(QIODevice::WriteOnly)) {
            qWarning("Could not write to %s", qPrintable(output.fileName()));
            return 1;
        }
        output.write(code.toUtf8());
        output.close();

    } else if (!strcmp(argv[1], "-h")) {
        usage();
        return 0;
    } else {
        // read source code
        QFile source(QString::fromLocal8Bit(argv[1]));
        if (!source.open(QIODevice::ReadOnly)) {
            qWarning("Could not open %s", qPrintable(source.fileName()));
            return 1;
        }
        QString code = QString::fromUtf8(source.readAll());
        source.close();

        // add links for XEPs
        QRegExp regexp("(XEP-([0-9]{4})(: [^\\s.]+( [A-Z][^\\s.]*)*)?)");
        code.replace(regexp, "\\1");

        QTextStream output(stdout);
        output << code;
    }

    return 0;
}

<|endoftext|>