// 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 |