Move GLES20 source into standard locations
Move Khronos headers into their respective components, to be exported by each.
Remove hostthreadadapter as nothing outside of the vghwapiwrapper, which now contains the code, needs it
/* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and /or associated documentation files
* (the "Materials "), to deal in the Materials without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Materials,
* and to permit persons to whom the Materials are furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Materials.
*
* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
* THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
#ifndef __SFFUNCTIONCACHE_H
#define __SFFUNCTIONCACHE_H
// (LRU) Cache for compiled pixelpipe functions. Never takes ownership of
// any of the objects.
// \todo LRU might not be the best strategy or the best strategy might
// depend on the use-case -> create more of these.
#include "riArray.h"
#if defined(__unix__)
# include <pthread.h>
#else
# include <windows.h>
#endif
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Module.h"
namespace llvm {
class Function;
}
namespace OpenVGRI {
template<class HashClass> class FunctionCache
{
private:
enum { IMPLEMENTATION_MAX_CACHE_ENTRIES = 1024 };
//enum { MAX_GLOBAL_TIME = 10000};
enum { MAX_GLOBAL_TIME = RI_UINT32_MAX };
struct CacheEntry
{
CacheEntry() : refCount(1) {}
CacheEntry(HashClass aHash, ::llvm::Function* aFunc, ::llvm::GlobalVariable* aConst, RIuint32 theUT) : refCount(1) {hash = aHash; llvmFunction = aFunc; llvmConstant = aConst; ut = theUT;}
bool operator==(const CacheEntry& rhs) const { return hash == rhs.hash; }
bool operator<(const CacheEntry& rhs) const { return ut < rhs.ut; } // Sort by time of usage.
HashClass hash;
::llvm::Function* llvmFunction;
::llvm::GlobalVariable* llvmConstant;
RIuint32 ut;
RIint32 refCount;
};
public:
typedef CacheEntry* EntryHandle;
public:
FunctionCache(int nMaxEntries) :
m_time(0)
{
// Limit so that if the cache is too large, you must optimize the implementation.
// Also note that the optimized pixel pipes are most likely small, so it would
// be better to have a fast cache and a lot of entries!
// \note A simple optimization is to sort the usage time sort order and remove the last
// item in the array (instead of the first).
RI_ASSERT(nMaxEntries > 0 && nMaxEntries < IMPLEMENTATION_MAX_CACHE_ENTRIES);
m_nMaxEntries = nMaxEntries;
m_entries.reserve(nMaxEntries);
}
~FunctionCache()
{
for (int i = 0; i < m_entries.size(); i++)
{
clearEntry(m_entries[i]);
}
}
// This info is needed for the module to remove functions and deallocate executable
// functions:
void setLLVMInterface(::llvm::ExecutionEngine* ee, ::llvm::Module* module)
{
m_executionEngine = ee;
m_module = module;
}
// \todo If we never need the entry index, the locking can be
// simplified a lot.
// Must lock the cache during this operation!
EntryHandle findCachedItemByHash(const HashClass& hash)
{
acquireMutex();
int i = findCachedItemIndexByHash(hash, true);
if (i == -1)
{
releaseMutex();
return NULL;
}
EntryHandle handle = &m_entries[i];
releaseMutex();
return handle;
}
/**
* \brief Caches a function. Sets the reference count to 1
* \return EntryHandle != NULL on success.
* \todo The cache must be locked during the operation.
*/
EntryHandle cacheFunction(HashClass hash, ::llvm::Function* function, ::llvm::GlobalVariable* constant)
{
acquireMutex();
RI_ASSERT(findCachedItemIndexByHash(hash) == -1);
if (m_entries.size() == m_nMaxEntries)
{
if (!removeLRU())
{
releaseMutex();
return NULL;
}
}
m_entries.push_back(CacheEntry(hash, function, constant, m_time));
RI_ASSERT(m_entries.size() > 0);
EntryHandle ret = &m_entries[m_entries.size()-1];
incrementGlobalTime();
releaseMutex();
return ret;
}
::llvm::Function* getFunction(EntryHandle handle)
{
return handle->llvmFunction;
}
// \note Does not remove the function from cache!
void releaseEntry(EntryHandle handle)
{
RI_ASSERT(handle->refCount > 0);
handle->refCount--;
}
private:
void incrementGlobalTime()
{
m_time++;
if (m_time == MAX_GLOBAL_TIME)
rebaseUsageTime();
}
void incrementAccessTime(CacheEntry &entry)
{
entry.ut = m_time;
incrementGlobalTime();
}
int findCachedItemIndexByHash(const HashClass& hash, bool reserve = false)
{
// \note Could just overload operator== from entry and use the Array.find function.
for (int i = 0; i < m_entries.size(); i++)
{
if (m_entries[i].hash == hash)
{
if (reserve)
{
incrementAccessTime(m_entries[i]);
m_entries[i].refCount++;
}
return i;
}
}
return -1;
}
void clearEntry(CacheEntry& entry)
{
m_executionEngine->freeMachineCodeForFunction(entry.llvmFunction);
entry.llvmFunction->eraseFromParent();
//entry.llvmConstant->eraseFromParent();
}
/**
* \return true if LRU item was successfully removed, false otherwise.
* \note Could try other pipes, but it is unlikely that the cache gets filled
* so soon that the blit for the least recently used blit has not been
* released.
* \todo Implement drop of other cache-entries?
*/
bool removeLRU()
{
// \note This is pretty inefficient for many cache size:
// After first LRU removal, the cache is almost sorted anyway, so
// more efficient solution should be implemented.
//
m_entries.sort();
if (m_entries[0].refCount > 0)
return false;
clearEntry(m_entries[0]);
m_entries.remove(m_entries[0]);
return true;
}
void rebaseUsageTime()
{
RIuint32 i;
m_entries.sort();
RI_ASSERT(m_entries.size() > 0);
for(i = 0; i < (RIuint32)m_entries.size(); i++)
{
m_entries[i].ut = i;
};
m_time = i;
}
static void acquireMutex();
static void releaseMutex();
private:
::llvm::Module *m_module;
::llvm::ExecutionEngine *m_executionEngine;
RIuint32 m_time;
Array <CacheEntry> m_entries;
int m_nMaxEntries;
static bool s_mutexInitialized;
#if defined(__unix__)
static pthread_mutex_t s_mutex;
#else
static CRITICAL_SECTION s_mutex;
#endif
};
template<class HashClass>
bool FunctionCache<HashClass>::s_mutexInitialized = false;
#if defined(__unix__)
template<class HashClass>
pthread_mutex_t FunctionCache<HashClass>::s_mutex;
#else
template<class HashClass>
CRITICAL_SECTION FunctionCache<HashClass>::s_mutex;
#endif
template<class HashClass>
void FunctionCache<HashClass>::acquireMutex()
{
if (!s_mutexInitialized)
{
#if defined(__unix__)
int ret;
pthread_mutexattr_t attr;
ret = pthread_mutexattr_init(&attr); //initially not locked
RI_ASSERT(!ret); //check that there aren't any errors
ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); //count the number of recursive locks
RI_ASSERT(!ret); //check that there aren't any errors
ret = pthread_mutex_init(&s_mutex, &attr);
pthread_mutexattr_destroy(&attr);
RI_ASSERT(!ret); //check that there aren't more errors
#else
::InitializeCriticalSection(&s_mutex);
#endif
s_mutexInitialized = true;
}
#if defined(__unix__)
int ret = pthread_mutex_lock(&s_mutex);
RI_ASSERT(!ret);
#else
::EnterCriticalSection(&s_mutex);
#endif
}
template<class HashClass>
void FunctionCache<HashClass>::releaseMutex()
{
RI_ASSERT(s_mutexInitialized);
#if defined(__unix__)
int ret = pthread_mutex_unlock(&s_mutex);
RI_ASSERT(!ret);
#else
::LeaveCriticalSection(&s_mutex);
#endif
}
}
#endif