WIP multi-shader support, see details:

- picasso now accepts several input files, which are each compiled
  into DVLE objects inside the .shbin
- Uniform allocation is shared amongst all DVLEs.
- Constant allocation is private to each DVLE.
- Header file generation is temporarily disabled.
- New directives:
  .nodvle
    Disables the generation of a DVLE object for the current input file.
    This allows sharing code amongst shaders.
  .entry entryName
    Specifies the name of the entrypoint procedure of the current DVLE.
    By default it's 'main'.
This commit is contained in:
fincs 2015-08-13 21:46:08 +02:00
parent b250513be0
commit e152f4e626
4 changed files with 383 additions and 207 deletions

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61) AC_PREREQ(2.61)
AC_INIT([picasso],[1.0.0],[fincs.alt1@gmail.com]) AC_INIT([picasso],[2.0.0],[fincs.alt1@gmail.com])
AC_CONFIG_SRCDIR([source/picasso_frontend.cpp]) AC_CONFIG_SRCDIR([source/picasso_frontend.cpp])
AM_INIT_AUTOMAKE([1.10]) AM_INIT_AUTOMAKE([1.10])

View File

@ -58,10 +58,13 @@ enum
COND_UNK2, COND_UNK2,
}; };
//-----------------------------------------------------------------------------
// Global data
//-----------------------------------------------------------------------------
// Output buffer
typedef std::vector<u32> outputBufType; typedef std::vector<u32> outputBufType;
typedef outputBufType::iterator outputBufIter; typedef outputBufType::iterator outputBufIter;
extern bool g_isGeoShader;
extern outputBufType g_outputBuf; extern outputBufType g_outputBuf;
enum enum
@ -87,6 +90,7 @@ struct StackEntry
extern StackEntry g_stack[MAX_STACK]; extern StackEntry g_stack[MAX_STACK];
extern int g_stackPos; extern int g_stackPos;
// Operand descriptor stuff.
#define MAX_OPDESC 128 #define MAX_OPDESC 128
extern int g_opdescTable[MAX_OPDESC]; extern int g_opdescTable[MAX_OPDESC];
extern int g_opdeskMasks[MAX_OPDESC]; // used to keep track of used bits extern int g_opdeskMasks[MAX_OPDESC]; // used to keep track of used bits
@ -106,10 +110,45 @@ struct Uniform
int type; int type;
}; };
// List of uniforms
#define MAX_UNIFORM 0x60 #define MAX_UNIFORM 0x60
extern Uniform g_uniformTable[MAX_UNIFORM]; extern Uniform g_uniformTable[MAX_UNIFORM];
extern int g_uniformCount; extern int g_uniformCount;
struct DVLEData; // Forward declaration
typedef std::pair<size_t, size_t> procedure; // position, size
typedef std::pair<size_t, std::string> relocation; // position, name
typedef std::map<std::string, procedure> procTableType;
typedef std::map<std::string, size_t> labelTableType;
typedef std::map<std::string, int> aliasTableType;
typedef std::vector<relocation> relocTableType;
typedef std::list<DVLEData> dvleTableType;
typedef procTableType::iterator procTableIter;
typedef labelTableType::iterator labelTableIter;
typedef aliasTableType::iterator aliasTableIter;
typedef relocTableType::iterator relocTableIter;
typedef dvleTableType::iterator dvleTableIter;
extern procTableType g_procTable;
extern dvleTableType g_dvleTable;
extern relocTableType g_procRelocTable;
extern int g_totalDvleCount;
// The following are cleared before each file is processed
extern labelTableType g_labels;
extern relocTableType g_labelRelocTable;
extern aliasTableType g_aliases;
int AssembleString(char* str, const char* initialFilename);
int RelocateProduct(void);
//-----------------------------------------------------------------------------
// Local data
//-----------------------------------------------------------------------------
enum enum
{ {
OUTTYPE_POS = 0, OUTTYPE_POS = 0,
@ -123,10 +162,6 @@ enum
OUTTYPE_VIEW, OUTTYPE_VIEW,
}; };
#define MAX_OUTPUT 8
extern u64 g_outputTable[MAX_OUTPUT];
extern int g_outputCount;
struct Constant struct Constant
{ {
int regId; int regId;
@ -138,33 +173,32 @@ struct Constant
}; };
}; };
#define MAX_CONSTANT 0x60 struct DVLEData
extern Constant g_constantTable[MAX_CONSTANT];
extern int g_constantCount;
extern size_t g_constantSize;
struct Relocation
{ {
size_t instPos; // General config
const char* target; std::string filename;
bool isProc; std::string entrypoint;
size_t entryStart, entryEnd;
bool nodvle, isGeoShader;
// Uniforms
Uniform uniformTable[MAX_UNIFORM];
int uniformCount;
size_t symbolSize;
// Constants
#define MAX_CONSTANT 0x60
Constant constantTable[MAX_CONSTANT];
int constantCount;
size_t constantSize;
// Outputs
#define MAX_OUTPUT 8
u64 outputTable[MAX_OUTPUT];
int outputCount;
DVLEData(const char* filename) :
filename(filename), entrypoint("main"),
nodvle(false), isGeoShader(false),
uniformCount(0), symbolSize(0), constantCount(0), constantSize(0), outputCount(0) { }
}; };
typedef std::pair<size_t, size_t> procedure; // position, size
typedef std::map<std::string, procedure> procTableType;
typedef std::map<std::string, size_t> labelTableType;
typedef std::map<std::string, int> aliasTableType;
typedef std::vector<Relocation> relocTableType;
typedef procTableType::iterator procTableIter;
typedef labelTableType::iterator labelTableIter;
typedef aliasTableType::iterator aliasTableIter;
typedef relocTableType::iterator relocTableIter;
extern procTableType g_procTable;
extern labelTableType g_labels;
extern aliasTableType g_aliases;
extern relocTableType g_relocs;
int AssembleString(char* str, const char* initialFilename);

View File

@ -19,21 +19,63 @@ int g_opdescMasks[MAX_OPDESC];
Uniform g_uniformTable[MAX_UNIFORM]; Uniform g_uniformTable[MAX_UNIFORM];
int g_uniformCount; int g_uniformCount;
static int fvecUnifPos = 0x20;
static int ivecUnifPos = 0x80;
static int boolUnifPos = 0x88;
Constant g_constantTable[MAX_CONSTANT]; class UniformAlloc
int g_constantCount; {
size_t g_constantSize; int start, end, bound, tend;
public:
UniformAlloc(int start, int end) : start(start), end(end), bound(end), tend(end) { }
void ClearLocal(void) { end = tend; }
int AllocGlobal(int size)
{
if ((start+size) > bound) return -1;
int ret = start;
start += size;
return ret;
}
int AllocLocal(int size)
{
int pos = end - size;
if (pos < start) return -1;
bound = pos < bound ? pos : bound;
return pos;
}
};
u64 g_outputTable[MAX_OUTPUT]; static UniformAlloc fvecAlloc(0x20, 0x80), ivecAlloc(0x80, 0x84), boolAlloc(0x88, 0x98);
int g_outputCount;
procTableType g_procTable; procTableType g_procTable;
dvleTableType g_dvleTable;
relocTableType g_procRelocTable;
int g_totalDvleCount;
labelTableType g_labels; labelTableType g_labels;
relocTableType g_labelRelocTable;
aliasTableType g_aliases; aliasTableType g_aliases;
relocTableType g_relocs;
static DVLEData* curDvle;
static void ClearStatus(void)
{
fvecAlloc.ClearLocal();
ivecAlloc.ClearLocal();
boolAlloc.ClearLocal();
g_labels.clear();
g_labelRelocTable.clear();
g_aliases.clear();
curDvle = NULL;
}
static DVLEData* GetDvleData(void)
{
if (!curDvle)
{
g_dvleTable.push_back( DVLEData(curFile) );
curDvle = &g_dvleTable.back();
g_totalDvleCount ++;
}
return curDvle;
}
static char* mystrtok_pos; static char* mystrtok_pos;
static char* mystrtok(char* str, const char* delim) static char* mystrtok(char* str, const char* delim)
@ -126,13 +168,15 @@ static int parseInt(char* pos, int& out, long long min, long long max)
} while(0) } while(0)
static int ProcessCommand(const char* cmd); static int ProcessCommand(const char* cmd);
static int FixupRelocations(); static int FixupLabelRelocations();
int AssembleString(char* str, const char* initialFilename) int AssembleString(char* str, const char* initialFilename)
{ {
curFile = initialFilename; curFile = initialFilename;
curLine = 1; curLine = 1;
ClearStatus();
int nextLineIncr = 0; int nextLineIncr = 0;
char* nextStr = NULL; char* nextStr = NULL;
for (; str; str = nextStr, curLine += nextLineIncr) for (; str; str = nextStr, curLine += nextLineIncr)
@ -192,35 +236,55 @@ int AssembleString(char* str, const char* initialFilename)
if (g_stackPos) if (g_stackPos)
return throwError("unclosed block(s)\n"); return throwError("unclosed block(s)\n");
safe_call(FixupRelocations()); safe_call(FixupLabelRelocations());
return 0; return 0;
} }
int FixupRelocations() int FixupLabelRelocations()
{ {
for (relocTableIter it = g_relocs.begin(); it != g_relocs.end(); ++it) for (relocTableIter it = g_labelRelocTable.begin(); it != g_labelRelocTable.end(); ++it)
{ {
Relocation& r = *it; relocation& r = *it;
u32& inst = BUF[r.instPos]; u32& inst = BUF[r.first];
if (r.isProc) labelTableIter lbl = g_labels.find(r.second);
{ if (lbl == g_labels.end())
procTableIter proc = g_procTable.find(r.target); return throwError("label '%s' is undefined\n", r.second.c_str());
if (proc == g_procTable.end()) u32 dst = lbl->second;
return throwError("procedure '%s' is undefined\n", r.target); inst &= ~(0xFFF << 10);
u32 dst = proc->second.first; inst |= dst << 10;
u32 num = proc->second.second; }
inst &= ~0x3FFFFF; return 0;
inst |= num | (dst << 10); }
} else
{ int RelocateProduct()
labelTableIter lbl = g_labels.find(r.target); {
if (lbl == g_labels.end()) for (relocTableIter it = g_procRelocTable.begin(); it != g_procRelocTable.end(); ++it)
return throwError("label '%s' is undefined\n", r.target); {
u32 dst = lbl->second; relocation& r = *it;
inst &= ~(0xFFF << 10); u32& inst = BUF[r.first];
inst |= dst << 10; procTableIter proc = g_procTable.find(r.second);
} if (proc == g_procTable.end())
return throwError("procedure '%s' is undefined\n", r.second.c_str());
u32 dst = proc->second.first;
u32 num = proc->second.second;
inst &= ~0x3FFFFF;
inst |= num | (dst << 10);
}
if (g_totalDvleCount == 0)
return throwError("no DVLEs can be generated from the given input file(s)\n");
for (dvleTableIter it = g_dvleTable.begin(); it != g_dvleTable.end(); ++it)
{
if (it->nodvle) continue;
curFile = it->filename.c_str();
curLine = 1;
procTableIter mainIt = g_procTable.find(it->entrypoint);
if (mainIt == g_procTable.end())
return throwError("entrypoint '%s' is undefined\n", it->entrypoint.c_str());
it->entryStart = mainIt->second.first;
it->entryEnd = it->entryStart + mainIt->second.second;
} }
return 0; return 0;
} }
@ -422,12 +486,16 @@ static int parseSwizzling(const char* b)
return out<<1; return out<<1;
} }
static int maskFromSwizzling(int sw) static int maskFromSwizzling(int sw, bool reverse = true)
{ {
sw >>= 1; // get rid of negation bit sw >>= 1; // get rid of negation bit
int out = 0; int out = 0;
for (int i = 0; i < 4; i ++) for (int i = 0; i < 4; i ++)
out |= BIT(3-((sw>>(i*2))&3)); {
int bitid = (sw>>(i*2))&3;
if (reverse) bitid = 3 - bitid;
out |= BIT(bitid);
}
return out; return out;
} }
@ -841,10 +909,10 @@ DEF_COMMAND(formatsetemit)
safe_call(parseSetEmitFlags(flagStr, isPrim, isInv)); safe_call(parseSetEmitFlags(flagStr, isPrim, isInv));
#ifdef DEBUG #ifdef DEBUG
printf("%s:%02X vtx%d, %s, %s\n", cmdName, opcode, vtxId, isPrim?"true":"false", isInv=?"true":"false"); printf("%s:%02X vtx%d, %s, %s\n", cmdName, opcode, vtxId, isPrim?"true":"false", isInv?"true":"false");
#endif #endif
BUF.push_back(FMT_OPCODE(opcode) | ((u32)isInv<<22) | ((u32)isPrim<<23) | (vtxId<<24)); BUF.push_back(FMT_OPCODE(opcode) | ((u32)isInv<<22) | ((u32)isPrim<<23) | (vtxId<<24));
g_isGeoShader = true; GetDvleData()->isGeoShader = true;
return 0; return 0;
} }
@ -856,11 +924,7 @@ DEF_COMMAND(formatcall)
ARG_TARGET(procName); ARG_TARGET(procName);
Relocation r; g_procRelocTable.push_back( std::make_pair(BUF.size(), procName) );
r.instPos = BUF.size();
r.target = procName;
r.isProc = true;
g_relocs.push_back(r);
BUF.push_back(FMT_OPCODE(opcode)); BUF.push_back(FMT_OPCODE(opcode));
@ -919,11 +983,8 @@ DEF_COMMAND(format2)
ARG_TARGET(targetName); ARG_TARGET(targetName);
Relocation r; relocTableType& rt = opcode==MAESTRO_CALLC ? g_procRelocTable : g_labelRelocTable;
r.instPos = BUF.size(); rt.push_back( std::make_pair(BUF.size(), targetName) );
r.target = targetName;
r.isProc = opcode==MAESTRO_CALLC;
g_relocs.push_back(r);
#ifdef DEBUG #ifdef DEBUG
printf("%s:%02X %s, %s\n", cmdName, opcode, condExp, targetName); printf("%s:%02X %s, %s\n", cmdName, opcode, condExp, targetName);
@ -971,11 +1032,8 @@ DEF_COMMAND(format3)
ARG_TARGET(targetName); ARG_TARGET(targetName);
Relocation r; relocTableType& rt = opcode==MAESTRO_CALLU ? g_procRelocTable : g_labelRelocTable;
r.instPos = BUF.size(); rt.push_back( std::make_pair(BUF.size(), targetName) );
r.target = targetName;
r.isProc = opcode==MAESTRO_CALLU;
g_relocs.push_back(r);
#ifdef DEBUG #ifdef DEBUG
printf("%s:%02X d%02X, %s\n", cmdName, opcode, regId, targetName); printf("%s:%02X d%02X, %s\n", cmdName, opcode, regId, targetName);
@ -1185,21 +1243,20 @@ DEF_DIRECTIVE(alias)
return 0; return 0;
} }
static inline int& getAllocVar(int type, int& bound) static inline UniformAlloc& getAlloc(int type)
{ {
switch (type) switch (type)
{ {
default: default:
case UTYPE_FVEC: bound = 0x80; return fvecUnifPos; case UTYPE_FVEC: return fvecAlloc;
case UTYPE_IVEC: bound = 0x84; return ivecUnifPos; case UTYPE_IVEC: return ivecAlloc;
case UTYPE_BOOL: bound = 0x98; return boolUnifPos; case UTYPE_BOOL: return boolAlloc;
} }
} }
DEF_DIRECTIVE(uniform) DEF_DIRECTIVE(uniform)
{ {
int bound; UniformAlloc& alloc = getAlloc(dirParam);
int& uniformPos = getAllocVar(dirParam, bound);
for (;;) for (;;)
{ {
@ -1222,19 +1279,55 @@ DEF_DIRECTIVE(uniform)
} }
if (!validateIdentifier(argText)) if (!validateIdentifier(argText))
return throwError("invalid uniform name: %s\n", argText); return throwError("invalid uniform name: %s\n", argText);
if ((uniformPos+uSize) >= bound)
return throwError("not enough uniform registers: %s[%d]\n", argText, uSize);
if (g_uniformCount == MAX_UNIFORM)
return throwError("too many uniforms: %s[%d]\n", argText, uSize);
if (g_aliases.find(argText) != g_aliases.end()) if (g_aliases.find(argText) != g_aliases.end())
return duplicateIdentifier(argText); return duplicateIdentifier(argText);
int uniformPos = -1;
// Find the uniform in the table
int i;
for (i = 0; i < g_uniformCount; i ++)
{
Uniform& uniform = g_uniformTable[i];
if (uniform.name == argText)
{
if (uniform.type != dirParam)
return throwError("mismatched uniform type: %s\n", argText);
if (uniform.size != uSize)
return throwError("uniform '%s' previously declared as having size %d\n", argText, uniform.size);
break;
}
}
// If not found, create it
if (i == g_uniformCount && uniformPos < 0)
{
if (g_uniformCount == MAX_UNIFORM)
return throwError("too many global uniforms: %s\n", argText);
uniformPos = alloc.AllocGlobal(uSize);
if (uniformPos < 0)
return throwError("not enough uniform space: %s[%d]\n", argText, uSize);
}
Uniform& uniform = g_uniformTable[g_uniformCount++]; Uniform& uniform = g_uniformTable[g_uniformCount++];
uniform.name = argText; uniform.name = argText;
uniform.pos = uniformPos; uniform.pos = uniformPos;
uniform.size = uSize; uniform.size = uSize;
uniform.type = dirParam; uniform.type = dirParam;
uniformPos += uSize; uniformPos += uSize;
if (*argText != '_')
{
DVLEData* dvle = GetDvleData();
// Add the uniform to the table
if (dvle->uniformCount == MAX_UNIFORM)
return throwError("too many referenced uniforms: %s\n", argText);
dvle->uniformTable[dvle->uniformCount++] = uniform; // Copy constructor
dvle->symbolSize += strlen(argText)+1;
}
g_aliases.insert( std::pair<std::string,int>(argText, uniform.pos | (DEFAULT_OPSRC<<8)) ); g_aliases.insert( std::pair<std::string,int>(argText, uniform.pos | (DEFAULT_OPSRC<<8)) );
#ifdef DEBUG #ifdef DEBUG
@ -1246,8 +1339,8 @@ DEF_DIRECTIVE(uniform)
DEF_DIRECTIVE(const) DEF_DIRECTIVE(const)
{ {
int bound; DVLEData* dvle = GetDvleData();
int& uniformPos = getAllocVar(dirParam, bound); UniformAlloc& alloc = getAlloc(dirParam);
NEXT_ARG_CPAREN(constName); NEXT_ARG_CPAREN(constName);
NEXT_ARG(arg0Text); NEXT_ARG(arg0Text);
@ -1260,14 +1353,18 @@ DEF_DIRECTIVE(const)
*parenPos = 0; *parenPos = 0;
arg3Text = trim_whitespace(arg3Text); arg3Text = trim_whitespace(arg3Text);
if (g_constantCount == MAX_CONSTANT || uniformPos>=bound)
return throwError("not enough space for constant\n");
if (g_aliases.find(constName) != g_aliases.end()) if (g_aliases.find(constName) != g_aliases.end())
return duplicateIdentifier(constName); return duplicateIdentifier(constName);
Constant& ct = g_constantTable[g_constantCount++]; int uniformPos = alloc.AllocLocal(1);
ct.regId = uniformPos++; if (uniformPos < 0)
return throwError("not enough space for local constant '%s'\n", constName);
if (dvle->constantCount == MAX_CONSTANT)
return throwError("too many local constants\n");
Constant& ct = dvle->constantTable[dvle->constantCount++];
ct.regId = uniformPos;
ct.type = dirParam; ct.type = dirParam;
if (dirParam == UTYPE_FVEC) if (dirParam == UTYPE_FVEC)
{ {
@ -1275,14 +1372,14 @@ DEF_DIRECTIVE(const)
ct.fparam[1] = atof(arg1Text); ct.fparam[1] = atof(arg1Text);
ct.fparam[2] = atof(arg2Text); ct.fparam[2] = atof(arg2Text);
ct.fparam[3] = atof(arg3Text); ct.fparam[3] = atof(arg3Text);
g_constantSize += 4 + 4*4; dvle->constantSize += 4 + 4*4;
} else if (dirParam == UTYPE_IVEC) } else if (dirParam == UTYPE_IVEC)
{ {
ct.iparam[0] = atoi(arg0Text) & 0xFF; ct.iparam[0] = atoi(arg0Text) & 0xFF;
ct.iparam[1] = atoi(arg1Text) & 0xFF; ct.iparam[1] = atoi(arg1Text) & 0xFF;
ct.iparam[2] = atoi(arg2Text) & 0xFF; ct.iparam[2] = atoi(arg2Text) & 0xFF;
ct.iparam[3] = atoi(arg3Text) & 0xFF; ct.iparam[3] = atoi(arg3Text) & 0xFF;
g_constantSize += 4 + 4; dvle->constantSize += 4 + 4;
} }
g_aliases.insert( std::pair<std::string,int>(constName, ct.regId | (DEFAULT_OPSRC<<8)) ); g_aliases.insert( std::pair<std::string,int>(constName, ct.regId | (DEFAULT_OPSRC<<8)) );
@ -1321,6 +1418,8 @@ static int parseOutType(const char* text)
DEF_DIRECTIVE(out) DEF_DIRECTIVE(out)
{ {
DVLEData* dvle = GetDvleData();
NEXT_ARG_SPC(outName); NEXT_ARG_SPC(outName);
NEXT_ARG_SPC(outType); NEXT_ARG_SPC(outType);
ENSURE_NO_MORE_ARGS(); ENSURE_NO_MORE_ARGS();
@ -1337,28 +1436,54 @@ DEF_DIRECTIVE(out)
if (sw < 0) if (sw < 0)
return throwError("invalid output mask: %s\n", dotPos); return throwError("invalid output mask: %s\n", dotPos);
} }
int mask = maskFromSwizzling(sw); int mask = maskFromSwizzling(sw, false);
int type = parseOutType(outType); int type = parseOutType(outType);
if (type < 0) if (type < 0)
return throwError("invalid output type: %s\n", outType); return throwError("invalid output type: %s\n", outType);
if (g_outputCount==MAX_OUTPUT) if (dvle->outputCount==MAX_OUTPUT)
return throwError("too many outputs\n"); return throwError("too many outputs\n");
if (g_aliases.find(outName) != g_aliases.end()) if (g_aliases.find(outName) != g_aliases.end())
return duplicateIdentifier(outName); return duplicateIdentifier(outName);
int oid = g_outputCount; int oid = dvle->outputCount;
#ifdef DEBUG #ifdef DEBUG
printf("output %s <- o%d (%d:%X)\n", outName, oid, type, mask); printf("output %s <- o%d (%d:%X)\n", outName, oid, type, mask);
#endif #endif
g_outputTable[g_outputCount++] = OUTPUT_MAKE(type, oid, mask); dvle->outputTable[dvle->outputCount++] = OUTPUT_MAKE(type, oid, mask);
g_aliases.insert( std::pair<std::string,int>(outName, oid | (sw<<8)) ); g_aliases.insert( std::pair<std::string,int>(outName, oid | (sw<<8)) );
return 0; return 0;
} }
DEF_DIRECTIVE(entry)
{
DVLEData* dvle = GetDvleData();
NEXT_ARG_SPC(entrypoint);
ENSURE_NO_MORE_ARGS();
if (!validateIdentifier(entrypoint))
return throwError("invalid identifier: %s\n", entrypoint);
dvle->entrypoint = entrypoint;
return 0;
}
DEF_DIRECTIVE(nodvle)
{
DVLEData* dvle = GetDvleData();
ENSURE_NO_MORE_ARGS();
if (!dvle->nodvle)
{
dvle->nodvle = true;
g_totalDvleCount --;
}
}
static const cmdTableType dirTable[] = static const cmdTableType dirTable[] =
{ {
DEC_DIRECTIVE(proc), DEC_DIRECTIVE(proc),
@ -1371,6 +1496,8 @@ static const cmdTableType dirTable[] =
DEC_DIRECTIVE2(constf, const, UTYPE_FVEC), DEC_DIRECTIVE2(constf, const, UTYPE_FVEC),
DEC_DIRECTIVE2(consti, const, UTYPE_IVEC), DEC_DIRECTIVE2(consti, const, UTYPE_IVEC),
DEC_DIRECTIVE(out), DEC_DIRECTIVE(out),
DEC_DIRECTIVE(entry),
DEC_DIRECTIVE(nodvle),
{ NULL, NULL }, { NULL, NULL },
}; };

View File

@ -33,44 +33,49 @@ int usage(const char* prog)
{ {
fprintf(stderr, fprintf(stderr,
"Usage:\n\n" "Usage:\n\n"
"%s shbinFile vshFile [hFile]\n", prog); "%s output.shbin input1.pica input2.pica ...\n", prog);
return 0; return 0;
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
if (argc < 3 || argc > 4) if (argc < 3)
return usage(argv[0]); return usage(argv[0]);
char* shbinFile = argv[1]; char* shbinFile = argv[1];
char* vshFile = argv[2]; //char* hFile = argc > 3 ? argv[3] : NULL;
char* hFile = argc > 3 ? argv[3] : NULL;
#ifdef WIN32 #ifdef WIN32
FixMinGWPath(shbinFile); FixMinGWPath(shbinFile);
FixMinGWPath(vshFile); //FixMinGWPath(hFile);
FixMinGWPath(hFile);
#endif #endif
char* sourceCode = StringFromFile(vshFile); int rc = 0;
if (!sourceCode) for (int i = 2; i < argc; i ++)
{ {
fprintf(stderr, "Cannot open input file!\n"); char* vshFile = argv[i];
return 1;
#ifdef WIN32
FixMinGWPath(vshFile);
#endif
char* sourceCode = StringFromFile(vshFile);
if (!sourceCode)
{
fprintf(stderr, "error: cannot open input file: %s\n");
return 1;
}
rc = AssembleString(sourceCode, vshFile);
free(sourceCode);
if (rc != 0)
return rc;
} }
int rc = AssembleString(sourceCode, vshFile); rc = RelocateProduct();
free(sourceCode);
if (rc != 0) if (rc != 0)
return rc; return rc;
procTableIter mainIt = g_procTable.find("main");
if (mainIt == g_procTable.end())
{
fprintf(stderr, "Error: main proc not defined\n");
return 1;
}
FileClass f(shbinFile, "wb"); FileClass f(shbinFile, "wb");
if (f.openerror()) if (f.openerror())
@ -79,54 +84,39 @@ int main(int argc, char* argv[])
return 1; return 1;
} }
u32 progSize = g_outputBuf.size();
u32 dvlpSize = 10*4 + progSize*4 + g_opdescCount*8;
// Write DVLB header
f.WriteWord(0x424C5644); // DVLB f.WriteWord(0x424C5644); // DVLB
f.WriteWord(1); // 1 DVLE f.WriteWord(g_totalDvleCount); // Number of DVLEs
f.WriteWord(3*4 + 0x28); // offset to DVLE
u32 dvlpStart = f.Tell(); // Calculate and write DVLE offsets
u32 shaderSize = g_outputBuf.size(); u32 curOff = 2*4 + g_totalDvleCount*4 + dvlpSize;
u32 paramStart = 0x28 + 0x40; for (dvleTableIter dvle = g_dvleTable.begin(); dvle != g_dvleTable.end(); ++dvle)
{
if (dvle->nodvle) continue;
f.WriteWord(curOff);
curOff += 16*4; // Header
curOff += dvle->constantSize;
curOff += dvle->outputCount*8;
curOff += dvle->uniformCount*8;
curOff += dvle->symbolSize;
}
// Write DVLP header
f.WriteWord(0x504C5644); // DVLP f.WriteWord(0x504C5644); // DVLP
f.WriteWord(0); // version f.WriteWord(0); // version
f.WriteWord(paramStart); // offset to shader binary blob f.WriteWord(10*4); // offset to shader binary blob
f.WriteWord(shaderSize); // size of shader binary blob f.WriteWord(progSize); // size of shader binary blob
paramStart += shaderSize*4; f.WriteWord(10*4 + progSize*4); // offset to opdesc table
f.WriteWord(paramStart); // offset to opdesc table
f.WriteWord(g_opdescCount); // number of opdescs f.WriteWord(g_opdescCount); // number of opdescs
paramStart += g_opdescCount*8; f.WriteWord(dvlpSize); // offset to symtable (TODO)
f.WriteWord(paramStart); // offset to symtable (TODO)
f.WriteWord(0); // ???? f.WriteWord(0); // ????
f.WriteWord(0); // ???? f.WriteWord(0); // ????
f.WriteWord(0); // ???? f.WriteWord(0); // ????
u32 dvleStart = f.Tell();
paramStart -= dvleStart - dvlpStart;
f.WriteWord(0x454C5644); // DVLE
f.WriteHword(0); // padding?
f.WriteHword(g_isGeoShader ? 1 : 0); // Shader type
f.WriteWord(mainIt->second.first); // offset to main
f.WriteWord(mainIt->second.first+mainIt->second.second); // offset to end of main
f.WriteWord(0); // ???
f.WriteWord(0); // ???
f.WriteWord(paramStart); // offset to constant table
f.WriteWord(g_constantCount); // size of constant table
paramStart += g_constantSize;
f.WriteWord(paramStart); // offset to label table (TODO)
f.WriteWord(0); // size of label table (TODO)
f.WriteWord(paramStart); // offset to output table
f.WriteWord(g_outputCount); // size of output table
paramStart += g_outputCount*8;
f.WriteWord(paramStart); // offset to uniform table
f.WriteWord(g_uniformCount); // size of uniform table
paramStart += g_uniformCount*8;
f.WriteWord(paramStart); // offset to symbol table
u32 temp = f.Tell();
f.WriteWord(0); // size of symbol table
// Write program // Write program
//for (u32 p : g_outputBuf)
for (outputBufIter it = g_outputBuf.begin(); it != g_outputBuf.end(); ++it) for (outputBufIter it = g_outputBuf.begin(); it != g_outputBuf.end(); ++it)
f.WriteWord(*it); f.WriteWord(*it);
@ -134,53 +124,77 @@ int main(int argc, char* argv[])
for (int i = 0; i < g_opdescCount; i ++) for (int i = 0; i < g_opdescCount; i ++)
f.WriteDword(g_opdescTable[i]); f.WriteDword(g_opdescTable[i]);
// Write constants // Write DVLEs
for (int i = 0; i < g_constantCount; i ++) for (dvleTableIter dvle = g_dvleTable.begin(); dvle != g_dvleTable.end(); ++dvle)
{ {
Constant& ct = g_constantTable[i]; if (dvle->nodvle) continue;
f.WriteHword(ct.type); curOff = 16*4;
if (ct.type == UTYPE_FVEC)
f.WriteWord(0x454C5644); // DVLE
f.WriteHword(0); // padding?
f.WriteHword(dvle->isGeoShader ? 1 : 0); // Shader type
f.WriteWord(dvle->entryStart); // offset to main
f.WriteWord(dvle->entryEnd); // offset to end of main
f.WriteWord(0); // ???
f.WriteWord(0); // ???
f.WriteWord(curOff); // offset to constant table
f.WriteWord(dvle->constantCount); // size of constant table
curOff += dvle->constantSize;
f.WriteWord(curOff); // offset to label table (TODO)
f.WriteWord(0); // size of label table (TODO)
f.WriteWord(curOff); // offset to output table
f.WriteWord(dvle->outputCount); // size of output table
curOff += dvle->outputCount*8;
f.WriteWord(curOff); // offset to uniform table
f.WriteWord(dvle->uniformCount); // size of uniform table
curOff += dvle->uniformCount*8;
f.WriteWord(curOff); // offset to symbol table
u32 temp = f.Tell();
f.WriteWord(dvle->symbolSize); // size of symbol table
// Write constants
for (int i = 0; i < dvle->constantCount; i ++)
{ {
f.WriteHword(ct.regId-0x20); Constant& ct = dvle->constantTable[i];
for (int j = 0; j < 4; j ++) f.WriteHword(ct.type);
f.WriteWord(f32tof24(ct.fparam[j])); if (ct.type == UTYPE_FVEC)
} else if (ct.type == UTYPE_IVEC) {
f.WriteHword(ct.regId-0x20);
for (int j = 0; j < 4; j ++)
f.WriteWord(f32tof24(ct.fparam[j]));
} else if (ct.type == UTYPE_IVEC)
{
f.WriteHword(ct.regId-0x80);
for (int j = 0; j < 4; j ++)
f.WriteByte(ct.iparam[j]);
}
}
// Write outputs
for (int i = 0; i < dvle->outputCount; i ++)
f.WriteDword(dvle->outputTable[i]);
// Write uniforms
size_t sp = 0;
for (int i = 0; i < dvle->uniformCount; i ++)
{ {
f.WriteHword(ct.regId-0x80); Uniform& u = dvle->uniformTable[i];
for (int j = 0; j < 4; j ++) size_t l = u.name.length()+1;
f.WriteByte(ct.iparam[j]); f.WriteWord(sp); sp += l;
f.WriteHword(u.pos-0x10);
f.WriteHword(u.pos+u.size-1-0x10);
}
// Write symbols
for (int i = 0; i < dvle->uniformCount; i ++)
{
std::string& u = dvle->uniformTable[i].name;
size_t l = u.length()+1;
f.WriteRaw(u.c_str(), l);
} }
} }
// Write outputs #if 0
for (int i = 0; i < g_outputCount; i ++)
f.WriteDword(g_outputTable[i]);
// Write uniforms
size_t sp = 0;
for (int i = 0; i < g_uniformCount; i ++)
{
Uniform& u = g_uniformTable[i];
size_t l = u.name.length()+1;
f.WriteWord(sp); sp += l;
f.WriteHword(u.pos-0x10);
f.WriteHword(u.pos+u.size-1-0x10);
}
// Write size of symbol table
u32 temp2 = f.Tell();
f.Seek(temp, SEEK_SET);
f.WriteWord(sp);
f.Seek(temp2, SEEK_SET);
// Write symbols
for (int i = 0; i < g_uniformCount; i ++)
{
std::string& u = g_uniformTable[i].name;
size_t l = u.length()+1;
f.WriteRaw(u.c_str(), l);
}
if (hFile) if (hFile)
{ {
FILE* f2 = fopen(hFile, "w"); FILE* f2 = fopen(hFile, "w");
@ -213,6 +227,7 @@ int main(int argc, char* argv[])
fclose(f2); fclose(f2);
} }
#endif
return 0; return 0;
} }