|
|
/**
|
|
|
* MojoShader; generate shader programs from bytecode of compiled
|
|
|
* Direct3D shaders.
|
|
|
*
|
|
|
* Please see the file LICENSE.txt in the source's root directory.
|
|
|
*
|
|
|
* This file written by Ryan C. Gordon.
|
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
|
#include <stdarg.h>
|
|
|
#include <sys/types.h>
|
|
|
#include <errno.h>
|
|
|
|
|
|
#include "mojoshader.h"
|
|
|
|
|
|
#if FINDERRORS_COMPILE_SHADERS
|
|
|
#include "SDL.h"
|
|
|
static SDL_Window *sdlwindow = NULL;
|
|
|
static void *lookup(const char *fnname, void *unused)
|
|
|
{
|
|
|
(void) unused;
|
|
|
return SDL_GL_GetProcAddress(fnname);
|
|
|
} // lookup
|
|
|
#endif
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
#define WIN32_LEAN_AND_MEAN 1
|
|
|
#include <windows.h>
|
|
|
#include <malloc.h> // for alloca().
|
|
|
#define snprintf _snprintf
|
|
|
#else
|
|
|
#include <dirent.h>
|
|
|
#include <sys/stat.h>
|
|
|
#endif
|
|
|
|
|
|
#define report printf
|
|
|
|
|
|
static int isdir(const char *dname)
|
|
|
{
|
|
|
#ifdef _MSC_VER
|
|
|
WIN32_FILE_ATTRIBUTE_DATA winstat;
|
|
|
if (!GetFileAttributesExA(dname, GetFileExInfoStandard, &winstat))
|
|
|
return 0;
|
|
|
return winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
|
|
#else
|
|
|
struct stat statbuf;
|
|
|
if (stat(dname, &statbuf) == -1)
|
|
|
return 0;
|
|
|
return S_ISDIR(statbuf.st_mode);
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
static int do_dir(const char *dname, const char *profile);
|
|
|
|
|
|
static int do_file(const char *profile, const char *dname, const char *fn, int *total)
|
|
|
{
|
|
|
int do_quit = 0;
|
|
|
|
|
|
if ((strcmp(fn, ".") == 0) || (strcmp(fn, "..") == 0))
|
|
|
return 1; // skip these.
|
|
|
|
|
|
#if FINDERRORS_COMPILE_SHADERS
|
|
|
SDL_Event e; // pump event queue to keep OS happy.
|
|
|
while (SDL_PollEvent(&e))
|
|
|
{
|
|
|
if (e.type == SDL_QUIT)
|
|
|
do_quit = 1;
|
|
|
} // while
|
|
|
SDL_GL_SwapWindow(sdlwindow);
|
|
|
#endif
|
|
|
|
|
|
if (do_quit)
|
|
|
{
|
|
|
report("FAIL: user requested quit!\n");
|
|
|
return 0;
|
|
|
} // if
|
|
|
|
|
|
char *fname = (char *) alloca(strlen(fn) + strlen(dname) + 2);
|
|
|
sprintf(fname, "%s/%s", dname, fn);
|
|
|
|
|
|
if (isdir(fname))
|
|
|
{
|
|
|
*total += do_dir(fname, profile);
|
|
|
return 1;
|
|
|
} // if
|
|
|
|
|
|
int assembly = 0;
|
|
|
if (strstr(fn, ".bytecode") != NULL)
|
|
|
assembly = 0;
|
|
|
else if (strstr(fn, ".disasm") != NULL)
|
|
|
assembly = 1;
|
|
|
else
|
|
|
return 1;
|
|
|
|
|
|
(*total)++;
|
|
|
|
|
|
FILE *io = fopen(fname, "rb");
|
|
|
if (io == NULL)
|
|
|
{
|
|
|
report("FAIL: %s fopen() failed.\n", fname);
|
|
|
return 1;
|
|
|
} // if
|
|
|
|
|
|
static unsigned char buf[1024 * 256];
|
|
|
int rc = fread(buf, 1, sizeof (buf), io);
|
|
|
fclose(io);
|
|
|
if (rc == -1)
|
|
|
{
|
|
|
report("FAIL: %s %s\n", fname, strerror(errno));
|
|
|
return 1;
|
|
|
} // if
|
|
|
|
|
|
if (assembly)
|
|
|
{
|
|
|
const MOJOSHADER_parseData *a;
|
|
|
|
|
|
buf[rc] = '\0'; // make sure the source is null-terminated.
|
|
|
a = MOJOSHADER_assemble(fname, (char *) buf, rc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
|
|
|
|
if (a->error_count > 0)
|
|
|
{
|
|
|
report("FAIL: %s (line %d) %s\n",
|
|
|
a->errors[0].filename ? a->errors[0].filename : "???",
|
|
|
a->errors[0].error_position,
|
|
|
a->errors[0].error);
|
|
|
return 1;
|
|
|
} // if
|
|
|
|
|
|
else if (a->output_len > sizeof (buf))
|
|
|
{
|
|
|
report("FAIL: %s buffer overflow in finderrors.c\n", fname);
|
|
|
return 1;
|
|
|
} // if
|
|
|
|
|
|
rc = a->output_len;
|
|
|
memcpy(buf, a->output, rc);
|
|
|
MOJOSHADER_freeParseData(a);
|
|
|
} // if
|
|
|
|
|
|
#if FINDERRORS_COMPILE_SHADERS
|
|
|
MOJOSHADER_glShader *shader = MOJOSHADER_glCompileShader(buf, rc, NULL, 0, NULL, 0);
|
|
|
if (shader == NULL)
|
|
|
report("FAIL: %s %s\n", fname, MOJOSHADER_glGetError());
|
|
|
else
|
|
|
{
|
|
|
const MOJOSHADER_parseData *pd = MOJOSHADER_glGetShaderParseData(shader);
|
|
|
MOJOSHADER_glShader *v = (pd->shader_type == MOJOSHADER_TYPE_VERTEX) ? shader : NULL;
|
|
|
MOJOSHADER_glShader *p = (pd->shader_type == MOJOSHADER_TYPE_PIXEL) ? shader : NULL;
|
|
|
MOJOSHADER_glProgram *program = MOJOSHADER_glLinkProgram(v, p);
|
|
|
if (program == NULL)
|
|
|
report("FAIL: %s %s\n", fname, MOJOSHADER_glGetError());
|
|
|
else
|
|
|
{
|
|
|
report("PASS: %s\n", fname);
|
|
|
MOJOSHADER_glDeleteProgram(program);
|
|
|
} // else
|
|
|
MOJOSHADER_glDeleteShader(shader);
|
|
|
}
|
|
|
#else
|
|
|
const MOJOSHADER_parseData *pd = MOJOSHADER_parse(profile, NULL, buf, rc, NULL, 0, NULL, 0, NULL, NULL, NULL);
|
|
|
if (pd->error_count == 0)
|
|
|
report("PASS: %s\n", fname);
|
|
|
else
|
|
|
{
|
|
|
int i;
|
|
|
for (i = 0; i < pd->error_count; i++)
|
|
|
{
|
|
|
report("FAIL: %s (position %d) %s\n", pd->errors[i].filename,
|
|
|
pd->errors[i].error_position, pd->errors[i].error);
|
|
|
} // for
|
|
|
} // else
|
|
|
MOJOSHADER_freeParseData(pd);
|
|
|
#endif
|
|
|
|
|
|
return 1;
|
|
|
} // do_file
|
|
|
|
|
|
|
|
|
static int do_dir(const char *dname, const char *profile)
|
|
|
{
|
|
|
int total = 0;
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
const size_t wildcardlen = strlen(dname) + 3;
|
|
|
char *wildcard = (char *) alloca(wildcardlen);
|
|
|
SDL_snprintf(wildcard, wildcardlen, "%s\\*", dname);
|
|
|
|
|
|
WIN32_FIND_DATAA dent;
|
|
|
HANDLE dirp = FindFirstFileA(wildcard, &dent);
|
|
|
if (dirp != INVALID_HANDLE_VALUE)
|
|
|
{
|
|
|
do
|
|
|
{
|
|
|
if (!do_file(profile, dname, dent.cFileName, &total))
|
|
|
break;
|
|
|
} while (FindNextFileA(dirp, &dent) != 0);
|
|
|
FindClose(dirp);
|
|
|
} // if
|
|
|
#else
|
|
|
struct dirent *dent = NULL;
|
|
|
DIR *dirp = opendir(dname);
|
|
|
if (dirp != NULL)
|
|
|
{
|
|
|
while ((dent = readdir(dirp)) != NULL)
|
|
|
{
|
|
|
if (!do_file(profile, dname, dent->d_name, &total))
|
|
|
break;
|
|
|
} // while
|
|
|
closedir(dirp);
|
|
|
} // if
|
|
|
#endif
|
|
|
|
|
|
return total;
|
|
|
} // do_dir
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
{
|
|
|
//printf("MojoShader finderrors\n");
|
|
|
//printf("Compiled against changeset %s\n", MOJOSHADER_CHANGESET);
|
|
|
//printf("Linked against changeset %s\n", MOJOSHADER_changeset());
|
|
|
//printf("\n");
|
|
|
|
|
|
if (argc <= 2)
|
|
|
printf("\n\nUSAGE: %s <profile> [dir1] ... [dirN]\n\n", argv[0]);
|
|
|
else
|
|
|
{
|
|
|
int okay = 0;
|
|
|
int total = 0;
|
|
|
int i;
|
|
|
const char *profile = argv[1];
|
|
|
|
|
|
#if FINDERRORS_COMPILE_SHADERS
|
|
|
MOJOSHADER_glContext *ctx = NULL;
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) == -1)
|
|
|
fprintf(stderr, "SDL_Init() error: %s\n", SDL_GetError());
|
|
|
else if (SDL_GL_LoadLibrary(NULL) == -1)
|
|
|
fprintf(stderr, "SDL_GL_LoadLibrary() error: %s\n", SDL_GetError());
|
|
|
else if ((sdlwindow = SDL_CreateWindow(argv[0], SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_OPENGL)) == NULL)
|
|
|
fprintf(stderr, "SDL_CreateWindow() error: %s\n", SDL_GetError());
|
|
|
else if (SDL_GL_CreateContext(sdlwindow) == NULL)
|
|
|
fprintf(stderr, "SDL_GL_CreateContext() error: %s\n", SDL_GetError());
|
|
|
else if ((ctx = MOJOSHADER_glCreateContext(profile, lookup, 0, 0, 0, 0)) == NULL)
|
|
|
fprintf(stderr, "MOJOSHADER_glCreateContext() fail: %s\n", MOJOSHADER_glGetError());
|
|
|
else
|
|
|
{
|
|
|
printf("Best profile is '%s'\n", MOJOSHADER_glBestProfile(lookup, 0, NULL, NULL, NULL));
|
|
|
MOJOSHADER_glMakeContextCurrent(ctx);
|
|
|
okay = 1;
|
|
|
}
|
|
|
#else
|
|
|
okay = 1;
|
|
|
#endif
|
|
|
|
|
|
if (okay)
|
|
|
{
|
|
|
for (i = 2; i < argc; i++)
|
|
|
total += do_dir(argv[i], profile);
|
|
|
printf("Saw %d files.\n", total);
|
|
|
} // if
|
|
|
|
|
|
#if FINDERRORS_COMPILE_SHADERS
|
|
|
if (ctx)
|
|
|
MOJOSHADER_glDestroyContext(ctx);
|
|
|
SDL_Quit();
|
|
|
#endif
|
|
|
} // else
|
|
|
|
|
|
return 0;
|
|
|
} // main
|
|
|
|
|
|
// end of finderrors.c ...
|
|
|
|
|
|
|