blob: 5e421e85aaf82c3e5da196e4af0923fc2c6a7643 [file] [log] [blame]
// SwiftShader Software Renderer
//
// Copyright(c) 2005-2012 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//
#ifndef sw_RoutineCache_hpp
#define sw_RoutineCache_hpp
#include "LRUCache.hpp"
#include "Reactor/Reactor.hpp"
namespace sw
{
template<class State>
class RoutineCache : public LRUCache<State, Routine>
{
public:
RoutineCache(int n, const char *precache = 0);
~RoutineCache();
private:
const char *precache;
#if defined(_WIN32)
HMODULE precacheDLL;
#endif
};
}
#if defined(_WIN32)
#include "Shader/Constants.hpp"
#include "Reactor/DLL.hpp"
#endif
namespace sw
{
template<class State>
RoutineCache<State>::RoutineCache(int n, const char *precache) : LRUCache<State, Routine>(n), precache(precache)
{
#if defined(_WIN32)
precacheDLL = 0;
if(precache)
{
char dllName[1024]; sprintf(dllName, "%s.dll", precache);
char dirName[1024]; sprintf(dirName, "%s.dir", precache);
precacheDLL = LoadLibrary(dllName);
FILE *dir = fopen(dirName, "rb");
int ordinal = 1;
while(precacheDLL && dir)
{
State state;
int offset;
int size;
size_t bytes = fread(&state, 1, sizeof(State), dir);
bytes += fread(&offset, 1, sizeof(offset), dir);
bytes += fread(&size, 1, sizeof(size), dir);
if(bytes != sizeof(State) + sizeof(offset) + sizeof(size))
{
break;
}
void (*routine)(void) = (void(*)(void))GetProcAddress(precacheDLL, (char*)ordinal);
ordinal++;
if(routine)
{
add(state, new Routine(routine, size, offset));
}
}
if(dir)
{
fclose(dir);
}
}
#endif
}
template<class State>
RoutineCache<State>::~RoutineCache()
{
#if defined(_WIN32)
char dllName[1024]; sprintf(dllName, "%s.dll", precache);
char dirName[1024]; sprintf(dirName, "%s.dir", precache);
if(precache)
{
DLL dll(dllName, &constants, sizeof(Constants));
FILE *dir = fopen(dirName, "wb");
for(int i = 0; i < getSize(); i++)
{
State &state = getKey(i);
Routine *routine = query(state);
if(routine)
{
unsigned char *buffer = (unsigned char*)routine->getBuffer();
unsigned char *entry = (unsigned char*)routine->getEntry();
int size = routine->getBufferSize();
int codeSize = routine->getCodeSize();
#ifndef _M_AMD64
for(int j = 1; j < codeSize - 4; j++)
{
unsigned char modRM_SIB = entry[j - 1];
unsigned int address = *(unsigned int*)&entry[j];
if((modRM_SIB & 0x05) == 0x05 && (address % 4) == 0)
{
if(address >= (unsigned int)buffer && address < (unsigned int)entry) // Constant stored above the function entry
{
dll.addRelocation(buffer, &entry[j], true);
j += 4;
}
}
}
#else
for(int j = 1; j < codeSize - 4; j++)
{
unsigned char modRM_SIB = entry[j - 1];
uint64_t address = *(uint64_t*)&entry[j];
// if((modRM_SIB & 0x05) == 0x05 && (address % 4) == 0)
{
if(address >= (uint64_t)buffer && address < (uint64_t)entry) // Constant stored above the function entry
{
dll.addRelocation(buffer, &entry[j], true);
j += 4;
}
}
}
#endif
dll.addFunction(buffer, entry, size);
fwrite(&state, 1, sizeof(State), dir);
int offset = (int)(entry - buffer);
fwrite(&offset, 1, sizeof(offset), dir);
fwrite(&size, 1, sizeof(size), dir);
}
}
FreeLibrary(precacheDLL);
dll.emit();
fclose(dir);
}
else
{
FreeLibrary(precacheDLL);
remove(dllName);
remove(dirName);
}
#endif
}
}
#endif // sw_RoutineCache_hpp