diff --git a/.gitignore b/.gitignore index be603a90f..141e3e706 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,5 @@ m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 m4/lt~obsolete.m4 +/t +/src/libprojectM/libprojectM.pc diff --git a/src/libprojectM/Renderer/HLSLTranslator.cpp b/src/libprojectM/Renderer/HLSLTranslator.cpp index cf51f4fe5..33313c170 100644 --- a/src/libprojectM/Renderer/HLSLTranslator.cpp +++ b/src/libprojectM/Renderer/HLSLTranslator.cpp @@ -5,15 +5,156 @@ using namespace M4; -std::unique_ptr HLSLTranslator::parse(GLenum shaderType, const char *fileName, const char *source, size_t size) { +std::string HLSLShaderTemplate = "" +" static const float M_PI = 3.14159265359;\n" +" static const float M_PI_2 = 6.28318530718;\n" +" static const float M_INV_PI_2 = 0.159154943091895;\n" + +" float q1;\n" +" float q2;\n" +" float q3;\n" +" float q4;\n" +" float q5;\n" +" float q6;\n" +" float q7;\n" +" float q8;\n" +" float q9;\n" +" float q10;\n" +" float q11;\n" +" float q12;\n" +" float q13;\n" +" float q14;\n" +" float q15;\n" +" float q16;\n" +" float q17;\n" +" float q18;\n" +" float q19;\n" +" float q20;\n" +" float q21;\n" +" float q22;\n" +" float q23;\n" +" float q24;\n" +" float q25;\n" +" float q26;\n" +" float q27;\n" +" float q28;\n" +" float q29;\n" +" float q30;\n" +" float q31;\n" +" float q32;\n" + +//" #define tex2d tex2D\n" +//" #define tex3d tex3D\n" +// +//" #define sampler sampler2D\n" +//" #define uv_orig uv\n" + +" uniform sampler2D sampler_main;\n" +" uniform sampler2D sampler_fw_main;\n" +" uniform sampler2D sampler_pw_main;\n" +" uniform sampler2D sampler_fc_main;\n" +" uniform sampler2D sampler_pc_main;\n" + +" uniform sampler2D sampler_noise_lq;\n" +" uniform sampler2D sampler_noise_lq_lite;\n" +" uniform sampler2D sampler_noise_mq;\n" +" uniform sampler2D sampler_noise_hq;\n" +" uniform sampler2D sampler_noise_perlin;\n" +" uniform sampler3D sampler_noisevol_lq;\n" +" uniform sampler3D sampler_noisevol_hq;\n" + +" uniform sampler2D sampler_blur1;\n" +" uniform sampler2D sampler_blur2;\n" +" uniform sampler2D sampler_blur3;\n" + +" float4 texsize_noise_lq;\n" +" float4 texsize_noise_mq;\n" +" float4 texsize_noise_hq;\n" +" float4 texsize_noise_perlin;\n" +" float4 texsize_noise_lq_lite;\n" +" float4 texsize_noisevol_hq;\n" + +" float blur1_min;\n" +" float blur1_max;\n" +" float blur2_min;\n" +" float blur2_max;\n" +" float blur3_min;\n" +" float blur3_max;\n" + +" float4 slow_roam_cos;\n" +" float4 roam_cos;\n" +" float4 slow_roam_sin;\n" +" float4 roam_sin;\n" + +" float time;\n" +" float4 rand_preset;\n" +" float4 rand_frame;\n" +" float progress;\n" +" float frame;\n" +" float fps;\n" +" float bass;\n" +" float mid;\n" +" float treb;\n" +" float vol;\n" +" float bass_att;\n" +" float mid_att;\n" +" float treb_att;\n" +" float vol_att;\n" +" float4 texsize;\n" +" float4 aspect;\n" + +//" #define getrad sqrt((uv.x-0.5)*2*(uv.x-0.5)*2+(uv.y-0.5)*2*(uv.y-0.5)*2)*.7071067\n" +//" #define getang atan2(((uv.y-0.5)*2),((uv.x-0.5)*2))\n" +//" float rad = sqrt((uv.x-0.5)*2*(uv.x-0.5)*2+(uv.y-0.5)*2*(uv.y-0.5)*2)*.7071067;\n" +//" float getang = atan2(((uv.y-0.5)*2),((uv.x-0.5)*2));\n" + +//" #define GetMain(uv) (tex2D(sampler_main,uv).xyz)\n" +//" #define GetPixel(uv) (tex2D(sampler_main,uv).xyz)\n" +" float3 GetMain(float2 uv) { return tex2D(sampler_main,uv).xyz; }\n" +" float3 GetPixel(float2 uv) { return tex2D(sampler_main,uv).xyz; }\n" +" float lum(float3 x) { return dot(x, float3(0.32,0.49,0.29)); }\n" + +" float3 GetBlur1(float2 uv) {return tex2D(sampler_blur1,uv).xyz*blur1_max+blur1_min;}\n" +" float3 GetBlur2(float2 uv) {return tex2D(sampler_blur2,uv).xyz*blur2_max+blur2_min;}\n" +" float3 GetBlur3(float2 uv) {return tex2D(sampler_blur3,uv).xyz*blur3_max+blur3_min;}\n" + + +" float max( float a, float b ) {\n" +" return (a > b ? a : b);\n" +" }\n" + +" float3 max(float3 a, float4 b) {\n" +" return float3( a.x > b.x ? a.x : b.x,\n" +" a.y > b.y ? a.y : b.y,\n" +" a.z > b.z ? a.z : b.z );\n" +" }\n" + +" float3 max(float3 a, float3 b) {\n" +" return float3( a.x > b.x ? a.x : b.x,\n" +" a.y > b.y ? a.y : b.y,\n" +" a.z > b.z ? a.z : b.z );\n" +" }\n" + +" struct outtype {float4 color : COLOR;};\n" +" outtype OUT;\n" +" float3 ret;\n\n"; + + +std::unique_ptr HLSLTranslator::parse(GLenum shaderType, const char *fileName, std::string &source) { // alloc GLSLGenerator generator; Allocator allocator; - HLSLParser parser(&allocator, fileName, source, size); - HLSLTree tree( &allocator ); + + // prepend our Cg/HLSL template to the actual program source + std::string fullSource; + fullSource.append(HLSLShaderTemplate); + fullSource.append(source); // parse - if( !parser.Parse( &tree ) ) { +// std::cout << "FULL PROGRAM:\n\n****\n\n" << fullSource << "\n\n\n\n"; + HLSLParser parser(&allocator, fileName, fullSource.c_str(), fullSource.size()); + HLSLTree tree( &allocator ); + if( !parser.Parse(&tree) ) { fprintf(stderr, "Failed to parse HLSL shader\n"); return nullptr; } @@ -33,7 +174,7 @@ std::unique_ptr HLSLTranslator::parse(GLenum shaderType, const char } // generate GLSL - if (!generator.Generate( &tree, GLSLGenerator::Target(shaderType), GLSLGenerator::Version_140, "shader_body" )) { + if (!generator.Generate(&tree, GLSLGenerator::Target(shaderType), GLSLGenerator::Version_110, "projectm")) { fprintf(stderr, "Failed to transpile HLSL shader to GLSL\n"); return nullptr; } diff --git a/src/libprojectM/Renderer/HLSLTranslator.hpp b/src/libprojectM/Renderer/HLSLTranslator.hpp index 84bcae9e1..4b5e1531f 100644 --- a/src/libprojectM/Renderer/HLSLTranslator.hpp +++ b/src/libprojectM/Renderer/HLSLTranslator.hpp @@ -21,12 +21,12 @@ #include "GLSLGenerator.h" #include #include "projectM-opengl.h" +#include +#include class HLSLTranslator { public: - // HLSLTranslator(); - // virtual ~HLSLTranslator(); - std::unique_ptr parse(GLenum shaderType, const char *fileName, const char *source, size_t size); + std::unique_ptr parse(GLenum shaderType, const char *fileName, std::string &source); }; #endif diff --git a/src/libprojectM/Renderer/MilkdropWaveform.cpp b/src/libprojectM/Renderer/MilkdropWaveform.cpp index 9728806bf..06c5b9158 100644 --- a/src/libprojectM/Renderer/MilkdropWaveform.cpp +++ b/src/libprojectM/Renderer/MilkdropWaveform.cpp @@ -19,6 +19,8 @@ void MilkdropWaveform::Draw(RenderContext &context) { WaveformMath(context); +#ifndef GL_TRANSITION + #ifndef EMSCRIPTEN glMatrixMode( GL_MODELVIEW ); #endif @@ -74,6 +76,8 @@ void MilkdropWaveform::Draw(RenderContext &context) #endif glPopMatrix(); + +#endif } void MilkdropWaveform::ModulateOpacityByVolume(RenderContext &context) @@ -93,7 +97,7 @@ void MilkdropWaveform::ModulateOpacityByVolume(RenderContext &context) void MilkdropWaveform::MaximizeColors(RenderContext &context) { - +#ifndef GL_TRANSITION float wave_r_switch=0, wave_g_switch=0, wave_b_switch=0; //wave color brightening // @@ -150,6 +154,7 @@ void MilkdropWaveform::MaximizeColors(RenderContext &context) { glColor4f(r, g, b, temp_a * masterAlpha); } +#endif } diff --git a/src/libprojectM/Renderer/Renderer.cpp b/src/libprojectM/Renderer/Renderer.cpp index e5bbc6a3a..c54d1990a 100644 --- a/src/libprojectM/Renderer/Renderer.cpp +++ b/src/libprojectM/Renderer/Renderer.cpp @@ -113,7 +113,8 @@ void Renderer::SetPipeline(Pipeline &pipeline) { currentPipe = &pipeline; shaderEngine.reset(); - shaderEngine.loadShader(GL_VERTEX_SHADER, pipeline.warpShader, pipeline.warpShaderFilename); + // N.B. i'm actually not sure if they're always fragment shaders... I think so... -mischa + shaderEngine.loadShader(GL_FRAGMENT_SHADER, pipeline.warpShader, pipeline.warpShaderFilename); shaderEngine.loadShader(GL_FRAGMENT_SHADER, pipeline.compositeShader, pipeline.compositeShaderFilename); } @@ -266,9 +267,9 @@ void Renderer::RenderFrame(const Pipeline &pipeline, const PipelineContext &pipe SetupPass1(pipeline, pipelineContext); -// shaderEngine.enableShader(currentPipe->warpShader, pipeline, pipelineContext); + shaderEngine.enableShader(currentPipe->warpShader, pipeline, pipelineContext); Interpolation(pipeline); -// shaderEngine.disableShader(); + shaderEngine.disableShader(currentPipe->warpShader); RenderItems(pipeline, pipelineContext); FinishPass1(); @@ -755,7 +756,7 @@ void Renderer::CompositeOutput(const Pipeline &pipeline, const PipelineContext & glEnable(GL_TEXTURE_2D); -// shaderEngine.enableShader(currentPipe->compositeShader, pipeline, pipelineContext); + shaderEngine.enableShader(currentPipe->compositeShader, pipeline, pipelineContext); float tex[4][2] = { @@ -785,7 +786,7 @@ void Renderer::CompositeOutput(const Pipeline &pipeline, const PipelineContext & glDisableClientState(GL_TEXTURE_COORD_ARRAY); -// shaderEngine.disableShader(); + shaderEngine.disableShader(currentPipe->compositeShader); for (std::vector::const_iterator pos = pipeline.compositeDrawables.begin(); pos != pipeline.compositeDrawables.end(); ++pos) diff --git a/src/libprojectM/Renderer/ShaderEngine.cpp b/src/libprojectM/Renderer/ShaderEngine.cpp index 28a4136bc..70d7bdfe1 100644 --- a/src/libprojectM/Renderer/ShaderEngine.cpp +++ b/src/libprojectM/Renderer/ShaderEngine.cpp @@ -155,9 +155,7 @@ bool ShaderEngine::LoadHLSLProgram(GLenum shaderType, Shader &pmShader, std::str if (found != std::string::npos) { //std::cout << "first 'shader_body' found at: " << int(found) << std::endl; - // HLSL version: -// program.replace(int(found), 11, "outtype projectm(float2 uv : TEXCOORD0)\n"); - program.replace(int(found), 11, "void main()\n"); + program.replace(int(found), 11, "outtype projectm(float2 uv : TEXCOORD0)\n"); } else return false; @@ -173,7 +171,6 @@ bool ShaderEngine::LoadHLSLProgram(GLenum shaderType, Shader &pmShader, std::str if (end != std::string::npos) { - std::string sampler = program.substr((int) found, (int) end - found); UserTexture* texture = new UserTexture(sampler); @@ -226,6 +223,7 @@ bool ShaderEngine::LoadHLSLProgram(GLenum shaderType, Shader &pmShader, std::str else delete (texture); + // we need to pass the sampler in to the source before transpiling it } found = program.find("sampler_", found); @@ -268,11 +266,13 @@ bool ShaderEngine::LoadHLSLProgram(GLenum shaderType, Shader &pmShader, std::str } } - std::cout << "Got program: " << program << std::endl; +// std::cout << "Got program: " << program << std::endl; + + // now we need to prepend the HLSL template to the program // transpile from HLSL (aka preset shader aka directX shader) to GLSL (aka OpenGL shader lang) HLSLTranslator translator = HLSLTranslator(); - std::unique_ptr glslSource = translator.parse(shaderType, shaderFilename.c_str(), program.c_str(), program.size()); + std::unique_ptr glslSource = translator.parse(shaderType, shaderFilename.c_str(), program); if (!glslSource) { std::cerr << "Failed to parse shader from " << shaderFilename << std::endl; return false; @@ -281,24 +281,31 @@ bool ShaderEngine::LoadHLSLProgram(GLenum shaderType, Shader &pmShader, std::str // https://www.khronos.org/opengl/wiki/Shader_Compilation#Shader_object_compilation GLuint shader = glCreateShader(shaderType); + // replace shader_body in preset with parameters and main(): + // const char *main = "void main(in sampler2D myTexture)\n"; + // program.replace(int(found), 11, main); + // Get strings for glShaderSource. + std::cout << "Got program: " << glslSource.get()->c_str() << std::endl; const char *shaderSourceCStr = glslSource.get()->c_str(); glShaderSource(shader, 1, &shaderSourceCStr, NULL); + // compile shader glCompileShader(shader); + // check result GLint isCompiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); if (isCompiled == GL_FALSE) { - GLint maxLength = 0; + GLint maxLength = 1024; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); // The maxLength includes the NULL character - std::vector errorLog(maxLength); - glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); + GLchar infoLog[512]; + glGetShaderInfoLog(shader, 512, nullptr, infoLog); - std::cerr << "Error compiling GLSL shader: " << errorLog[0] << std::endl; + std::cerr << (std::string("Failed to compile shader: ") + infoLog) << std::endl; glDeleteShader(shader); // Don't leak the shader. return false; @@ -352,12 +359,10 @@ GLuint ShaderEngine::makeShader(GLenum type, const char *filename) void ShaderEngine::InitShaderProgram() { GLuint projectMShader, blurShader; - projectMShader = makeShader(GL_FRAGMENT_SHADER, "/usr/local/share/projectM/shaders/projectM.cg"); blurShader = makeShader(GL_FRAGMENT_SHADER, "/usr/local/share/projectM/shaders/blur"); GLint program_ok; GLuint program = glCreateProgram(); - glAttachShader(program, projectMShader); glAttachShader(program, blurShader); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &program_ok); @@ -428,47 +433,55 @@ void ShaderEngine::SetupShaderVariables(GLuint program, const Pipeline &pipeline } */ } -/* -void ShaderEngine::SetupUserTexture(CGprogram program, const UserTexture* texture) + +void ShaderEngine::SetupUserTexture(GLuint program, const UserTexture* texture) { std::string samplerName = "sampler_" + texture->qname; - CGparameter param = glGetUniformLocation(program, samplerName.c_str()); - checkForCgError("getting parameter"); - cgGLSetTextureParameter(param, texture->texID); - checkForCgError("setting parameter"); - cgGLEnableTextureParameter(param); - checkForCgError("enabling parameter"); - //std::cout<texID<<" "<texID); + if (texture->texsizeDefined) { std::string texsizeName = "texsize_" + texture->name; - glProgramUniform4f(glGetUniformLocation(program, texsizeName.c_str()), texture->width, texture->height, 1 - / (float) texture->width, 1 / (float) texture->height); - checkForCgError("setting parameter texsize"); + GLint textSizeParam = glGetUniformLocation(program, texsizeName.c_str()); + if (param >= 0) { + glProgramUniform4f(textSizeParam, texture->width, texture->height, 0, + 1 / (float) texture->width, 1 / (float) texture->height); + } else { + std::cerr << "invalid texsizeName " << texsizeName << std::endl; + return; + } } } -*/ + void ShaderEngine::SetupUserTextureState( const UserTexture* texture) { - glBindTexture(GL_TEXTURE_2D, texture->texID); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texture->bilinear ? GL_LINEAR : GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture->bilinear ? GL_LINEAR : GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texture->wrap ? GL_REPEAT : GL_CLAMP); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texture->wrap ? GL_REPEAT : GL_CLAMP); + glBindTexture(GL_TEXTURE_2D, texture->texID); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texture->bilinear ? GL_LINEAR : GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture->bilinear ? GL_LINEAR : GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texture->wrap ? GL_REPEAT : GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texture->wrap ? GL_REPEAT : GL_CLAMP); } void ShaderEngine::SetupShaderQVariables(GLuint program, const Pipeline &q) { - glProgramUniform4f(glGetUniformLocation(program, "_qa"), 4, q.q[0], q.q[1], q.q[2], q.q[3]); - glProgramUniform4f(glGetUniformLocation(program, "_qb"), 4, q.q[4], q.q[5], q.q[6], q.q[7]); - glProgramUniform4f(glGetUniformLocation(program, "_qc"), 4, q.q[8], q.q[9], q.q[10], q.q[11]); - glProgramUniform4f(glGetUniformLocation(program, "_qd"), 4, q.q[12], q.q[13], q.q[14], q.q[15]); - glProgramUniform4f(glGetUniformLocation(program, "_qe"), 4, q.q[16], q.q[17], q.q[18], q.q[19]); - glProgramUniform4f(glGetUniformLocation(program, "_qf"), 4, q.q[20], q.q[21], q.q[22], q.q[23]); - glProgramUniform4f(glGetUniformLocation(program, "_qg"), 4, q.q[24], q.q[25], q.q[26], q.q[27]); - glProgramUniform4f(glGetUniformLocation(program, "_qh"), 4, q.q[28], q.q[29], q.q[30], q.q[31]); + // set program uniform "q" values (q1, q2, ... q32) + for (int i=0; i < 32; i++) { + std::string varName = "q"; + varName.append(std::to_string(i+1)); + int loc = glGetUniformLocation(program, varName.c_str()); + glProgramUniform1f(program, loc, q.q[i]); + } } void ShaderEngine::setAspect(float aspect) @@ -606,45 +619,37 @@ void ShaderEngine::loadShader(GLenum shaderType, Shader &shader, std::string &sh shader.enabled = LoadHLSLProgram(shaderType, shader, shaderFilename); } -// void ShaderEngine::disableShader() -// { -// if (enabled) -// { -// cgGLUnbindProgram(myCgProfile); -// checkForCgError("disabling fragment profile"); -// cgGLDisableProfile(myCgProfile); -// checkForCgError("disabling fragment profile"); -// } -// enabled = false; -// } + void ShaderEngine::disableShader(Shader &shader) + { + if (enabled) { + // NOTE: this is probably wrong. if we re-enable a program after calling this probably terrible things will happen. + // this is temporary. + GLuint program = programs[&shader]; + glDeleteProgram(program); + } + enabled = false; + } -// void ShaderEngine::enableShader(Shader &shader, const Pipeline &pipeline, const PipelineContext &pipelineContext) -// { -// enabled = false; -// if (shader.enabled) -// { + void ShaderEngine::enableShader(Shader &shader, const Pipeline &pipeline, const PipelineContext &pipelineContext) + { + enabled = false; + if (shader.enabled) + { + for (std::map::const_iterator pos = shader.textures.begin(); pos != shader.textures.end(); ++pos) + SetupUserTextureState(pos->second); -// for (std::map::const_iterator pos = shader.textures.begin(); pos != shader.textures.end(); ++pos) -// SetupUserTextureState( pos->second); + GLuint program = programs[&shader]; + for (std::map::const_iterator pos = shader.textures.begin(); pos != shader.textures.end(); ++pos) + SetupUserTexture(program, pos->second); + glUseProgram(program); -// CGprogram program = programs[&shader]; -// for (std::map::const_iterator pos = shader.textures.begin(); pos -// != shader.textures.end(); ++pos) -// SetupUserTexture(program, pos->second); +// SetupCgVariables(program, pipeline, pipelineContext); +// SetupCgQVariables(program, pipeline); -// cgGLEnableProfile(myCgProfile); -// checkForCgError("enabling warp profile"); - -// cgGLBindProgram(program); -// checkForCgError("binding warp program"); - -// SetupCgVariables(program, pipeline, pipelineContext); -// SetupCgQVariables(program, pipeline); - -// enabled = true; -// } -// } + enabled = true; + } + } void ShaderEngine::reset() { diff --git a/src/libprojectM/Renderer/ShaderEngine.hpp b/src/libprojectM/Renderer/ShaderEngine.hpp index cc678027a..f304f7824 100644 --- a/src/libprojectM/Renderer/ShaderEngine.hpp +++ b/src/libprojectM/Renderer/ShaderEngine.hpp @@ -58,7 +58,7 @@ class ShaderEngine void InitShaderProgram(); void SetupShaderQVariables(GLuint program, const Pipeline &q); void SetupShaderVariables(GLuint program, const Pipeline &pipeline, const PipelineContext &pipelineContext); - // void SetupUserTexture(CGprogram program, const UserTexture* texture); + void SetupUserTexture(GLuint program, const UserTexture* texture); void SetupUserTextureState(const UserTexture* texture); GLuint makeShader(GLenum type, const char *filename); bool LoadHLSLProgram(GLenum shaderType, Shader &shader, std::string &shaderFilename); @@ -68,6 +68,8 @@ public: virtual ~ShaderEngine(); void RenderBlurTextures(const Pipeline &pipeline, const PipelineContext &pipelineContext, const int texsize); void loadShader(GLenum shaderType, Shader &shader, std::string &shaderFilename); + void enableShader(Shader &shader, const Pipeline &pipeline, const PipelineContext &pipelineContext); + void disableShader(Shader &shader); void setParams(const int texsize, const unsigned int texId, const float aspect, BeatDetect *beatDetect, TextureManager *textureManager); void reset(); diff --git a/src/libprojectM/Renderer/VideoEcho.cpp b/src/libprojectM/Renderer/VideoEcho.cpp index 6ac805c1a..297242acc 100644 --- a/src/libprojectM/Renderer/VideoEcho.cpp +++ b/src/libprojectM/Renderer/VideoEcho.cpp @@ -35,16 +35,19 @@ void VideoEcho::Draw(RenderContext &context) { 0.5, 0.5}, { 0.5, -0.5}}; +#ifndef GL_TRANSITION glEnableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2,GL_FLOAT,0,points); glTexCoordPointer(2,GL_FLOAT,0,tex); - +#endif + //Now Blend the Video Echo glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#ifndef GL_TRANSITION glMatrixMode(GL_TEXTURE); //draw video echo @@ -52,7 +55,7 @@ void VideoEcho::Draw(RenderContext &context) glTranslatef(.5, .5, 0); glScalef(1.0/zoom, 1.0/zoom, 1); glTranslatef(-.5, -.5, 0); - + int flipx=1, flipy=1; switch (orientation) { @@ -75,5 +78,6 @@ void VideoEcho::Draw(RenderContext &context) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisableClientState(GL_TEXTURE_COORD_ARRAY); +#endif } diff --git a/src/libprojectM/Renderer/Waveform.cpp b/src/libprojectM/Renderer/Waveform.cpp index 6ff47859e..9f1f39954 100644 --- a/src/libprojectM/Renderer/Waveform.cpp +++ b/src/libprojectM/Renderer/Waveform.cpp @@ -88,6 +88,7 @@ void Waveform::Draw(RenderContext &context) } +#ifndef GL_TRANSITION glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); @@ -105,7 +106,7 @@ void Waveform::Draw(RenderContext &context) #endif glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // glPopMatrix(); - +#endif delete[] colors; delete[] p; delete[] value1; diff --git a/src/libprojectM/Renderer/hlslparser/src/CodeWriter.cpp b/src/libprojectM/Renderer/hlslparser/src/CodeWriter.cpp old mode 100644 new mode 100755 diff --git a/src/libprojectM/Renderer/hlslparser/src/CodeWriter.h b/src/libprojectM/Renderer/hlslparser/src/CodeWriter.h old mode 100644 new mode 100755 diff --git a/src/libprojectM/Renderer/hlslparser/src/GLSLGenerator.cpp b/src/libprojectM/Renderer/hlslparser/src/GLSLGenerator.cpp old mode 100644 new mode 100755 index 5f9d5d3f0..7ca9cca38 --- a/src/libprojectM/Renderer/hlslparser/src/GLSLGenerator.cpp +++ b/src/libprojectM/Renderer/hlslparser/src/GLSLGenerator.cpp @@ -447,7 +447,7 @@ void GLSLGenerator::OutputExpressionList(HLSLExpression* expression, HLSLArgumen const HLSLType* commonScalarType(const HLSLType& lhs, const HLSLType& rhs) { - if (!isScalarType(lhs) || !isScalarType(rhs)) + if (!IsScalarType(lhs) || !IsScalarType(rhs)) return NULL; if (lhs.baseType == HLSLBaseType_Float || lhs.baseType == HLSLBaseType_Half || @@ -523,12 +523,10 @@ void GLSLGenerator::OutputExpression(HLSLExpression* expression, const HLSLType* } break; case HLSLBaseType_Int: + case HLSLBaseType_Uint: m_writer.Write("%d", literalExpression->iValue); break; - case HLSLBaseType_Uint: - m_writer.Write("%uu", literalExpression->iValue); - break; - case HLSLBaseType_Bool: + case HLSLBaseType_Bool: m_writer.Write("%s", literalExpression->bValue ? "true" : "false"); break; default: @@ -573,8 +571,8 @@ void GLSLGenerator::OutputExpression(HLSLExpression* expression, const HLSLType* const HLSLType* dstType2 = NULL; // - bool vectorExpression = isVectorType( binaryExpression->expression1->expressionType ) || isVectorType( binaryExpression->expression2->expressionType ); - if( vectorExpression && isCompareOp( binaryExpression->binaryOp )) + bool vectorExpression = IsVectorType( binaryExpression->expression1->expressionType ) || IsVectorType( binaryExpression->expression2->expressionType ); + if( vectorExpression && IsCompareOp( binaryExpression->binaryOp )) { switch (binaryExpression->binaryOp) { @@ -588,9 +586,9 @@ void GLSLGenerator::OutputExpression(HLSLExpression* expression, const HLSLType* ASSERT(0); // is so, check isCompareOp } - if( isVectorType( binaryExpression->expression1->expressionType ) && isScalarType( binaryExpression->expression2->expressionType ) ) + if( IsVectorType( binaryExpression->expression1->expressionType ) && IsScalarType( binaryExpression->expression2->expressionType ) ) dstType2 = &binaryExpression->expression1->expressionType; - else if( isScalarType( binaryExpression->expression1->expressionType ) && isVectorType( binaryExpression->expression2->expressionType ) ) + else if( IsScalarType( binaryExpression->expression1->expressionType ) && IsVectorType( binaryExpression->expression2->expressionType ) ) dstType1 = &binaryExpression->expression2->expressionType; // TODO if both expressions are vector but with different dimension handle it here or in parser? @@ -621,8 +619,8 @@ void GLSLGenerator::OutputExpression(HLSLExpression* expression, const HLSLType* case HLSLBinaryOp_And: op = " && "; dstType1 = dstType2 = &binaryExpression->expressionType; break; case HLSLBinaryOp_Or: op = " || "; dstType1 = dstType2 = &binaryExpression->expressionType; break; case HLSLBinaryOp_BitAnd: op = " & "; dstType1 = dstType2 = commonScalarType(binaryExpression->expression1->expressionType, binaryExpression->expression2->expressionType); break; - case HLSLBinaryOp_BitOr: op = " | "; dstType1 = dstType2 = commonScalarType(binaryExpression->expression1->expressionType, binaryExpression->expression2->expressionType); break; - case HLSLBinaryOp_BitXor: op = " ^ "; dstType1 = dstType2 = commonScalarType(binaryExpression->expression1->expressionType, binaryExpression->expression2->expressionType); break; + case HLSLBinaryOp_BitOr: op = " | "; dstType1 = dstType2 = commonScalarType(binaryExpression->expression1->expressionType, binaryExpression->expression2->expressionType); break; + case HLSLBinaryOp_BitXor: op = " ^ "; dstType1 = dstType2 = commonScalarType(binaryExpression->expression1->expressionType, binaryExpression->expression2->expressionType); break; default: ASSERT(0); } @@ -636,7 +634,7 @@ void GLSLGenerator::OutputExpression(HLSLExpression* expression, const HLSLType* else if (expression->nodeType == HLSLNodeType_ConditionalExpression) { HLSLConditionalExpression* conditionalExpression = static_cast(expression); - if( isVectorType( conditionalExpression->condition->expressionType ) ) + if( IsVectorType( conditionalExpression->condition->expressionType ) ) { m_writer.Write( "%s", m_bvecTernary ); m_writer.Write( "( " ); diff --git a/src/libprojectM/Renderer/hlslparser/src/GLSLGenerator.h b/src/libprojectM/Renderer/hlslparser/src/GLSLGenerator.h old mode 100644 new mode 100755 diff --git a/src/libprojectM/Renderer/hlslparser/src/HLSLGenerator.cpp b/src/libprojectM/Renderer/hlslparser/src/HLSLGenerator.cpp old mode 100644 new mode 100755 index 7bb34e113..57123b669 --- a/src/libprojectM/Renderer/hlslparser/src/HLSLGenerator.cpp +++ b/src/libprojectM/Renderer/hlslparser/src/HLSLGenerator.cpp @@ -32,15 +32,15 @@ static const char* GetTypeName(const HLSLType& type) case HLSLBaseType_Float4x4: return "float4x4"; case HLSLBaseType_Float4x3: return "float4x3"; case HLSLBaseType_Float4x2: return "float4x2"; - case HLSLBaseType_Half: return "half"; - case HLSLBaseType_Half2: return "half2"; - case HLSLBaseType_Half3: return "half3"; - case HLSLBaseType_Half4: return "half4"; - case HLSLBaseType_Half2x2: return "half2x2"; - case HLSLBaseType_Half3x3: return "half3x3"; - case HLSLBaseType_Half4x4: return "half4x4"; - case HLSLBaseType_Half4x3: return "half4x3"; - case HLSLBaseType_Half4x2: return "half4x2"; + case HLSLBaseType_Half: return "float"; + case HLSLBaseType_Half2: return "float2"; + case HLSLBaseType_Half3: return "float3"; + case HLSLBaseType_Half4: return "float4"; + case HLSLBaseType_Half2x2: return "float2x2"; + case HLSLBaseType_Half3x3: return "float3x3"; + case HLSLBaseType_Half4x4: return "float4x4"; + case HLSLBaseType_Half4x3: return "float4x3"; + case HLSLBaseType_Half4x2: return "float4x2"; case HLSLBaseType_Bool: return "bool"; case HLSLBaseType_Bool2: return "bool2"; case HLSLBaseType_Bool3: return "bool3"; @@ -750,6 +750,8 @@ void HLSLGenerator::OutputArguments(HLSLArgument* argument) case HLSLArgumentModifier_Uniform: m_writer.Write("uniform "); break; + default: + break; } const char * semantic = argument->sv_semantic ? argument->sv_semantic : argument->semantic; diff --git a/src/libprojectM/Renderer/hlslparser/src/HLSLGenerator.h b/src/libprojectM/Renderer/hlslparser/src/HLSLGenerator.h old mode 100644 new mode 100755 diff --git a/src/libprojectM/Renderer/hlslparser/src/HLSLParser.cpp b/src/libprojectM/Renderer/hlslparser/src/HLSLParser.cpp old mode 100644 new mode 100755 index 892e28e3d..d61738c99 --- a/src/libprojectM/Renderer/hlslparser/src/HLSLParser.cpp +++ b/src/libprojectM/Renderer/hlslparser/src/HLSLParser.cpp @@ -27,6 +27,7 @@ enum CompareFunctionsResult Function2Better }; + /** This structure stores a HLSLFunction-like declaration for an intrinsic function */ struct Intrinsic { @@ -93,6 +94,14 @@ struct Intrinsic HLSLFunction function; HLSLArgument argument[4]; }; + +Intrinsic SamplerIntrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType arg1, HLSLBaseType samplerType, HLSLBaseType arg2) +{ + Intrinsic i(name, returnType, arg1, arg2); + i.argument[0].type.samplerType = samplerType; + return i; +} + enum NumericType { @@ -411,15 +420,25 @@ struct BaseTypeDescription #define INTRINSIC_FLOAT3_FUNCTION(name) \ Intrinsic( name, HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float ), \ - Intrinsic( name, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float, HLSLBaseType_Float2 ), \ - Intrinsic( name, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float, HLSLBaseType_Float3 ), \ - Intrinsic( name, HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float, HLSLBaseType_Float4 ), \ + Intrinsic( name, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2 ), \ + Intrinsic( name, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3 ), \ + Intrinsic( name, HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4 ), \ Intrinsic( name, HLSLBaseType_Half, HLSLBaseType_Half, HLSLBaseType_Half, HLSLBaseType_Half ), \ - Intrinsic( name, HLSLBaseType_Half2, HLSLBaseType_Half2, HLSLBaseType_Half2, HLSLBaseType_Half2 ), \ - Intrinsic( name, HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3 ), \ + Intrinsic( name, HLSLBaseType_Half2, HLSLBaseType_Half2, HLSLBaseType_Half2, HLSLBaseType_Half2 ), \ + Intrinsic( name, HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3, HLSLBaseType_Half3 ), \ Intrinsic( name, HLSLBaseType_Half4, HLSLBaseType_Half4, HLSLBaseType_Half4, HLSLBaseType_Half4 ) -const Intrinsic _intrinsic[] = +#if 0 +// @@ IC: For some reason this is not working with the Visual Studio compiler: +#define SAMPLER_INTRINSIC_FUNCTION(name, sampler, arg1) \ + SamplerIntrinsic( name, HLSLBaseType_Float4, sampler, HLSLBaseType_Float, arg1), \ + SamplerIntrinsic( name, HLSLBaseType_Half4, sampler, HLSLBaseType_Half, arg1 ) +#else +#define SAMPLER_INTRINSIC_FUNCTION(name, sampler, arg1) \ + Intrinsic( name, HLSLBaseType_Float4, sampler, arg1) +#endif + +const Intrinsic _intrinsic[] = { INTRINSIC_FLOAT1_FUNCTION( "abs" ), INTRINSIC_FLOAT1_FUNCTION( "acos" ), @@ -521,6 +540,9 @@ const Intrinsic _intrinsic[] = Intrinsic( "transpose", HLSLBaseType_Float2x2, HLSLBaseType_Float2x2 ), Intrinsic( "transpose", HLSLBaseType_Float3x3, HLSLBaseType_Float3x3 ), Intrinsic( "transpose", HLSLBaseType_Float4x4, HLSLBaseType_Float4x4 ), + Intrinsic( "transpose", HLSLBaseType_Half2x2, HLSLBaseType_Half2x2 ), + Intrinsic( "transpose", HLSLBaseType_Half3x3, HLSLBaseType_Half3x3 ), + Intrinsic( "transpose", HLSLBaseType_Half4x4, HLSLBaseType_Half4x4 ), INTRINSIC_FLOAT1_FUNCTION( "normalize" ), INTRINSIC_FLOAT2_FUNCTION( "pow" ), @@ -545,11 +567,17 @@ const Intrinsic _intrinsic[] = INTRINSIC_FLOAT1_FUNCTION("isinf"), Intrinsic("asuint", HLSLBaseType_Uint, HLSLBaseType_Float), - Intrinsic("tex2D", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float2), + + SAMPLER_INTRINSIC_FUNCTION("tex2D", HLSLBaseType_Sampler2D, HLSLBaseType_Float2), + Intrinsic("tex2Dproj", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float4), - Intrinsic("tex2Dlod", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float4), + + SAMPLER_INTRINSIC_FUNCTION("tex2Dlod", HLSLBaseType_Sampler2D, HLSLBaseType_Float4), + Intrinsic("tex2Dlod", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float4, HLSLBaseType_Int2), // With offset. - Intrinsic("tex2Dbias", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float4), + + SAMPLER_INTRINSIC_FUNCTION("tex2Dbias", HLSLBaseType_Sampler2D, HLSLBaseType_Float4), + Intrinsic("tex2Dgrad", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2), Intrinsic("tex2Dgather", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float2, HLSLBaseType_Int), Intrinsic("tex2Dgather", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float2, HLSLBaseType_Int2, HLSLBaseType_Int), // With offset. @@ -624,7 +652,7 @@ const BaseTypeDescription _baseTypeDescriptions[HLSLBaseType_Count] = { "half2", NumericType_Half, 2, 1, 1, 1 }, // HLSLBaseType_Half2 { "half3", NumericType_Half, 3, 1, 1, 1 }, // HLSLBaseType_Half3 { "half4", NumericType_Half, 4, 1, 1, 1 }, // HLSLBaseType_Half4 - { "half2x2", NumericType_Float, 2, 2, 2, 0 }, // HLSLBaseType_Half2x2 + { "half2x2", NumericType_Float, 2, 2, 2, 0 }, // HLSLBaseType_Half2x2 { "half3x3", NumericType_Half, 3, 2, 3, 1 }, // HLSLBaseType_Half3x3 { "half4x4", NumericType_Half, 4, 2, 4, 1 }, // HLSLBaseType_Half4x4 { "half4x3", NumericType_Half, 4, 2, 3, 1 }, // HLSLBaseType_Half4x3 @@ -653,7 +681,8 @@ const BaseTypeDescription _baseTypeDescriptions[HLSLBaseType_Count] = { "sampler2DShadow", NumericType_NaN, 1, 0, 0, -1 }, // HLSLBaseType_Sampler2DShadow { "sampler2DMS", NumericType_NaN, 1, 0, 0, -1 }, // HLSLBaseType_Sampler2DMS { "sampler2DArray", NumericType_NaN, 1, 0, 0, -1 }, // HLSLBaseType_Sampler2DArray - { "user defined", NumericType_NaN, 1, 0, 0, -1 } // HLSLBaseType_UserDefined + { "user defined", NumericType_NaN, 1, 0, 0, -1 }, // HLSLBaseType_UserDefined + { "expression", NumericType_NaN, 1, 0, 0, -1 } // HLSLBaseType_Expression }; // IC: I'm not sure this table is right, but any errors should be caught by the backend compiler. @@ -960,6 +989,11 @@ static int GetTypeCastRank(HLSLTree * tree, const HLSLType& srcType, const HLSLT if (srcType.baseType == dstType.baseType) { + if (IsSamplerType(srcType.baseType)) + { + return srcType.samplerType == dstType.samplerType ? 0 : -1; + } + return 0; } @@ -1254,9 +1288,10 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) int line = GetLineNumber(); const char* fileName = GetFileName(); - HLSLBaseType type; - const char* typeName = NULL; - int typeFlags = false; + HLSLType type; + //HLSLBaseType type; + //const char* typeName = NULL; + //int typeFlags = false; bool doesNotExpectSemicolon = false; @@ -1367,7 +1402,7 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) statement = buffer; } - else if (AcceptType(true, type, typeName, &typeFlags)) + else if (AcceptType(true, type)) { // Global declaration (uniform or function). const char* globalName = NULL; @@ -1382,12 +1417,13 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) HLSLFunction* function = m_tree->AddNode(fileName, line); function->name = globalName; - function->returnType.baseType = type; - function->returnType.typeName = typeName; + function->returnType.baseType = type.baseType; + function->returnType.typeName = type.typeName; + function->attributes = attributes; BeginScope(); - if (!ParseArgumentList(function->argument, function->numArguments)) + if (!ParseArgumentList(function->argument, function->numArguments, function->numOutputArguments)) { return false; } @@ -1437,6 +1473,7 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) // Note, no semi-colon at the end of a function declaration. statement = function; + return true; } else @@ -1444,8 +1481,7 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) // Uniform declaration. HLSLDeclaration* declaration = m_tree->AddNode(fileName, line); declaration->name = globalName; - declaration->type.baseType = type; - declaration->type.flags = typeFlags; + declaration->type = type; // Handle array syntax. if (Accept('[')) @@ -1502,22 +1538,31 @@ bool HLSLParser::ParseTopLevel(HLSLStatement*& statement) return doesNotExpectSemicolon || Expect(';'); } -bool HLSLParser::ParseStatementOrBlock(HLSLStatement*& firstStatement, const HLSLType& returnType) +bool HLSLParser::ParseStatementOrBlock(HLSLStatement*& firstStatement, const HLSLType& returnType, bool scoped/*=true*/) { - if (Accept('{')) + if (scoped) { BeginScope(); + } + if (Accept('{')) + { if (!ParseBlock(firstStatement, returnType)) { return false; } - EndScope(); - return true; } else { - return ParseStatement(firstStatement, returnType); + if (!ParseStatement(firstStatement, returnType)) + { + return false; + } } + if (scoped) + { + EndScope(); + } + return true; } bool HLSLParser::ParseBlock(HLSLStatement*& firstStatement, const HLSLType& returnType) @@ -1545,6 +1590,7 @@ bool HLSLParser::ParseBlock(HLSLStatement*& firstStatement, const HLSLType& retu lastStatement->nextStatement = statement; } lastStatement = statement; + while (lastStatement->nextStatement) lastStatement = lastStatement->nextStatement; } } return true; @@ -1564,6 +1610,74 @@ bool HLSLParser::ParseStatement(HLSLStatement*& statement, const HLSLType& retur HLSLAttribute * attributes = NULL; ParseAttributeBlock(attributes); // @@ Leak if not assigned to node? +#if 0 // @@ Work in progress. + // Static statements: @if only for now. + if (Accept('@')) + { + if (Accept(HLSLToken_If)) + { + //HLSLIfStatement* ifStatement = m_tree->AddNode(fileName, line); + //ifStatement->isStatic = true; + //ifStatement->attributes = attributes; + + HLSLExpression * condition = NULL; + + m_allowUndeclaredIdentifiers = true; // Not really correct... better to push to stack? + if (!Expect('(') || !ParseExpression(condition) || !Expect(')')) + { + m_allowUndeclaredIdentifiers = false; + return false; + } + m_allowUndeclaredIdentifiers = false; + + if ((condition->expressionType.flags & HLSLTypeFlag_Const) == 0) + { + m_tokenizer.Error("Syntax error: @if condition is not constant"); + return false; + } + + int conditionValue; + if (!m_tree->GetExpressionValue(condition, conditionValue)) + { + m_tokenizer.Error("Syntax error: Cannot evaluate @if condition"); + return false; + } + + if (!conditionValue) m_disableSemanticValidation = true; + + HLSLStatement * ifStatements = NULL; + HLSLStatement * elseStatements = NULL; + + if (!ParseStatementOrBlock(ifStatements, returnType, /*scoped=*/false)) + { + m_disableSemanticValidation = false; + return false; + } + if (Accept(HLSLToken_Else)) + { + if (conditionValue) m_disableSemanticValidation = true; + + if (!ParseStatementOrBlock(elseStatements, returnType, /*scoped=*/false)) + { + m_disableSemanticValidation = false; + return false; + } + } + m_disableSemanticValidation = false; + + if (conditionValue) statement = ifStatements; + else statement = elseStatements; + + // @@ Free the pruned statements? + + return true; + } + else { + m_tokenizer.Error("Syntax error: unexpected token '@'"); + } + } +#endif + // If statement. if (Accept(HLSLToken_If)) { @@ -1584,7 +1698,7 @@ bool HLSLParser::ParseStatement(HLSLStatement*& statement, const HLSLType& retur } return true; } - + // For statement. if (Accept(HLSLToken_For)) { @@ -1708,7 +1822,7 @@ bool HLSLParser::ParseDeclaration(HLSLDeclaration*& declaration) int line = GetLineNumber(); HLSLType type; - if (!AcceptType(/*allowVoid=*/false, type.baseType, type.typeName, &type.flags)) + if (!AcceptType(/*allowVoid=*/false, type)) { return false; } @@ -2018,6 +2132,10 @@ bool HLSLParser::ParseBinaryExpression(int priority, HLSLExpression*& expression return false; } + + // Propagate constness. + binaryExpression->expressionType.flags = (expression->expressionType.flags | expression2->expressionType.flags) & HLSLTypeFlag_Const; + expression = binaryExpression; } else if (_conditionalOpPriority > priority && Accept('?')) @@ -2112,6 +2230,9 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need if (unaryOp == HLSLUnaryOp_Not) { unaryExpression->expressionType = HLSLType(HLSLBaseType_Bool); + + // Propagate constness. + unaryExpression->expressionType.flags = unaryExpression->expression->expressionType.flags & HLSLTypeFlag_Const; } else { @@ -2126,7 +2247,7 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need { // Check for a casting operator. HLSLType type; - if (AcceptType(false, type.baseType, type.typeName, &type.flags)) + if (AcceptType(false, type)) { // This is actually a type constructor like (float2(... if (Accept('(')) @@ -2204,25 +2325,25 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need } // Type constructor. - HLSLBaseType type; - const char* typeName = NULL; - if (AcceptType(/*allowVoid=*/false, type, typeName, NULL)) + HLSLType type; + if (AcceptType(/*allowVoid=*/false, type)) { Expect('('); - if (!ParsePartialConstructor(expression, type, typeName)) + if (!ParsePartialConstructor(expression, type.baseType, type.typeName)) { return false; } } else { - HLSLIdentifierExpression* identifierExpression = m_tree->AddNode(fileName, line); if (!ExpectIdentifier(identifierExpression->name)) { return false; } + bool undeclaredIdentifier = false; + const HLSLType* identifierType = FindVariable(identifierExpression->name, identifierExpression->global); if (identifierType != NULL) { @@ -2230,16 +2351,37 @@ bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, bool& need } else { - if (!GetIsFunction(identifierExpression->name)) + if (GetIsFunction(identifierExpression->name)) + { + // Functions are always global scope. + identifierExpression->global = true; + } + else + { + undeclaredIdentifier = true; + } + } + + if (undeclaredIdentifier) + { + if (m_allowUndeclaredIdentifiers) + { + HLSLLiteralExpression* literalExpression = m_tree->AddNode(fileName, line); + literalExpression->bValue = false; + literalExpression->type = HLSLBaseType_Bool; + literalExpression->expressionType.baseType = literalExpression->type; + literalExpression->expressionType.flags = HLSLTypeFlag_Const; + expression = literalExpression; + } + else { m_tokenizer.Error("Undeclared identifier '%s'", identifierExpression->name); return false; } - // Functions are always global scope. - identifierExpression->global = true; } - - expression = identifierExpression; + else { + expression = identifierExpression; + } } } @@ -2432,7 +2574,7 @@ bool HLSLParser::ParseExpressionList(int endToken, bool allowEmptyEnd, HLSLExpre return true; } -bool HLSLParser::ParseArgumentList(HLSLArgument*& firstArgument, int& numArguments) +bool HLSLParser::ParseArgumentList(HLSLArgument*& firstArgument, int& numArguments, int& numOutputArguments) { const char* fileName = GetFileName(); int line = GetLineNumber(); @@ -2489,6 +2631,10 @@ bool HLSLParser::ParseArgumentList(HLSLArgument*& firstArgument, int& numArgumen lastArgument = argument; ++numArguments; + if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) + { + ++numOutputArguments; + } } return true; } @@ -2950,6 +3096,7 @@ bool HLSLParser::ParseAttributeList(HLSLAttribute*& firstAttribute) if (strcmp(identifier, "unroll") == 0) attribute->attributeType = HLSLAttributeType_Unroll; else if (strcmp(identifier, "flatten") == 0) attribute->attributeType = HLSLAttributeType_Flatten; else if (strcmp(identifier, "branch") == 0) attribute->attributeType = HLSLAttributeType_Branch; + else if (strcmp(identifier, "nofastmath") == 0) attribute->attributeType = HLSLAttributeType_NoFastMath; // @@ parse arguments, () not required if attribute constructor has no arguments. @@ -3066,6 +3213,7 @@ bool HLSLParser::Parse(HLSLTree* tree) lastStatement->nextStatement = statement; } lastStatement = statement; + while (lastStatement->nextStatement) lastStatement = lastStatement->nextStatement; } } return true; @@ -3140,143 +3288,172 @@ bool HLSLParser::AcceptInterpolationModifier(int& flags) } -bool HLSLParser::AcceptType(bool allowVoid, HLSLBaseType& type, const char*& typeName, int* typeFlags) +bool HLSLParser::AcceptType(bool allowVoid, HLSLType& type/*, bool acceptFlags*/) { - if (typeFlags != NULL) { - *typeFlags = 0; - while(AcceptTypeModifier(*typeFlags) || AcceptInterpolationModifier(*typeFlags)) {} + //if (type.flags != NULL) + { + type.flags = 0; + while(AcceptTypeModifier(type.flags) || AcceptInterpolationModifier(type.flags)) {} } int token = m_tokenizer.GetToken(); // Check built-in types. - type = HLSLBaseType_Void; + type.baseType = HLSLBaseType_Void; switch (token) { case HLSLToken_Float: - type = HLSLBaseType_Float; + type.baseType = HLSLBaseType_Float; break; case HLSLToken_Float2: - type = HLSLBaseType_Float2; + type.baseType = HLSLBaseType_Float2; break; case HLSLToken_Float3: - type = HLSLBaseType_Float3; + type.baseType = HLSLBaseType_Float3; break; case HLSLToken_Float4: - type = HLSLBaseType_Float4; + type.baseType = HLSLBaseType_Float4; break; case HLSLToken_Float2x2: - type = HLSLBaseType_Float2x2; + type.baseType = HLSLBaseType_Float2x2; break; case HLSLToken_Float3x3: - type = HLSLBaseType_Float3x3; + type.baseType = HLSLBaseType_Float3x3; break; case HLSLToken_Float4x4: - type = HLSLBaseType_Float4x4; + type.baseType = HLSLBaseType_Float4x4; break; case HLSLToken_Float4x3: - type = HLSLBaseType_Float4x3; + type.baseType = HLSLBaseType_Float4x3; break; case HLSLToken_Float4x2: - type = HLSLBaseType_Float4x2; + type.baseType = HLSLBaseType_Float4x2; break; case HLSLToken_Half: - type = HLSLBaseType_Half; + type.baseType = HLSLBaseType_Half; break; case HLSLToken_Half2: - type = HLSLBaseType_Half2; + type.baseType = HLSLBaseType_Half2; break; case HLSLToken_Half3: - type = HLSLBaseType_Half3; + type.baseType = HLSLBaseType_Half3; break; case HLSLToken_Half4: - type = HLSLBaseType_Half4; + type.baseType = HLSLBaseType_Half4; break; case HLSLToken_Half2x2: - type = HLSLBaseType_Half2x2; + type.baseType = HLSLBaseType_Half2x2; break; case HLSLToken_Half3x3: - type = HLSLBaseType_Half3x3; + type.baseType = HLSLBaseType_Half3x3; break; case HLSLToken_Half4x4: - type = HLSLBaseType_Half4x4; + type.baseType = HLSLBaseType_Half4x4; break; case HLSLToken_Half4x3: - type = HLSLBaseType_Half4x3; + type.baseType = HLSLBaseType_Half4x3; break; case HLSLToken_Half4x2: - type = HLSLBaseType_Half4x2; + type.baseType = HLSLBaseType_Half4x2; break; case HLSLToken_Bool: - type = HLSLBaseType_Bool; + type.baseType = HLSLBaseType_Bool; break; case HLSLToken_Bool2: - type = HLSLBaseType_Bool2; + type.baseType = HLSLBaseType_Bool2; break; case HLSLToken_Bool3: - type = HLSLBaseType_Bool3; + type.baseType = HLSLBaseType_Bool3; break; case HLSLToken_Bool4: - type = HLSLBaseType_Bool4; + type.baseType = HLSLBaseType_Bool4; break; case HLSLToken_Int: - type = HLSLBaseType_Int; + type.baseType = HLSLBaseType_Int; break; case HLSLToken_Int2: - type = HLSLBaseType_Int2; + type.baseType = HLSLBaseType_Int2; break; case HLSLToken_Int3: - type = HLSLBaseType_Int3; + type.baseType = HLSLBaseType_Int3; break; case HLSLToken_Int4: - type = HLSLBaseType_Int4; + type.baseType = HLSLBaseType_Int4; break; case HLSLToken_Uint: - type = HLSLBaseType_Uint; + type.baseType = HLSLBaseType_Uint; break; case HLSLToken_Uint2: - type = HLSLBaseType_Uint2; + type.baseType = HLSLBaseType_Uint2; break; case HLSLToken_Uint3: - type = HLSLBaseType_Uint3; + type.baseType = HLSLBaseType_Uint3; break; case HLSLToken_Uint4: - type = HLSLBaseType_Uint4; + type.baseType = HLSLBaseType_Uint4; break; case HLSLToken_Texture: - type = HLSLBaseType_Texture; + type.baseType = HLSLBaseType_Texture; break; case HLSLToken_Sampler: - type = HLSLBaseType_Sampler2D; // @@ IC: For now we assume that generic samplers are always sampler2D + type.baseType = HLSLBaseType_Sampler2D; // @@ IC: For now we assume that generic samplers are always sampler2D break; case HLSLToken_Sampler2D: - type = HLSLBaseType_Sampler2D; + type.baseType = HLSLBaseType_Sampler2D; break; case HLSLToken_Sampler3D: - type = HLSLBaseType_Sampler3D; + type.baseType = HLSLBaseType_Sampler3D; break; case HLSLToken_SamplerCube: - type = HLSLBaseType_SamplerCube; + type.baseType = HLSLBaseType_SamplerCube; break; case HLSLToken_Sampler2DShadow: - type = HLSLBaseType_Sampler2DShadow; + type.baseType = HLSLBaseType_Sampler2DShadow; break; case HLSLToken_Sampler2DMS: - type = HLSLBaseType_Sampler2DMS; + type.baseType = HLSLBaseType_Sampler2DMS; break; case HLSLToken_Sampler2DArray: - type = HLSLBaseType_Sampler2DArray; + type.baseType = HLSLBaseType_Sampler2DArray; break; } - if (type != HLSLBaseType_Void) + if (type.baseType != HLSLBaseType_Void) { m_tokenizer.Next(); + + if (IsSamplerType(type.baseType)) + { + // Parse optional sampler type. + if (Accept('<')) + { + int token = m_tokenizer.GetToken(); + if (token == HLSLToken_Float) + { + type.samplerType = HLSLBaseType_Float; + } + else if (token == HLSLToken_Half) + { + type.samplerType = HLSLBaseType_Half; + } + else + { + m_tokenizer.Error("Expected half or float."); + return false; + } + m_tokenizer.Next(); + + if (!Expect('>')) + { + return false; + } + } + } return true; } if (allowVoid && Accept(HLSLToken_Void)) { - type = HLSLBaseType_Void; + type.baseType = HLSLBaseType_Void; return true; } if (token == HLSLToken_Identifier) @@ -3285,17 +3462,17 @@ bool HLSLParser::AcceptType(bool allowVoid, HLSLBaseType& type, const char*& typ if (FindUserDefinedType(identifier) != NULL) { m_tokenizer.Next(); - type = HLSLBaseType_UserDefined; - typeName = identifier; + type.baseType = HLSLBaseType_UserDefined; + type.typeName = identifier; return true; } } return false; } -bool HLSLParser::ExpectType(bool allowVoid, HLSLBaseType& type, const char*& typeName, int* typeFlags) +bool HLSLParser::ExpectType(bool allowVoid, HLSLType& type) { - if (!AcceptType(allowVoid, type, typeName, typeFlags)) + if (!AcceptType(allowVoid, type)) { m_tokenizer.Error("Expected type"); return false; @@ -3305,7 +3482,7 @@ bool HLSLParser::ExpectType(bool allowVoid, HLSLBaseType& type, const char*& typ bool HLSLParser::AcceptDeclaration(bool allowUnsizedArray, HLSLType& type, const char*& name) { - if (!AcceptType(/*allowVoid=*/false, type.baseType, type.typeName, &type.flags)) + if (!AcceptType(/*allowVoid=*/false, type)) { return false; } diff --git a/src/libprojectM/Renderer/hlslparser/src/HLSLParser.h b/src/libprojectM/Renderer/hlslparser/src/HLSLParser.h old mode 100644 new mode 100755 index 6030e39f0..f08791b41 --- a/src/libprojectM/Renderer/hlslparser/src/HLSLParser.h +++ b/src/libprojectM/Renderer/hlslparser/src/HLSLParser.h @@ -49,8 +49,8 @@ private: bool AcceptFloat(float& value); bool AcceptHalf( float& value ); bool AcceptInt(int& value); - bool AcceptType(bool allowVoid, HLSLBaseType& type, const char*& typeName, int* typeFlags); - bool ExpectType(bool allowVoid, HLSLBaseType& type, const char*& typeName, int* typeFlags); + bool AcceptType(bool allowVoid, HLSLType& type); + bool ExpectType(bool allowVoid, HLSLType& type); bool AcceptBinaryOperator(int priority, HLSLBinaryOp& binaryOp); bool AcceptUnaryOperator(bool pre, HLSLUnaryOp& unaryOp); bool AcceptAssign(HLSLBinaryOp& binaryOp); @@ -66,7 +66,7 @@ private: bool ParseTopLevel(HLSLStatement*& statement); bool ParseBlock(HLSLStatement*& firstStatement, const HLSLType& returnType); - bool ParseStatementOrBlock(HLSLStatement*& firstStatement, const HLSLType& returnType); + bool ParseStatementOrBlock(HLSLStatement*& firstStatement, const HLSLType& returnType, bool scoped = true); bool ParseStatement(HLSLStatement*& statement, const HLSLType& returnType); bool ParseDeclaration(HLSLDeclaration*& declaration); bool ParseFieldDeclaration(HLSLStructField*& field); @@ -75,7 +75,7 @@ private: bool ParseBinaryExpression(int priority, HLSLExpression*& expression); bool ParseTerminalExpression(HLSLExpression*& expression, bool& needsEndParen); bool ParseExpressionList(int endToken, bool allowEmptyEnd, HLSLExpression*& firstExpression, int& numExpressions); - bool ParseArgumentList(HLSLArgument*& firstArgument, int& numArguments); + bool ParseArgumentList(HLSLArgument*& firstArgument, int& numArguments, int& numOutputArguments); bool ParseDeclarationAssignment(HLSLDeclaration* declaration); bool ParsePartialConstructor(HLSLExpression*& expression, HLSLBaseType type, const char* typeName); @@ -135,8 +135,11 @@ private: int m_numGlobals; HLSLTree* m_tree; + + bool m_allowUndeclaredIdentifiers = false; + bool m_disableSemanticValidation = false; }; } -#endif \ No newline at end of file +#endif diff --git a/src/libprojectM/Renderer/hlslparser/src/HLSLTokenizer.cpp b/src/libprojectM/Renderer/hlslparser/src/HLSLTokenizer.cpp old mode 100644 new mode 100755 index 72127ef90..826810d12 --- a/src/libprojectM/Renderer/hlslparser/src/HLSLTokenizer.cpp +++ b/src/libprojectM/Renderer/hlslparser/src/HLSLTokenizer.cpp @@ -99,6 +99,7 @@ static bool GetIsSymbol(char c) case '.': case '<': case '>': case '|': case '&': case '^': case '~': + case '@': return true; } return false; @@ -228,7 +229,6 @@ void HLSLTokenizer::Next() } // Must be an identifier or a reserved word. - while (m_buffer < m_bufferEnd && m_buffer[0] != 0 && !GetIsSymbol(m_buffer[0]) && !isspace(m_buffer[0])) { ++m_buffer; @@ -237,7 +237,7 @@ void HLSLTokenizer::Next() size_t length = m_buffer - start; memcpy(m_identifier, start, length); m_identifier[length] = 0; - + const int numReservedWords = sizeof(_reservedWords) / sizeof(const char*); for (int i = 0; i < numReservedWords; ++i) { @@ -623,7 +623,7 @@ void HLSLTokenizer::GetTokenName(int token, char buffer[s_maxIdentifier]) break; case HLSLToken_EndOfStream: strcpy(buffer, ""); - break; + break; default: strcpy(buffer, "unknown"); break; diff --git a/src/libprojectM/Renderer/hlslparser/src/HLSLTokenizer.h b/src/libprojectM/Renderer/hlslparser/src/HLSLTokenizer.h old mode 100644 new mode 100755 index 33ea9241d..2e1642ddc --- a/src/libprojectM/Renderer/hlslparser/src/HLSLTokenizer.h +++ b/src/libprojectM/Renderer/hlslparser/src/HLSLTokenizer.h @@ -92,7 +92,7 @@ enum HLSLToken HLSLToken_DivideEqual, HLSLToken_AndAnd, // && HLSLToken_BarBar, // || - + // Other token types. HLSLToken_FloatLiteral, HLSLToken_HalfLiteral, @@ -169,4 +169,4 @@ private: } -#endif \ No newline at end of file +#endif diff --git a/src/libprojectM/Renderer/hlslparser/src/HLSLTree.cpp b/src/libprojectM/Renderer/hlslparser/src/HLSLTree.cpp old mode 100644 new mode 100755 index 428af06d2..3571dfdfe --- a/src/libprojectM/Renderer/hlslparser/src/HLSLTree.cpp +++ b/src/libprojectM/Renderer/hlslparser/src/HLSLTree.cpp @@ -2,10 +2,105 @@ #include "Engine.h" #include "HLSLTree.h" +#include namespace M4 { +const HLSLTypeDimension BaseTypeDimension[HLSLBaseType_Count] = +{ + HLSLTypeDimension_None, // HLSLBaseType_Unknown, + HLSLTypeDimension_None, // HLSLBaseType_Void, + HLSLTypeDimension_Scalar, // HLSLBaseType_Float, + HLSLTypeDimension_Vector2, // HLSLBaseType_Float2, + HLSLTypeDimension_Vector3, // HLSLBaseType_Float3, + HLSLTypeDimension_Vector4, // HLSLBaseType_Float4, + HLSLTypeDimension_Matrix2x2,// HLSLBaseType_Float2x2, + HLSLTypeDimension_Matrix3x3,// HLSLBaseType_Float3x3, + HLSLTypeDimension_Matrix4x4,// HLSLBaseType_Float4x4, + HLSLTypeDimension_Matrix4x3,// HLSLBaseType_Float4x3, + HLSLTypeDimension_Matrix4x2,// HLSLBaseType_Float4x2, + HLSLTypeDimension_Scalar, // HLSLBaseType_Half, + HLSLTypeDimension_Vector2, // HLSLBaseType_Half2, + HLSLTypeDimension_Vector3, // HLSLBaseType_Half3, + HLSLTypeDimension_Vector4, // HLSLBaseType_Half4, + HLSLTypeDimension_Matrix2x2,// HLSLBaseType_Half2x2, + HLSLTypeDimension_Matrix3x3,// HLSLBaseType_Half3x3, + HLSLTypeDimension_Matrix4x4,// HLSLBaseType_Half4x4, + HLSLTypeDimension_Matrix4x3,// HLSLBaseType_Half4x3, + HLSLTypeDimension_Matrix4x2,// HLSLBaseType_Half4x2, + HLSLTypeDimension_Scalar, // HLSLBaseType_Bool, + HLSLTypeDimension_Vector2, // HLSLBaseType_Bool2, + HLSLTypeDimension_Vector3, // HLSLBaseType_Bool3, + HLSLTypeDimension_Vector4, // HLSLBaseType_Bool4, + HLSLTypeDimension_Scalar, // HLSLBaseType_Int, + HLSLTypeDimension_Vector2, // HLSLBaseType_Int2, + HLSLTypeDimension_Vector3, // HLSLBaseType_Int3, + HLSLTypeDimension_Vector4, // HLSLBaseType_Int4, + HLSLTypeDimension_Scalar, // HLSLBaseType_Uint, + HLSLTypeDimension_Vector2, // HLSLBaseType_Uint2, + HLSLTypeDimension_Vector3, // HLSLBaseType_Uint3, + HLSLTypeDimension_Vector4, // HLSLBaseType_Uint4, + HLSLTypeDimension_None, // HLSLBaseType_Texture, + HLSLTypeDimension_None, // HLSLBaseType_Sampler, // @@ use type inference to determine sampler type. + HLSLTypeDimension_None, // HLSLBaseType_Sampler2D, + HLSLTypeDimension_None, // HLSLBaseType_Sampler3D, + HLSLTypeDimension_None, // HLSLBaseType_SamplerCube, + HLSLTypeDimension_None, // HLSLBaseType_Sampler2DShadow, + HLSLTypeDimension_None, // HLSLBaseType_Sampler2DMS, + HLSLTypeDimension_None, // HLSLBaseType_Sampler2DArray, + HLSLTypeDimension_None, // HLSLBaseType_UserDefined, // struct + HLSLTypeDimension_None, // HLSLBaseType_Expression, // type argument for defined() sizeof() and typeof(). + HLSLTypeDimension_None, // HLSLBaseType_Auto, +}; + +const HLSLBaseType ScalarBaseType[HLSLBaseType_Count] = { + HLSLBaseType_Unknown, // HLSLBaseType_Unknown, + HLSLBaseType_Void, // HLSLBaseType_Void, + HLSLBaseType_Float, // HLSLBaseType_Float, + HLSLBaseType_Float, // HLSLBaseType_Float2, + HLSLBaseType_Float, // HLSLBaseType_Float3, + HLSLBaseType_Float, // HLSLBaseType_Float4, + HLSLBaseType_Float, // HLSLBaseType_Float2x2, + HLSLBaseType_Float, // HLSLBaseType_Float3x3, + HLSLBaseType_Float, // HLSLBaseType_Float4x4, + HLSLBaseType_Float, // HLSLBaseType_Float4x3, + HLSLBaseType_Float, // HLSLBaseType_Float4x2, + HLSLBaseType_Half, // HLSLBaseType_Half, + HLSLBaseType_Half, // HLSLBaseType_Half2, + HLSLBaseType_Half, // HLSLBaseType_Half3, + HLSLBaseType_Half, // HLSLBaseType_Half4, + HLSLBaseType_Half, // HLSLBaseType_Half2x2, + HLSLBaseType_Half, // HLSLBaseType_Half3x3, + HLSLBaseType_Half, // HLSLBaseType_Half4x4, + HLSLBaseType_Half, // HLSLBaseType_Half4x3, + HLSLBaseType_Half, // HLSLBaseType_Half4x2, + HLSLBaseType_Bool, // HLSLBaseType_Bool, + HLSLBaseType_Bool, // HLSLBaseType_Bool2, + HLSLBaseType_Bool, // HLSLBaseType_Bool3, + HLSLBaseType_Bool, // HLSLBaseType_Bool4, + HLSLBaseType_Int, // HLSLBaseType_Int, + HLSLBaseType_Int, // HLSLBaseType_Int2, + HLSLBaseType_Int, // HLSLBaseType_Int3, + HLSLBaseType_Int, // HLSLBaseType_Int4, + HLSLBaseType_Uint, // HLSLBaseType_Uint, + HLSLBaseType_Uint, // HLSLBaseType_Uint2, + HLSLBaseType_Uint, // HLSLBaseType_Uint3, + HLSLBaseType_Uint, // HLSLBaseType_Uint4, + HLSLBaseType_Unknown, // HLSLBaseType_Texture, + HLSLBaseType_Unknown, // HLSLBaseType_Sampler, // @@ use type inference to determine sampler type. + HLSLBaseType_Unknown, // HLSLBaseType_Sampler2D, + HLSLBaseType_Unknown, // HLSLBaseType_Sampler3D, + HLSLBaseType_Unknown, // HLSLBaseType_SamplerCube, + HLSLBaseType_Unknown, // HLSLBaseType_Sampler2DShadow, + HLSLBaseType_Unknown, // HLSLBaseType_Sampler2DMS, + HLSLBaseType_Unknown, // HLSLBaseType_Sampler2DArray, + HLSLBaseType_Unknown, // HLSLBaseType_UserDefined, // struct + HLSLBaseType_Unknown, // HLSLBaseType_Expression, // type argument for defined() sizeof() and typeof(). + HLSLBaseType_Unknown, // HLSLBaseType_Auto, +}; + + HLSLTree::HLSLTree(Allocator* allocator) : m_allocator(allocator), m_stringPool(allocator) { @@ -634,6 +729,9 @@ void HLSLTreeVisitor::VisitTopLevelStatement(HLSLStatement * node) else if (node->nodeType == HLSLNodeType_Technique) { VisitTechnique((HLSLTechnique *)node); } + else if (node->nodeType == HLSLNodeType_Pipeline) { + VisitPipeline((HLSLPipeline *)node); + } else { ASSERT(0); } @@ -918,6 +1016,11 @@ void HLSLTreeVisitor::VisitTechnique(HLSLTechnique * node) } } +void HLSLTreeVisitor::VisitPipeline(HLSLPipeline * node) +{ + // @@ ? +} + void HLSLTreeVisitor::VisitFunctions(HLSLRoot * root) { HLSLStatement * statement = root->statement; @@ -1392,7 +1495,7 @@ public: VisitStatements(function->statement); return found; } - + virtual void VisitStatements(HLSLStatement * statement) override { while (statement != NULL && !found) @@ -1474,7 +1577,8 @@ bool EmulateAlphaTest(HLSLTree* tree, const char* entryName, float alphaRef/*=0. { alpha = returnStatement->expression; // @@ Is reference OK? Or should we clone expression? } - else { + else + { return false; } @@ -1505,5 +1609,356 @@ bool EmulateAlphaTest(HLSLTree* tree, const char* entryName, float alphaRef/*=0. return true; } +bool NeedsFlattening(HLSLExpression * expr, int level = 0) { + if (expr == NULL) { + return false; + } + if (expr->nodeType == HLSLNodeType_UnaryExpression) { + HLSLUnaryExpression * unaryExpr = (HLSLUnaryExpression *)expr; + return NeedsFlattening(unaryExpr->expression, level+1) || NeedsFlattening(expr->nextExpression, level); + } + else if (expr->nodeType == HLSLNodeType_BinaryExpression) { + HLSLBinaryExpression * binaryExpr = (HLSLBinaryExpression *)expr; + if (IsAssignOp(binaryExpr->binaryOp)) { + return NeedsFlattening(binaryExpr->expression2, level+1) || NeedsFlattening(expr->nextExpression, level); + } + else { + return NeedsFlattening(binaryExpr->expression1, level+1) || NeedsFlattening(binaryExpr->expression2, level+1) || NeedsFlattening(expr->nextExpression, level); + } + } + else if (expr->nodeType == HLSLNodeType_ConditionalExpression) { + HLSLConditionalExpression * conditionalExpr = (HLSLConditionalExpression *)expr; + return NeedsFlattening(conditionalExpr->condition, level+1) || NeedsFlattening(conditionalExpr->trueExpression, level+1) || NeedsFlattening(conditionalExpr->falseExpression, level+1) || NeedsFlattening(expr->nextExpression, level); + } + else if (expr->nodeType == HLSLNodeType_CastingExpression) { + HLSLCastingExpression * castingExpr = (HLSLCastingExpression *)expr; + return NeedsFlattening(castingExpr->expression, level+1) || NeedsFlattening(expr->nextExpression, level); + } + else if (expr->nodeType == HLSLNodeType_LiteralExpression) { + return NeedsFlattening(expr->nextExpression, level); + } + else if (expr->nodeType == HLSLNodeType_IdentifierExpression) { + return NeedsFlattening(expr->nextExpression, level); + } + else if (expr->nodeType == HLSLNodeType_ConstructorExpression) { + HLSLConstructorExpression * constructorExpr = (HLSLConstructorExpression *)expr; + return NeedsFlattening(constructorExpr->argument, level+1) || NeedsFlattening(expr->nextExpression, level); + } + else if (expr->nodeType == HLSLNodeType_MemberAccess) { + return NeedsFlattening(expr->nextExpression, level+1); + } + else if (expr->nodeType == HLSLNodeType_ArrayAccess) { + HLSLArrayAccess * arrayAccess = (HLSLArrayAccess *)expr; + return NeedsFlattening(arrayAccess->array, level+1) || NeedsFlattening(arrayAccess->index, level+1) || NeedsFlattening(expr->nextExpression, level); + } + else if (expr->nodeType == HLSLNodeType_FunctionCall) { + HLSLFunctionCall * functionCall = (HLSLFunctionCall *)expr; + if (functionCall->function->numOutputArguments > 0) { + if (level > 0) { + return true; + } + } + return NeedsFlattening(functionCall->argument, level+1) || NeedsFlattening(expr->nextExpression, level); + } + else { + //assert(false); + return false; + } +} + + +struct StatementList { + HLSLStatement * head = NULL; + HLSLStatement * tail = NULL; + void append(HLSLStatement * st) { + if (head == NULL) { + tail = head = st; + } + tail->nextStatement = st; + tail = st; + } +}; + + + class ExpressionFlattener : public HLSLTreeVisitor + { + public: + HLSLTree * m_tree; + int tmp_index; + HLSLStatement ** statement_pointer; + HLSLFunction * current_function; + + ExpressionFlattener() + { + m_tree = NULL; + tmp_index = 0; + statement_pointer = NULL; + current_function = NULL; + } + + void FlattenExpressions(HLSLTree * tree) + { + m_tree = tree; + VisitRoot(tree->GetRoot()); + } + + // Visit all statements updating the statement_pointer so that we can insert and replace statements. @@ Add this to the default visitor? + virtual void VisitFunction(HLSLFunction * node) override + { + current_function = node; + statement_pointer = &node->statement; + VisitStatements(node->statement); + statement_pointer = NULL; + current_function = NULL; + } + + virtual void VisitIfStatement(HLSLIfStatement * node) override + { + if (NeedsFlattening(node->condition, 1)) { + assert(false); // @@ Add statements before if statement. + } + + statement_pointer = &node->statement; + VisitStatements(node->statement); + if (node->elseStatement) { + statement_pointer = &node->elseStatement; + VisitStatements(node->elseStatement); + } + } + + virtual void VisitForStatement(HLSLForStatement * node) override + { + if (NeedsFlattening(node->initialization->assignment, 1)) { + assert(false); // @@ Add statements before for statement. + } + if (NeedsFlattening(node->condition, 1) || NeedsFlattening(node->increment, 1)) { + assert(false); // @@ These are tricky to implement. Need to handle all loop exits. + } + + statement_pointer = &node->statement; + VisitStatements(node->statement); + } + + virtual void VisitBlockStatement(HLSLBlockStatement * node) override + { + statement_pointer = &node->statement; + VisitStatements(node->statement); + } + + virtual void VisitStatements(HLSLStatement * statement) override + { + while (statement != NULL) { + VisitStatement(statement); + statement_pointer = &statement->nextStatement; + statement = statement->nextStatement; + } + } + + // This is usually a function call or assignment. + virtual void VisitExpressionStatement(HLSLExpressionStatement * node) override + { + if (NeedsFlattening(node->expression, 0)) + { + StatementList statements; + Flatten(node->expression, statements, false); + + // Link beginning of statement list. + *statement_pointer = statements.head; + + // Link end of statement list. + HLSLStatement * tail = statements.tail; + tail->nextStatement = node->nextStatement; + + // Update statement pointer. + statement_pointer = &tail->nextStatement; + + // @@ Delete node? + } + } + + virtual void VisitDeclaration(HLSLDeclaration * node) override + { + // Skip global declarations. + if (statement_pointer == NULL) return; + + if (NeedsFlattening(node->assignment, 1)) + { + StatementList statements; + HLSLIdentifierExpression * ident = Flatten(node->assignment, statements, true); + + // @@ Delete node->assignment? + + node->assignment = ident; + statements.append(node); + + // Link beginning of statement list. + *statement_pointer = statements.head; + + // Link end of statement list. + HLSLStatement * tail = statements.tail; + tail->nextStatement = node->nextStatement; + + // Update statement pointer. + statement_pointer = &tail->nextStatement; + } + } + + virtual void VisitReturnStatement(HLSLReturnStatement * node) override + { + if (NeedsFlattening(node->expression, 1)) + { + StatementList statements; + HLSLIdentifierExpression * ident = Flatten(node->expression, statements, true); + + // @@ Delete node->expression? + + node->expression = ident; + statements.append(node); + + // Link beginning of statement list. + *statement_pointer = statements.head; + + // Link end of statement list. + HLSLStatement * tail = statements.tail; + tail->nextStatement = node->nextStatement; + + // Update statement pointer. + statement_pointer = &tail->nextStatement; + } + } + + + HLSLDeclaration * BuildTemporaryDeclaration(HLSLExpression * expr) + { + assert(expr->expressionType.baseType != HLSLBaseType_Void); + + HLSLDeclaration * declaration = m_tree->AddNode(expr->fileName, expr->line); + declaration->name = m_tree->AddStringFormat("tmp%d", tmp_index++); + declaration->type = expr->expressionType; + declaration->assignment = expr; + + HLSLIdentifierExpression * ident = (HLSLIdentifierExpression *)expr; + + return declaration; + } + + HLSLExpressionStatement * BuildExpressionStatement(HLSLExpression * expr) + { + HLSLExpressionStatement * statement = m_tree->AddNode(expr->fileName, expr->line); + statement->expression = expr; + return statement; + } + + HLSLIdentifierExpression * AddExpressionStatement(HLSLExpression * expr, StatementList & statements, bool wantIdent) + { + if (wantIdent) { + HLSLDeclaration * declaration = BuildTemporaryDeclaration(expr); + statements.append(declaration); + + HLSLIdentifierExpression * ident = m_tree->AddNode(expr->fileName, expr->line); + ident->name = declaration->name; + ident->expressionType = declaration->type; + return ident; + } + else { + HLSLExpressionStatement * statement = BuildExpressionStatement(expr); + statements.append(statement); + return NULL; + } + } + + HLSLIdentifierExpression * Flatten(HLSLExpression * expr, StatementList & statements, bool wantIdent = true) + { + if (!NeedsFlattening(expr, wantIdent)) { + return AddExpressionStatement(expr, statements, wantIdent); + } + + if (expr->nodeType == HLSLNodeType_UnaryExpression) { + assert(expr->nextExpression == NULL); + + HLSLUnaryExpression * unaryExpr = (HLSLUnaryExpression *)expr; + + HLSLIdentifierExpression * tmp = Flatten(unaryExpr->expression, statements, true); + + HLSLUnaryExpression * newUnaryExpr = m_tree->AddNode(unaryExpr->fileName, unaryExpr->line); + newUnaryExpr->unaryOp = unaryExpr->unaryOp; + newUnaryExpr->expression = tmp; + newUnaryExpr->expressionType = unaryExpr->expressionType; + + return AddExpressionStatement(newUnaryExpr, statements, wantIdent); + } + else if (expr->nodeType == HLSLNodeType_BinaryExpression) { + assert(expr->nextExpression == NULL); + + HLSLBinaryExpression * binaryExpr = (HLSLBinaryExpression *)expr; + + if (IsAssignOp(binaryExpr->binaryOp)) { + // Flatten right hand side only. + HLSLIdentifierExpression * tmp2 = Flatten(binaryExpr->expression2, statements, true); + + HLSLBinaryExpression * newBinaryExpr = m_tree->AddNode(binaryExpr->fileName, binaryExpr->line); + newBinaryExpr->binaryOp = binaryExpr->binaryOp; + newBinaryExpr->expression1 = binaryExpr->expression1; + newBinaryExpr->expression2 = tmp2; + newBinaryExpr->expressionType = binaryExpr->expressionType; + + return AddExpressionStatement(newBinaryExpr, statements, wantIdent); + } + else { + HLSLIdentifierExpression * tmp1 = Flatten(binaryExpr->expression1, statements, true); + HLSLIdentifierExpression * tmp2 = Flatten(binaryExpr->expression2, statements, true); + + HLSLBinaryExpression * newBinaryExpr = m_tree->AddNode(binaryExpr->fileName, binaryExpr->line); + newBinaryExpr->binaryOp = binaryExpr->binaryOp; + newBinaryExpr->expression1 = tmp1; + newBinaryExpr->expression2 = tmp2; + newBinaryExpr->expressionType = binaryExpr->expressionType; + + return AddExpressionStatement(newBinaryExpr, statements, wantIdent); + } + } + else if (expr->nodeType == HLSLNodeType_ConditionalExpression) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_CastingExpression) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_LiteralExpression) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_IdentifierExpression) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_ConstructorExpression) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_MemberAccess) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_ArrayAccess) { + assert(false); + } + else if (expr->nodeType == HLSLNodeType_FunctionCall) { + HLSLFunctionCall * functionCall = (HLSLFunctionCall *)expr; + + // @@ Output function as is? + // @@ We have to flatten function arguments! This is tricky, need to handle input/output arguments. + assert(!NeedsFlattening(functionCall->argument)); + + return AddExpressionStatement(expr, statements, wantIdent); + } + else { + assert(false); + } + return NULL; + } + }; + + +void FlattenExpressions(HLSLTree* tree) { + ExpressionFlattener flattener; + flattener.FlattenExpressions(tree); +} + } // M4 diff --git a/src/libprojectM/Renderer/hlslparser/src/HLSLTree.h b/src/libprojectM/Renderer/hlslparser/src/HLSLTree.h old mode 100644 new mode 100755 index 9c51beda3..73c812e3c --- a/src/libprojectM/Renderer/hlslparser/src/HLSLTree.h +++ b/src/libprojectM/Renderer/hlslparser/src/HLSLTree.h @@ -47,6 +47,20 @@ enum HLSLNodeType HLSLNodeType_Stage, }; +enum HLSLTypeDimension +{ + HLSLTypeDimension_None, + HLSLTypeDimension_Scalar, + HLSLTypeDimension_Vector2, + HLSLTypeDimension_Vector3, + HLSLTypeDimension_Vector4, + HLSLTypeDimension_Matrix2x2, + HLSLTypeDimension_Matrix3x3, + HLSLTypeDimension_Matrix4x4, + HLSLTypeDimension_Matrix4x3, + HLSLTypeDimension_Matrix4x2 +}; + enum HLSLBaseType { HLSLBaseType_Unknown, @@ -83,6 +97,14 @@ enum HLSLBaseType HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4, + /*HLSLBaseType_Short, // @@ Separate dimension from Base type, this is getting out of control. + HLSLBaseType_Short2, + HLSLBaseType_Short3, + HLSLBaseType_Short4, + HLSLBaseType_Ushort, + HLSLBaseType_Ushort2, + HLSLBaseType_Ushort3, + HLSLBaseType_Ushort4,*/ HLSLBaseType_LastInteger = HLSLBaseType_Uint4, HLSLBaseType_LastNumeric = HLSLBaseType_Uint4, HLSLBaseType_Texture, @@ -94,10 +116,15 @@ enum HLSLBaseType HLSLBaseType_Sampler2DMS, HLSLBaseType_Sampler2DArray, HLSLBaseType_UserDefined, // struct + HLSLBaseType_Expression, // type argument for defined() sizeof() and typeof(). + HLSLBaseType_Auto, HLSLBaseType_Count, HLSLBaseType_NumericCount = HLSLBaseType_LastNumeric - HLSLBaseType_FirstNumeric + 1 }; + +extern const HLSLTypeDimension BaseTypeDimension[HLSLBaseType_Count]; +extern const HLSLBaseType ScalarBaseType[HLSLBaseType_Count]; inline bool IsSamplerType(HLSLBaseType baseType) { @@ -116,7 +143,7 @@ inline bool IsMatrixType(HLSLBaseType baseType) baseType == HLSLBaseType_Half3x3 || baseType == HLSLBaseType_Half4x4 || baseType == HLSLBaseType_Half4x3 || baseType == HLSLBaseType_Half4x2; } -inline bool isScalarType( HLSLBaseType baseType ) +inline bool IsScalarType( HLSLBaseType baseType ) { return baseType == HLSLBaseType_Float || baseType == HLSLBaseType_Half || @@ -125,7 +152,7 @@ inline bool isScalarType( HLSLBaseType baseType ) baseType == HLSLBaseType_Uint; } -inline bool isVectorType( HLSLBaseType baseType ) +inline bool IsVectorType( HLSLBaseType baseType ) { return baseType == HLSLBaseType_Float2 || baseType == HLSLBaseType_Float3 || @@ -169,7 +196,7 @@ enum HLSLBinaryOp HLSLBinaryOp_DivAssign, }; -inline bool isCompareOp( HLSLBinaryOp op ) +inline bool IsCompareOp( HLSLBinaryOp op ) { return op == HLSLBinaryOp_Less || op == HLSLBinaryOp_Greater || @@ -179,6 +206,30 @@ inline bool isCompareOp( HLSLBinaryOp op ) op == HLSLBinaryOp_NotEqual; } +inline bool IsArithmeticOp( HLSLBinaryOp op ) +{ + return op == HLSLBinaryOp_Add || + op == HLSLBinaryOp_Sub || + op == HLSLBinaryOp_Mul || + op == HLSLBinaryOp_Div; +} + +inline bool IsLogicOp( HLSLBinaryOp op ) +{ + return op == HLSLBinaryOp_And || + op == HLSLBinaryOp_Or; +} + +inline bool IsAssignOp( HLSLBinaryOp op ) +{ + return op == HLSLBinaryOp_Assign || + op == HLSLBinaryOp_AddAssign || + op == HLSLBinaryOp_SubAssign || + op == HLSLBinaryOp_MulAssign || + op == HLSLBinaryOp_DivAssign; +} + + enum HLSLUnaryOp { HLSLUnaryOp_Negative, // -x @@ -223,7 +274,7 @@ enum HLSLTypeFlags HLSLTypeFlag_Sample = 0x100000, // Misc. - //HLSLTypeFlag_Swizzle_BGRA = 0x200000, + HLSLTypeFlag_NoPromote = 0x200000, }; enum HLSLAttributeType @@ -232,6 +283,7 @@ enum HLSLAttributeType HLSLAttributeType_Unroll, HLSLAttributeType_Branch, HLSLAttributeType_Flatten, + HLSLAttributeType_NoFastMath, }; enum HLSLAddressSpace @@ -269,6 +321,7 @@ struct HLSLType explicit HLSLType(HLSLBaseType _baseType = HLSLBaseType_Unknown) { baseType = _baseType; + samplerType = HLSLBaseType_Float; typeName = NULL; array = false; arraySize = NULL; @@ -276,6 +329,7 @@ struct HLSLType addressSpace = HLSLAddressSpace_Undefined; } HLSLBaseType baseType; + HLSLBaseType samplerType; // Half or Float const char* typeName; // For user defined types. bool array; HLSLExpression* arraySize; @@ -288,14 +342,14 @@ inline bool IsSamplerType(const HLSLType & type) return IsSamplerType(type.baseType); } -inline bool isScalarType(const HLSLType & type) +inline bool IsScalarType(const HLSLType & type) { - return isScalarType(type.baseType); + return IsScalarType(type.baseType); } -inline bool isVectorType(const HLSLType & type) +inline bool IsVectorType(const HLSLType & type) { - return isVectorType(type.baseType); + return IsVectorType(type.baseType); } @@ -421,6 +475,7 @@ struct HLSLFunction : public HLSLStatement statement = NULL; argument = NULL; numArguments = 0; + numOutputArguments = 0; forward = NULL; } const char* name; @@ -428,6 +483,7 @@ struct HLSLFunction : public HLSLStatement const char* semantic; const char* sv_semantic; int numArguments; + int numOutputArguments; // Includes out and inout arguments. HLSLArgument* argument; HLSLStatement* statement; HLSLFunction* forward; // Which HLSLFunction this one forward-declares @@ -501,10 +557,12 @@ struct HLSLIfStatement : public HLSLStatement condition = NULL; statement = NULL; elseStatement = NULL; + isStatic = false; } HLSLExpression* condition; HLSLStatement* statement; HLSLStatement* elseStatement; + bool isStatic; }; struct HLSLForStatement : public HLSLStatement @@ -886,6 +944,8 @@ public: virtual void VisitSamplerState(HLSLSamplerState * node); virtual void VisitPass(HLSLPass * node); virtual void VisitTechnique(HLSLTechnique * node); + virtual void VisitPipeline(HLSLPipeline * node); + virtual void VisitFunctions(HLSLRoot * root); virtual void VisitParameters(HLSLRoot * root); @@ -902,7 +962,8 @@ extern void SortTree(HLSLTree* tree); extern void GroupParameters(HLSLTree* tree); extern void HideUnusedArguments(HLSLFunction * function); extern bool EmulateAlphaTest(HLSLTree* tree, const char* entryName, float alphaRef = 0.5f); - +extern void FlattenExpressions(HLSLTree* tree); + } // M4 #endif diff --git a/src/libprojectM/Renderer/hlslparser/src/MSLGenerator.cpp b/src/libprojectM/Renderer/hlslparser/src/MSLGenerator.cpp old mode 100644 new mode 100755 index e592eecfa..1c6d5967c --- a/src/libprojectM/Renderer/hlslparser/src/MSLGenerator.cpp +++ b/src/libprojectM/Renderer/hlslparser/src/MSLGenerator.cpp @@ -18,8 +18,6 @@ #include // MSL limitations: -// - Passing swizzled expressions as out or inout arguments. Out arguments are passed by reference in C++, but -// swizzled expressions are not addressable. // - Some type conversions and constructors don't work exactly the same way. For example, casts to smaller size vectors are not alloweed in C++. @@ Add more details... // - Swizzles on scalar types, whether or not it expands them. a_float.x, a_float.xxxx both cause compile errors. // - Using ints as floats without the trailing .0 makes the compiler sad. @@ -32,57 +30,6 @@ namespace M4 { -static const char* GetTypeName(const HLSLType& type) -{ - switch (type.baseType) - { - case HLSLBaseType_Void: return "void"; - case HLSLBaseType_Float: return "float"; - case HLSLBaseType_Float2: return "float2"; - case HLSLBaseType_Float3: return "float3"; - case HLSLBaseType_Float4: return "float4"; - case HLSLBaseType_Float2x2: return "float2x2"; - case HLSLBaseType_Float3x3: return "float3x3"; - case HLSLBaseType_Float4x4: return "float4x4"; - case HLSLBaseType_Float4x3: return "float3x4"; - case HLSLBaseType_Float4x2: return "float2x4"; - case HLSLBaseType_Half: return "half"; - case HLSLBaseType_Half2: return "half2"; - case HLSLBaseType_Half3: return "half3"; - case HLSLBaseType_Half4: return "half4"; - case HLSLBaseType_Half2x2: return "half2x2"; - case HLSLBaseType_Half3x3: return "half3x3"; - case HLSLBaseType_Half4x4: return "half4x4"; - case HLSLBaseType_Half4x3: return "half3x4"; - case HLSLBaseType_Half4x2: return "half2x4"; - case HLSLBaseType_Bool: return "bool"; - case HLSLBaseType_Bool2: return "bool2"; - case HLSLBaseType_Bool3: return "bool3"; - case HLSLBaseType_Bool4: return "bool4"; - case HLSLBaseType_Int: return "int"; - case HLSLBaseType_Int2: return "int2"; - case HLSLBaseType_Int3: return "int3"; - case HLSLBaseType_Int4: return "int4"; - case HLSLBaseType_Uint: return "uint"; - case HLSLBaseType_Uint2: return "uint2"; - case HLSLBaseType_Uint3: return "uint3"; - case HLSLBaseType_Uint4: return "uint4"; - case HLSLBaseType_Texture: return "texture"; - case HLSLBaseType_Sampler: return "sampler"; - // ACoget-TODO: How to detect non-float textures, if relevant? - case HLSLBaseType_Sampler2D: return "texture2d"; - case HLSLBaseType_Sampler3D: return "texture3d"; - case HLSLBaseType_SamplerCube: return "texturecube"; - case HLSLBaseType_Sampler2DShadow: return "depth2d"; - case HLSLBaseType_Sampler2DMS: return "texture2d_ms"; - case HLSLBaseType_Sampler2DArray: return "texture2d_array"; - case HLSLBaseType_UserDefined: return type.typeName; - default: - ASSERT(0); - return ""; - } -} - static void ParseSemantic(const char* semantic, unsigned int* outputLength, unsigned int* outputIndex) { const char* semanticIndex = semantic; @@ -124,6 +71,16 @@ static int ParseRegister(const char* registerName, int& nextRegister) return result; } +inline bool IsHalf(HLSLBaseType type) +{ + return type >= HLSLBaseType_Half && type <= HLSLBaseType_Half4x2; +} + +inline bool IsFloat(HLSLBaseType type) +{ + return type >= HLSLBaseType_Float && type <= HLSLBaseType_Float4x2; +} + MSLGenerator::MSLGenerator() { @@ -134,6 +91,8 @@ MSLGenerator::MSLGenerator() m_firstClassArgument = NULL; m_lastClassArgument = NULL; + + m_currentFunction = NULL; } // Copied from GLSLGenerator @@ -166,7 +125,8 @@ inline void MSLGenerator::AddClassArgument(ClassArgument* arg) } m_lastClassArgument = arg; } - + + void MSLGenerator::Prepass(HLSLTree* tree, Target target, HLSLFunction* entryFunction) { // Hide unused arguments. @@ It would be good to do this in the other generators too. @@ -289,6 +249,12 @@ void MSLGenerator::Prepass(HLSLTree* tree, Target target, HLSLFunction* entryFun { field->sv_semantic = TranslateInputSemantic(field->semantic); + // Force type to uint. + if (field->sv_semantic && strcmp(field->sv_semantic, "sample_id") == 0) { + field->type.baseType = HLSLBaseType_Uint; + field->type.flags |= HLSLTypeFlag_NoPromote; + } + /*if (target == Target_VertexShader && is_semantic(field->semantic, "COLOR")) { field->type.flags |= HLSLTypeFlag_Swizzle_BGRA; @@ -300,6 +266,12 @@ void MSLGenerator::Prepass(HLSLTree* tree, Target target, HLSLFunction* entryFun else { argument->sv_semantic = TranslateInputSemantic(argument->semantic); + + // Force type to uint. + if (argument->sv_semantic && strcmp(argument->sv_semantic, "sample_id") == 0) { + argument->type.baseType = HLSLBaseType_Uint; + argument->type.flags |= HLSLTypeFlag_NoPromote; + } } } @@ -361,25 +333,47 @@ void MSLGenerator::PrependDeclarations() m_writer.WriteLine(0, "using namespace metal;"); m_writer.WriteLine(0, ""); - // 'mad' should be translated as 'fma' - if (m_tree->NeedsFunction("mad")) { - m_writer.WriteLine(0, "inline float mad(float a, float b, float c) {"); - m_writer.WriteLine(1, "return a * b + c;"); - m_writer.WriteLine(0, "}"); - m_writer.WriteLine(0, "inline float2 mad(float2 a, float2 b, float2 c) {"); - m_writer.WriteLine(1, "return a * b + c;"); - m_writer.WriteLine(0, "}"); - m_writer.WriteLine(0, "inline float3 mad(float3 a, float3 b, float3 c) {"); - m_writer.WriteLine(1, "return a * b + c;"); - m_writer.WriteLine(0, "}"); - m_writer.WriteLine(0, "inline float4 mad(float4 a, float4 b, float4 c) {"); - m_writer.WriteLine(1, "return a * b + c;"); - m_writer.WriteLine(0, "}"); + if (m_options.usePreciseFma) + { + m_writer.WriteLine(0, "#define mad precise::fma"); + } + else + { + m_writer.WriteLine(0, "inline float mad(float a, float b, float c) {"); + m_writer.WriteLine(1, "return a * b + c;"); + m_writer.WriteLine(0, "}"); + m_writer.WriteLine(0, "inline float2 mad(float2 a, float2 b, float2 c) {"); + m_writer.WriteLine(1, "return a * b + c;"); + m_writer.WriteLine(0, "}"); + m_writer.WriteLine(0, "inline float3 mad(float3 a, float3 b, float3 c) {"); + m_writer.WriteLine(1, "return a * b + c;"); + m_writer.WriteLine(0, "}"); + m_writer.WriteLine(0, "inline float4 mad(float4 a, float4 b, float4 c) {"); + m_writer.WriteLine(1, "return a * b + c;"); + m_writer.WriteLine(0, "}"); + + if (!m_options.treatHalfAsFloat) + { + m_writer.WriteLine(0, "inline half mad(half a, half b, half c) {"); + m_writer.WriteLine(1, "return a * b + c;"); + m_writer.WriteLine(0, "}"); + m_writer.WriteLine(0, "inline half2 mad(half2 a, half2 b, half2 c) {"); + m_writer.WriteLine(1, "return a * b + c;"); + m_writer.WriteLine(0, "}"); + m_writer.WriteLine(0, "inline half3 mad(half3 a, half3 b, half3 c) {"); + m_writer.WriteLine(1, "return a * b + c;"); + m_writer.WriteLine(0, "}"); + m_writer.WriteLine(0, "inline half4 mad(half4 a, half4 b, half4 c) {"); + m_writer.WriteLine(1, "return a * b + c;"); + m_writer.WriteLine(0, "}"); + } + } } - if (m_tree->NeedsFunction("max")) + // @@ These should not be needed anymore. + /*if (m_tree->NeedsFunction("max")) { m_writer.WriteLine(0, "inline float max(int a, float b) {"); m_writer.WriteLine(1, "return max((float)a, b);"); @@ -396,13 +390,13 @@ void MSLGenerator::PrependDeclarations() m_writer.WriteLine(0, "inline float min(float a, int b) {"); m_writer.WriteLine(1, "return min(a, (float)b);"); m_writer.WriteLine(0, "}"); - } + }*/ if (m_tree->NeedsFunction("lerp")) { - m_writer.WriteLine(0, "template inline T mix(T a, T b, int x) {"); - m_writer.WriteLine(1, "return mix(a, b, (float)x);"); - m_writer.WriteLine(0, "}"); + //m_writer.WriteLine(0, "template inline T mix(T a, T b, X x) {"); + //m_writer.WriteLine(1, "return mix(a, b, (float)x);"); + //m_writer.WriteLine(0, "}"); m_writer.WriteLine(0, "#define lerp mix"); } @@ -411,35 +405,33 @@ void MSLGenerator::PrependDeclarations() const char* am = (m_options.flags & Flag_PackMatrixRowMajor) ? "m * a" : "a * m"; const char* ma = (m_options.flags & Flag_PackMatrixRowMajor) ? "a * m" : "m * a"; - // @@ Add all mul variants? Replace by * ? - m_writer.WriteLine(0, "inline float2 mul(float2 a, float2x2 m) {"); - m_writer.WriteLine(1, "return %s;", am); - m_writer.WriteLine(0, "}"); + m_writer.WriteLine(0, "inline float2 mul(float2 a, float2x2 m) { return %s; }", am); + m_writer.WriteLine(0, "inline float3 mul(float3 a, float3x3 m) { return %s; }", am); + m_writer.WriteLine(0, "inline float4 mul(float4 a, float4x4 m) { return %s; }", am); - m_writer.WriteLine(0, "inline float3 mul(float3 a, float3x3 m) {"); - m_writer.WriteLine(1, "return %s;", am); - m_writer.WriteLine(0, "}"); - - m_writer.WriteLine(0, "inline float4 mul(float4 a, float4x4 m) {"); - m_writer.WriteLine(1, "return %s;", am); - m_writer.WriteLine(0, "}"); - - m_writer.WriteLine(0, "inline float2 mul(float2x2 m, float2 a) {"); - m_writer.WriteLine(1, "return %s;", ma); - m_writer.WriteLine(0, "}"); - - m_writer.WriteLine(0, "inline float3 mul(float3x3 m, float3 a) {"); - m_writer.WriteLine(1, "return %s;", ma); - m_writer.WriteLine(0, "}"); - - m_writer.WriteLine(0, "inline float4 mul(float4x4 m, float4 a) {"); - m_writer.WriteLine(1, "return %s;", ma); - m_writer.WriteLine(0, "}"); + m_writer.WriteLine(0, "inline float2 mul(float2x2 m, float2 a) { return %s; }", ma); + m_writer.WriteLine(0, "inline float3 mul(float3x3 m, float3 a) { return %s; }", ma); + m_writer.WriteLine(0, "inline float4 mul(float4x4 m, float4 a) { return %s; }", ma); // TODO: Support PackMatrixRowMajor for float3x4/float4x3 - m_writer.WriteLine(0, "inline float3 mul(float4 a, float3x4 m) {"); - m_writer.WriteLine(1, "return a * m;"); - m_writer.WriteLine(0, "}"); + m_writer.WriteLine(0, "inline float3 mul(float4 a, float3x4 m) { return a * m; }"); + m_writer.WriteLine(0, "inline float2 mul(float4 a, float2x4 m) { return a * m; }"); + + if (!m_options.treatHalfAsFloat) + { + m_writer.WriteLine(0, "inline half2 mul(half2 a, half2x2 m) { return %s; }", am); + m_writer.WriteLine(0, "inline half3 mul(half3 a, half3x3 m) { return %s; }", am); + m_writer.WriteLine(0, "inline half4 mul(half4 a, half4x4 m) { return %s; }", am); + + m_writer.WriteLine(0, "inline half2 mul(half2x2 m, half2 a) { return %s; }", ma); + m_writer.WriteLine(0, "inline half3 mul(half3x3 m, half3 a) { return %s; }", ma); + m_writer.WriteLine(0, "inline half4 mul(half4x4 m, half4 a) { return %s; }", ma); + + // TODO: Support PackMatrixRowMajor for half3x4/half4x3 + m_writer.WriteLine(0, "inline half3 mul(half4 a, half3x4 m) { return a * m; }"); + m_writer.WriteLine(0, "inline half2 mul(half4 a, half2x4 m) { return a * m; }"); + } + } // @@ How do we know if these will be needed? We could write these after parsing the whole file and prepend them. @@ -471,6 +463,7 @@ void MSLGenerator::PrependDeclarations() m_writer.WriteLine(1, " return float3x3(m[0].xyz, m[1].xyz, m[2].xyz);"); m_writer.WriteLine(0, "}"); + if (m_tree->NeedsFunction("clip")) { m_writer.WriteLine(0, "inline void clip(float x) {"); @@ -482,6 +475,10 @@ void MSLGenerator::PrependDeclarations() m_writer.WriteLine(0, "inline float rcp(float x) {"); m_writer.WriteLine(1, "return 1.0f / x;"); m_writer.WriteLine(0, "}"); + + m_writer.WriteLine(0, "inline half rcp(half x) {"); + m_writer.WriteLine(1, "return 1.0h / x;"); + m_writer.WriteLine(0, "}"); } if (m_tree->NeedsFunction("ddx")) m_writer.WriteLine(0, "#define ddx dfdx"); @@ -490,6 +487,18 @@ void MSLGenerator::PrependDeclarations() //m_writer.WriteLine(0, "#define mad fma"); // @@ This doesn't seem to work. + const char * samplerType = "float"; + /*if (m_options.halfTextureSamplers) + { + samplerType = "half"; + }*/ + const char * intType = "int"; + const char * uintType = "uint"; + if (m_options.use16BitIntegers) { + intType = "short"; + uintType = "ushort"; + } + if (m_tree->NeedsFunction("tex2D") || m_tree->NeedsFunction("tex2Dlod") || m_tree->NeedsFunction("tex2Dgrad") || @@ -497,10 +506,18 @@ void MSLGenerator::PrependDeclarations() m_tree->NeedsFunction("tex2Dfetch")) { m_writer.WriteLine(0, "struct Texture2DSampler {"); + m_writer.WriteLine(1, "Texture2DSampler(thread const texture2d& t, thread const sampler& s) : t(t), s(s) {};"); m_writer.WriteLine(1, "const thread texture2d& t;"); m_writer.WriteLine(1, "const thread sampler& s;"); - m_writer.WriteLine(1, "Texture2DSampler(thread const texture2d& t, thread const sampler& s) : t(t), s(s) {};"); m_writer.WriteLine(0, "};"); + + if (!m_options.treatHalfAsFloat) { + m_writer.WriteLine(0, "struct Texture2DHalfSampler {"); + m_writer.WriteLine(1, "Texture2DHalfSampler(thread const texture2d& t, thread const sampler& s) : t(t), s(s) {};"); + m_writer.WriteLine(1, "const thread texture2d& t;"); + m_writer.WriteLine(1, "const thread sampler& s;"); + m_writer.WriteLine(0, "};"); + } } if (m_tree->NeedsFunction("tex2D")) @@ -508,12 +525,26 @@ void MSLGenerator::PrependDeclarations() m_writer.WriteLine(0, "inline float4 tex2D(Texture2DSampler ts, float2 texCoord) {"); m_writer.WriteLine(1, "return ts.t.sample(ts.s, texCoord);"); m_writer.WriteLine(0, "}"); + + if (!m_options.treatHalfAsFloat) + { + m_writer.WriteLine(0, "inline half4 tex2D(Texture2DHalfSampler ts, float2 texCoord) {"); + m_writer.WriteLine(1, "return ts.t.sample(ts.s, texCoord);"); + m_writer.WriteLine(0, "}"); + } } if (m_tree->NeedsFunction("tex2Dlod")) { m_writer.WriteLine(0, "inline float4 tex2Dlod(Texture2DSampler ts, float4 texCoordMip) {"); m_writer.WriteLine(1, "return ts.t.sample(ts.s, texCoordMip.xy, level(texCoordMip.w));"); m_writer.WriteLine(0, "}"); + + if (!m_options.treatHalfAsFloat) + { + m_writer.WriteLine(0, "inline half4 tex2Dlod(Texture2DHalfSampler ts, float4 texCoordMip) {"); + m_writer.WriteLine(1, "return ts.t.sample(ts.s, texCoordMip.xy, level(texCoordMip.w));"); + m_writer.WriteLine(0, "}"); + } } if (m_tree->NeedsFunction("tex2Dgrad")) { @@ -526,11 +557,19 @@ void MSLGenerator::PrependDeclarations() m_writer.WriteLine(0, "inline float4 tex2Dbias(Texture2DSampler ts, float4 texCoordBias) {"); m_writer.WriteLine(1, "return ts.t.sample(ts.s, texCoordBias.xy, bias(texCoordBias.w));"); m_writer.WriteLine(0, "}"); + + if (!m_options.treatHalfAsFloat) + { + m_writer.WriteLine(0, "inline half4 tex2Dbias(Texture2DHalfSampler ts, float4 texCoordBias) {"); + m_writer.WriteLine(1, "return ts.t.sample(ts.s, texCoordBias.xy, bias(texCoordBias.w));"); + m_writer.WriteLine(0, "}"); + } } if (m_tree->NeedsFunction("tex2Dfetch")) { - m_writer.WriteLine(0, "inline float4 tex2Dfetch(Texture2DSampler ts, uint2 texCoord) {"); - m_writer.WriteLine(1, "return ts.t.read(texCoord);"); + // @@ not used? not tested? + m_writer.WriteLine(0, "inline float4 tex2Dfetch(Texture2DSampler ts, %s2 texCoord) {", intType); + m_writer.WriteLine(1, "return ts.t.read((uint2)texCoord);"); m_writer.WriteLine(0, "}"); } @@ -538,9 +577,9 @@ void MSLGenerator::PrependDeclarations() m_tree->NeedsFunction("tex3Dlod")) { m_writer.WriteLine(0, "struct Texture3DSampler {"); + m_writer.WriteLine(1, "Texture3DSampler(thread const texture3d& t, thread const sampler& s) : t(t), s(s) {};"); m_writer.WriteLine(1, "const thread texture3d& t;"); m_writer.WriteLine(1, "const thread sampler& s;"); - m_writer.WriteLine(1, "Texture3DSampler(thread const texture3d& t, thread const sampler& s) : t(t), s(s) {};"); m_writer.WriteLine(0, "};"); } @@ -562,9 +601,9 @@ void MSLGenerator::PrependDeclarations() m_tree->NeedsFunction("texCUBEbias")) { m_writer.WriteLine(0, "struct TextureCubeSampler {"); + m_writer.WriteLine(1, "TextureCubeSampler(thread const texturecube& t, thread const sampler& s) : t(t), s(s) {};"); m_writer.WriteLine(1, "const thread texturecube& t;"); m_writer.WriteLine(1, "const thread sampler& s;"); - m_writer.WriteLine(1, "TextureCubeSampler(thread const texturecube& t, thread const sampler& s) : t(t), s(s) {};"); m_writer.WriteLine(0, "};"); } @@ -592,9 +631,9 @@ void MSLGenerator::PrependDeclarations() if (m_tree->NeedsFunction("tex2Dcmp")) { m_writer.WriteLine(0, "struct Texture2DShadowSampler {"); + m_writer.WriteLine(1, "Texture2DShadowSampler(thread const depth2d& t, thread const sampler& s) : t(t), s(s) {};"); m_writer.WriteLine(1, "const thread depth2d& t;"); m_writer.WriteLine(1, "const thread sampler& s;"); - m_writer.WriteLine(1, "Texture2DShadowSampler(thread const depth2d& t, thread const sampler& s) : t(t), s(s) {};"); m_writer.WriteLine(0, "};"); m_writer.WriteLine(0, "inline float4 tex2Dcmp(Texture2DShadowSampler ts, float4 texCoordCompare) {"); @@ -613,8 +652,8 @@ void MSLGenerator::PrependDeclarations() if (m_tree->NeedsFunction("tex2DMSfetch")) { - m_writer.WriteLine(0, "inline float4 tex2DMSfetch(texture2d_ms t, int2 texCoord, int sample) {"); - m_writer.WriteLine(1, "return t.read(uint2(texCoord), sample);"); + m_writer.WriteLine(0, "inline float4 tex2DMSfetch(texture2d_ms t, %s2 texCoord, %s sample) {", intType, intType); + m_writer.WriteLine(1, "return t.read((uint2)texCoord, (uint)sample);"); m_writer.WriteLine(0, "}"); } @@ -885,9 +924,17 @@ void MSLGenerator::OutputStatements(int indent, HLSLStatement* statement) if (statement->nodeType == HLSLNodeType_Declaration) { HLSLDeclaration* declaration = static_cast(statement); - m_writer.BeginLine(indent, declaration->fileName, declaration->line); - OutputDeclaration(declaration); - m_writer.EndLine(";"); + + if (declaration->assignment && declaration->assignment->nodeType == HLSLNodeType_FunctionCall) + { + OutputFunctionCallStatement(indent, (HLSLFunctionCall*)declaration->assignment, declaration); + } + else + { + m_writer.BeginLine(indent, declaration->fileName, declaration->line); + OutputDeclaration(declaration); + m_writer.EndLine(";"); + } } else if (statement->nodeType == HLSLNodeType_Struct) { @@ -911,13 +958,13 @@ void MSLGenerator::OutputStatements(int indent, HLSLStatement* statement) else if (statement->nodeType == HLSLNodeType_ExpressionStatement) { HLSLExpressionStatement* expressionStatement = static_cast(statement); + HLSLExpression* expression = expressionStatement->expression; - // IC: This works, but it only helps in very few scenarios. We need a more general solution that involves more complex syntax tree transformations. - /*if (expressionStatement->expression->nodeType == HLSLNodeType_FunctionCall) + if (expression->nodeType == HLSLNodeType_FunctionCall) { - OutputFunctionCallStatement(indent, (HLSLFunctionCall*)expressionStatement->expression); + OutputFunctionCallStatement(indent, (HLSLFunctionCall*)expression, NULL); } - else*/ + else { m_writer.BeginLine(indent, statement->fileName, statement->line); OutputExpression(expressionStatement->expression, NULL); @@ -927,11 +974,37 @@ void MSLGenerator::OutputStatements(int indent, HLSLStatement* statement) else if (statement->nodeType == HLSLNodeType_ReturnStatement) { HLSLReturnStatement* returnStatement = static_cast(statement); - if (returnStatement->expression != NULL) + if (m_currentFunction->numOutputArguments > 0) + { + m_writer.BeginLine(indent, returnStatement->fileName, returnStatement->line); + m_writer.Write("return { "); + + int numArguments = 0; + if (returnStatement->expression != NULL) + { + OutputTypedExpression(m_currentFunction->returnType, returnStatement->expression, NULL); + numArguments++; + } + + HLSLArgument * argument = m_currentFunction->argument; + while (argument != NULL) + { + if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) + { + if (numArguments) m_writer.Write(", "); + m_writer.Write("%s", argument->name); + numArguments++; + } + argument = argument->nextArgument; + } + + m_writer.EndLine(" };"); + } + else if (returnStatement->expression != NULL) { m_writer.BeginLine(indent, returnStatement->fileName, returnStatement->line); m_writer.Write("return "); - OutputExpression(returnStatement->expression, NULL); + OutputTypedExpression(m_currentFunction->returnType, returnStatement->expression, NULL); m_writer.EndLine(";"); } else @@ -957,18 +1030,33 @@ void MSLGenerator::OutputStatements(int indent, HLSLStatement* statement) else if (statement->nodeType == HLSLNodeType_IfStatement) { HLSLIfStatement* ifStatement = static_cast(statement); - m_writer.BeginLine(indent, ifStatement->fileName, ifStatement->line); - m_writer.Write("if ("); - OutputExpression(ifStatement->condition, NULL); - m_writer.Write(") {"); - m_writer.EndLine(); - OutputStatements(indent + 1, ifStatement->statement); - m_writer.WriteLine(indent, "}"); - if (ifStatement->elseStatement != NULL) - { - m_writer.WriteLine(indent, "else {"); - OutputStatements(indent + 1, ifStatement->elseStatement); + + if (ifStatement->isStatic) { + int value; + if (!m_tree->GetExpressionValue(ifStatement->condition, value)) { + Error("@if condition could not be evaluated.\n"); + } + if (value != 0) { + OutputStatements(indent + 1, ifStatement->statement); + } + else if (ifStatement->elseStatement != NULL) { + OutputStatements(indent + 1, ifStatement->elseStatement); + } + } + else { + m_writer.BeginLine(indent, ifStatement->fileName, ifStatement->line); + m_writer.Write("if ("); + OutputExpression(ifStatement->condition, NULL); + m_writer.Write(") {"); + m_writer.EndLine(); + OutputStatements(indent + 1, ifStatement->statement); m_writer.WriteLine(indent, "}"); + if (ifStatement->elseStatement != NULL) + { + m_writer.WriteLine(indent, "else {"); + OutputStatements(indent + 1, ifStatement->elseStatement); + m_writer.WriteLine(indent, "}"); + } } } else if (statement->nodeType == HLSLNodeType_ForStatement) @@ -1043,24 +1131,45 @@ void MSLGenerator::OutputDeclaration(HLSLDeclaration* declaration) // Declare a texture and a sampler instead // We do not handle multiple textures on the same line ASSERT(declaration->nextDeclaration == NULL); + const char * typeName = "float"; + if (declaration->type.samplerType == HLSLBaseType_Half && !m_options.treatHalfAsFloat) + { + typeName = "half"; + } + if (declaration->type.baseType == HLSLBaseType_Sampler2D) - m_writer.Write("thread texture2d& %s_texture; thread sampler& %s_sampler", declaration->name, declaration->name); + { + m_writer.Write("thread texture2d<%s>& %s_texture; thread sampler& %s_sampler", typeName, declaration->name, declaration->name); + } else if (declaration->type.baseType == HLSLBaseType_Sampler3D) - m_writer.Write("thread texture3d& %s_texture; thread sampler& %s_sampler", declaration->name, declaration->name); + { + m_writer.Write("thread texture3d<%s>& %s_texture; thread sampler& %s_sampler", typeName, declaration->name, declaration->name); + } else if (declaration->type.baseType == HLSLBaseType_SamplerCube) - m_writer.Write("thread texturecube& %s_texture; thread sampler& %s_sampler", declaration->name, declaration->name); + { + m_writer.Write("thread texturecube<%s>& %s_texture; thread sampler& %s_sampler", typeName, declaration->name, declaration->name); + } else if (declaration->type.baseType == HLSLBaseType_Sampler2DShadow) + { m_writer.Write("thread depth2d& %s_texture; thread sampler& %s_sampler", declaration->name, declaration->name); + } else if (declaration->type.baseType == HLSLBaseType_Sampler2DMS) - m_writer.Write("thread texture2d_ms& %s_texture", declaration->name); + { + m_writer.Write("thread texture2d_ms<%s>& %s_texture", typeName, declaration->name); + } else if (declaration->type.baseType == HLSLBaseType_Sampler2DArray) - m_writer.Write("thread texture2d_array& %s_texture; thread sampler& %s_sampler", declaration->name, declaration->name); + { + m_writer.Write("thread texture2d_array<%s>& %s_texture; thread sampler& %s_sampler", typeName, declaration->name, declaration->name); + } else + { m_writer.Write(""); + } } else { OutputDeclaration(declaration->type, declaration->name, declaration->assignment); + declaration = declaration->nextDeclaration; while(declaration != NULL) { @@ -1121,15 +1230,104 @@ void MSLGenerator::OutputFunction(int indent, HLSLFunction* function) const char* functionName = function->name; const char* returnTypeName = GetTypeName(function->returnType); - m_writer.BeginLine(indent, function->fileName, function->line); - m_writer.Write("%s %s(", returnTypeName, functionName); + // Declare output tuple. + if (function->numOutputArguments > 0) + { + returnTypeName = m_tree->AddStringFormat("%s_out%d", functionName, function->line); // @@ Find a better way to generate unique name. + + m_writer.BeginLine(indent, function->fileName, function->line); + m_writer.Write("struct %s { ", returnTypeName); + m_writer.EndLine(); + + if (function->returnType.baseType != HLSLBaseType_Void) + { + m_writer.BeginLine(indent+1, function->fileName, function->line); + OutputDeclaration(function->returnType, "__result", /*defaultValue=*/NULL, /*isRef=*/false, /*isConst=*/false); + m_writer.EndLine(";"); + } + + HLSLArgument * argument = function->argument; + while (argument != NULL) + { + if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) + { + m_writer.BeginLine(indent+1, function->fileName, function->line); + OutputDeclaration(argument->type, argument->name, /*defaultValue=*/NULL, /*isRef=*/false, /*isConst=*/false); + m_writer.EndLine(";"); + } + argument = argument->nextArgument; + } + + m_writer.WriteLine(indent, "};"); + + // Create unique function name to avoid collision with overloads and different return types. + m_writer.BeginLine(indent, function->fileName, function->line); + m_writer.Write("%s %s_%d(", returnTypeName, functionName, function->line); + } + else + { + m_writer.BeginLine(indent, function->fileName, function->line); + m_writer.Write("%s %s(", returnTypeName, functionName); + } OutputArguments(function->argument); m_writer.EndLine(") {"); + m_currentFunction = function; + + // Local declarations for output arguments. + HLSLArgument * argument = function->argument; + while (argument != NULL) + { + if (argument->modifier == HLSLArgumentModifier_Out) + { + m_writer.BeginLine(indent + 1, function->fileName, function->line); + OutputDeclaration(argument->type, argument->name, /*defaultValue=*/NULL, /*isRef=*/false, /*isConst=*/false); + m_writer.EndLine(";"); + } + argument = argument->nextArgument; + } + + OutputStatements(indent + 1, function->statement); // @@ Modify return statements if function has multiple output arguments! + + // Output implicit return. + if (function->numOutputArguments > 0) + { + bool needsImplicitReturn = true; + HLSLStatement * statement = function->statement; + if (statement != NULL) + { + while (statement->nextStatement != NULL) + { + statement = statement->nextStatement; + } + needsImplicitReturn = (statement->nodeType != HLSLNodeType_ReturnStatement) && function->returnType.baseType == HLSLBaseType_Void; + } + + if (needsImplicitReturn) + { + m_writer.BeginLine(indent+1); + m_writer.Write("return { "); + + int numArguments = 0; + HLSLArgument * argument = m_currentFunction->argument; + while (argument != NULL) + { + if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) + { + if (numArguments) m_writer.Write(", "); + m_writer.Write("%s ", argument->name); + numArguments++; + } + argument = argument->nextArgument; + } + + m_writer.EndLine(" };"); + } + } - OutputStatements(indent + 1, function->statement); m_writer.WriteLine(indent, "};"); + m_currentFunction = NULL; } @@ -1156,6 +1354,50 @@ static bool NeedsParenthesis(HLSLExpression* expression, HLSLExpression* parentE return true; } +bool MSLGenerator::NeedsCast(const HLSLType & target, const HLSLType & source) +{ + HLSLBaseType targetType = target.baseType; + HLSLBaseType sourceType = source.baseType; + + if (sourceType == HLSLBaseType_Int) { + int k = 1; + } + + /*if (IsScalarType(target)) + { + // Scalar types do not need casting. + return false; + }*/ + + if (m_options.treatHalfAsFloat) + { + if (IsHalf(targetType)) targetType = HLSLBaseType(targetType + HLSLBaseType_Float - HLSLBaseType_Half); + if (IsHalf(sourceType)) sourceType = HLSLBaseType(sourceType + HLSLBaseType_Float - HLSLBaseType_Half); + } + + return targetType != sourceType && (BaseTypeDimension[targetType] == BaseTypeDimension[sourceType] || BaseTypeDimension[sourceType] == HLSLTypeDimension_Scalar); +} + + +void MSLGenerator::OutputTypedExpression(const HLSLType& type, HLSLExpression* expression, HLSLExpression* parentExpression) +{ + // If base types are not exactly the same, do explicit cast. + bool closeCastExpression = false; + if (NeedsCast(type, expression->expressionType)) + { + OutputCast(type); + m_writer.Write("("); + closeCastExpression = true; + } + + OutputExpression(expression, parentExpression); + + if (closeCastExpression) + { + m_writer.Write(")"); + } +} + void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* parentExpression) { if (expression->nodeType == HLSLNodeType_IdentifierExpression) @@ -1166,7 +1408,16 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* if (identifierExpression->global && IsSamplerType(identifierExpression->expressionType)) { if (identifierExpression->expressionType.baseType == HLSLBaseType_Sampler2D) - m_writer.Write("Texture2DSampler(%s_texture, %s_sampler)", name, name); + { + if (identifierExpression->expressionType.samplerType == HLSLBaseType_Half && !m_options.treatHalfAsFloat) + { + m_writer.Write("Texture2DHalfSampler(%s_texture, %s_sampler)", name, name); + } + else + { + m_writer.Write("Texture2DSampler(%s_texture, %s_sampler)", name, name); + } + } else if (identifierExpression->expressionType.baseType == HLSLBaseType_Sampler3D) m_writer.Write("Texture3DSampler(%s_texture, %s_sampler)", name, name); else if (identifierExpression->expressionType.baseType == HLSLBaseType_SamplerCube) @@ -1230,6 +1481,7 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* { HLSLConstructorExpression* constructorExpression = static_cast(expression); m_writer.Write("%s(", GetTypeName(constructorExpression->type)); + //OutputExpressionList(constructorExpression->type, constructorExpression->argument); // @@ Get element type. OutputExpressionList(constructorExpression->argument); m_writer.Write(")"); } @@ -1239,13 +1491,15 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* switch (literalExpression->type) { case HLSLBaseType_Half: + if (m_options.treatHalfAsFloat) { + m_writer.Write("%ff", literalExpression->fValue); + } + else { + m_writer.Write("%fh", literalExpression->fValue); + } + break; case HLSLBaseType_Float: - { - // Don't use printf directly so that we don't use the system locale. - char buffer[64]; - String_FormatFloat(buffer, sizeof(buffer), literalExpression->fValue); - m_writer.Write("%s", buffer); - } + m_writer.Write("%ff", literalExpression->fValue); break; case HLSLBaseType_Int: m_writer.Write("%d", literalExpression->iValue); @@ -1314,7 +1568,23 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* if (!rewrite_assign) { - OutputExpression(binaryExpression->expression1, binaryExpression); + if (IsArithmeticOp(binaryExpression->binaryOp) || IsLogicOp(binaryExpression->binaryOp)) + { + // Do intermediate type promotion, without changing dimension: + HLSLType promotedType = binaryExpression->expression1->expressionType; + + if (ScalarBaseType[binaryExpression->expressionType.baseType] != ScalarBaseType[promotedType.baseType]) + { + promotedType.baseType = HLSLBaseType(ScalarBaseType[binaryExpression->expressionType.baseType] + BaseTypeDimension[promotedType.baseType] - 1); + } + + OutputTypedExpression(promotedType, binaryExpression->expression1, binaryExpression); + } + else + { + OutputExpression(binaryExpression->expression1, binaryExpression); + } + const char* op = "?"; switch (binaryExpression->binaryOp) { @@ -1342,7 +1612,30 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* ASSERT(0); } m_writer.Write("%s", op); - OutputExpression(binaryExpression->expression2, binaryExpression); + + if (binaryExpression->binaryOp == HLSLBinaryOp_MulAssign || + binaryExpression->binaryOp == HLSLBinaryOp_DivAssign || + IsArithmeticOp(binaryExpression->binaryOp) || + IsLogicOp(binaryExpression->binaryOp)) + { + // Do intermediate type promotion, without changing dimension: + HLSLType promotedType = binaryExpression->expression2->expressionType; + + if (ScalarBaseType[binaryExpression->expressionType.baseType] != ScalarBaseType[promotedType.baseType]) + { + promotedType.baseType = HLSLBaseType(ScalarBaseType[binaryExpression->expressionType.baseType] + BaseTypeDimension[promotedType.baseType] - 1); + } + + OutputTypedExpression(promotedType, binaryExpression->expression2, binaryExpression); + } + else if (IsAssignOp(binaryExpression->binaryOp)) + { + OutputTypedExpression(binaryExpression->expressionType, binaryExpression->expression2, binaryExpression); + } + else + { + OutputExpression(binaryExpression->expression2, binaryExpression); + } } if (addParenthesis) m_writer.Write(")"); } @@ -1398,7 +1691,7 @@ void MSLGenerator::OutputExpression(HLSLExpression* expression, HLSLExpression* else if (expression->nodeType == HLSLNodeType_FunctionCall) { HLSLFunctionCall* functionCall = static_cast(expression); - OutputFunctionCall(functionCall); + OutputFunctionCall(functionCall, parentExpression); } else { @@ -1415,7 +1708,7 @@ void MSLGenerator::OutputCast(const HLSLType& type) else { m_writer.Write("("); - OutputDeclarationType(type); + OutputDeclarationType(type, /*isConst=*/false, /*isRef=*/false, /*alignment=*/0, /*isTypeCast=*/true); m_writer.Write(")"); } } @@ -1426,7 +1719,8 @@ void MSLGenerator::OutputArguments(HLSLArgument* argument) int numArgs = 0; while (argument != NULL) { - if (argument->hidden) + // Skip hidden and output arguments. + if (argument->hidden || argument->modifier == HLSLArgumentModifier_Out) { argument = argument->nextArgument; continue; @@ -1437,19 +1731,18 @@ void MSLGenerator::OutputArguments(HLSLArgument* argument) m_writer.Write(", "); } - bool isRef = false; + //bool isRef = false; bool isConst = false; - if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) + /*if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) { isRef = true; - - } + }*/ if (argument->modifier == HLSLArgumentModifier_In || argument->modifier == HLSLArgumentModifier_Const) { isConst = true; } - - OutputDeclaration(argument->type, argument->name, argument->defaultValue, isRef, isConst); + + OutputDeclaration(argument->type, argument->name, argument->defaultValue, /*isRef=*/false, isConst); argument = argument->nextArgument; ++numArgs; } @@ -1461,26 +1754,36 @@ void MSLGenerator::OutputDeclaration(const HLSLType& type, const char* name, HLS OutputDeclarationBody(type, name, assignment, isRef); } -void MSLGenerator::OutputDeclarationType(const HLSLType& type, bool isRef, bool isConst, int alignment) +void MSLGenerator::OutputDeclarationType(const HLSLType& type, bool isRef, bool isConst, int alignment, bool isTypeCast) { const char* typeName = GetTypeName(type); - if (isRef) + + /*if (!isTypeCast)*/ { - m_writer.Write("thread "); - } - if (isConst || type.flags & HLSLTypeFlag_Const) - { - m_writer.Write("const "); - - if (type.flags & HLSLTypeFlag_Static) + if (isRef && !isTypeCast) { - m_writer.Write("static constant constexpr "); + m_writer.Write("thread "); + } + if (isConst || type.flags & HLSLTypeFlag_Const) + { + m_writer.Write("const "); + + if ((type.flags & HLSLTypeFlag_Static) != 0 && !isTypeCast) + { + m_writer.Write("static constant constexpr "); + } } } if (IsSamplerType(type)) { - if (type.baseType == HLSLBaseType_Sampler2D) - typeName = "Texture2DSampler"; + if (type.baseType == HLSLBaseType_Sampler2D) { + if (type.samplerType == HLSLBaseType_Half && !m_options.treatHalfAsFloat) { + typeName = "Texture2DHalfSampler"; + } + else { + typeName = "Texture2DSampler"; + } + } else if (type.baseType == HLSLBaseType_Sampler3D) typeName = "Texture3DSampler"; else if (type.baseType == HLSLBaseType_SamplerCube) @@ -1494,13 +1797,19 @@ void MSLGenerator::OutputDeclarationType(const HLSLType& type, bool isRef, bool else typeName = ""; } - else if (alignment != 0) + else if (alignment != 0 && !isTypeCast) { m_writer.Write("alignas(%d) ", alignment); } m_writer.Write("%s", typeName); + if (isTypeCast) + { + // Do not output modifiers inside type cast expressions. + return; + } + // Interpolation modifiers. if (type.flags & HLSLTypeFlag_NoInterpolation) { @@ -1583,11 +1892,11 @@ void MSLGenerator::OutputDeclarationBody(const HLSLType& type, const char* name, } else { - OutputExpression(assignment, NULL); + OutputTypedExpression(type, assignment, NULL); } } } - + void MSLGenerator::OutputExpressionList(HLSLExpression* expression) { int numExpressions = 0; @@ -1603,6 +1912,48 @@ void MSLGenerator::OutputExpressionList(HLSLExpression* expression) } } +// Cast all expressions to given type. +void MSLGenerator::OutputExpressionList(const HLSLType & type, HLSLExpression* expression) +{ + int numExpressions = 0; + while (expression != NULL) + { + if (numExpressions > 0) + { + m_writer.Write(", "); + } + + OutputTypedExpression(type, expression, NULL); + expression = expression->nextExpression; + ++numExpressions; + } +} + +// Cast each expression to corresponding argument type. +void MSLGenerator::OutputExpressionList(HLSLArgument* argument, HLSLExpression* expression) +{ + int numExpressions = 0; + while (expression != NULL) + { + ASSERT(argument != NULL); + if (argument->modifier != HLSLArgumentModifier_Out) + { + if (numExpressions > 0) + { + m_writer.Write(", "); + } + + OutputTypedExpression(argument->type, expression, NULL); + ++numExpressions; + } + + expression = expression->nextExpression; + argument = argument->nextArgument; + } +} + + + inline bool isAddressable(HLSLExpression* expression) { if (expression->nodeType == HLSLNodeType_IdentifierExpression) @@ -1621,8 +1972,73 @@ inline bool isAddressable(HLSLExpression* expression) return false; } -void MSLGenerator::OutputFunctionCallStatement(int indent, HLSLFunctionCall* functionCall) + +void MSLGenerator::OutputFunctionCallStatement(int indent, HLSLFunctionCall* functionCall, HLSLDeclaration* declaration) { + // Nothing special about these cases: + if (functionCall->function->numOutputArguments == 0) + { + m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); + if (declaration) + { + OutputDeclaration(declaration); + } + else + { + OutputExpression(functionCall, NULL); + } + m_writer.EndLine(";"); + return; + } + + + // Transform this: + // float foo = functionCall(bah, poo); + + // Into: + // auto tmp = functionCall(bah, poo); + // bah = tmp.bah; + // poo = tmp.poo; + // float foo = tmp.__result; + + const char* functionName = functionCall->function->name; + + m_writer.BeginLine(indent, functionCall->fileName, functionCall->line); + m_writer.Write("auto out%d = %s_%d(", functionCall->line, functionName, functionCall->function->line); + OutputExpressionList(functionCall->function->argument, functionCall->argument); + m_writer.EndLine(");"); + + HLSLExpression * expression = functionCall->argument; + HLSLArgument * argument = functionCall->function->argument; + while (argument != NULL) + { + if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout) + { + m_writer.BeginLine(indent); + OutputExpression(expression, NULL); + // @@ This assignment may need a cast. + m_writer.Write(" = "); + if (NeedsCast(expression->expressionType, argument->type)) { + m_writer.Write("(%s)", GetTypeName(expression->expressionType)); + } + m_writer.Write("out%d.%s;", functionCall->line, argument->name); + m_writer.EndLine(); + } + + expression = expression->nextExpression; + argument = argument->nextArgument; + } + + if (declaration) + { + m_writer.BeginLine(indent); + OutputDeclarationType(declaration->type); + m_writer.Write(" %s = out%d.__result;", declaration->name, functionCall->line); + m_writer.EndLine(); + } + + +#if 0 int argumentIndex = 0; HLSLArgument* argument = functionCall->function->argument; HLSLExpression* expression = functionCall->argument; @@ -1698,16 +2114,36 @@ void MSLGenerator::OutputFunctionCallStatement(int indent, HLSLFunctionCall* fun expression = expression->nextExpression; argumentIndex++; } +#endif // 0 } -void MSLGenerator::OutputFunctionCall(HLSLFunctionCall* functionCall) +void MSLGenerator::OutputFunctionCall(HLSLFunctionCall* functionCall, HLSLExpression * parentExpression) { - // @@ All these shenanigans only work if the function call is a statement... - - const char* name = functionCall->function->name; - m_writer.Write("%s(", name); - OutputExpressionList(functionCall->argument); - m_writer.Write(")"); + if (functionCall->function->numOutputArguments > 0) + { + ASSERT(false); + } + + const char* functionName = functionCall->function->name; + + // If function begins with tex, then it returns float4 or half4 depending on options.halfTextureSamplers + /*if (strncmp(functionName, "tex", 3) == 0) + { + if (parentExpression && IsFloat(parentExpression->expressionType.baseType)) + { + if (m_options.halfTextureSamplers) + { + OutputCast(functionCall->expressionType); + } + } + }*/ + + { + m_writer.Write("%s(", functionName); + OutputExpressionList(functionCall->function->argument, functionCall->argument); + //OutputExpressionList(functionCall->argument); + m_writer.Write(")"); + } } const char* MSLGenerator::TranslateInputSemantic(const char * semantic) @@ -1747,6 +2183,10 @@ const char* MSLGenerator::TranslateInputSemantic(const char * semantic) if (String_Equal(semantic, "SV_Position")) return "position"; if (String_Equal(semantic, "VFACE")) return "front_facing"; if (String_Equal(semantic, "TARGET_INDEX")) return "render_target_array_index"; + if (String_Equal(semantic, "DST_COLOR")) return "color(0)"; + if (String_Equal(semantic, "SAMPLE_ID")) return "sample_id"; + //if (String_Equal(semantic, "SAMPLE_MASK")) return "sample_mask"; + //if (String_Equal(semantic, "SAMPLE_MASK")) return "sample_mask,post_depth_coverage"; } return NULL; @@ -1799,4 +2239,64 @@ const char* MSLGenerator::TranslateOutputSemantic(const char * semantic) return NULL; } +const char* MSLGenerator::GetTypeName(const HLSLType& type) +{ + bool promote = ((type.flags & HLSLTypeFlag_NoPromote) == 0); + + bool float_to_half = false; + bool half_to_float = promote && m_options.treatHalfAsFloat; + bool int_to_short = promote && m_options.use16BitIntegers; + bool half_samplers = promote && type.samplerType == HLSLBaseType_Half && !m_options.treatHalfAsFloat; + + + switch (type.baseType) + { + case HLSLBaseType_Void: return "void"; + case HLSLBaseType_Float: return float_to_half ? "half" : "float"; + case HLSLBaseType_Float2: return float_to_half ? "half2" : "float2"; + case HLSLBaseType_Float3: return float_to_half ? "half3" : "float3"; + case HLSLBaseType_Float4: return float_to_half ? "half4" : "float4"; + case HLSLBaseType_Float2x2: return float_to_half ? "half2x2" : "float2x2"; + case HLSLBaseType_Float3x3: return float_to_half ? "half3x3" : "float3x3"; + case HLSLBaseType_Float4x4: return float_to_half ? "half4x4" : "float4x4"; + case HLSLBaseType_Float4x3: return float_to_half ? "half3x4" : "float3x4"; + case HLSLBaseType_Float4x2: return float_to_half ? "half2x4" : "float2x4"; + case HLSLBaseType_Half: return half_to_float ? "float" : "half"; + case HLSLBaseType_Half2: return half_to_float ? "float2" : "half2"; + case HLSLBaseType_Half3: return half_to_float ? "float3" : "half3"; + case HLSLBaseType_Half4: return half_to_float ? "float4" : "half4"; + case HLSLBaseType_Half2x2: return half_to_float ? "float2x2" : "half2x2"; + case HLSLBaseType_Half3x3: return half_to_float ? "float3x3" : "half3x3"; + case HLSLBaseType_Half4x4: return half_to_float ? "float4x4" : "half4x4"; + case HLSLBaseType_Half4x3: return half_to_float ? "float3x4" : "half3x4"; + case HLSLBaseType_Half4x2: return half_to_float ? "float2x4" : "half2x4"; + case HLSLBaseType_Bool: return "bool"; + case HLSLBaseType_Bool2: return "bool2"; + case HLSLBaseType_Bool3: return "bool3"; + case HLSLBaseType_Bool4: return "bool4"; + case HLSLBaseType_Int: return int_to_short ? "short" : "int"; + case HLSLBaseType_Int2: return int_to_short ? "short2" : "int2"; + case HLSLBaseType_Int3: return int_to_short ? "short3" : "int3"; + case HLSLBaseType_Int4: return int_to_short ? "short4" : "int4"; + case HLSLBaseType_Uint: return int_to_short ? "ushort" : "uint"; + case HLSLBaseType_Uint2: return int_to_short ? "ushort2" : "uint2"; + case HLSLBaseType_Uint3: return int_to_short ? "ushort3" : "uint3"; + case HLSLBaseType_Uint4: return int_to_short ? "ushort4" : "uint4"; + case HLSLBaseType_Texture: return "texture"; + case HLSLBaseType_Sampler: return "sampler"; + case HLSLBaseType_Sampler2D: return half_samplers ? "texture2d" : "texture2d"; + case HLSLBaseType_Sampler3D: return half_samplers ? "texture3d" : "texture3d"; + case HLSLBaseType_SamplerCube: return half_samplers ? "texturecube" : "texturecube"; + case HLSLBaseType_Sampler2DShadow: return "depth2d"; + case HLSLBaseType_Sampler2DMS: return half_samplers ? "texture2d_ms" : "texture2d_ms"; + case HLSLBaseType_Sampler2DArray: return half_samplers ? "texture2d_array" : "texture2d_array"; + case HLSLBaseType_UserDefined: return type.typeName; + default: + ASSERT(0); + return ""; + } +} + + + } // M4 diff --git a/src/libprojectM/Renderer/hlslparser/src/MSLGenerator.h b/src/libprojectM/Renderer/hlslparser/src/MSLGenerator.h old mode 100644 new mode 100755 index 2cff60f00..e56ec250e --- a/src/libprojectM/Renderer/hlslparser/src/MSLGenerator.h +++ b/src/libprojectM/Renderer/hlslparser/src/MSLGenerator.h @@ -35,12 +35,18 @@ public: unsigned int flags; unsigned int bufferRegisterOffset; int (*attributeCallback)(const char* name, unsigned int index); + bool treatHalfAsFloat; + bool usePreciseFma; + bool use16BitIntegers; Options() { flags = 0; bufferRegisterOffset = 0; attributeCallback = NULL; + treatHalfAsFloat = true; + usePreciseFma = false; + use16BitIntegers = false; } }; @@ -82,19 +88,26 @@ private: void OutputBuffer(int indent, HLSLBuffer* buffer); void OutputFunction(int indent, HLSLFunction* function); void OutputExpression(HLSLExpression* expression, HLSLExpression* parentExpression); + void OutputTypedExpression(const HLSLType& type, HLSLExpression* expression, HLSLExpression* parentExpression); + bool NeedsCast(const HLSLType & target, const HLSLType & source); void OutputCast(const HLSLType& type); void OutputArguments(HLSLArgument* argument); void OutputDeclaration(const HLSLType& type, const char* name, HLSLExpression* assignment, bool isRef = false, bool isConst = false, int alignment = 0); - void OutputDeclarationType(const HLSLType& type, bool isConst = false, bool isRef = false, int alignment = 0); + void OutputDeclarationType(const HLSLType& type, bool isConst = false, bool isRef = false, int alignment = 0, bool isTypeCast = false); void OutputDeclarationBody(const HLSLType& type, const char* name, HLSLExpression* assignment, bool isRef = false); void OutputExpressionList(HLSLExpression* expression); - void OutputFunctionCallStatement(int indent, HLSLFunctionCall* functionCall); - void OutputFunctionCall(HLSLFunctionCall* functionCall); + void OutputExpressionList(const HLSLType& type, HLSLExpression* expression); + void OutputExpressionList(HLSLArgument* argument, HLSLExpression* expression); + + void OutputFunctionCallStatement(int indent, HLSLFunctionCall* functionCall, HLSLDeclaration* assingmentExpression); + void OutputFunctionCall(HLSLFunctionCall* functionCall, HLSLExpression * parentExpression); const char* TranslateInputSemantic(const char* semantic); const char* TranslateOutputSemantic(const char* semantic); + const char* GetTypeName(const HLSLType& type); + void Error(const char* format, ...); private: @@ -110,6 +123,8 @@ private: ClassArgument * m_firstClassArgument; ClassArgument * m_lastClassArgument; + + HLSLFunction * m_currentFunction; }; } // M4 diff --git a/src/libprojectM/Renderer/hlslparser/src/Main.cpp b/src/libprojectM/Renderer/hlslparser/src/Main.cpp old mode 100644 new mode 100755 diff --git a/src/libprojectM/projectM-opengl.h b/src/libprojectM/projectM-opengl.h index d87f157e1..58cf9291a 100644 --- a/src/libprojectM/projectM-opengl.h +++ b/src/libprojectM/projectM-opengl.h @@ -5,6 +5,8 @@ #ifndef __PROJECTM_OPENGL_H__ #define __PROJECTM_OPENGL_H__ +//#define GL_TRANSITION + //#include #ifdef __APPLE__