You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
804 lines
22 KiB
C++
804 lines
22 KiB
C++
// Modifications copyright Amazon.com, Inc. or its affiliates
|
|
// Modifications copyright Crytek GmbH
|
|
|
|
#include <inttypes.h>
|
|
#include "hlslcc.hpp"
|
|
#include "stdlib.h"
|
|
#include "stdio.h"
|
|
#include <string>
|
|
#include <string.h>
|
|
#include "hash.h"
|
|
#include "serializeReflection.h"
|
|
#include "hlslcc_bin.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
|
|
#ifdef _WIN32
|
|
#include <direct.h>
|
|
#else
|
|
#include <sys/stat.h>
|
|
#endif
|
|
|
|
#include "timer.h"
|
|
|
|
#if defined(_WIN32) && !defined(PORTABLE)
|
|
//#define VALIDATE_OUTPUT // NOTE: THIS IS OK DURING HLSLcc DEV BUT SHOULD NOT BE USED IN PRODUCTION. SOME EXT USED ARE NO SUPPORTED ON WINDOWS.
|
|
#endif
|
|
|
|
#if defined(VALIDATE_OUTPUT)
|
|
#if defined(_WIN32)
|
|
#include <windows.h>
|
|
#include <gl/GL.h>
|
|
|
|
#pragma comment(lib, "opengl32.lib")
|
|
|
|
typedef char GLcharARB; /* native character */
|
|
typedef unsigned int GLhandleARB; /* shader object handle */
|
|
#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
|
|
#define GL_OBJECT_LINK_STATUS_ARB 0x8B82
|
|
#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84
|
|
typedef void (WINAPI * PFNGLDELETEOBJECTARBPROC)(GLhandleARB obj);
|
|
typedef GLhandleARB (WINAPI * PFNGLCREATESHADEROBJECTARBPROC)(GLenum shaderType);
|
|
typedef void (WINAPI * PFNGLSHADERSOURCEARBPROC)(GLhandleARB shaderObj, GLsizei count, const GLcharARB** string, const GLint* length);
|
|
typedef void (WINAPI * PFNGLCOMPILESHADERARBPROC)(GLhandleARB shaderObj);
|
|
typedef void (WINAPI * PFNGLGETINFOLOGARBPROC)(GLhandleARB obj, GLsizei maxLength, GLsizei* length, GLcharARB* infoLog);
|
|
typedef void (WINAPI * PFNGLGETOBJECTPARAMETERIVARBPROC)(GLhandleARB obj, GLenum pname, GLint* params);
|
|
typedef GLhandleARB (WINAPI * PFNGLCREATEPROGRAMOBJECTARBPROC)(void);
|
|
typedef void (WINAPI * PFNGLATTACHOBJECTARBPROC)(GLhandleARB containerObj, GLhandleARB obj);
|
|
typedef void (WINAPI * PFNGLLINKPROGRAMARBPROC)(GLhandleARB programObj);
|
|
typedef void (WINAPI * PFNGLUSEPROGRAMOBJECTARBPROC)(GLhandleARB programObj);
|
|
typedef void (WINAPI * PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLcharARB* infoLog);
|
|
|
|
static PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
|
|
static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
|
|
static PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
|
|
static PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
|
|
static PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
|
|
static PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
|
|
static PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
|
|
static PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
|
|
static PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
|
|
static PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
|
|
static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
|
|
|
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
|
|
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
|
|
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
|
|
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
|
#define ERROR_INVALID_VERSION_ARB 0x2095
|
|
#define ERROR_INVALID_PROFILE_ARB 0x2096
|
|
|
|
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
|
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
|
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
|
|
|
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hDC, HGLRC hShareContext, const int* attribList);
|
|
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
|
|
|
|
void InitOpenGL()
|
|
{
|
|
HGLRC rc;
|
|
|
|
// setup minimal required GL
|
|
HWND wnd = CreateWindowA(
|
|
"STATIC",
|
|
"GL",
|
|
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
|
0, 0, 16, 16,
|
|
NULL, NULL,
|
|
GetModuleHandle(NULL), NULL);
|
|
HDC dc = GetDC(wnd);
|
|
|
|
PIXELFORMATDESCRIPTOR pfd = {
|
|
sizeof(PIXELFORMATDESCRIPTOR), 1,
|
|
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
|
|
PFD_TYPE_RGBA, 32,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
16, 0,
|
|
0, PFD_MAIN_PLANE, 0, 0, 0, 0
|
|
};
|
|
|
|
int fmt = ChoosePixelFormat(dc, &pfd);
|
|
SetPixelFormat(dc, fmt, &pfd);
|
|
|
|
rc = wglCreateContext(dc);
|
|
wglMakeCurrent(dc, rc);
|
|
|
|
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
|
|
|
|
if (wglCreateContextAttribsARB)
|
|
{
|
|
const int OpenGLContextAttribs [] = {
|
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
|
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
|
|
#if defined(_DEBUG)
|
|
//WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB,
|
|
#else
|
|
//WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
|
|
#endif
|
|
//WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
0, 0
|
|
};
|
|
|
|
const HGLRC OpenGLContext = wglCreateContextAttribsARB(dc, 0, OpenGLContextAttribs);
|
|
|
|
wglMakeCurrent(dc, OpenGLContext);
|
|
|
|
wglDeleteContext(rc);
|
|
|
|
rc = OpenGLContext;
|
|
}
|
|
|
|
glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)wglGetProcAddress("glDeleteObjectARB");
|
|
glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)wglGetProcAddress("glCreateShaderObjectARB");
|
|
glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)wglGetProcAddress("glShaderSourceARB");
|
|
glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)wglGetProcAddress("glCompileShaderARB");
|
|
glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB");
|
|
glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB");
|
|
glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)wglGetProcAddress("glCreateProgramObjectARB");
|
|
glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)wglGetProcAddress("glAttachObjectARB");
|
|
glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)wglGetProcAddress("glLinkProgramARB");
|
|
glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)wglGetProcAddress("glUseProgramObjectARB");
|
|
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
|
|
}
|
|
#endif
|
|
|
|
void PrintSingleLineError(FILE* pFile, const char* error)
|
|
{
|
|
while (*error != '\0')
|
|
{
|
|
const char* pLineEnd = strchr(error, '\n');
|
|
if (pLineEnd == 0)
|
|
{
|
|
pLineEnd = error + strlen(error) - 1;
|
|
}
|
|
fwrite(error, 1, pLineEnd - error, pFile);
|
|
fwrite("\r", 1, 1, pFile);
|
|
error = pLineEnd + 1;
|
|
}
|
|
}
|
|
|
|
int TryCompileShader(GLenum eShaderType, const char* inFilename, const char* shader, double* pCompileTime, int useStdErr)
|
|
{
|
|
GLint iCompileStatus;
|
|
GLuint hShader;
|
|
Timer_t timer;
|
|
|
|
InitTimer(&timer);
|
|
|
|
InitOpenGL();
|
|
|
|
hShader = glCreateShaderObjectARB(eShaderType);
|
|
glShaderSourceARB(hShader, 1, (const char**)&shader, NULL);
|
|
|
|
ResetTimer(&timer);
|
|
glCompileShaderARB(hShader);
|
|
*pCompileTime = ReadTimer(&timer);
|
|
|
|
/* Check it compiled OK */
|
|
glGetObjectParameterivARB (hShader, GL_OBJECT_COMPILE_STATUS_ARB, &iCompileStatus);
|
|
|
|
if (iCompileStatus != GL_TRUE)
|
|
{
|
|
FILE* errorFile = NULL;
|
|
GLint iInfoLogLength = 0;
|
|
char* pszInfoLog;
|
|
|
|
glGetObjectParameterivARB (hShader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &iInfoLogLength);
|
|
|
|
pszInfoLog = new char[iInfoLogLength];
|
|
|
|
printf("Error: Failed to compile GLSL shader\n");
|
|
|
|
glGetInfoLogARB (hShader, iInfoLogLength, NULL, pszInfoLog);
|
|
|
|
printf(pszInfoLog);
|
|
|
|
if (!useStdErr)
|
|
{
|
|
std::string filename;
|
|
filename += inFilename;
|
|
filename += "_compileErrors.txt";
|
|
|
|
//Dump to file
|
|
fopen_s(&errorFile, filename.c_str(), "w");
|
|
|
|
fclose(errorFile);
|
|
}
|
|
else
|
|
{
|
|
// Present error to stderror with no "new lines" as required by remote shader compiler
|
|
fprintf(stderr, "%s(-) error: ", inFilename);
|
|
PrintSingleLineError(stderr, pszInfoLog);
|
|
fprintf(stderr, "\rshader: ");
|
|
PrintSingleLineError(stderr, shader);
|
|
}
|
|
|
|
delete [] pszInfoLog;
|
|
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
int fileExists(const char* path)
|
|
{
|
|
FILE* shaderFile;
|
|
shaderFile = fopen(path, "rb");
|
|
|
|
if (shaderFile)
|
|
{
|
|
fclose(shaderFile);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
GLLang LanguageFromString(const char* str)
|
|
{
|
|
if (strcmp(str, "es100") == 0)
|
|
{
|
|
return LANG_ES_100;
|
|
}
|
|
if (strcmp(str, "es300") == 0)
|
|
{
|
|
return LANG_ES_300;
|
|
}
|
|
if (strcmp(str, "es310") == 0)
|
|
{
|
|
return LANG_ES_310;
|
|
}
|
|
if (strcmp(str, "120") == 0)
|
|
{
|
|
return LANG_120;
|
|
}
|
|
if (strcmp(str, "130") == 0)
|
|
{
|
|
return LANG_130;
|
|
}
|
|
if (strcmp(str, "140") == 0)
|
|
{
|
|
return LANG_140;
|
|
}
|
|
if (strcmp(str, "150") == 0)
|
|
{
|
|
return LANG_150;
|
|
}
|
|
if (strcmp(str, "330") == 0)
|
|
{
|
|
return LANG_330;
|
|
}
|
|
if (strcmp(str, "400") == 0)
|
|
{
|
|
return LANG_400;
|
|
}
|
|
if (strcmp(str, "410") == 0)
|
|
{
|
|
return LANG_410;
|
|
}
|
|
if (strcmp(str, "420") == 0)
|
|
{
|
|
return LANG_420;
|
|
}
|
|
if (strcmp(str, "430") == 0)
|
|
{
|
|
return LANG_430;
|
|
}
|
|
if (strcmp(str, "440") == 0)
|
|
{
|
|
return LANG_440;
|
|
}
|
|
return LANG_DEFAULT;
|
|
}
|
|
|
|
#define MAX_PATH_CHARS 256
|
|
#define MAX_FXC_CMD_CHARS 1024
|
|
|
|
typedef struct
|
|
{
|
|
GLLang language;
|
|
|
|
int flags;
|
|
|
|
const char* shaderFile;
|
|
char* outputShaderFile;
|
|
|
|
char* reflectPath;
|
|
|
|
char cacheKey[MAX_PATH_CHARS];
|
|
|
|
int bUseFxc;
|
|
std::string fxcCmdLine;
|
|
} Options;
|
|
|
|
void InitOptions(Options* psOptions)
|
|
{
|
|
psOptions->language = LANG_DEFAULT;
|
|
psOptions->flags = 0;
|
|
psOptions->reflectPath = NULL;
|
|
|
|
psOptions->shaderFile = NULL;
|
|
|
|
psOptions->bUseFxc = 0;
|
|
}
|
|
|
|
void PrintHelp()
|
|
{
|
|
printf("Command line options:\n");
|
|
|
|
printf("\t-lang=X \t GLSL language to use. e.g. es100 or 140 or metal.\n");
|
|
printf("\t-flags=X \t The integer value of the HLSLCC_FLAGS to used.\n");
|
|
printf("\t-reflect=X \t File to write reflection JSON to.\n");
|
|
printf("\t-in=X \t Shader file to compile.\n");
|
|
printf("\t-out=X \t File to write the compiled shader from -in to.\n");
|
|
|
|
printf("\t-hashout=[dir/]out-file-name \t Output file name is a hash of 'out-file-name', put in the directory 'dir'.\n");
|
|
|
|
printf("\t-fxc=\"CMD\" HLSL compiler command line. If specified the input shader will be first compiled through this command first and then the resulting bytecode translated.\n");
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
int GetOptions(int argc, char** argv, Options* psOptions)
|
|
{
|
|
int i;
|
|
int fullShaderChain = -1;
|
|
|
|
InitOptions(psOptions);
|
|
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
char* option;
|
|
|
|
option = strstr(argv[i], "-help");
|
|
if (option != NULL)
|
|
{
|
|
PrintHelp();
|
|
return 0;
|
|
}
|
|
|
|
option = strstr(argv[i], "-reflect=");
|
|
if (option != NULL)
|
|
{
|
|
psOptions->reflectPath = option + strlen("-reflect=");
|
|
}
|
|
|
|
option = strstr(argv[i], "-lang=");
|
|
if (option != NULL)
|
|
{
|
|
psOptions->language = LanguageFromString((&option[strlen("-lang=")]));
|
|
}
|
|
|
|
option = strstr(argv[i], "-flags=");
|
|
if (option != NULL)
|
|
{
|
|
psOptions->flags = atol(&option[strlen("-flags=")]);
|
|
}
|
|
|
|
option = strstr(argv[i], "-in=");
|
|
if (option != NULL)
|
|
{
|
|
fullShaderChain = 0;
|
|
psOptions->shaderFile = option + strlen("-in=");
|
|
if (!fileExists(psOptions->shaderFile))
|
|
{
|
|
printf("Invalid path: %s\n", psOptions->shaderFile);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
option = strstr(argv[i], "-out=");
|
|
if (option != NULL)
|
|
{
|
|
fullShaderChain = 0;
|
|
psOptions->outputShaderFile = option + strlen("-out=");
|
|
}
|
|
|
|
option = strstr(argv[i], "-hashout");
|
|
if (option != NULL)
|
|
{
|
|
fullShaderChain = 0;
|
|
psOptions->outputShaderFile = option + strlen("-hashout=");
|
|
|
|
char* dir;
|
|
int64_t length;
|
|
|
|
uint64_t hash = hash64((const uint8_t*)psOptions->outputShaderFile, (uint32_t)strlen(psOptions->outputShaderFile), 0);
|
|
|
|
|
|
dir = strrchr(psOptions->outputShaderFile, '\\');
|
|
|
|
if (!dir)
|
|
{
|
|
dir = strrchr(psOptions->outputShaderFile, '//');
|
|
}
|
|
|
|
if (!dir)
|
|
{
|
|
length = 0;
|
|
}
|
|
else
|
|
{
|
|
length = (int)(dir - psOptions->outputShaderFile) + 1;
|
|
}
|
|
|
|
for (i = 0; i < length; ++i)
|
|
{
|
|
psOptions->cacheKey[i] = psOptions->outputShaderFile[i];
|
|
}
|
|
|
|
//sprintf(psOptions->cacheKey, "%x%x", high, low);
|
|
sprintf(&psOptions->cacheKey[i], "%010" PRIX64, hash);
|
|
|
|
psOptions->outputShaderFile = psOptions->cacheKey;
|
|
}
|
|
|
|
option = strstr(argv[i], "-fxc=");
|
|
if (option != NULL)
|
|
{
|
|
char* cmdLine = option + strlen("-fxc=");
|
|
size_t cmdLineLen = strlen(cmdLine);
|
|
if (cmdLineLen == 0 || cmdLineLen + 1 >= MAX_FXC_CMD_CHARS)
|
|
{
|
|
return 0;
|
|
}
|
|
psOptions->fxcCmdLine = std::string(cmdLine, cmdLineLen);
|
|
psOptions->bUseFxc = 1;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void* malloc_hook(size_t size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
void* calloc_hook(size_t num, size_t size)
|
|
{
|
|
return calloc(num, size);
|
|
}
|
|
void* realloc_hook(void* p, size_t size)
|
|
{
|
|
return realloc(p, size);
|
|
}
|
|
void free_hook(void* p)
|
|
{
|
|
free(p);
|
|
}
|
|
|
|
int Run(const char* srcPath, const char* destPath, GLLang language, int flags, const char* reflectPath, GLSLShader* shader, int useStdErr)
|
|
{
|
|
FILE* outputFile;
|
|
GLSLShader tempShader;
|
|
GLSLShader* result = shader ? shader : &tempShader;
|
|
Timer_t timer;
|
|
int compiledOK = 0;
|
|
double crossCompileTime = 0;
|
|
|
|
HLSLcc_SetMemoryFunctions(malloc_hook, calloc_hook, free_hook, realloc_hook);
|
|
|
|
InitTimer(&timer);
|
|
|
|
ResetTimer(&timer);
|
|
GlExtensions ext;
|
|
ext.ARB_explicit_attrib_location = 0;
|
|
ext.ARB_explicit_uniform_location = 0;
|
|
ext.ARB_shading_language_420pack = 0;
|
|
compiledOK = TranslateHLSLFromFile(srcPath, flags, language, &ext, result);
|
|
|
|
crossCompileTime = ReadTimer(&timer);
|
|
|
|
if (compiledOK)
|
|
{
|
|
printf("cc time: %.2f us\n", crossCompileTime);
|
|
|
|
if (destPath)
|
|
{
|
|
//Dump to file
|
|
outputFile = fopen(destPath, "w");
|
|
fprintf(outputFile, result->sourceCode);
|
|
fclose(outputFile);
|
|
}
|
|
|
|
if (reflectPath)
|
|
{
|
|
const char* jsonString = SerializeReflection(&result->reflection);
|
|
outputFile = fopen(reflectPath, "w");
|
|
fprintf(outputFile, jsonString);
|
|
fclose(outputFile);
|
|
}
|
|
|
|
#if defined(VALIDATE_OUTPUT)
|
|
std::string shaderSource;
|
|
if (flags & HLSLCC_FLAG_NO_VERSION_STRING)
|
|
{
|
|
// Need to add the version string so that the shader will compile
|
|
shaderSource = GetVersionString(language);
|
|
shaderSource += result->sourceCode;
|
|
}
|
|
else
|
|
{
|
|
shaderSource = result->sourceCode;
|
|
}
|
|
compiledOK = TryCompileShader(result->shaderType, destPath ? destPath : "", shaderSource.c_str(), &glslCompileTime, useStdErr);
|
|
|
|
if (compiledOK)
|
|
{
|
|
printf("glsl time: %.2f us\n", glslCompileTime);
|
|
}
|
|
#endif
|
|
|
|
if (!shader)
|
|
{
|
|
FreeGLSLShader(result);
|
|
}
|
|
}
|
|
else if (useStdErr)
|
|
{
|
|
fprintf(stderr, "TranslateHLSLFromFile failed");
|
|
}
|
|
|
|
return compiledOK;
|
|
}
|
|
|
|
struct SDXBCFile
|
|
{
|
|
FILE* m_pFile;
|
|
|
|
bool Read(void* pElements, size_t uSize)
|
|
{
|
|
return fread(pElements, 1, uSize, m_pFile) == uSize;
|
|
}
|
|
|
|
bool Write(const void* pElements, size_t uSize)
|
|
{
|
|
return fwrite(pElements, 1, uSize, m_pFile) == uSize;
|
|
}
|
|
|
|
bool SeekRel(int32_t iOffset)
|
|
{
|
|
return fseek(m_pFile, iOffset, SEEK_CUR) == 0;
|
|
}
|
|
|
|
bool SeekAbs(uint32_t uPosition)
|
|
{
|
|
return fseek(m_pFile, uPosition, SEEK_SET) == 0;
|
|
}
|
|
};
|
|
|
|
int CombineDXBCWithGLSL(char* dxbcFileName, char* outputFileName, GLSLShader* shader)
|
|
{
|
|
SDXBCFile dxbcFile = { fopen(dxbcFileName, "rb") };
|
|
SDXBCFile outputFile = { fopen(outputFileName, "wb") };
|
|
|
|
bool result =
|
|
dxbcFile.m_pFile != NULL && outputFile.m_pFile != NULL &&
|
|
DXBCCombineWithGLSL(dxbcFile, outputFile, shader);
|
|
|
|
if (dxbcFile.m_pFile != NULL)
|
|
{
|
|
fclose(dxbcFile.m_pFile);
|
|
}
|
|
if (outputFile.m_pFile != NULL)
|
|
{
|
|
fclose(outputFile.m_pFile);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#if !defined(_MSC_VER)
|
|
#define sprintf_s(dest, size, ...) sprintf(dest, __VA_ARGS__)
|
|
#endif
|
|
|
|
#if defined(_WIN32) && defined(PORTABLE)
|
|
|
|
DWORD FilterException(DWORD uExceptionCode)
|
|
{
|
|
const char* szExceptionName;
|
|
char acTemp[10];
|
|
switch (uExceptionCode)
|
|
{
|
|
#define _CASE(_Name) \
|
|
case _Name: \
|
|
szExceptionName = #_Name; \
|
|
break;
|
|
_CASE(EXCEPTION_ACCESS_VIOLATION)
|
|
_CASE(EXCEPTION_DATATYPE_MISALIGNMENT)
|
|
_CASE(EXCEPTION_BREAKPOINT)
|
|
_CASE(EXCEPTION_SINGLE_STEP)
|
|
_CASE(EXCEPTION_ARRAY_BOUNDS_EXCEEDED)
|
|
_CASE(EXCEPTION_FLT_DENORMAL_OPERAND)
|
|
_CASE(EXCEPTION_FLT_DIVIDE_BY_ZERO)
|
|
_CASE(EXCEPTION_FLT_INEXACT_RESULT)
|
|
_CASE(EXCEPTION_FLT_INVALID_OPERATION)
|
|
_CASE(EXCEPTION_FLT_OVERFLOW)
|
|
_CASE(EXCEPTION_FLT_STACK_CHECK)
|
|
_CASE(EXCEPTION_FLT_UNDERFLOW)
|
|
_CASE(EXCEPTION_INT_DIVIDE_BY_ZERO)
|
|
_CASE(EXCEPTION_INT_OVERFLOW)
|
|
_CASE(EXCEPTION_PRIV_INSTRUCTION)
|
|
_CASE(EXCEPTION_IN_PAGE_ERROR)
|
|
_CASE(EXCEPTION_ILLEGAL_INSTRUCTION)
|
|
_CASE(EXCEPTION_NONCONTINUABLE_EXCEPTION)
|
|
_CASE(EXCEPTION_STACK_OVERFLOW)
|
|
_CASE(EXCEPTION_INVALID_DISPOSITION)
|
|
_CASE(EXCEPTION_GUARD_PAGE)
|
|
_CASE(EXCEPTION_INVALID_HANDLE)
|
|
//_CASE(EXCEPTION_POSSIBLE_DEADLOCK)
|
|
#undef _CASE
|
|
default:
|
|
sprintf_s(acTemp, "0x%08X", uExceptionCode);
|
|
szExceptionName = acTemp;
|
|
}
|
|
|
|
fprintf(stderr, "Hardware exception thrown (%s)\n", szExceptionName);
|
|
return 1;
|
|
}
|
|
|
|
#endif
|
|
|
|
const char* PatchHLSLShaderFile(const char* path)
|
|
{
|
|
// Need to transform "half" into "min16float" so FXC preserve min precision to the operands.
|
|
static char patchedFileName[MAX_PATH_CHARS];
|
|
const char* defines = "#define half min16float\n"
|
|
"#define half2 min16float2\n"
|
|
"#define half3 min16float3\n"
|
|
"#define half4 min16float4\n";
|
|
|
|
sprintf_s(patchedFileName, sizeof(patchedFileName), "%s.hlslPatched", path);
|
|
FILE* shaderFile = fopen(path, "rb");
|
|
if (!shaderFile)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
FILE* patchedFile = fopen(patchedFileName, "wb");
|
|
if (!patchedFile)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Get size of file
|
|
bool result = false;
|
|
fseek(shaderFile, 0, SEEK_END);
|
|
long size = ftell(shaderFile);
|
|
fseek(shaderFile, 0, SEEK_SET);
|
|
unsigned char* data = new unsigned char[size + 1]; // Extra byte for the '/0' character.
|
|
if (fread(data, 1, size, shaderFile) == size)
|
|
{
|
|
data[size] = '\0';
|
|
fprintf(patchedFile, "%s%s", defines, data);
|
|
result = true;
|
|
}
|
|
|
|
if (shaderFile)
|
|
{
|
|
fclose(shaderFile);
|
|
}
|
|
|
|
if (patchedFile)
|
|
{
|
|
fclose(patchedFile);
|
|
}
|
|
|
|
delete[] data;
|
|
return result ? patchedFileName : NULL;
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
Options options;
|
|
|
|
#if defined(_WIN32) && defined(PORTABLE)
|
|
__try
|
|
{
|
|
#endif
|
|
|
|
if (!GetOptions(argc, argv, &options))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if (options.bUseFxc)
|
|
{
|
|
char dxbcFileName[MAX_PATH_CHARS];
|
|
char glslFileName[MAX_PATH_CHARS];
|
|
char fullFxcCmdLine[MAX_FXC_CMD_CHARS];
|
|
int retValue;
|
|
|
|
if (options.flags & HLSLCC_FLAG_HALF_FLOAT_TRANSFORM)
|
|
{
|
|
options.shaderFile = PatchHLSLShaderFile(options.shaderFile);
|
|
if (!options.shaderFile)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
sprintf_s(dxbcFileName, sizeof(dxbcFileName), "%s.dxbc", options.shaderFile);
|
|
sprintf_s(glslFileName, sizeof(glslFileName), "%s.patched", options.shaderFile);
|
|
|
|
// Need to extract the path to the executable so we can enclose it in quotes
|
|
// in case it contains spaces.
|
|
const std::string fxcExeName = "fxc.exe";
|
|
|
|
// Case insensitive search
|
|
std::string::iterator fxcPos = std::search(
|
|
options.fxcCmdLine.begin(), options.fxcCmdLine.end(),
|
|
fxcExeName.begin(), fxcExeName.end(),
|
|
[](char ch1, char ch2) { return std::tolower(ch1) == std::tolower(ch2); }
|
|
);
|
|
|
|
if (fxcPos == options.fxcCmdLine.end())
|
|
{
|
|
fprintf(stderr, "Could not find fxc.exe in command line");
|
|
return 1;
|
|
}
|
|
|
|
// Add the fxcExeName so it gets copied to the fxcExe path.
|
|
fxcPos += fxcExeName.length();
|
|
std::string fxcExe(options.fxcCmdLine.begin(), fxcPos);
|
|
std::string fxcArguments(fxcPos, options.fxcCmdLine.end());
|
|
|
|
#if defined(APPLE)
|
|
fprintf(stderr, "fxc.exe cannot be executed on Mac");
|
|
return 1;
|
|
#else
|
|
// Need an extra set of quotes around the full command line because the way "system" executes it using cmd.
|
|
sprintf_s(fullFxcCmdLine, sizeof(fullFxcCmdLine), "\"\"%s\" %s \"%s\" \"%s\"\"", fxcExe.c_str(), fxcArguments.c_str(), dxbcFileName, options.shaderFile);
|
|
#endif
|
|
|
|
retValue = system(fullFxcCmdLine);
|
|
|
|
if (retValue == 0)
|
|
{
|
|
GLSLShader shader;
|
|
retValue = !Run(dxbcFileName, glslFileName, options.language, options.flags, options.reflectPath, &shader, 1);
|
|
|
|
if (retValue == 0)
|
|
{
|
|
retValue = !CombineDXBCWithGLSL(dxbcFileName, options.outputShaderFile, &shader);
|
|
FreeGLSLShader(&shader);
|
|
}
|
|
}
|
|
|
|
remove(dxbcFileName);
|
|
remove(glslFileName);
|
|
if (options.flags & HLSLCC_FLAG_HALF_FLOAT_TRANSFORM)
|
|
{
|
|
// Removed the hlsl patched file that was created.
|
|
remove(options.shaderFile);
|
|
}
|
|
|
|
return retValue;
|
|
}
|
|
|
|
if (options.shaderFile)
|
|
{
|
|
if (!Run(options.shaderFile, options.outputShaderFile, options.language, options.flags, options.reflectPath, NULL, 0))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#if defined(_WIN32) && defined(PORTABLE)
|
|
}
|
|
__except (FilterException(GetExceptionCode()))
|
|
{
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
|
|
return 0;
|
|
}
|