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.
220 lines
8.9 KiB
C
220 lines
8.9 KiB
C
// Modifications copyright Amazon.com, Inc. or its affiliates
|
|
// Modifications copyright Crytek GmbH
|
|
|
|
#include "internal_includes/toGLSLInstruction.h"
|
|
#include "internal_includes/toGLSLOperand.h"
|
|
#include "internal_includes/languages.h"
|
|
#include "bstrlib.h"
|
|
#include "stdio.h"
|
|
#include "internal_includes/debug.h"
|
|
#include "internal_includes/hlslcc_malloc.h"
|
|
#include "amazon_changes.h"
|
|
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic ignored "-Wpointer-sign"
|
|
#endif
|
|
|
|
extern void AddIndentation(HLSLCrossCompilerContext* psContext);
|
|
|
|
// These are .c files, so no C++ or C++11 for us :(
|
|
#define MAX_VARIABLE_LENGTH 16
|
|
|
|
// This struct is used to keep track of each valid occurance of xxxBitsToxxx(variable) and store all relevant information for fixing that instance
|
|
typedef struct ShaderCastLocation
|
|
{
|
|
char tempVariableName[MAX_VARIABLE_LENGTH];
|
|
char replacementVariableName[MAX_VARIABLE_LENGTH];
|
|
unsigned int castType;
|
|
|
|
// Since we have no stl, here's our list
|
|
struct ShaderCastLocation* next;
|
|
} ShaderCastLocation;
|
|
|
|
// Structure used to prebuild the list of all functions that need to be replaced.
|
|
typedef struct ShaderCastType
|
|
{
|
|
const char* functionName;
|
|
unsigned int castType;
|
|
const char* variableTypeName; // String for the variable type used when declaring a temporary variable to replace the source temp vector
|
|
} ShaderCastType;
|
|
|
|
enum ShaderCasts
|
|
{
|
|
CAST_UINTBITSTOFLOAT,
|
|
CAST_INTBITSTOFLOAT,
|
|
CAST_FLOATBITSTOUINT,
|
|
CAST_FLOATBITSTOINT,
|
|
CAST_NUMCASTS
|
|
};
|
|
|
|
// NOTICE: Order is important here because intBitsToFloat is a substring of uintBitsToFloat, so do not change the ordering here!
|
|
static const ShaderCastType s_castFunctions[CAST_NUMCASTS] =
|
|
{
|
|
{ "uintBitsToFloat", CAST_UINTBITSTOFLOAT, "uvec4" },
|
|
{ "intBitsToFloat", CAST_INTBITSTOFLOAT, "ivec4" },
|
|
{ "floatBitsToUint", CAST_FLOATBITSTOUINT, "vec4" },
|
|
{ "floatBitsToInt", CAST_FLOATBITSTOINT, "vec4" }
|
|
};
|
|
|
|
int IsValidUseCase( char* variableStart, char* outVariableName, ShaderCastLocation* foundShaderCastsHead, int currentType )
|
|
{
|
|
// Cases we have to replace (this is very strict in definition):
|
|
// 1) floatBitsToInt(Temp2)
|
|
// 2) floatBitsToInt(Temp2.x)
|
|
// 3) floatBitsToInt(Temp[0])
|
|
// 4) floatBitsToInt(Temp[0].x)
|
|
// Cases we do not have to replace:
|
|
// 1) floatBitsToInt(vec4(Temp2))
|
|
// 2) floatBitsToInt(Output0.x != 0.0f ? 1.0f : 0.0f)
|
|
// 3) Any other version that evaluates an expression within the ()
|
|
if ( strncmp(variableStart, "Temp", 4) != 0 )
|
|
return 0;
|
|
|
|
unsigned int lengthOfVariable = 4; // Start at 4 for temp
|
|
|
|
while ( 1 )
|
|
{
|
|
char val = *(variableStart + lengthOfVariable);
|
|
|
|
// If alphanumeric or [] (array), we have a valid variable name
|
|
if ( isalnum( val ) || (val == '[') || (val == ']') )
|
|
{
|
|
lengthOfVariable++;
|
|
}
|
|
else if ( (val == ')') || (val == '.') )
|
|
{
|
|
// Found end of variable
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Found something unexpected, so abort
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ASSERT( lengthOfVariable < MAX_VARIABLE_LENGTH );
|
|
|
|
// Now ensure that no duplicates of this declaration already exist
|
|
ShaderCastLocation* currentLink = foundShaderCastsHead;
|
|
while ( currentLink )
|
|
{
|
|
// If we have the same type and the same name
|
|
if ( (currentType == currentLink->castType) && (strncmp(variableStart, currentLink->tempVariableName, lengthOfVariable) == 0) )
|
|
return 0; // Do not add because an entry already exists for this variable and this cast function
|
|
|
|
// Hmm...I guess this scenario is possible, but it has not shown up in any shaders.
|
|
// The only time we could ever hit this is if the same line casts a float to both an int and uint in separate calls
|
|
// Seems highly unlikely, so let's just assert for now and fix it if we have to.
|
|
if ( strncmp(variableStart, currentLink->tempVariableName, lengthOfVariable) == 0 )
|
|
{
|
|
// TODO: Implement this case where we cast the same variable to multiple types on the same line of GLSL
|
|
ASSERT(0);
|
|
}
|
|
|
|
currentLink = currentLink->next;
|
|
}
|
|
|
|
// We found a unique instance, so store it
|
|
strncpy( outVariableName, variableStart, lengthOfVariable );
|
|
return 1;
|
|
}
|
|
|
|
void ModifyLineForQualcommReinterpretCastBug( HLSLCrossCompilerContext* psContext, bstring* originalString, bstring* overloadString )
|
|
{
|
|
unsigned int numFoundCasts = 0;
|
|
|
|
ShaderCastLocation* foundShaderCastsHead = NULL;
|
|
ShaderCastLocation* currentShaderCasts = NULL;
|
|
|
|
// Find all occurances of the *BitsTo* functions
|
|
// Note that this would be cleaner, but 'intBitsToFloat' is a substring of 'uintBitsToFloat' so parsing order is important here.
|
|
char* parsingString = bdataofs(*overloadString, 0);
|
|
while ( parsingString )
|
|
{
|
|
char* result = NULL;
|
|
|
|
for ( int index=0; index<CAST_NUMCASTS; ++index )
|
|
{
|
|
result = strstr( parsingString, s_castFunctions[index].functionName );
|
|
if ( result != NULL )
|
|
{
|
|
// Now determine if this is a case that requires a workaround
|
|
char* variableStart = result + strlen( s_castFunctions[index].functionName ) + 1; // Add the function name + first parenthesis
|
|
char tempVariableName[MAX_VARIABLE_LENGTH];
|
|
memset( tempVariableName, 0, MAX_VARIABLE_LENGTH );
|
|
|
|
// Now the next word must be Temp, or this is not a valid case
|
|
if ( IsValidUseCase( variableStart, tempVariableName, foundShaderCastsHead, index ) )
|
|
{
|
|
// Now store the information about this cast. Allocate a new link in the list.
|
|
if ( !foundShaderCastsHead )
|
|
{
|
|
foundShaderCastsHead = (ShaderCastLocation*)hlslcc_malloc( sizeof(ShaderCastLocation) );
|
|
memset( foundShaderCastsHead, 0x0, sizeof(ShaderCastLocation) );
|
|
currentShaderCasts = foundShaderCastsHead;
|
|
}
|
|
else
|
|
{
|
|
ASSERT( !currentShaderCasts->next );
|
|
currentShaderCasts->next = (ShaderCastLocation*)hlslcc_malloc( sizeof(ShaderCastLocation) );
|
|
memset( currentShaderCasts->next, 0x0, sizeof(ShaderCastLocation) );
|
|
currentShaderCasts = currentShaderCasts->next;
|
|
}
|
|
|
|
currentShaderCasts->castType = index;
|
|
strcpy( currentShaderCasts->tempVariableName, tempVariableName );
|
|
|
|
numFoundCasts++;
|
|
}
|
|
result += strlen( s_castFunctions[index].functionName );
|
|
|
|
// Break out of the loop because we have to advance the search string and start over with uintBitsToFloat again due to the problem with intBitsToFloat being a substring
|
|
break;
|
|
}
|
|
}
|
|
|
|
parsingString = result;
|
|
}
|
|
|
|
// If we have found no casts, then append the line to the primary string
|
|
if ( numFoundCasts == 0 )
|
|
{
|
|
bconcat( *originalString, *overloadString );
|
|
return;
|
|
}
|
|
|
|
// Now we start creating our temporary variables to workaround the crash
|
|
currentShaderCasts = foundShaderCastsHead;
|
|
|
|
// NOTE: We want a count of all variables processed for this entire shader. This could be fancier...
|
|
static unsigned int currentVariableIndex = 0;
|
|
|
|
while ( currentShaderCasts )
|
|
{
|
|
// Generate new variable name
|
|
sprintf( currentShaderCasts->replacementVariableName, "LYTemp%i", currentVariableIndex );
|
|
|
|
// Write out the new variable name declaration and initialize it
|
|
AddIndentation( psContext );
|
|
bformata( *originalString, "%s %s=%s;\n", s_castFunctions[currentShaderCasts->castType].variableTypeName, currentShaderCasts->replacementVariableName, currentShaderCasts->tempVariableName );
|
|
|
|
// Now replace all instances of the variable in question with the new variable name.
|
|
// Note: We can't do a breplace on the temp variable name because the variable can still be legally used without a reinterpret cast in that line.
|
|
// Do a full replace on the xxBitsToxx(TempVar) here
|
|
bstring tempVarName = bformat( "%s(%s)", s_castFunctions[currentShaderCasts->castType].functionName, currentShaderCasts->tempVariableName );
|
|
bstring replacementVarName = bformat( "%s(%s)", s_castFunctions[currentShaderCasts->castType].functionName, currentShaderCasts->replacementVariableName );
|
|
bfindreplace( *overloadString, tempVarName, replacementVarName, 0 );
|
|
|
|
// Cleanup bstrings allocated from bformat
|
|
bdestroy( tempVarName );
|
|
bdestroy( replacementVarName );
|
|
|
|
currentVariableIndex++;
|
|
currentShaderCasts = currentShaderCasts->next;
|
|
}
|
|
|
|
// Now append our modified string to the full shader file
|
|
bconcat( *originalString, *overloadString );
|
|
}
|