Update to June 11 2013 code drop.
This should fix the hang bug we've been seeing.
diff --git a/src/Shader/Shader.cpp b/src/Shader/Shader.cpp
index e08b786..7f0f68f 100644
--- a/src/Shader/Shader.cpp
+++ b/src/Shader/Shader.cpp
@@ -1,6 +1,6 @@
// SwiftShader Software Renderer
//
-// Copyright(c) 2005-2012 TransGaming Inc.
+// Copyright(c) 2005-2013 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
@@ -16,6 +16,7 @@
#include "Math.hpp"
#include "Debug.hpp"
+#include <set>
#include <fstream>
#include <sstream>
#include <stdarg.h>
@@ -730,6 +731,7 @@
{
switch(opcode)
{
+ case OPCODE_NULL: return "null";
case OPCODE_NOP: return "nop";
case OPCODE_MOV: return "mov";
case OPCODE_ADD: return "add";
@@ -1372,6 +1374,110 @@
return instruction[i];
}
+ void Shader::optimize()
+ {
+ optimizeLeave();
+ optimizeCall();
+ removeNull();
+ }
+
+ void Shader::optimizeLeave()
+ {
+ // A return (leave) right before the end of a function or the shader can be removed
+ for(unsigned int i = 0; i < instruction.size(); i++)
+ {
+ if(instruction[i]->opcode == OPCODE_LEAVE)
+ {
+ if(i == instruction.size() - 1 || instruction[i + 1]->opcode == OPCODE_RET)
+ {
+ instruction[i]->opcode = OPCODE_NULL;
+ }
+ }
+ }
+ }
+
+ void Shader::optimizeCall()
+ {
+ // Eliminate uncalled functions
+ std::set<int> calledFunctions;
+ bool rescan = true;
+
+ while(rescan)
+ {
+ calledFunctions.clear();
+ rescan = false;
+
+ for(unsigned int i = 0; i < instruction.size(); i++)
+ {
+ if(instruction[i]->isCall())
+ {
+ calledFunctions.insert(instruction[i]->dst.label);
+ }
+ }
+
+ if(!calledFunctions.empty())
+ {
+ for(unsigned int i = 0; i < instruction.size(); i++)
+ {
+ if(instruction[i]->opcode == OPCODE_LABEL)
+ {
+ if(calledFunctions.find(instruction[i]->dst.label) == calledFunctions.end())
+ {
+ for( ; i < instruction.size(); i++)
+ {
+ Opcode oldOpcode = instruction[i]->opcode;
+ instruction[i]->opcode = OPCODE_NULL;
+
+ if(oldOpcode == OPCODE_RET)
+ {
+ rescan = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Optimize the entry call
+ if(instruction.size() >= 2 && instruction[0]->opcode == OPCODE_CALL && instruction[1]->opcode == OPCODE_RET)
+ {
+ if(calledFunctions.size() == 1)
+ {
+ instruction[0]->opcode = OPCODE_NULL;
+ instruction[1]->opcode = OPCODE_NULL;
+
+ for(int i = 2; i < instruction.size(); i++)
+ {
+ if(instruction[i]->opcode == OPCODE_LABEL || instruction[i]->opcode == OPCODE_RET)
+ {
+ instruction[i]->opcode = OPCODE_NULL;
+ }
+ }
+ }
+ }
+ }
+
+ void Shader::removeNull()
+ {
+ int size = 0;
+ for(int i = 0; i < instruction.size(); i++)
+ {
+ if(instruction[i]->opcode != OPCODE_NULL)
+ {
+ instruction[size] = instruction[i];
+ size++;
+ }
+ else
+ {
+ delete instruction[i];
+ }
+ }
+
+ instruction.resize(size);
+ }
+
void Shader::analyzeDirtyConstants()
{
dirtyConstantsF = 0;