<commit_before>// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "support/lockedpool.h"
#include "support/cleanse.h"

#if defined(HAVE_CONFIG_H)
#include "config/pivx-config.h"
#endif

#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <sys/mman.h> // for mmap
#include <sys/resource.h> // for getrlimit
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

#include <algorithm>
#ifdef ARENA_DEBUG
#include <iomanip>
#include <iostream>
#endif

LockedPoolManager* LockedPoolManager::_instance = nullptr;
std::once_flag LockedPoolManager::init_flag;

/*******************************************************************************/
// Utilities
//
/** Align up to power of 2 */
static inline size_t align_up(size_t x, size_t align)
{
    return (x + align - 1) & ~(align - 1);
}

/*******************************************************************************/
// Implementation: Arena

Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
    base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
{
    // Start with one free chunk that covers the entire arena
    auto it = size_to_free_chunk.emplace(size_in, base);
    chunks_free.emplace(base, it);
    chunks_free_end.emplace(base + size_in, it);
}

Arena::~Arena()
{
}

void* Arena::alloc(size_t size)
{
    // Round to next multiple of alignment
    size = align_up(size, alignment);

    // Don't handle zero-sized chunks
    if (size == 0)
        return nullptr;

    // Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key.
    // This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review",
    // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit
    // policies seem to work well in practice.
    auto size_ptr_it = size_to_free_chunk.lower_bound(size);
    if (size_ptr_it == size_to_free_chunk.end())
        return nullptr;

    // Create the used-chunk, taking its space from the end of the free-chunk
    const size_t size_remaining = size_ptr_it->first - size;
    auto alloced = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first;
    chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first);
    if (size_ptr_it->first == size) {
        // whole chunk is used up
        chunks_free.erase(size_ptr_it->second);
    } else {
        // still some memory left in the chunk
        auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second);
        chunks_free[size_ptr_it->second] = it_remaining;
        chunks_free_end.emplace(size_ptr_it->second + size_remaining, it_remaining);
    }
    size_to_free_chunk.erase(size_ptr_it);

    return reinterpret_cast<void*>(alloced->first);
}

void Arena::free(void *ptr)
{
    // Freeing the nullptr pointer is OK.
    if (ptr == nullptr) {
        return;
    }

    // Remove chunk from used map
    auto i = chunks_used.find(static_cast<char*>(ptr));
    if (i == chunks_used.end()) {
        throw std::runtime_error("Arena: invalid or double free");
    }
    std::pair<char*, size_t> freed = *i;
    chunks_used.erase(i);

    // coalesce freed with previous chunk
    auto prev = chunks_free_end.find(freed.first);
    if (prev != chunks_free_end.end()) {
        freed.first -= prev->second->first;
        freed.second += prev->second->first;
        size_to_free_chunk.erase(prev->second);
        chunks_free_end.erase(prev);
    }

    // coalesce freed with chunk after freed
    auto next = chunks_free.find(freed.first + freed.second);
    if (next != chunks_free.end()) {
        freed.second += next->second->first;
        size_to_free_chunk.erase(next->second);
        chunks_free.erase(next);
    }

    // Add/set space with coalesced free chunk
    auto it = size_to_free_chunk.emplace(freed.second, freed.first);
    chunks_free[freed.first] = it;
    chunks_free_end[freed.first + freed.second] = it;
}

Arena::Stats Arena::stats() const
{
    Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };
    for (const auto& chunk: chunks_used)
        r.used += chunk.second;
    for (const auto& chunk: chunks_free)
        r.free += chunk.second->first;
    r.total = r.used + r.free;
    return r;
}

#ifdef ARENA_DEBUG
static void printchunk(void* base, size_t sz, bool used) {
    std::cout <<
        "0x" << std::hex << std::setw(16) << std::setfill('0') << base <<
        " 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<
        " 0x" << used << std::endl;
}
void Arena::walk() const
{
    for (const auto& chunk: chunks_used)
        printchunk(chunk.first, chunk.second, true);
    std::cout << std::endl;
    for (const auto& chunk: chunks_free)
        printchunk(chunk.first, chunk.second->first, false);
    std::cout << std::endl;
}
#endif

/*******************************************************************************/
// Implementation: Win32LockedPageAllocator

#ifdef WIN32
/** LockedPageAllocator specialized for Windows.
 */
class Win32LockedPageAllocator: public LockedPageAllocator
{
public:
    Win32LockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess);
    void FreeLocked(void* addr, size_t len);
    size_t GetLimit();
private:
    size_t page_size;
};

Win32LockedPageAllocator::Win32LockedPageAllocator()
{
    // Determine system page size in bytes
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
}
void *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    len = align_up(len, page_size);
    void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (addr) {
        // VirtualLock is used to attempt to keep keying material out of swap. Note
        // that it does not provide this as a guarantee, but, in practice, memory
        // that has been VirtualLock'd almost never gets written to the pagefile
        // except in rare circumstances where memory is extremely low.
        *lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;
    }
    return addr;
}
void Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    VirtualUnlock(const_cast<void*>(addr), len);
}

size_t Win32LockedPageAllocator::GetLimit()
{
    // TODO is there a limit on windows, how to get it?
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: PosixLockedPageAllocator

#ifndef WIN32
/** LockedPageAllocator specialized for OSes that don't try to be
 * special snowflakes.
 */
class PosixLockedPageAllocator: public LockedPageAllocator
{
public:
    PosixLockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess);
    void FreeLocked(void* addr, size_t len);
    size_t GetLimit();
private:
    size_t page_size;
};

PosixLockedPageAllocator::PosixLockedPageAllocator()
{
    // Determine system page size in bytes
#if defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else                   // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
}

// Some systems (at least OS X) do not define MAP_ANONYMOUS yet and define
// MAP_ANON which is deprecated
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif

void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    void *addr;
    len = align_up(len, page_size);
    addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED) {
        return nullptr;
    }
    if (addr) {
        *lockingSuccess = mlock(addr, len) == 0;
#ifdef MADV_DONTDUMP
        madvise(addr, len, MADV_DONTDUMP);
#endif
    }
    return addr;
}
void PosixLockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    munlock(addr, len);
    munmap(addr, len);
}
size_t PosixLockedPageAllocator::GetLimit()
{
#ifdef RLIMIT_MEMLOCK
    struct rlimit rlim;
    if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
        if (rlim.rlim_cur != RLIM_INFINITY) {
            return rlim.rlim_cur;
        }
    }
#endif
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: LockedPool

LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):
    allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)
{
}

LockedPool::~LockedPool()
{
}
void* LockedPool::alloc(size_t size)
{
    std::lock_guard<std::mutex> lock(mutex);

    // Don't handle impossible sizes
    if (size == 0 || size > ARENA_SIZE)
        return nullptr;

    // Try allocating from each current arena
    for (auto &arena: arenas) {
        void *addr = arena.alloc(size);
        if (addr) {
            return addr;
        }
    }
    // If that fails, create a new one
    if (new_arena(ARENA_SIZE, ARENA_ALIGN)) {
        return arenas.back().alloc(size);
    }
    return nullptr;
}

void LockedPool::free(void *ptr)
{
    std::lock_guard<std::mutex> lock(mutex);
    // TODO we can do better than this linear search by keeping a map of arena
    // extents to arena, and looking up the address.
    for (auto &arena: arenas) {
        if (arena.addressInArena(ptr)) {
            arena.free(ptr);
            return;
        }
    }
    throw std::runtime_error("LockedPool: invalid address not pointing to any arena");
}

LockedPool::Stats LockedPool::stats() const
{
    std::lock_guard<std::mutex> lock(mutex);
    LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};
    for (const auto &arena: arenas) {
        Arena::Stats i = arena.stats();
        r.used += i.used;
        r.free += i.free;
        r.total += i.total;
        r.chunks_used += i.chunks_used;
        r.chunks_free += i.chunks_free;
    }
    return r;
}

bool LockedPool::new_arena(size_t size, size_t align)
{
    bool locked;
    // If this is the first arena, handle this specially: Cap the upper size
    // by the process limit. This makes sure that the first arena will at least
    // be locked. An exception to this is if the process limit is 0:
    // in this case no memory can be locked at all so we'll skip past this logic.
    if (arenas.empty()) {
        size_t limit = allocator->GetLimit();
        if (limit > 0) {
            size = std::min(size, limit);
        }
    }
    void *addr = allocator->AllocateLocked(size, &locked);
    if (!addr) {
        return false;
    }
    if (locked) {
        cumulative_bytes_locked += size;
    } else if (lf_cb) { // Call the locking-failed callback if locking failed
        if (!lf_cb()) { // If the callback returns false, free the memory and fail, otherwise consider the user warned and proceed.
            allocator->FreeLocked(addr, size);
            return false;
        }
    }
    arenas.emplace_back(allocator.get(), addr, size, align);
    return true;
}

LockedPool::LockedPageArena::LockedPageArena(LockedPageAllocator *allocator_in, void *base_in, size_t size_in, size_t align_in):
    Arena(base_in, size_in, align_in), base(base_in), size(size_in), allocator(allocator_in)
{
}
LockedPool::LockedPageArena::~LockedPageArena()
{
    allocator->FreeLocked(base, size);
}

/*******************************************************************************/
// Implementation: LockedPoolManager
//
LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator):
    LockedPool(std::move(allocator), &LockedPoolManager::LockingFailed)
{
}

bool LockedPoolManager::LockingFailed()
{
    // TODO: log something but how? without including util.h
    return true;
}

void LockedPoolManager::CreateInstance()
{
    // Using a local static instance guarantees that the object is initialized
    // when it's first needed and also deinitialized after all objects that use
    // it are done with it.  I can think of one unlikely scenario where we may
    // have a static deinitialization order/problem, but the check in
    // LockedPoolManagerBase's destructor helps us detect if that ever happens.
#ifdef WIN32
    std::unique_ptr<LockedPageAllocator> allocator(new Win32LockedPageAllocator());
#else
    std::unique_ptr<LockedPageAllocator> allocator(new PosixLockedPageAllocator());
#endif
    static LockedPoolManager instance(std::move(allocator));
    LockedPoolManager::_instance = &instance;
}
<commit_msg>lockedpool: avoid sensitive data in core files (FreeBSD)<commit_after>// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "support/lockedpool.h"
#include "support/cleanse.h"

#if defined(HAVE_CONFIG_H)
#include "config/pivx-config.h"
#endif

#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <sys/mman.h> // for mmap
#include <sys/resource.h> // for getrlimit
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

#include <algorithm>
#ifdef ARENA_DEBUG
#include <iomanip>
#include <iostream>
#endif

LockedPoolManager* LockedPoolManager::_instance = nullptr;
std::once_flag LockedPoolManager::init_flag;

/*******************************************************************************/
// Utilities
//
/** Align up to power of 2 */
static inline size_t align_up(size_t x, size_t align)
{
    return (x + align - 1) & ~(align - 1);
}

/*******************************************************************************/
// Implementation: Arena

Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
    base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
{
    // Start with one free chunk that covers the entire arena
    auto it = size_to_free_chunk.emplace(size_in, base);
    chunks_free.emplace(base, it);
    chunks_free_end.emplace(base + size_in, it);
}

Arena::~Arena()
{
}

void* Arena::alloc(size_t size)
{
    // Round to next multiple of alignment
    size = align_up(size, alignment);

    // Don't handle zero-sized chunks
    if (size == 0)
        return nullptr;

    // Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key.
    // This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review",
    // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit
    // policies seem to work well in practice.
    auto size_ptr_it = size_to_free_chunk.lower_bound(size);
    if (size_ptr_it == size_to_free_chunk.end())
        return nullptr;

    // Create the used-chunk, taking its space from the end of the free-chunk
    const size_t size_remaining = size_ptr_it->first - size;
    auto alloced = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first;
    chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first);
    if (size_ptr_it->first == size) {
        // whole chunk is used up
        chunks_free.erase(size_ptr_it->second);
    } else {
        // still some memory left in the chunk
        auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second);
        chunks_free[size_ptr_it->second] = it_remaining;
        chunks_free_end.emplace(size_ptr_it->second + size_remaining, it_remaining);
    }
    size_to_free_chunk.erase(size_ptr_it);

    return reinterpret_cast<void*>(alloced->first);
}

void Arena::free(void *ptr)
{
    // Freeing the nullptr pointer is OK.
    if (ptr == nullptr) {
        return;
    }

    // Remove chunk from used map
    auto i = chunks_used.find(static_cast<char*>(ptr));
    if (i == chunks_used.end()) {
        throw std::runtime_error("Arena: invalid or double free");
    }
    std::pair<char*, size_t> freed = *i;
    chunks_used.erase(i);

    // coalesce freed with previous chunk
    auto prev = chunks_free_end.find(freed.first);
    if (prev != chunks_free_end.end()) {
        freed.first -= prev->second->first;
        freed.second += prev->second->first;
        size_to_free_chunk.erase(prev->second);
        chunks_free_end.erase(prev);
    }

    // coalesce freed with chunk after freed
    auto next = chunks_free.find(freed.first + freed.second);
    if (next != chunks_free.end()) {
        freed.second += next->second->first;
        size_to_free_chunk.erase(next->second);
        chunks_free.erase(next);
    }

    // Add/set space with coalesced free chunk
    auto it = size_to_free_chunk.emplace(freed.second, freed.first);
    chunks_free[freed.first] = it;
    chunks_free_end[freed.first + freed.second] = it;
}

Arena::Stats Arena::stats() const
{
    Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };
    for (const auto& chunk: chunks_used)
        r.used += chunk.second;
    for (const auto& chunk: chunks_free)
        r.free += chunk.second->first;
    r.total = r.used + r.free;
    return r;
}

#ifdef ARENA_DEBUG
static void printchunk(void* base, size_t sz, bool used) {
    std::cout <<
        "0x" << std::hex << std::setw(16) << std::setfill('0') << base <<
        " 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<
        " 0x" << used << std::endl;
}
void Arena::walk() const
{
    for (const auto& chunk: chunks_used)
        printchunk(chunk.first, chunk.second, true);
    std::cout << std::endl;
    for (const auto& chunk: chunks_free)
        printchunk(chunk.first, chunk.second->first, false);
    std::cout << std::endl;
}
#endif

/*******************************************************************************/
// Implementation: Win32LockedPageAllocator

#ifdef WIN32
/** LockedPageAllocator specialized for Windows.
 */
class Win32LockedPageAllocator: public LockedPageAllocator
{
public:
    Win32LockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess);
    void FreeLocked(void* addr, size_t len);
    size_t GetLimit();
private:
    size_t page_size;
};

Win32LockedPageAllocator::Win32LockedPageAllocator()
{
    // Determine system page size in bytes
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
}
void *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    len = align_up(len, page_size);
    void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (addr) {
        // VirtualLock is used to attempt to keep keying material out of swap. Note
        // that it does not provide this as a guarantee, but, in practice, memory
        // that has been VirtualLock'd almost never gets written to the pagefile
        // except in rare circumstances where memory is extremely low.
        *lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;
    }
    return addr;
}
void Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    VirtualUnlock(const_cast<void*>(addr), len);
}

size_t Win32LockedPageAllocator::GetLimit()
{
    // TODO is there a limit on windows, how to get it?
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: PosixLockedPageAllocator

#ifndef WIN32
/** LockedPageAllocator specialized for OSes that don't try to be
 * special snowflakes.
 */
class PosixLockedPageAllocator: public LockedPageAllocator
{
public:
    PosixLockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess);
    void FreeLocked(void* addr, size_t len);
    size_t GetLimit();
private:
    size_t page_size;
};

PosixLockedPageAllocator::PosixLockedPageAllocator()
{
    // Determine system page size in bytes
#if defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else                   // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
}

// Some systems (at least OS X) do not define MAP_ANONYMOUS yet and define
// MAP_ANON which is deprecated
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif

void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    void *addr;
    len = align_up(len, page_size);
    addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED) {
        return nullptr;
    }
    if (addr) {
        *lockingSuccess = mlock(addr, len) == 0;
#if defined(MADV_DONTDUMP) // Linux
        madvise(addr, len, MADV_DONTDUMP);
#elif defined(MADV_NOCORE) // FreeBSD
        madvise(addr, len, MADV_NOCORE);
#endif
    }
    return addr;
}
void PosixLockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    munlock(addr, len);
    munmap(addr, len);
}
size_t PosixLockedPageAllocator::GetLimit()
{
#ifdef RLIMIT_MEMLOCK
    struct rlimit rlim;
    if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
        if (rlim.rlim_cur != RLIM_INFINITY) {
            return rlim.rlim_cur;
        }
    }
#endif
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: LockedPool

LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):
    allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)
{
}

LockedPool::~LockedPool()
{
}
void* LockedPool::alloc(size_t size)
{
    std::lock_guard<std::mutex> lock(mutex);

    // Don't handle impossible sizes
    if (size == 0 || size > ARENA_SIZE)
        return nullptr;

    // Try allocating from each current arena
    for (auto &arena: arenas) {
        void *addr = arena.alloc(size);
        if (addr) {
            return addr;
        }
    }
    // If that fails, create a new one
    if (new_arena(ARENA_SIZE, ARENA_ALIGN)) {
        return arenas.back().alloc(size);
    }
    return nullptr;
}

void LockedPool::free(void *ptr)
{
    std::lock_guard<std::mutex> lock(mutex);
    // TODO we can do better than this linear search by keeping a map of arena
    // extents to arena, and looking up the address.
    for (auto &arena: arenas) {
        if (arena.addressInArena(ptr)) {
            arena.free(ptr);
            return;
        }
    }
    throw std::runtime_error("LockedPool: invalid address not pointing to any arena");
}

LockedPool::Stats LockedPool::stats() const
{
    std::lock_guard<std::mutex> lock(mutex);
    LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};
    for (const auto &arena: arenas) {
        Arena::Stats i = arena.stats();
        r.used += i.used;
        r.free += i.free;
        r.total += i.total;
        r.chunks_used += i.chunks_used;
        r.chunks_free += i.chunks_free;
    }
    return r;
}

bool LockedPool::new_arena(size_t size, size_t align)
{
    bool locked;
    // If this is the first arena, handle this specially: Cap the upper size
    // by the process limit. This makes sure that the first arena will at least
    // be locked. An exception to this is if the process limit is 0:
    // in this case no memory can be locked at all so we'll skip past this logic.
    if (arenas.empty()) {
        size_t limit = allocator->GetLimit();
        if (limit > 0) {
            size = std::min(size, limit);
        }
    }
    void *addr = allocator->AllocateLocked(size, &locked);
    if (!addr) {
        return false;
    }
    if (locked) {
        cumulative_bytes_locked += size;
    } else if (lf_cb) { // Call the locking-failed callback if locking failed
        if (!lf_cb()) { // If the callback returns false, free the memory and fail, otherwise consider the user warned and proceed.
            allocator->FreeLocked(addr, size);
            return false;
        }
    }
    arenas.emplace_back(allocator.get(), addr, size, align);
    return true;
}

LockedPool::LockedPageArena::LockedPageArena(LockedPageAllocator *allocator_in, void *base_in, size_t size_in, size_t align_in):
    Arena(base_in, size_in, align_in), base(base_in), size(size_in), allocator(allocator_in)
{
}
LockedPool::LockedPageArena::~LockedPageArena()
{
    allocator->FreeLocked(base, size);
}

/*******************************************************************************/
// Implementation: LockedPoolManager
//
LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator):
    LockedPool(std::move(allocator), &LockedPoolManager::LockingFailed)
{
}

bool LockedPoolManager::LockingFailed()
{
    // TODO: log something but how? without including util.h
    return true;
}

void LockedPoolManager::CreateInstance()
{
    // Using a local static instance guarantees that the object is initialized
    // when it's first needed and also deinitialized after all objects that use
    // it are done with it.  I can think of one unlikely scenario where we may
    // have a static deinitialization order/problem, but the check in
    // LockedPoolManagerBase's destructor helps us detect if that ever happens.
#ifdef WIN32
    std::unique_ptr<LockedPageAllocator> allocator(new Win32LockedPageAllocator());
#else
    std::unique_ptr<LockedPageAllocator> allocator(new PosixLockedPageAllocator());
#endif
    static LockedPoolManager instance(std::move(allocator));
    LockedPoolManager::_instance = &instance;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2018 Google, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "systemc/core/kernel.hh"

#include "base/logging.hh"
#include "systemc/core/channel.hh"
#include "systemc/core/module.hh"
#include "systemc/core/port.hh"
#include "systemc/core/scheduler.hh"

namespace sc_gem5
{

namespace
{

bool scMainDone = false;
bool stopAfterCallbacks = false;
bool startComplete = false;
bool endComplete = false;

sc_core::sc_status _status = sc_core::SC_ELABORATION;

} // anonymous namespace

bool Kernel::startOfSimulationComplete() { return startComplete; }
bool Kernel::endOfSimulationComplete() { return endComplete; }

bool Kernel::scMainFinished() { return scMainDone; }
void Kernel::scMainFinished(bool finished) { scMainDone = finished; }

sc_core::sc_status Kernel::status() { return _status; }
void Kernel::status(sc_core::sc_status s) { _status = s; }

Kernel::Kernel(Params *params) :
    SimObject(params), t0Event(this, false, EventBase::Default_Pri - 1)
{
    // Install ourselves as the scheduler's event manager.
    ::sc_gem5::scheduler.setEventQueue(eventQueue());
}

void
Kernel::init()
{
    if (scMainDone)
        return;

    if (stopAfterCallbacks)
        fatal("Simulation called sc_stop during elaboration.\n");

    status(::sc_core::SC_BEFORE_END_OF_ELABORATION);
    for (auto p: allPorts)
        p->sc_port_base()->before_end_of_elaboration();
    for (auto m: sc_gem5::allModules)
        m->beforeEndOfElaboration();
    for (auto c: sc_gem5::allChannels)
        c->sc_chan()->before_end_of_elaboration();
}

void
Kernel::regStats()
{
    if (scMainDone || stopAfterCallbacks)
        return;

    try {
        for (auto p: allPorts)
            p->finalize();
        for (auto p: allPorts)
            p->regPort();

        status(::sc_core::SC_END_OF_ELABORATION);
        for (auto p: allPorts)
            p->sc_port_base()->end_of_elaboration();
        for (auto m: sc_gem5::allModules)
            m->endOfElaboration();
        for (auto c: sc_gem5::allChannels)
            c->sc_chan()->end_of_elaboration();
    } catch (...) {
        ::sc_gem5::scheduler.throwToScMain();
    }

    ::sc_gem5::scheduler.elaborationDone(true);
}

void
Kernel::startup()
{
    if (scMainDone)
        return;

    schedule(t0Event, curTick());

    if (stopAfterCallbacks)
        return;

    try {
        status(::sc_core::SC_START_OF_SIMULATION);
        for (auto p: allPorts)
            p->sc_port_base()->start_of_simulation();
        for (auto m: sc_gem5::allModules)
            m->startOfSimulation();
        for (auto c: sc_gem5::allChannels)
            c->sc_chan()->start_of_simulation();
    } catch (...) {
        ::sc_gem5::scheduler.throwToScMain();
    }

    startComplete = true;

    if (stopAfterCallbacks)
        stopWork();

    kernel->status(::sc_core::SC_RUNNING);
}

void
Kernel::stop()
{
    if (status() < ::sc_core::SC_RUNNING)
        stopAfterCallbacks = true;
    else
        stopWork();
}

void
Kernel::stopWork()
{
    status(::sc_core::SC_END_OF_SIMULATION);
    try {
        for (auto p: allPorts)
            p->sc_port_base()->end_of_simulation();
        for (auto m: sc_gem5::allModules)
            m->endOfSimulation();
        for (auto c: sc_gem5::allChannels)
            c->sc_chan()->end_of_simulation();
    } catch (...) {
        ::sc_gem5::scheduler.throwToScMain();
    }

    endComplete = true;

    status(::sc_core::SC_STOPPED);
}

void
Kernel::t0Handler()
{
    if (stopAfterCallbacks) {
        scheduler.clear();
        ::sc_gem5::scheduler.initPhase();
        scheduler.scheduleStop(false);
    } else {
        ::sc_gem5::scheduler.initPhase();
        status(::sc_core::SC_RUNNING);
    }
}

Kernel *kernel;

} // namespace sc_gem5

sc_gem5::Kernel *
SystemC_KernelParams::create()
{
    panic_if(sc_gem5::kernel,
            "Only one systemc kernel object may be defined.\n");
    sc_gem5::kernel = new sc_gem5::Kernel(this);
    return sc_gem5::kernel;
}
<commit_msg>systemc: Change the point where elaboration is considered over.<commit_after>/*
 * Copyright 2018 Google, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "systemc/core/kernel.hh"

#include "base/logging.hh"
#include "systemc/core/channel.hh"
#include "systemc/core/module.hh"
#include "systemc/core/port.hh"
#include "systemc/core/scheduler.hh"

namespace sc_gem5
{

namespace
{

bool scMainDone = false;
bool stopAfterCallbacks = false;
bool startComplete = false;
bool endComplete = false;

sc_core::sc_status _status = sc_core::SC_ELABORATION;

} // anonymous namespace

bool Kernel::startOfSimulationComplete() { return startComplete; }
bool Kernel::endOfSimulationComplete() { return endComplete; }

bool Kernel::scMainFinished() { return scMainDone; }
void Kernel::scMainFinished(bool finished) { scMainDone = finished; }

sc_core::sc_status Kernel::status() { return _status; }
void Kernel::status(sc_core::sc_status s) { _status = s; }

Kernel::Kernel(Params *params) :
    SimObject(params), t0Event(this, false, EventBase::Default_Pri - 1)
{
    // Install ourselves as the scheduler's event manager.
    ::sc_gem5::scheduler.setEventQueue(eventQueue());
}

void
Kernel::init()
{
    if (scMainDone)
        return;

    if (stopAfterCallbacks)
        fatal("Simulation called sc_stop during elaboration.\n");

    status(::sc_core::SC_BEFORE_END_OF_ELABORATION);
    for (auto p: allPorts)
        p->sc_port_base()->before_end_of_elaboration();
    for (auto m: sc_gem5::allModules)
        m->beforeEndOfElaboration();
    for (auto c: sc_gem5::allChannels)
        c->sc_chan()->before_end_of_elaboration();

    ::sc_gem5::scheduler.elaborationDone(true);
}

void
Kernel::regStats()
{
    if (scMainDone || stopAfterCallbacks)
        return;

    try {
        for (auto p: allPorts)
            p->finalize();
        for (auto p: allPorts)
            p->regPort();

        status(::sc_core::SC_END_OF_ELABORATION);
        for (auto p: allPorts)
            p->sc_port_base()->end_of_elaboration();
        for (auto m: sc_gem5::allModules)
            m->endOfElaboration();
        for (auto c: sc_gem5::allChannels)
            c->sc_chan()->end_of_elaboration();
    } catch (...) {
        ::sc_gem5::scheduler.throwToScMain();
    }
}

void
Kernel::startup()
{
    if (scMainDone)
        return;

    schedule(t0Event, curTick());

    if (stopAfterCallbacks)
        return;

    try {
        status(::sc_core::SC_START_OF_SIMULATION);
        for (auto p: allPorts)
            p->sc_port_base()->start_of_simulation();
        for (auto m: sc_gem5::allModules)
            m->startOfSimulation();
        for (auto c: sc_gem5::allChannels)
            c->sc_chan()->start_of_simulation();
    } catch (...) {
        ::sc_gem5::scheduler.throwToScMain();
    }

    startComplete = true;

    if (stopAfterCallbacks)
        stopWork();

    kernel->status(::sc_core::SC_RUNNING);
}

void
Kernel::stop()
{
    if (status() < ::sc_core::SC_RUNNING)
        stopAfterCallbacks = true;
    else
        stopWork();
}

void
Kernel::stopWork()
{
    status(::sc_core::SC_END_OF_SIMULATION);
    try {
        for (auto p: allPorts)
            p->sc_port_base()->end_of_simulation();
        for (auto m: sc_gem5::allModules)
            m->endOfSimulation();
        for (auto c: sc_gem5::allChannels)
            c->sc_chan()->end_of_simulation();
    } catch (...) {
        ::sc_gem5::scheduler.throwToScMain();
    }

    endComplete = true;

    status(::sc_core::SC_STOPPED);
}

void
Kernel::t0Handler()
{
    if (stopAfterCallbacks) {
        scheduler.clear();
        ::sc_gem5::scheduler.initPhase();
        scheduler.scheduleStop(false);
    } else {
        ::sc_gem5::scheduler.initPhase();
        status(::sc_core::SC_RUNNING);
    }
}

Kernel *kernel;

} // namespace sc_gem5

sc_gem5::Kernel *
SystemC_KernelParams::create()
{
    panic_if(sc_gem5::kernel,
            "Only one systemc kernel object may be defined.\n");
    sc_gem5::kernel = new sc_gem5::Kernel(this);
    return sc_gem5::kernel;
}
<|endoftext|>


<commit_before>/*
===============================================================================

  FILE:  formats.hpp

  CONTENTS:
    Format support

  PROGRAMMERS:

    martin.isenburg@rapidlasso.com  -  http://rapidlasso.com
    uday.karan@gmail.com - Hobu, Inc.

  COPYRIGHT:

    (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
    (c) 2014, Uday Verma, Hobu, Inc.

    This is free software; you can redistribute and/or modify it under the
    terms of the GNU Lesser General Licence as published by the Free Software
    Foundation. See the COPYING file for more information.

    This software is distributed WITHOUT ANY WARRANTY and without even the
    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

===============================================================================
*/
#ifndef __formats_hpp__
#define __formats_hpp__

#include <iostream>
#include "compressor.hpp"
#include "decompressor.hpp"

namespace laszip {
	namespace formats {
		template<typename T>
		struct packers {
			static_assert(sizeof(T) == 0,
					"Only specialized instances of packers should be used");
		};

		template<>
		struct packers<unsigned int> {
			static unsigned int unpack(const char *in) {
				unsigned int b1 = in[0],
							 b2 = in[1],
							 b3 = in[2],
							 b4 = in[3];

				return (b4 << 24) |
					((b3 & 0xFF) << 16) |
					((b2 & 0xFF) << 8) |
					(b1 & 0xFF);
			}

			static void pack(const unsigned int& v, char *out) {
				out[3] = (v >> 24) & 0xFF;
				out[2] = (v >> 16) & 0xFF;
				out[1] = (v >> 8) & 0xFF;
				out[0] = v & 0xFF;
			}
		};

		template<>
		struct packers<unsigned short> {
			static unsigned short unpack(const char *in) {
				unsigned short b1 = in[0],
							 b2 = in[1];

				return (((b2 & 0xFF) << 8) | (b1 & 0xFF));
			}

			static void pack(const unsigned short& v, char *out) {
				out[1] = (v >> 8) & 0xFF;
				out[0] = v & 0xFF;
			}
		};

		template<>
		struct packers<unsigned char> {
			static unsigned char unpack(const char *in) {
				return static_cast<unsigned char>(in[0]);
			}

			static void pack(const unsigned char& c, char *out) {
				out[0] = static_cast<char>(c);
			}
		};

		template<>
		struct packers<int> {
			static int unpack(const char *in) {
				return static_cast<int>(packers<unsigned int>::unpack(in));
			}

			static void pack(const int& t, char *out) {
				packers<unsigned int>::pack(static_cast<unsigned int>(t), out);
			}
		};

		template<>
		struct packers<short> {
			static short unpack(const char *in) {
				return static_cast<short>(packers<unsigned short>::unpack(in));
			}

			static void pack(const short& t, char *out) {
				packers<unsigned short>::pack(static_cast<unsigned short>(t), out);
			}
		};

		template<>
		struct packers<char> {
			static char unpack(const char *in) {
				return in[0];
			}

			static void pack(const char& t, char *out) {
				out[0] = t;
			}
		};

		/** A simple strategy which returns simple diffs */
		template<typename T>
		struct standard_diff_method {
			standard_diff_method<T>()
				: have_value_(false) {}

			inline void push(const T& v) {
				if (!have_value_)
					have_value_ = true;

				value = v;
			}

			inline bool have_value() const {
				return have_value_;
			}

			T value;
			bool have_value_;
		};

		struct base_field {
			typedef std::shared_ptr<base_field> ptr;

			virtual ~base_field() {
				// hello 1996
			}

			virtual size_t field_size() = 0;
			virtual void compressRaw(const char *) {}
			virtual void decompressRaw(char *) {}
		};

		template<typename T, typename TDiffMethod = standard_diff_method<T> >
		struct field {
			static_assert(std::is_integral<T>::value,
					"Default implementation for field only handles integral types");

			typedef T type;

			field() :
				compressor_(sizeof(T) * 8),
				decompressor_(sizeof(T) * 8),
				compressor_inited_(false),
				decompressor_inited_(false) { }

			template<
				typename TEncoder
			>
			inline void compressWith(TEncoder& encoder, const T& this_val) {
				if (!compressor_inited_)
					compressor_.init();

				// Let the differ decide what values we're going to push
				//
				if (differ_.have_value()) {
					compressor_.compress(encoder, differ_.value, this_val, 0);
				}
				else {
					// differ is not ready for us to start encoding values for us, so we need to write raw into
					// the outputstream
					//
					char buf[sizeof(T)];
					packers<T>::pack(this_val, buf);

					encoder.getOutStream().putBytes((unsigned char*)buf, sizeof(T));
				}

				differ_.push(this_val);
			}

			template<
				typename TDecoder
			>
			inline T decompressWith(TDecoder& decoder) {
				if (!decompressor_inited_)
					decompressor_.init();

				T r;
				if (differ_.have_value()) {
					r = static_cast<T>(decompressor_.decompress(decoder, differ_.value, 0));
				}
				else {
					// this is probably the first time we're reading stuff, read the record as is
					char buffer[sizeof(T)];
					decoder.getInStream().getBytes((unsigned char*)buffer, sizeof(T));

					r = packers<T>::unpack(buffer);
				}

				differ_.push(r);
				return r;
			}

			laszip::compressors::integer compressor_;
			laszip::decompressors::integer decompressor_;

			bool compressor_inited_, decompressor_inited_;

			TDiffMethod differ_;
		};

		template<typename... TS>
		struct record_compressor;

		template<typename... TS>
		struct record_decompressor;

		template<>
		struct record_compressor<> {
			record_compressor() {}
			template<
				typename T
			>
			inline void compressWith(T&, const char *) { }
		};

		template<typename T, typename... TS>
		struct record_compressor<T, TS...> {
			record_compressor() {}

			template<
				typename TEncoder
			>
			inline void compressWith(TEncoder& encoder, const char *buffer) {
				typedef typename T::type this_field_type;

				this_field_type v = packers<this_field_type>::unpack(buffer);
				field_.compressWith(encoder, v);

				// Move on to the next field
				next_.compressWith(encoder, buffer + sizeof(typename T::type));
			}

			// The field that we handle
			T field_;

			// Our default strategy right now is to just encode diffs, but we would employ more advanced techniques soon
			record_compressor<TS...> next_;
		};

		template<>
		struct record_decompressor<> {
			record_decompressor() : firstDecompress(true) {}
			template<
				typename TDecoder
			>
			inline void decompressWith(TDecoder& decoder, char *) {
				if (firstDecompress) {
					decoder.readInitBytes();
					firstDecompress = false;
				}
			}

			bool firstDecompress;
		};

		template<typename T, typename... TS>
		struct record_decompressor<T, TS...> {
			record_decompressor() {}

			template<
				typename TDecoder
			>
			inline void decompressWith(TDecoder& decoder, char *buffer) {
				typedef typename T::type this_field_type;

				this_field_type v = static_cast<this_field_type>(field_.decompressWith(decoder));
				packers<this_field_type>::pack(v, buffer);

				// Move on to the next field
				next_.decompressWith(decoder, buffer + sizeof(typename T::type));
			}

			// The field that we handle
			T field_;

			// Our default strategy right now is to just encode diffs, but we would employ more advanced techniques soon
			record_decompressor<TS...> next_;
		};

		struct dynamic_compressor {
			typedef std::shared_ptr<dynamic_compressor> ptr;

			virtual void compress(const char *in) = 0;
			virtual ~dynamic_compressor() {}
		};

		struct dynamic_decompressor {
			typedef std::shared_ptr<dynamic_decompressor> ptr;

			virtual void decompress(char *in) = 0;
			virtual ~dynamic_decompressor() {}
		};

		template<
			typename TEncoder,
			typename TRecordCompressor
		>
		struct dynamic_compressor1 : public dynamic_compressor {
			dynamic_compressor1(TEncoder& enc, TRecordCompressor* compressor) :
				enc_(enc), compressor_(compressor) {}

			virtual void compress(const char *in) {
				compressor_->compressWith(enc_, in);
			}

			dynamic_compressor1(const dynamic_compressor1<TEncoder , TRecordCompressor>&) = delete;
			dynamic_compressor1<TEncoder, TRecordCompressor>& operator=(dynamic_compressor1<TEncoder, TRecordCompressor>&) = delete;

			TEncoder& enc_;
			TRecordCompressor* compressor_;
		};

		template<
			typename TEncoder,
			typename TRecordCompressor
		>
		static dynamic_compressor::ptr make_dynamic_compressor(TEncoder& encoder, TRecordCompressor* compressor) {
			return dynamic_compressor::ptr(
					new dynamic_compressor1<TEncoder, TRecordCompressor>(encoder, compressor));
		}

		template<
			typename TDecoder,
			typename TRecordDecompressor
		>
		struct dynamic_decompressor1 : public dynamic_decompressor {
			dynamic_decompressor1(TDecoder& dec, TRecordDecompressor* decompressor) :
				dec_(dec), decompressor_(decompressor) {}

			virtual void decompress(char *in) {
				decompressor_->decompressWith(dec_, in);
			}

			~dynamic_decompressor1() {
				delete decompressor_;
			}

			dynamic_decompressor1(const dynamic_decompressor1<TDecoder, TRecordDecompressor>&) = delete;
			dynamic_decompressor1<TDecoder, TRecordDecompressor>& operator=(dynamic_decompressor1<TDecoder, TRecordDecompressor>&) = delete;

			TDecoder& dec_;
			TRecordDecompressor* decompressor_;
		};

		template<
			typename TDecoder,
			typename TRecordDecompressor
		>
		static dynamic_decompressor::ptr make_dynamic_decompressor(TDecoder& decoder, TRecordDecompressor* decompressor) {
			return dynamic_decompressor::ptr(
					new dynamic_decompressor1<TDecoder, TRecordDecompressor>(decoder, decompressor));
		}

		// type-erasure stuff for fields
		template<
			typename TEncoderDecoder,
			typename TField
		>
		struct dynamic_compressor_field : base_field {
			dynamic_compressor_field(TEncoderDecoder& encdec) : encdec_(encdec), field_() {}

			virtual void compressRaw(const char *in) {
				typedef packers<typename TField::type> p;

				auto to_compress = p::unpack(in);
				field_.compressWith(encdec_, to_compress);
			}

			virtual size_t field_size() {
				return sizeof(typename TField::type);
			}

			TEncoderDecoder& encdec_;
			TField field_;
		};

		template<
			typename TEncoderDecoder,
			typename TField
		>
		struct dynamic_decompressor_field : base_field {
			dynamic_decompressor_field(TEncoderDecoder& encdec) : encdec_(encdec), field_() {}

			virtual void decompressRaw(char *out) {
				typedef packers<typename TField::type> p;

				auto decomp = field_.decompressWith(encdec_);
				p::pack(decomp, out);
			}

			virtual size_t field_size() {
				return sizeof(typename TField::type);
			}

			TEncoderDecoder& encdec_;
			TField field_;
		};

		template<
			typename TEncoder
		>
		struct dynamic_field_compressor: dynamic_compressor {
            typedef dynamic_field_compressor<TEncoder>  this_type;
            typedef std::shared_ptr<this_type>          ptr;

			dynamic_field_compressor(TEncoder& encoder) : enc_(encoder), fields_() { }

			template<typename TFieldType>
			void add_field() {
				fields_.push_back(base_field::ptr(new
							dynamic_compressor_field<TEncoder, field<TFieldType> >(enc_)));
			};

			virtual void compress(const char *in) {
                size_t offset = 0;
                for (auto f: fields_) {
                    f->compressRaw(in + offset);
                    offset += f->field_size();
                }
			}

			TEncoder& enc_;
			std::vector<base_field::ptr> fields_;
		};

        template<
            typename TDecoder
        >
        struct dynamic_field_decompressor : dynamic_decompressor {
            typedef dynamic_field_decompressor<TDecoder> this_type;
            typedef std::shared_ptr<this_type>           ptr;

			dynamic_field_decompressor(TDecoder& decoder) : dec_(decoder), fields_(), first_decomp_(true) { }

			template<typename TFieldType>
			void add_field() {
				fields_.push_back(base_field::ptr(new
							dynamic_decompressor_field<TDecoder, field<TFieldType> >(dec_)));
			};

			virtual void decompress(char *out) {
				// will do soemthign with in
                size_t offset = 0;
                for (auto f: fields_) {
                    f->decompressRaw(out + offset);
                    offset += f->field_size();
                }

                // the decoder needs to be told that it should read the init bytes
                // after the first record has been read
                //
                if (first_decomp_) {
                    first_decomp_ = false;
                    dec_.readInitBytes();
                }
			}

			TDecoder& dec_;
			std::vector<base_field::ptr> fields_;
            bool first_decomp_;
        };

        template<
            typename TEncoder
        >
        static typename dynamic_field_compressor<TEncoder>::ptr make_dynamic_compressor(TEncoder& encoder) {
            typedef typename dynamic_field_compressor<TEncoder>::ptr ptr;
            return ptr(new dynamic_field_compressor<TEncoder>(encoder));
        }

		template<
			typename TDecoder
		>
		static typename dynamic_field_decompressor<TDecoder>::ptr make_dynamic_decompressor(TDecoder& decoder) {
            typedef typename dynamic_field_decompressor<TDecoder>::ptr ptr;
            return ptr(new dynamic_field_decompressor<TDecoder>(decoder));
		}

	}
}

#endif // __formats_hpp__
<commit_msg>Make sure type types are properly sized and that all 3 char types are handled.<commit_after>/*
===============================================================================

  FILE:  formats.hpp

  CONTENTS:
    Format support

  PROGRAMMERS:

    martin.isenburg@rapidlasso.com  -  http://rapidlasso.com
    uday.karan@gmail.com - Hobu, Inc.

  COPYRIGHT:

    (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
    (c) 2014, Uday Verma, Hobu, Inc.

    This is free software; you can redistribute and/or modify it under the
    terms of the GNU Lesser General Licence as published by the Free Software
    Foundation. See the COPYING file for more information.

    This software is distributed WITHOUT ANY WARRANTY and without even the
    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

===============================================================================
*/
#ifndef __formats_hpp__
#define __formats_hpp__

#include <cstdint>
#include <iostream>
#include "compressor.hpp"
#include "decompressor.hpp"

namespace laszip {
	namespace formats {
		template<typename T>
		struct packers {
			static_assert(sizeof(T) == 0,
					"Only specialized instances of packers should be used");
		};

		template<>
		struct packers<uint32_t> {
			static unsigned int unpack(const char *in) {
				uint32_t b1 = in[0],
					b2 = in[1],
					b3 = in[2],
					b4 = in[3];

				return (b4 << 24) |
					((b3 & 0xFF) << 16) |
					((b2 & 0xFF) << 8) |
					(b1 & 0xFF);
			}

			static void pack(const uint32_t& v, char *out) {
				out[3] = (v >> 24) & 0xFF;
				out[2] = (v >> 16) & 0xFF;
				out[1] = (v >> 8) & 0xFF;
				out[0] = v & 0xFF;
			}
		};

		template<>
		struct packers<uint16_t> {
			static unsigned short unpack(const char *in) {
				uint16_t b1 = in[0],
							 b2 = in[1];

				return (((b2 & 0xFF) << 8) | (b1 & 0xFF));
			}

			static void pack(const uint16_t& v, char *out) {
				out[1] = (v >> 8) & 0xFF;
				out[0] = v & 0xFF;
			}
		};

		template<>
		struct packers<uint8_t> {
			static unsigned char unpack(const char *in) {
				return static_cast<uint8_t>(in[0]);
			}

			static void pack(const uint8_t& c, char *out) {
				out[0] = static_cast<int8_t>(c);
			}
		};

		template<>
		struct packers<int32_t> {
			static int unpack(const char *in) {
				return static_cast<int32_t>(packers<uint32_t>::unpack(in));
			}

			static void pack(const int32_t& t, char *out) {
				packers<uint32_t>::pack(static_cast<uint32_t>(t), out);
			}
		};

		template<>
		struct packers<int16_t> {
			static short unpack(const char *in) {
				return static_cast<int16_t>(packers<uint16_t>::unpack(in));
			}

			static void pack(const int16_t& t, char *out) {
				packers<uint16_t>::pack(static_cast<uint16_t>(t), out);
			}
		};

		template<>
		struct packers<int8_t> {
			static int8_t unpack(const char *in) {
				return in[0];
			}

			static void pack(const int8_t& t, char *out) {
				out[0] = t;
			}
		};

        // Char is neither signed char nor unsigned char.
		template<>
		struct packers<char> {
			static char unpack(const char *in) {
				return in[0];
			}

			static void pack(const char& t, char *out) {
				out[0] = t;
			}
		};

		/** A simple strategy which returns simple diffs */
		template<typename T>
		struct standard_diff_method {
			standard_diff_method<T>()
				: have_value_(false) {}

			inline void push(const T& v) {
				if (!have_value_)
					have_value_ = true;

				value = v;
			}

			inline bool have_value() const {
				return have_value_;
			}

			T value;
			bool have_value_;
		};

		struct base_field {
			typedef std::shared_ptr<base_field> ptr;

			virtual ~base_field() {
				// hello 1996
			}

			virtual size_t field_size() = 0;
			virtual void compressRaw(const char *) {}
			virtual void decompressRaw(char *) {}
		};

		template<typename T, typename TDiffMethod = standard_diff_method<T> >
		struct field {
			static_assert(std::is_integral<T>::value,
					"Default implementation for field only handles integral types");

			typedef T type;

			field() :
				compressor_(sizeof(T) * 8),
				decompressor_(sizeof(T) * 8),
				compressor_inited_(false),
				decompressor_inited_(false) { }

			template<
				typename TEncoder
			>
			inline void compressWith(TEncoder& encoder, const T& this_val) {
				if (!compressor_inited_)
					compressor_.init();

				// Let the differ decide what values we're going to push
				//
				if (differ_.have_value()) {
					compressor_.compress(encoder, differ_.value, this_val, 0);
				}
				else {
					// differ is not ready for us to start encoding values for us, so we need to write raw into
					// the outputstream
					//
					char buf[sizeof(T)];
					packers<T>::pack(this_val, buf);

					encoder.getOutStream().putBytes((unsigned char*)buf, sizeof(T));
				}

				differ_.push(this_val);
			}

			template<
				typename TDecoder
			>
			inline T decompressWith(TDecoder& decoder) {
				if (!decompressor_inited_)
					decompressor_.init();

				T r;
				if (differ_.have_value()) {
					r = static_cast<T>(decompressor_.decompress(decoder, differ_.value, 0));
				}
				else {
					// this is probably the first time we're reading stuff, read the record as is
					char buffer[sizeof(T)];
					decoder.getInStream().getBytes((unsigned char*)buffer, sizeof(T));

					r = packers<T>::unpack(buffer);
				}

				differ_.push(r);
				return r;
			}

			laszip::compressors::integer compressor_;
			laszip::decompressors::integer decompressor_;

			bool compressor_inited_, decompressor_inited_;

			TDiffMethod differ_;
		};

		template<typename... TS>
		struct record_compressor;

		template<typename... TS>
		struct record_decompressor;

		template<>
		struct record_compressor<> {
			record_compressor() {}
			template<
				typename T
			>
			inline void compressWith(T&, const char *) { }
		};

		template<typename T, typename... TS>
		struct record_compressor<T, TS...> {
			record_compressor() {}

			template<
				typename TEncoder
			>
			inline void compressWith(TEncoder& encoder, const char *buffer) {
				typedef typename T::type this_field_type;

				this_field_type v = packers<this_field_type>::unpack(buffer);
				field_.compressWith(encoder, v);

				// Move on to the next field
				next_.compressWith(encoder, buffer + sizeof(typename T::type));
			}

			// The field that we handle
			T field_;

			// Our default strategy right now is to just encode diffs, but we would employ more advanced techniques soon
			record_compressor<TS...> next_;
		};

		template<>
		struct record_decompressor<> {
			record_decompressor() : firstDecompress(true) {}
			template<
				typename TDecoder
			>
			inline void decompressWith(TDecoder& decoder, char *) {
				if (firstDecompress) {
					decoder.readInitBytes();
					firstDecompress = false;
				}
			}

			bool firstDecompress;
		};

		template<typename T, typename... TS>
		struct record_decompressor<T, TS...> {
			record_decompressor() {}

			template<
				typename TDecoder
			>
			inline void decompressWith(TDecoder& decoder, char *buffer) {
				typedef typename T::type this_field_type;

				this_field_type v = static_cast<this_field_type>(field_.decompressWith(decoder));
				packers<this_field_type>::pack(v, buffer);

				// Move on to the next field
				next_.decompressWith(decoder, buffer + sizeof(typename T::type));
			}

			// The field that we handle
			T field_;

			// Our default strategy right now is to just encode diffs, but we would employ more advanced techniques soon
			record_decompressor<TS...> next_;
		};

		struct dynamic_compressor {
			typedef std::shared_ptr<dynamic_compressor> ptr;

			virtual void compress(const char *in) = 0;
			virtual ~dynamic_compressor() {}
		};

		struct dynamic_decompressor {
			typedef std::shared_ptr<dynamic_decompressor> ptr;

			virtual void decompress(char *in) = 0;
			virtual ~dynamic_decompressor() {}
		};

		template<
			typename TEncoder,
			typename TRecordCompressor
		>
		struct dynamic_compressor1 : public dynamic_compressor {
			dynamic_compressor1(TEncoder& enc, TRecordCompressor* compressor) :
				enc_(enc), compressor_(compressor) {}

			virtual void compress(const char *in) {
				compressor_->compressWith(enc_, in);
			}

			dynamic_compressor1(const dynamic_compressor1<TEncoder , TRecordCompressor>&) = delete;
			dynamic_compressor1<TEncoder, TRecordCompressor>& operator=(dynamic_compressor1<TEncoder, TRecordCompressor>&) = delete;

			TEncoder& enc_;
			TRecordCompressor* compressor_;
		};

		template<
			typename TEncoder,
			typename TRecordCompressor
		>
		static dynamic_compressor::ptr make_dynamic_compressor(TEncoder& encoder, TRecordCompressor* compressor) {
			return dynamic_compressor::ptr(
					new dynamic_compressor1<TEncoder, TRecordCompressor>(encoder, compressor));
		}

		template<
			typename TDecoder,
			typename TRecordDecompressor
		>
		struct dynamic_decompressor1 : public dynamic_decompressor {
			dynamic_decompressor1(TDecoder& dec, TRecordDecompressor* decompressor) :
				dec_(dec), decompressor_(decompressor) {}

			virtual void decompress(char *in) {
				decompressor_->decompressWith(dec_, in);
			}

			~dynamic_decompressor1() {
				delete decompressor_;
			}

			dynamic_decompressor1(const dynamic_decompressor1<TDecoder, TRecordDecompressor>&) = delete;
			dynamic_decompressor1<TDecoder, TRecordDecompressor>& operator=(dynamic_decompressor1<TDecoder, TRecordDecompressor>&) = delete;

			TDecoder& dec_;
			TRecordDecompressor* decompressor_;
		};

		template<
			typename TDecoder,
			typename TRecordDecompressor
		>
		static dynamic_decompressor::ptr make_dynamic_decompressor(TDecoder& decoder, TRecordDecompressor* decompressor) {
			return dynamic_decompressor::ptr(
					new dynamic_decompressor1<TDecoder, TRecordDecompressor>(decoder, decompressor));
		}

		// type-erasure stuff for fields
		template<
			typename TEncoderDecoder,
			typename TField
		>
		struct dynamic_compressor_field : base_field {
			dynamic_compressor_field(TEncoderDecoder& encdec) : encdec_(encdec), field_() {}

			virtual void compressRaw(const char *in) {
				typedef packers<typename TField::type> p;

				auto to_compress = p::unpack(in);
				field_.compressWith(encdec_, to_compress);
			}

			virtual size_t field_size() {
				return sizeof(typename TField::type);
			}

			TEncoderDecoder& encdec_;
			TField field_;
		};

		template<
			typename TEncoderDecoder,
			typename TField
		>
		struct dynamic_decompressor_field : base_field {
			dynamic_decompressor_field(TEncoderDecoder& encdec) : encdec_(encdec), field_() {}

			virtual void decompressRaw(char *out) {
				typedef packers<typename TField::type> p;

				auto decomp = field_.decompressWith(encdec_);
				p::pack(decomp, out);
			}

			virtual size_t field_size() {
				return sizeof(typename TField::type);
			}

			TEncoderDecoder& encdec_;
			TField field_;
		};

		template<
			typename TEncoder
		>
		struct dynamic_field_compressor: dynamic_compressor {
            typedef dynamic_field_compressor<TEncoder>  this_type;
            typedef std::shared_ptr<this_type>          ptr;

			dynamic_field_compressor(TEncoder& encoder) : enc_(encoder), fields_() { }

			template<typename TFieldType>
			void add_field() {
				fields_.push_back(base_field::ptr(new
							dynamic_compressor_field<TEncoder, field<TFieldType> >(enc_)));
			};

			virtual void compress(const char *in) {
                size_t offset = 0;
                for (auto f: fields_) {
                    f->compressRaw(in + offset);
                    offset += f->field_size();
                }
			}

			TEncoder& enc_;
			std::vector<base_field::ptr> fields_;
		};

        template<
            typename TDecoder
        >
        struct dynamic_field_decompressor : dynamic_decompressor {
            typedef dynamic_field_decompressor<TDecoder> this_type;
            typedef std::shared_ptr<this_type>           ptr;

			dynamic_field_decompressor(TDecoder& decoder) : dec_(decoder), fields_(), first_decomp_(true) { }

			template<typename TFieldType>
			void add_field() {
				fields_.push_back(base_field::ptr(new
							dynamic_decompressor_field<TDecoder, field<TFieldType> >(dec_)));
			};

			virtual void decompress(char *out) {
				// will do soemthign with in
                size_t offset = 0;
                for (auto f: fields_) {
                    f->decompressRaw(out + offset);
                    offset += f->field_size();
                }

                // the decoder needs to be told that it should read the init bytes
                // after the first record has been read
                //
                if (first_decomp_) {
                    first_decomp_ = false;
                    dec_.readInitBytes();
                }
			}

			TDecoder& dec_;
			std::vector<base_field::ptr> fields_;
            bool first_decomp_;
        };

        template<
            typename TEncoder
        >
        static typename dynamic_field_compressor<TEncoder>::ptr make_dynamic_compressor(TEncoder& encoder) {
            typedef typename dynamic_field_compressor<TEncoder>::ptr ptr;
            return ptr(new dynamic_field_compressor<TEncoder>(encoder));
        }

		template<
			typename TDecoder
		>
		static typename dynamic_field_decompressor<TDecoder>::ptr make_dynamic_decompressor(TDecoder& decoder) {
            typedef typename dynamic_field_decompressor<TDecoder>::ptr ptr;
            return ptr(new dynamic_field_decompressor<TDecoder>(decoder));
		}

	}
}

#endif // __formats_hpp__
<|endoftext|>


<commit_before>//
// ogles_gpgpu project - GPGPU for mobile devices and embedded systems using OpenGL ES 2.0
//
// Author: Markus Konrad <post@mkonrad.net>, Winter 2014/2015
// http://www.mkonrad.net
//
// See LICENSE file in project repository root for the license.
//

#include "../../common_includes.h"
#include "adapt_thresh_pass.h"

using namespace ogles_gpgpu;

// Adaptive thresholding - Pass 1 fragment shader
// Perform a vertical 5x1 average gray pixel value calculation
// Requires a grayscale image as input!
const char *AdaptThreshProcPass::fshaderAdaptThreshPass1Src = OG_TO_STR(

#if defined(OGLES_GPGPU_OPENGLES)
            precision mediump float;
#endif

            varying vec2 vTexCoord;
            uniform vec2 uPxD;
            uniform sampler2D uInputTex;
void main() {
    // get center pixel value
    float centerGray = texture2D(uInputTex, vTexCoord).r;
    // get the sum
    float sum = texture2D(uInputTex, vTexCoord + vec2(uPxD.x * -2.0, 0.0)).r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.x * -1.0, 0.0)).r +
                centerGray +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.x *  1.0, 0.0)).r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.x *  2.0, 0.0)).r;
    // get the average
    float avg = sum / 5.0;
    // Result stores average pixel value (R) and original gray value (G)
    gl_FragColor = vec4(avg, centerGray, 0.0, 1.0);
}
        );

// Adaptive thresholding - Pass 2
// Perform a horizontal 7x1 or 5x1 average gray pixel value calculation and
// the final binarization
const char *AdaptThreshProcPass::fshaderAdaptThreshPass2Src = OG_TO_STR(

#if defined(OGLES_GPGPU_OPENGLES)
            precision mediump float;
#endif

            varying vec2 vTexCoord;
            uniform vec2 uPxD;
            uniform sampler2D uInputTex;
void main() {
    vec4 centerPx = texture2D(uInputTex, vTexCoord); // stores: horizontal avg, orig. gray value, 0, 1
    const float bigC = 9.5 / 255.0;
    // get the sum
    float sum = texture2D(uInputTex, vTexCoord + vec2(uPxD.y * -2.0, 0.0)).r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.y * -1.0, 0.0)).r +
                centerPx.r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.y *  1.0, 0.0)).r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.y *  2.0, 0.0)).r;
    // get the average
    float avg = sum / 5.0;
    // create inverted binary value
    float bin = 1.0 - step(avg - bigC, centerPx.g); // centerPx.g is orig. gray value at current position
    // store thresholded values
    gl_FragColor = vec4(bin, bin, bin, 1.0);
}
        );

int AdaptThreshProcPass::init(int inW, int inH, unsigned int order, bool prepareForExternalInput) {
    OG_LOGINF(getProcName(), "render pass %d", renderPass);

    // create fbo for output
    createFBO();

    // parent init - set defaults
    baseInit(inW, inH, order, prepareForExternalInput, procParamOutW, procParamOutH, procParamOutScale);

    // calculate pixel delta values
    pxDx = 1.0f / (float)outFrameW;
    pxDy = 1.0f / (float)outFrameH;

    // get necessary fragment shader source
    const char *shSrc = renderPass == 1 ? fshaderAdaptThreshPass1Src : fshaderAdaptThreshPass2Src;

    // FilterProcBase init - create shaders, get shader params, set buffers for OpenGL
    filterInit(vshaderDefault, shSrc, RenderOrientationDiagonal);

    // get additional shader params
    shParamUPxD = shader->getParam(UNIF, "uPxD");

    return 1;
}

void AdaptThreshProcPass::createFBOTex(bool genMipmap) {
    assert(fbo);

    if (renderPass == 1) {
        fbo->createAttachedTex(outFrameH, outFrameW, genMipmap);   // swapped
    } else {
        fbo->createAttachedTex(outFrameW, outFrameH, genMipmap);
    }

    // update frame size, because it might be set to a POT size because of mipmapping
    outFrameW = fbo->getTexWidth();
    outFrameH = fbo->getTexHeight();
}

void AdaptThreshProcPass::render() {
    OG_LOGINF(getProcName(), "input tex %d, target %d, render pass %d, framebuffer of size %dx%d", texId, texTarget, renderPass, outFrameW, outFrameH);

    filterRenderPrepare();

    glUniform2f(shParamUPxD, pxDx, pxDy);	// texture pixel delta values

    Tools::checkGLErr(getProcName(), "render prepare");

    filterRenderSetCoords();
    Tools::checkGLErr(getProcName(), "render set coords");

    filterRenderDraw();
    Tools::checkGLErr(getProcName(), "render draw");

    filterRenderCleanup();
    Tools::checkGLErr(getProcName(), "render cleanup");
}
<commit_msg>format shader strings clobbered by autoindent that is not shader aware<commit_after>//
// ogles_gpgpu project - GPGPU for mobile devices and embedded systems using OpenGL ES 2.0
//
// Author: Markus Konrad <post@mkonrad.net>, Winter 2014/2015
// http://www.mkonrad.net
//
// See LICENSE file in project repository root for the license.
//

#include "../../common_includes.h"
#include "adapt_thresh_pass.h"

using namespace ogles_gpgpu;

// Adaptive thresholding - Pass 1 fragment shader
// Perform a vertical 5x1 average gray pixel value calculation
// Requires a grayscale image as input!
const char *AdaptThreshProcPass::fshaderAdaptThreshPass1Src = OG_TO_STR(

#if defined(OGLES_GPGPU_OPENGLES)
precision mediump float;
#endif

varying vec2 vTexCoord;
uniform vec2 uPxD;
uniform sampler2D uInputTex;
void main() {
    // get center pixel value
    float centerGray = texture2D(uInputTex, vTexCoord).r;
    // get the sum
    float sum = texture2D(uInputTex, vTexCoord + vec2(uPxD.x * -2.0, 0.0)).r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.x * -1.0, 0.0)).r +
                centerGray +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.x *  1.0, 0.0)).r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.x *  2.0, 0.0)).r;
    // get the average
    float avg = sum / 5.0;
    // Result stores average pixel value (R) and original gray value (G)
    gl_FragColor = vec4(avg, centerGray, 0.0, 1.0);
}
);

// Adaptive thresholding - Pass 2
// Perform a horizontal 7x1 or 5x1 average gray pixel value calculation and
// the final binarization
const char *AdaptThreshProcPass::fshaderAdaptThreshPass2Src = OG_TO_STR(

#if defined(OGLES_GPGPU_OPENGLES)
precision mediump float;
#endif

varying vec2 vTexCoord;
uniform vec2 uPxD;
uniform sampler2D uInputTex;
void main() {
    vec4 centerPx = texture2D(uInputTex, vTexCoord); // stores: horizontal avg, orig. gray value, 0, 1
    const float bigC = 9.5 / 255.0;
    // get the sum
    float sum = texture2D(uInputTex, vTexCoord + vec2(uPxD.y * -2.0, 0.0)).r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.y * -1.0, 0.0)).r +
                centerPx.r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.y *  1.0, 0.0)).r +
                texture2D(uInputTex, vTexCoord + vec2(uPxD.y *  2.0, 0.0)).r;
    // get the average
    float avg = sum / 5.0;
    // create inverted binary value
    float bin = 1.0 - step(avg - bigC, centerPx.g); // centerPx.g is orig. gray value at current position
    // store thresholded values
    gl_FragColor = vec4(bin, bin, bin, 1.0);
}
);

int AdaptThreshProcPass::init(int inW, int inH, unsigned int order, bool prepareForExternalInput) {
    OG_LOGINF(getProcName(), "render pass %d", renderPass);

    // create fbo for output
    createFBO();

    // parent init - set defaults
    baseInit(inW, inH, order, prepareForExternalInput, procParamOutW, procParamOutH, procParamOutScale);

    // calculate pixel delta values
    pxDx = 1.0f / (float)outFrameW;
    pxDy = 1.0f / (float)outFrameH;

    // get necessary fragment shader source
    const char *shSrc = renderPass == 1 ? fshaderAdaptThreshPass1Src : fshaderAdaptThreshPass2Src;

    // FilterProcBase init - create shaders, get shader params, set buffers for OpenGL
    filterInit(vshaderDefault, shSrc, RenderOrientationDiagonal);

    // get additional shader params
    shParamUPxD = shader->getParam(UNIF, "uPxD");

    return 1;
}

void AdaptThreshProcPass::createFBOTex(bool genMipmap) {
    assert(fbo);

    if (renderPass == 1) {
        fbo->createAttachedTex(outFrameH, outFrameW, genMipmap);   // swapped
    } else {
        fbo->createAttachedTex(outFrameW, outFrameH, genMipmap);
    }

    // update frame size, because it might be set to a POT size because of mipmapping
    outFrameW = fbo->getTexWidth();
    outFrameH = fbo->getTexHeight();
}

void AdaptThreshProcPass::render() {
    OG_LOGINF(getProcName(), "input tex %d, target %d, render pass %d, framebuffer of size %dx%d", texId, texTarget, renderPass, outFrameW, outFrameH);

    filterRenderPrepare();

    glUniform2f(shParamUPxD, pxDx, pxDy);	// texture pixel delta values

    Tools::checkGLErr(getProcName(), "render prepare");

    filterRenderSetCoords();
    Tools::checkGLErr(getProcName(), "render set coords");

    filterRenderDraw();
    Tools::checkGLErr(getProcName(), "render draw");

    filterRenderCleanup();
    Tools::checkGLErr(getProcName(), "render cleanup");
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KDE Libraries
 * Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
 *                    Tom Braun <braunt@fh-konstanz.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <QtCore/QString>

#include "config.h"

#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <execinfo.h>

#include "kcrash.h"

QString kBacktrace()
{
  QString s;

  void* trace[256];
  int n = backtrace(trace, 256);
  if (!n)
    return s;

  char** strings = backtrace_symbols (trace, n);

  s = QLatin1String("[\n");

  for (int i = 0; i < n; ++i)
    s += QString::number(i) +
         QLatin1String(": ") +
         QLatin1String(strings[i]) + QLatin1String("\n");
    s += QLatin1String("]\n");

  if (strings)
    free (strings);

  return s;
}
static KCrash::HandlerType s_emergencyMethod = 0;

void KCrash::setEmergencyMethod( HandlerType method )
{
  s_emergencyMethod = method;
}

static void defaultCrashHandler( int sig )
{
  if ( sig != SIGTERM && sig != SIGINT )
    fprintf( stderr, "%s", kBacktrace().toLatin1().data() );

  if ( s_emergencyMethod )
    s_emergencyMethod( sig );

  _exit(255);
}

void KCrash::init()
{
  HandlerType handler = defaultCrashHandler;

#ifdef Q_OS_UNIX
  if (!handler)
    handler = SIG_DFL;

  sigset_t mask;
  sigemptyset(&mask);

#ifdef SIGSEGV
  signal (SIGSEGV, handler);
  sigaddset(&mask, SIGSEGV);
#endif
#ifdef SIGFPE
  signal (SIGFPE, handler);
  sigaddset(&mask, SIGFPE);
#endif
#ifdef SIGILL
  signal (SIGILL, handler);
  sigaddset(&mask, SIGILL);
#endif
#ifdef SIGABRT
  signal (SIGABRT, handler);
  sigaddset(&mask, SIGABRT);
#endif
#ifdef SIGTERM
  signal (SIGTERM, handler);
  sigaddset(&mask, SIGTERM);
#endif
#ifdef SIGINT
  signal (SIGINT, handler);
  sigaddset(&mask, SIGINT);
#endif

  sigprocmask(SIG_UNBLOCK, &mask, 0);
#endif //Q_OS_UNIX

}

<commit_msg>execinfo is glibc-specific<commit_after>/*
 * This file is part of the KDE Libraries
 * Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
 *                    Tom Braun <braunt@fh-konstanz.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <QtCore/QString>

#include "config.h"

#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif

#include "kcrash.h"

QString kBacktrace()
{
  QString s;

/* FIXME: is there an equivalent for darwin, *BSD, or windows? */
#ifdef HAVE_EXECINFO_H
  void* trace[256];
  int n = backtrace(trace, 256);
  if (!n)
    return s;

  char** strings = backtrace_symbols (trace, n);

  s = QLatin1String("[\n");

  for (int i = 0; i < n; ++i)
    s += QString::number(i) +
         QLatin1String(": ") +
         QLatin1String(strings[i]) + QLatin1String("\n");
    s += QLatin1String("]\n");

  if (strings)
    free (strings);
#endif

  return s;
}
static KCrash::HandlerType s_emergencyMethod = 0;

void KCrash::setEmergencyMethod( HandlerType method )
{
  s_emergencyMethod = method;
}

static void defaultCrashHandler( int sig )
{
  if ( sig != SIGTERM && sig != SIGINT )
    fprintf( stderr, "%s", kBacktrace().toLatin1().data() );

  if ( s_emergencyMethod )
    s_emergencyMethod( sig );

  _exit(255);
}

void KCrash::init()
{
  HandlerType handler = defaultCrashHandler;

#ifdef Q_OS_UNIX
  if (!handler)
    handler = SIG_DFL;

  sigset_t mask;
  sigemptyset(&mask);

#ifdef SIGSEGV
  signal (SIGSEGV, handler);
  sigaddset(&mask, SIGSEGV);
#endif
#ifdef SIGFPE
  signal (SIGFPE, handler);
  sigaddset(&mask, SIGFPE);
#endif
#ifdef SIGILL
  signal (SIGILL, handler);
  sigaddset(&mask, SIGILL);
#endif
#ifdef SIGABRT
  signal (SIGABRT, handler);
  sigaddset(&mask, SIGABRT);
#endif
#ifdef SIGTERM
  signal (SIGTERM, handler);
  sigaddset(&mask, SIGTERM);
#endif
#ifdef SIGINT
  signal (SIGINT, handler);
  sigaddset(&mask, SIGINT);
#endif

  sigprocmask(SIG_UNBLOCK, &mask, 0);
#endif //Q_OS_UNIX

}

<|endoftext|>


<commit_before>/*     Copyright 2015-2018 Egor Yusov
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  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 OF ANY PROPRIETARY RIGHTS.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */

#include "pch.h"
#include "ShaderResourceBindingD3D12Impl.h"
#include "PipelineStateD3D12Impl.h"
#include "ShaderD3D12Impl.h"
#include "RenderDeviceD3D12Impl.h"

namespace Diligent
{

ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl(IReferenceCounters*     pRefCounters,
                                                               PipelineStateD3D12Impl* pPSO,
                                                               bool                    IsPSOInternal) :
    TBase( pRefCounters, pPSO, IsPSOInternal ),
    m_ShaderResourceCache(ShaderResourceCacheD3D12::DbgCacheContentType::SRBResources),
    m_NumShaders(static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaders()))
{
    auto* ppShaders = pPSO->GetShaders();

    auto* pRenderDeviceD3D12Impl = ValidatedCast<RenderDeviceD3D12Impl>(pPSO->GetDevice());
    auto& ResCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0);
    pPSO->GetRootSignature().InitResourceCache(pRenderDeviceD3D12Impl, m_ShaderResourceCache, ResCacheDataAllocator);

    auto *pVarMgrsRawMem = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerD3D12", m_NumShaders * sizeof(ShaderVariableManagerD3D12));
    m_pShaderVarMgrs = reinterpret_cast<ShaderVariableManagerD3D12*>(pVarMgrsRawMem);

    for (Uint32 s = 0; s < m_NumShaders; ++s)
    {
        auto* pShader = ppShaders[s];
        auto ShaderType = pShader->GetDesc().ShaderType;
        auto ShaderInd = GetShaderTypeIndex(ShaderType);

        // Create shader variable manager in place
        new (m_pShaderVarMgrs + s) ShaderVariableManagerD3D12(*this);

        auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s);

        // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Resource-Layouts-in-a-Shader-Resource-Binding-Object
        std::array<SHADER_VARIABLE_TYPE, 2> AllowedVarTypes = { SHADER_VARIABLE_TYPE_MUTABLE, SHADER_VARIABLE_TYPE_DYNAMIC };
        const auto& SrcLayout = pPSO->GetShaderResLayout(s);
        m_pShaderVarMgrs[s].Initialize(SrcLayout, VarDataAllocator, AllowedVarTypes.data(), static_cast<Uint32>(AllowedVarTypes.size()), m_ShaderResourceCache);

        m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s);
    }
}

ShaderResourceBindingD3D12Impl::~ShaderResourceBindingD3D12Impl()
{
    auto* pPSO = ValidatedCast<PipelineStateD3D12Impl>(m_pPSO);
    for(Uint32 s = 0; s < m_NumShaders; ++s)
    {
        auto &VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s);
        m_pShaderVarMgrs[s].Destroy(VarDataAllocator);
        m_pShaderVarMgrs[s].~ShaderVariableManagerD3D12();
    }

    GetRawAllocator().Free(m_pShaderVarMgrs);
}

IMPLEMENT_QUERY_INTERFACE( ShaderResourceBindingD3D12Impl, IID_ShaderResourceBindingD3D12, TBase )

void ShaderResourceBindingD3D12Impl::BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags)
{
    for (auto ShaderInd = 0; ShaderInd <= CSInd; ++ShaderInd )
    {
        if (ShaderFlags & GetShaderTypeFromIndex(ShaderInd))
        {
            auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
            if(ResLayoutInd >= 0)
            {
                m_pShaderVarMgrs[ResLayoutInd].BindResources(pResMapping, Flags);
            }
        }
    }
}

IShaderVariable *ShaderResourceBindingD3D12Impl::GetVariable(SHADER_TYPE ShaderType, const char *Name)
{
    auto ShaderInd = GetShaderTypeIndex(ShaderType);
    auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
    if (ResLayoutInd < 0)
    {
        LOG_ERROR("Unable to find mutable/dynamic variable '", Name, "': shader stage ", GetShaderTypeLiteralName(ShaderType), " is inactive");
        return nullptr;
    }
    return m_pShaderVarMgrs[ResLayoutInd].GetVariable(Name);
}

Uint32 ShaderResourceBindingD3D12Impl::GetVariableCount(SHADER_TYPE ShaderType) const
{
    auto ShaderInd = GetShaderTypeIndex(ShaderType);
    auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
    if (ResLayoutInd < 0)
    {
        LOG_ERROR("Unable to get the number of mutable/dynamic variables: shader stage ", GetShaderTypeLiteralName(ShaderType), " is inactive");
        return 0;
    }

    return m_pShaderVarMgrs[ResLayoutInd].GetVariableCount();
}

IShaderVariable* ShaderResourceBindingD3D12Impl::GetVariable(SHADER_TYPE ShaderType, Uint32 Index)
{
    auto ShaderInd = GetShaderTypeIndex(ShaderType);
    auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
    if (ResLayoutInd < 0)
    {
        LOG_ERROR("Unable to get mutable/dynamic variable at index ", Index, ": shader stage ", GetShaderTypeLiteralName(ShaderType), " is inactive");
        return nullptr;
    }

    return m_pShaderVarMgrs[ResLayoutInd].GetVariable(Index);
}

#ifdef DEVELOPMENT
void ShaderResourceBindingD3D12Impl::dvpVerifyResourceBindings(const PipelineStateD3D12Impl* pPSO)
{
    auto* pRefPSO = ValidatedCast<PipelineStateD3D12Impl>(GetPipelineState());
    if (pPSO->IsIncompatibleWith(pRefPSO))
    {
        LOG_ERROR("Shader resource binding is incompatible with the pipeline state \"", pPSO->GetDesc().Name, '\"');
        return;
    }
    for(Uint32 l = 0; l < m_NumShaders; ++l)
    {
        // Use reference layout from pipeline state that contains all shader resource types
        const auto& ShaderResLayout = pRefPSO->GetShaderResLayout(l);
        ShaderResLayout.dvpVerifyBindings(m_ShaderResourceCache);
    }
}
#endif

void ShaderResourceBindingD3D12Impl::InitializeStaticResources(const PipelineStateD3D12Impl* pPSO)
{
    VERIFY(!StaticResourcesInitialized(), "Static resources have already been initialized");
    VERIFY(pPSO == GetPipelineState(), "Invalid pipeline state provided");

    auto NumShaders = pPSO->GetNumShaders();
    auto ppShaders = pPSO->GetShaders();
    // Copy static resources
    for (Uint32 s = 0; s < NumShaders; ++s)
    {
        auto* pShader = ValidatedCast<ShaderD3D12Impl>( ppShaders[s] );
#ifdef DEVELOPMENT
        pShader->DvpVerifyStaticResourceBindings();
#endif
        const auto& ShaderResLayout = pPSO->GetShaderResLayout(s);
        auto& StaticResLayout = pShader->GetStaticResLayout();
        auto& StaticResCache = pShader->GetStaticResCache();
        StaticResLayout.CopyStaticResourceDesriptorHandles(StaticResCache, ShaderResLayout, m_ShaderResourceCache);
    }

    m_bStaticResourcesInitialized = true;
}

}
<commit_msg>Fixed debug check in ShaderResourceBindingD3D12Impl::InitializeStaticResources()<commit_after>/*     Copyright 2015-2018 Egor Yusov
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  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 OF ANY PROPRIETARY RIGHTS.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */

#include "pch.h"
#include "ShaderResourceBindingD3D12Impl.h"
#include "PipelineStateD3D12Impl.h"
#include "ShaderD3D12Impl.h"
#include "RenderDeviceD3D12Impl.h"

namespace Diligent
{

ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl(IReferenceCounters*     pRefCounters,
                                                               PipelineStateD3D12Impl* pPSO,
                                                               bool                    IsPSOInternal) :
    TBase( pRefCounters, pPSO, IsPSOInternal ),
    m_ShaderResourceCache(ShaderResourceCacheD3D12::DbgCacheContentType::SRBResources),
    m_NumShaders(static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaders()))
{
    auto* ppShaders = pPSO->GetShaders();

    auto* pRenderDeviceD3D12Impl = ValidatedCast<RenderDeviceD3D12Impl>(pPSO->GetDevice());
    auto& ResCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0);
    pPSO->GetRootSignature().InitResourceCache(pRenderDeviceD3D12Impl, m_ShaderResourceCache, ResCacheDataAllocator);

    auto *pVarMgrsRawMem = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerD3D12", m_NumShaders * sizeof(ShaderVariableManagerD3D12));
    m_pShaderVarMgrs = reinterpret_cast<ShaderVariableManagerD3D12*>(pVarMgrsRawMem);

    for (Uint32 s = 0; s < m_NumShaders; ++s)
    {
        auto* pShader = ppShaders[s];
        auto ShaderType = pShader->GetDesc().ShaderType;
        auto ShaderInd = GetShaderTypeIndex(ShaderType);

        // Create shader variable manager in place
        new (m_pShaderVarMgrs + s) ShaderVariableManagerD3D12(*this);

        auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s);

        // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Resource-Layouts-in-a-Shader-Resource-Binding-Object
        std::array<SHADER_VARIABLE_TYPE, 2> AllowedVarTypes = { SHADER_VARIABLE_TYPE_MUTABLE, SHADER_VARIABLE_TYPE_DYNAMIC };
        const auto& SrcLayout = pPSO->GetShaderResLayout(s);
        m_pShaderVarMgrs[s].Initialize(SrcLayout, VarDataAllocator, AllowedVarTypes.data(), static_cast<Uint32>(AllowedVarTypes.size()), m_ShaderResourceCache);

        m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s);
    }
}

ShaderResourceBindingD3D12Impl::~ShaderResourceBindingD3D12Impl()
{
    auto* pPSO = ValidatedCast<PipelineStateD3D12Impl>(m_pPSO);
    for(Uint32 s = 0; s < m_NumShaders; ++s)
    {
        auto &VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s);
        m_pShaderVarMgrs[s].Destroy(VarDataAllocator);
        m_pShaderVarMgrs[s].~ShaderVariableManagerD3D12();
    }

    GetRawAllocator().Free(m_pShaderVarMgrs);
}

IMPLEMENT_QUERY_INTERFACE( ShaderResourceBindingD3D12Impl, IID_ShaderResourceBindingD3D12, TBase )

void ShaderResourceBindingD3D12Impl::BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags)
{
    for (auto ShaderInd = 0; ShaderInd <= CSInd; ++ShaderInd )
    {
        if (ShaderFlags & GetShaderTypeFromIndex(ShaderInd))
        {
            auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
            if(ResLayoutInd >= 0)
            {
                m_pShaderVarMgrs[ResLayoutInd].BindResources(pResMapping, Flags);
            }
        }
    }
}

IShaderVariable *ShaderResourceBindingD3D12Impl::GetVariable(SHADER_TYPE ShaderType, const char *Name)
{
    auto ShaderInd = GetShaderTypeIndex(ShaderType);
    auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
    if (ResLayoutInd < 0)
    {
        LOG_ERROR("Unable to find mutable/dynamic variable '", Name, "': shader stage ", GetShaderTypeLiteralName(ShaderType), " is inactive");
        return nullptr;
    }
    return m_pShaderVarMgrs[ResLayoutInd].GetVariable(Name);
}

Uint32 ShaderResourceBindingD3D12Impl::GetVariableCount(SHADER_TYPE ShaderType) const
{
    auto ShaderInd = GetShaderTypeIndex(ShaderType);
    auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
    if (ResLayoutInd < 0)
    {
        LOG_ERROR("Unable to get the number of mutable/dynamic variables: shader stage ", GetShaderTypeLiteralName(ShaderType), " is inactive");
        return 0;
    }

    return m_pShaderVarMgrs[ResLayoutInd].GetVariableCount();
}

IShaderVariable* ShaderResourceBindingD3D12Impl::GetVariable(SHADER_TYPE ShaderType, Uint32 Index)
{
    auto ShaderInd = GetShaderTypeIndex(ShaderType);
    auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
    if (ResLayoutInd < 0)
    {
        LOG_ERROR("Unable to get mutable/dynamic variable at index ", Index, ": shader stage ", GetShaderTypeLiteralName(ShaderType), " is inactive");
        return nullptr;
    }

    return m_pShaderVarMgrs[ResLayoutInd].GetVariable(Index);
}

#ifdef DEVELOPMENT
void ShaderResourceBindingD3D12Impl::dvpVerifyResourceBindings(const PipelineStateD3D12Impl* pPSO)
{
    auto* pRefPSO = ValidatedCast<PipelineStateD3D12Impl>(GetPipelineState());
    if (pPSO->IsIncompatibleWith(pRefPSO))
    {
        LOG_ERROR("Shader resource binding is incompatible with the pipeline state \"", pPSO->GetDesc().Name, '\"');
        return;
    }
    for(Uint32 l = 0; l < m_NumShaders; ++l)
    {
        // Use reference layout from pipeline state that contains all shader resource types
        const auto& ShaderResLayout = pRefPSO->GetShaderResLayout(l);
        ShaderResLayout.dvpVerifyBindings(m_ShaderResourceCache);
    }
}
#endif

void ShaderResourceBindingD3D12Impl::InitializeStaticResources(const PipelineStateD3D12Impl* pPSO)
{
    VERIFY(!StaticResourcesInitialized(), "Static resources have already been initialized");
    VERIFY(pPSO->IsCompatibleWith(GetPipelineState()), "Currently bound pipeline state is not compatible with this SRB");

    auto NumShaders = pPSO->GetNumShaders();
    auto ppShaders = pPSO->GetShaders();
    // Copy static resources
    for (Uint32 s = 0; s < NumShaders; ++s)
    {
        auto* pShader = ValidatedCast<ShaderD3D12Impl>( ppShaders[s] );
#ifdef DEVELOPMENT
        pShader->DvpVerifyStaticResourceBindings();
#endif
        const auto& ShaderResLayout = pPSO->GetShaderResLayout(s);
        auto& StaticResLayout = pShader->GetStaticResLayout();
        auto& StaticResCache = pShader->GetStaticResCache();
        StaticResLayout.CopyStaticResourceDesriptorHandles(StaticResCache, ShaderResLayout, m_ShaderResourceCache);
    }

    m_bStaticResourcesInitialized = true;
}

}
<|endoftext|>


<commit_before>//
// ulib - a collection of useful classes
// Copyright (C) 2006,2007,2008,2009,2012,2017 Michael Fink
//
/// \file TestException.cpp tests for Exception class
//

#include "stdafx.h"
#include "CppUnitTest.h"
#include "Exception.hpp"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTest
{
   /// tests Exception class
   TEST_CLASS(TestException)
   {
   public:
      /// Tests default ctor
      TEST_METHOD(TestDefaultCtor)
      {
         Exception e1(__FILE__, __LINE__);
         Exception e2(_T("my message"), __FILE__, __LINE__);
      }

      /// tests throwing and catching by catch(...)
      TEST_METHOD(TestCatchingByCatchAll)
      {
#pragma warning(disable: 4072) // unreachable code
         try
         {
            throw Exception(__FILE__, __LINE__);
            Assert::Fail(_T("must throw exception"));
         }
         catch (...)
         {
            return;
         }
#pragma warning(default: 4072)
      }

      /// tests if Exception is derived from std::exception
      TEST_METHOD(TestDerivedByStdException)
      {
         try
         {
            throw Exception(__FILE__, __LINE__);
         }
         catch (const std::exception& ex)
         {
            ex;
            // ok
         }
#pragma warning(disable: 4286) // 'const Exception &': is caught by base class ('const std::exception &') on line xx
         catch (const Exception& ex)
         {
            ex;
            Assert::Fail(_T("must be caught by std::exception catch clause"));
         }
         catch (...)
         {
            Assert::Fail(_T("must be caught by std::exception catch clause"));
         }
      }

      /// tests rethrowing exception
      TEST_METHOD(TestRethrowException)
      {
         try
         {
            try
            {
               throw Exception(__FILE__, __LINE__);
            }
            catch (const Exception& ex)
            {
               throw ex;
            }
         }
         catch (const Exception& ex)
         {
            ex;
            return;
         }
      }
   };

} // namespace UnitTest
<commit_msg>fixed warning in TestException<commit_after>//
// ulib - a collection of useful classes
// Copyright (C) 2006,2007,2008,2009,2012,2017 Michael Fink
//
/// \file TestException.cpp tests for Exception class
//

#include "stdafx.h"
#include "CppUnitTest.h"
#include "Exception.hpp"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTest
{
   /// tests Exception class
   TEST_CLASS(TestException)
   {
   public:
      /// Tests default ctor
      TEST_METHOD(TestDefaultCtor)
      {
         Exception e1(__FILE__, __LINE__);
         Exception e2(_T("my message"), __FILE__, __LINE__);
      }

#pragma warning(disable: 4702) // unreachable code
      /// tests throwing and catching by catch(...)
      TEST_METHOD(TestCatchingByCatchAll)
      {
         try
         {
            throw Exception(__FILE__, __LINE__);
            Assert::Fail(_T("must throw exception"));
         }
         catch (...)
         {
            return;
         }
      }
#pragma warning(default: 4702)

      /// tests if Exception is derived from std::exception
      TEST_METHOD(TestDerivedByStdException)
      {
         try
         {
            throw Exception(__FILE__, __LINE__);
         }
         catch (const std::exception& ex)
         {
            ex;
            // ok
         }
#pragma warning(disable: 4286) // 'const Exception &': is caught by base class ('const std::exception &') on line xx
         catch (const Exception& ex)
         {
            ex;
            Assert::Fail(_T("must be caught by std::exception catch clause"));
         }
         catch (...)
         {
            Assert::Fail(_T("must be caught by std::exception catch clause"));
         }
      }

      /// tests rethrowing exception
      TEST_METHOD(TestRethrowException)
      {
         try
         {
            try
            {
               throw Exception(__FILE__, __LINE__);
            }
            catch (const Exception& ex)
            {
               throw ex;
            }
         }
         catch (const Exception& ex)
         {
            ex;
            return;
         }
      }
   };

} // namespace UnitTest
<|endoftext|>