Duplicate source files for Vulkan.
The Vulkan implementation needs a directory for each architectural
layer, similar to the OpenGL ES stack. The entire rendering stack is
duplicated, leaving only Reactor common between them:
Renderer -> Device
Shader -> Pipeline
Common -> System
Main -> WSI
Bug b/117152542
Change-Id: I9c26b23654016d637f88ec2416f019ef65b9afbd
Reviewed-on: https://swiftshader-review.googlesource.com/c/21248
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/System/CPUID.cpp b/src/System/CPUID.cpp
new file mode 100644
index 0000000..c080034
--- /dev/null
+++ b/src/System/CPUID.cpp
@@ -0,0 +1,301 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "CPUID.hpp"
+
+#if defined(_WIN32)
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #include <windows.h>
+ #include <intrin.h>
+ #include <float.h>
+#else
+ #include <unistd.h>
+ #include <sched.h>
+ #include <sys/types.h>
+#endif
+
+namespace sw
+{
+ bool CPUID::MMX = detectMMX();
+ bool CPUID::CMOV = detectCMOV();
+ bool CPUID::SSE = detectSSE();
+ bool CPUID::SSE2 = detectSSE2();
+ bool CPUID::SSE3 = detectSSE3();
+ bool CPUID::SSSE3 = detectSSSE3();
+ bool CPUID::SSE4_1 = detectSSE4_1();
+ int CPUID::cores = detectCoreCount();
+ int CPUID::affinity = detectAffinity();
+
+ bool CPUID::enableMMX = true;
+ bool CPUID::enableCMOV = true;
+ bool CPUID::enableSSE = true;
+ bool CPUID::enableSSE2 = true;
+ bool CPUID::enableSSE3 = true;
+ bool CPUID::enableSSSE3 = true;
+ bool CPUID::enableSSE4_1 = true;
+
+ void CPUID::setEnableMMX(bool enable)
+ {
+ enableMMX = enable;
+
+ if(!enableMMX)
+ {
+ enableSSE = false;
+ enableSSE2 = false;
+ enableSSE3 = false;
+ enableSSSE3 = false;
+ enableSSE4_1 = false;
+ }
+ }
+
+ void CPUID::setEnableCMOV(bool enable)
+ {
+ enableCMOV = enable;
+
+ if(!CMOV)
+ {
+ enableSSE = false;
+ enableSSE2 = false;
+ enableSSE3 = false;
+ enableSSSE3 = false;
+ enableSSE4_1 = false;
+ }
+ }
+
+ void CPUID::setEnableSSE(bool enable)
+ {
+ enableSSE = enable;
+
+ if(enableSSE)
+ {
+ enableMMX = true;
+ enableCMOV = true;
+ }
+ else
+ {
+ enableSSE2 = false;
+ enableSSE3 = false;
+ enableSSSE3 = false;
+ enableSSE4_1 = false;
+ }
+ }
+
+ void CPUID::setEnableSSE2(bool enable)
+ {
+ enableSSE2 = enable;
+
+ if(enableSSE2)
+ {
+ enableMMX = true;
+ enableCMOV = true;
+ enableSSE = true;
+ }
+ else
+ {
+ enableSSE3 = false;
+ enableSSSE3 = false;
+ enableSSE4_1 = false;
+ }
+ }
+
+ void CPUID::setEnableSSE3(bool enable)
+ {
+ enableSSE3 = enable;
+
+ if(enableSSE3)
+ {
+ enableMMX = true;
+ enableCMOV = true;
+ enableSSE = true;
+ enableSSE2 = true;
+ }
+ else
+ {
+ enableSSSE3 = false;
+ enableSSE4_1 = false;
+ }
+ }
+
+ void CPUID::setEnableSSSE3(bool enable)
+ {
+ enableSSSE3 = enable;
+
+ if(enableSSSE3)
+ {
+ enableMMX = true;
+ enableCMOV = true;
+ enableSSE = true;
+ enableSSE2 = true;
+ enableSSE3 = true;
+ }
+ else
+ {
+ enableSSE4_1 = false;
+ }
+ }
+
+ void CPUID::setEnableSSE4_1(bool enable)
+ {
+ enableSSE4_1 = enable;
+
+ if(enableSSE4_1)
+ {
+ enableMMX = true;
+ enableCMOV = true;
+ enableSSE = true;
+ enableSSE2 = true;
+ enableSSE3 = true;
+ enableSSSE3 = true;
+ }
+ }
+
+ static void cpuid(int registers[4], int info)
+ {
+ #if defined(__i386__) || defined(__x86_64__)
+ #if defined(_WIN32)
+ __cpuid(registers, info);
+ #else
+ __asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info));
+ #endif
+ #else
+ registers[0] = 0;
+ registers[1] = 0;
+ registers[2] = 0;
+ registers[3] = 0;
+ #endif
+ }
+
+ bool CPUID::detectMMX()
+ {
+ int registers[4];
+ cpuid(registers, 1);
+ return MMX = (registers[3] & 0x00800000) != 0;
+ }
+
+ bool CPUID::detectCMOV()
+ {
+ int registers[4];
+ cpuid(registers, 1);
+ return CMOV = (registers[3] & 0x00008000) != 0;
+ }
+
+ bool CPUID::detectSSE()
+ {
+ int registers[4];
+ cpuid(registers, 1);
+ return SSE = (registers[3] & 0x02000000) != 0;
+ }
+
+ bool CPUID::detectSSE2()
+ {
+ int registers[4];
+ cpuid(registers, 1);
+ return SSE2 = (registers[3] & 0x04000000) != 0;
+ }
+
+ bool CPUID::detectSSE3()
+ {
+ int registers[4];
+ cpuid(registers, 1);
+ return SSE3 = (registers[2] & 0x00000001) != 0;
+ }
+
+ bool CPUID::detectSSSE3()
+ {
+ int registers[4];
+ cpuid(registers, 1);
+ return SSSE3 = (registers[2] & 0x00000200) != 0;
+ }
+
+ bool CPUID::detectSSE4_1()
+ {
+ int registers[4];
+ cpuid(registers, 1);
+ return SSE4_1 = (registers[2] & 0x00080000) != 0;
+ }
+
+ int CPUID::detectCoreCount()
+ {
+ int cores = 0;
+
+ #if defined(_WIN32)
+ DWORD_PTR processAffinityMask = 1;
+ DWORD_PTR systemAffinityMask = 1;
+
+ GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask);
+
+ while(systemAffinityMask)
+ {
+ if(systemAffinityMask & 1)
+ {
+ cores++;
+ }
+
+ systemAffinityMask >>= 1;
+ }
+ #else
+ cores = sysconf(_SC_NPROCESSORS_ONLN);
+ #endif
+
+ if(cores < 1) cores = 1;
+ if(cores > 16) cores = 16;
+
+ return cores; // FIXME: Number of physical cores
+ }
+
+ int CPUID::detectAffinity()
+ {
+ int cores = 0;
+
+ #if defined(_WIN32)
+ DWORD_PTR processAffinityMask = 1;
+ DWORD_PTR systemAffinityMask = 1;
+
+ GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask);
+
+ while(processAffinityMask)
+ {
+ if(processAffinityMask & 1)
+ {
+ cores++;
+ }
+
+ processAffinityMask >>= 1;
+ }
+ #else
+ return detectCoreCount(); // FIXME: Assumes no affinity limitation
+ #endif
+
+ if(cores < 1) cores = 1;
+ if(cores > 16) cores = 16;
+
+ return cores;
+ }
+
+ void CPUID::setFlushToZero(bool enable)
+ {
+ #if defined(_MSC_VER)
+ _controlfp(enable ? _DN_FLUSH : _DN_SAVE, _MCW_DN);
+ #else
+ // Unimplemented
+ #endif
+ }
+
+ void CPUID::setDenormalsAreZero(bool enable)
+ {
+ // Unimplemented
+ }
+}
diff --git a/src/System/CPUID.hpp b/src/System/CPUID.hpp
new file mode 100644
index 0000000..3c21cd7
--- /dev/null
+++ b/src/System/CPUID.hpp
@@ -0,0 +1,137 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_CPUID_hpp
+#define sw_CPUID_hpp
+
+namespace sw
+{
+ #if !defined(__i386__) && defined(_M_IX86)
+ #define __i386__ 1
+ #endif
+
+ #if !defined(__x86_64__) && (defined(_M_AMD64) || defined (_M_X64))
+ #define __x86_64__ 1
+ #endif
+
+ class CPUID
+ {
+ public:
+ static bool supportsMMX();
+ static bool supportsCMOV();
+ static bool supportsMMX2(); // MMX instructions added by SSE: pshufw, pmulhuw, pmovmskb, pavgw/b, pextrw, pinsrw, pmaxsw/ub, etc.
+ static bool supportsSSE();
+ static bool supportsSSE2();
+ static bool supportsSSE3();
+ static bool supportsSSSE3();
+ static bool supportsSSE4_1();
+ static int coreCount();
+ static int processAffinity();
+
+ static void setEnableMMX(bool enable);
+ static void setEnableCMOV(bool enable);
+ static void setEnableSSE(bool enable);
+ static void setEnableSSE2(bool enable);
+ static void setEnableSSE3(bool enable);
+ static void setEnableSSSE3(bool enable);
+ static void setEnableSSE4_1(bool enable);
+
+ static void setFlushToZero(bool enable); // Denormal results are written as zero
+ static void setDenormalsAreZero(bool enable); // Denormal inputs are read as zero
+
+ private:
+ static bool MMX;
+ static bool CMOV;
+ static bool SSE;
+ static bool SSE2;
+ static bool SSE3;
+ static bool SSSE3;
+ static bool SSE4_1;
+ static int cores;
+ static int affinity;
+
+ static bool enableMMX;
+ static bool enableCMOV;
+ static bool enableSSE;
+ static bool enableSSE2;
+ static bool enableSSE3;
+ static bool enableSSSE3;
+ static bool enableSSE4_1;
+
+ static bool detectMMX();
+ static bool detectCMOV();
+ static bool detectSSE();
+ static bool detectSSE2();
+ static bool detectSSE3();
+ static bool detectSSSE3();
+ static bool detectSSE4_1();
+ static int detectCoreCount();
+ static int detectAffinity();
+ };
+}
+
+namespace sw
+{
+ inline bool CPUID::supportsMMX()
+ {
+ return MMX && enableMMX;
+ }
+
+ inline bool CPUID::supportsCMOV()
+ {
+ return CMOV && enableCMOV;
+ }
+
+ inline bool CPUID::supportsMMX2()
+ {
+ return supportsSSE(); // Coincides with 64-bit integer vector instructions supported by SSE
+ }
+
+ inline bool CPUID::supportsSSE()
+ {
+ return SSE && enableSSE;
+ }
+
+ inline bool CPUID::supportsSSE2()
+ {
+ return SSE2 && enableSSE2;
+ }
+
+ inline bool CPUID::supportsSSE3()
+ {
+ return SSE3 && enableSSE3;
+ }
+
+ inline bool CPUID::supportsSSSE3()
+ {
+ return SSSE3 && enableSSSE3;
+ }
+
+ inline bool CPUID::supportsSSE4_1()
+ {
+ return SSE4_1 && enableSSE4_1;
+ }
+
+ inline int CPUID::coreCount()
+ {
+ return cores;
+ }
+
+ inline int CPUID::processAffinity()
+ {
+ return affinity;
+ }
+}
+
+#endif // sw_CPUID_hpp
diff --git a/src/System/Configurator.cpp b/src/System/Configurator.cpp
new file mode 100644
index 0000000..ead1d28
--- /dev/null
+++ b/src/System/Configurator.cpp
@@ -0,0 +1,255 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Configurator.hpp"
+
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#if defined(__unix__)
+#include <unistd.h>
+#endif
+
+namespace sw
+{
+ Configurator::Configurator(string iniPath)
+ {
+ path = iniPath;
+
+ readFile();
+ }
+
+ Configurator::~Configurator()
+ {
+ }
+
+ bool Configurator::readFile()
+ {
+ #if defined(__unix__)
+ if(access(path.c_str(), R_OK) != 0)
+ {
+ return false;
+ }
+ #endif
+
+ fstream file(path.c_str(), ios::in);
+ if(file.fail()) return false;
+
+ string line;
+ string keyName;
+
+ while(getline(file, line))
+ {
+ if(line.length())
+ {
+ if(line[line.length() - 1] == '\r')
+ {
+ line = line.substr(0, line.length() - 1);
+ }
+
+ if(!isprint(line[0]))
+ {
+ // printf("Failing on char %d\n", line[0]);
+ file.close();
+ return false;
+ }
+
+ string::size_type pLeft = line.find_first_of(";#[=");
+
+ if(pLeft != string::npos)
+ {
+ switch(line[pLeft])
+ {
+ case '[':
+ {
+ string::size_type pRight = line.find_last_of("]");
+
+ if(pRight != string::npos && pRight > pLeft)
+ {
+ keyName = line.substr(pLeft + 1, pRight - pLeft - 1);
+ addKeyName(keyName);
+ }
+ }
+ break;
+ case '=':
+ {
+ string valueName = line.substr(0, pLeft);
+ string value = line.substr(pLeft + 1);
+ addValue(keyName, valueName, value);
+ }
+ break;
+ case ';':
+ case '#':
+ // Ignore comments
+ break;
+ }
+ }
+ }
+ }
+
+ file.close();
+
+ if(names.size())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ void Configurator::writeFile(std::string title)
+ {
+ #if defined(__unix__)
+ if(access(path.c_str(), W_OK) != 0)
+ {
+ return;
+ }
+ #endif
+
+ fstream file(path.c_str(), ios::out);
+ if(file.fail()) return;
+
+ file << "; " << title << endl << endl;
+
+ for(unsigned int keyID = 0; keyID < sections.size(); keyID++)
+ {
+ file << "[" << names[keyID] << "]" << endl;
+
+ for(unsigned int valueID = 0; valueID < sections[keyID].names.size(); valueID++)
+ {
+ file << sections[keyID].names[valueID] << "=" << sections[keyID].values[valueID] << endl;
+ }
+
+ file << endl;
+ }
+
+ file.close();
+ }
+
+ int Configurator::findKey(string keyName) const
+ {
+ for(unsigned int keyID = 0; keyID < names.size(); keyID++)
+ {
+ if(names[keyID] == keyName)
+ {
+ return keyID;
+ }
+ }
+
+ return -1;
+ }
+
+ int Configurator::findValue(unsigned int keyID, string valueName) const
+ {
+ if(!sections.size() || keyID >= sections.size())
+ {
+ return -1;
+ }
+
+ for(unsigned int valueID = 0; valueID < sections[keyID].names.size(); ++valueID)
+ {
+ if(sections[keyID].names[valueID] == valueName)
+ {
+ return valueID;
+ }
+ }
+
+ return -1;
+ }
+
+ unsigned int Configurator::addKeyName(string keyName)
+ {
+ names.resize(names.size() + 1, keyName);
+ sections.resize(sections.size() + 1);
+ return (unsigned int)names.size() - 1;
+ }
+
+ void Configurator::addValue(string const keyName, string const valueName, string const value)
+ {
+ int keyID = findKey(keyName);
+
+ if(keyID == -1)
+ {
+ keyID = addKeyName(keyName);
+ }
+
+ int valueID = findValue(keyID, valueName);
+
+ if(valueID == -1)
+ {
+ sections[keyID].names.resize(sections[keyID].names.size() + 1, valueName);
+ sections[keyID].values.resize(sections[keyID].values.size() + 1, value);
+ }
+ else
+ {
+ sections[keyID].values[valueID] = value;
+ }
+ }
+
+ string Configurator::getValue(string keyName, string valueName, string defaultValue) const
+ {
+ int keyID = findKey(keyName);
+ if(keyID == -1) return defaultValue;
+ int valueID = findValue((unsigned int)keyID, valueName);
+ if(valueID == -1) return defaultValue;
+
+ return sections[keyID].values[valueID];
+ }
+
+ int Configurator::getInteger(string keyName, string valueName, int defaultValue) const
+ {
+ char svalue[256];
+
+ sprintf(svalue, "%d", defaultValue);
+
+ return atoi(getValue(keyName, valueName, svalue).c_str());
+ }
+
+ bool Configurator::getBoolean(string keyName, string valueName, bool defaultValue) const
+ {
+ return getInteger(keyName, valueName, (int)defaultValue) != 0;
+ }
+
+ double Configurator::getFloat(string keyName, string valueName, double defaultValue) const
+ {
+ char svalue[256];
+
+ sprintf(svalue, "%f", defaultValue);
+
+ return atof(getValue(keyName, valueName, svalue).c_str());
+ }
+
+ unsigned int Configurator::getFormatted(string keyName, string valueName, char *format,
+ void *v1, void *v2, void *v3, void *v4,
+ void *v5, void *v6, void *v7, void *v8,
+ void *v9, void *v10, void *v11, void *v12,
+ void *v13, void *v14, void *v15, void *v16)
+ {
+ string value = getValue(keyName, valueName);
+
+ if(!value.length()) return false;
+
+ unsigned int nVals = sscanf(value.c_str(), format,
+ v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16);
+
+ return nVals;
+ }
+}
diff --git a/src/System/Configurator.hpp b/src/System/Configurator.hpp
new file mode 100644
index 0000000..6fd930c
--- /dev/null
+++ b/src/System/Configurator.hpp
@@ -0,0 +1,66 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_Configurator_hpp
+#define sw_Configurator_hpp
+
+#include <string>
+#include <vector>
+
+#include <stdlib.h>
+
+namespace sw
+{
+ class Configurator
+ {
+ public:
+ Configurator(std::string iniPath = "");
+
+ ~Configurator();
+
+ std::string getValue(std::string sectionName, std::string valueName, std::string defaultValue = "") const;
+ int getInteger(std::string sectionName, std::string valueName, int defaultValue = 0) const;
+ bool getBoolean(std::string sectionName, std::string valueName, bool defaultValue = false) const;
+ double getFloat(std::string sectionName, std::string valueName, double defaultValue = 0.0) const;
+ unsigned int getFormatted(std::string sectionName, std::string valueName, char *format,
+ void *v1 = 0, void *v2 = 0, void *v3 = 0, void *v4 = 0,
+ void *v5 = 0, void *v6 = 0, void *v7 = 0, void *v8 = 0,
+ void *v9 = 0, void *v10 = 0, void *v11 = 0, void *v12 = 0,
+ void *v13 = 0, void *v14 = 0, void *v15 = 0, void *v16 = 0);
+
+ void addValue(std::string sectionName, std::string valueName, std::string value);
+
+ void writeFile(std::string title = "Configuration File");
+
+ private:
+ bool readFile();
+
+ unsigned int addKeyName(std::string sectionName);
+ int findKey(std::string sectionName) const;
+ int findValue(unsigned int sectionID, std::string valueName) const;
+
+ std::string path;
+
+ struct Section
+ {
+ std::vector<std::string> names;
+ std::vector<std::string> values;
+ };
+
+ std::vector<Section> sections;
+ std::vector<std::string> names;
+ };
+}
+
+#endif // sw_Configurator_hpp
diff --git a/src/System/Debug.cpp b/src/System/Debug.cpp
new file mode 100644
index 0000000..acf469e
--- /dev/null
+++ b/src/System/Debug.cpp
@@ -0,0 +1,39 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Debug.hpp"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+namespace sw
+{
+void trace(const char *format, ...)
+{
+ if(false)
+ {
+ FILE *file = fopen("debug.txt", "a");
+
+ if(file)
+ {
+ va_list vararg;
+ va_start(vararg, format);
+ vfprintf(file, format, vararg);
+ va_end(vararg);
+
+ fclose(file);
+ }
+ }
+}
+}
diff --git a/src/System/Debug.hpp b/src/System/Debug.hpp
new file mode 100644
index 0000000..9758c3b
--- /dev/null
+++ b/src/System/Debug.hpp
@@ -0,0 +1,58 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef Debug_hpp
+#define Debug_hpp
+
+#if defined(__ANDROID__) && !defined(ANDROID_HOST_BUILD)
+#include "DebugAndroid.hpp"
+#else
+
+#include <assert.h>
+#include <stdio.h>
+
+#undef min
+#undef max
+
+namespace sw
+{
+void trace(const char *format, ...);
+inline void trace() {}
+}
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+ #define TRACE(format, ...) sw::trace("[0x%0.8X]%s(" format ")\n", this, __FUNCTION__, ##__VA_ARGS__)
+#else
+ #define TRACE(...) ((void)0)
+#endif
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+ #define UNIMPLEMENTED(...) do { \
+ sw::trace("\t! Unimplemented: %s(%d): ", __FUNCTION__, __LINE__); \
+ sw::trace(__VA_ARGS__); \
+ sw::trace("\n"); \
+ ASSERT(false); \
+ } while(0)
+#else
+ #define UNIMPLEMENTED(...) ((void)0)
+#endif
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+ #define ASSERT(expression) {if(!(expression)) sw::trace("\t! Assert failed in %s(%d): " #expression "\n", __FUNCTION__, __LINE__); assert(expression);}
+#else
+ #define ASSERT assert
+#endif
+
+#endif // !__ANDROID__
+#endif // Debug_hpp
diff --git a/src/System/DebugAndroid.cpp b/src/System/DebugAndroid.cpp
new file mode 100644
index 0000000..c511fc3
--- /dev/null
+++ b/src/System/DebugAndroid.cpp
@@ -0,0 +1,53 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "DebugAndroid.hpp"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <cutils/properties.h>
+
+void AndroidEnterDebugger()
+{
+ ALOGE(__FUNCTION__);
+#ifndef NDEBUG
+ static volatile int * const makefault = nullptr;
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.db.uid", value, "-1");
+ int debug_uid = atoi(value);
+ if((debug_uid >= 0) && (geteuid() < static_cast<uid_t>(debug_uid)))
+ {
+ ALOGE("Waiting for debugger: gdbserver :${PORT} --attach %u. Look for thread %u", getpid(), gettid());
+ volatile int waiting = 1;
+ while (waiting) {
+ sleep(1);
+ }
+ }
+ else
+ {
+ ALOGE("No debugger");
+ }
+#endif
+}
+
+void trace(const char *format, ...)
+{
+#ifndef NDEBUG
+ va_list vararg;
+ va_start(vararg, format);
+ android_vprintLog(ANDROID_LOG_VERBOSE, NULL, LOG_TAG, format, vararg);
+ va_end(vararg);
+#endif
+}
diff --git a/src/System/DebugAndroid.hpp b/src/System/DebugAndroid.hpp
new file mode 100644
index 0000000..eced194
--- /dev/null
+++ b/src/System/DebugAndroid.hpp
@@ -0,0 +1,99 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef DebugAndroid_hpp
+#define DebugAndroid_hpp
+
+#if ANDROID_PLATFORM_SDK_VERSION < 27
+#include <cutils/log.h>
+#elif ANDROID_PLATFORM_SDK_VERSION >= 27
+#include <log/log.h>
+#else
+#error "ANDROID_PLATFORM_SDK_VERSION is not defined"
+#endif
+
+#include <cassert>
+
+// On Android Virtual Devices we heavily depend on logging, even in
+// production builds. We do this because AVDs are components of larger
+// systems, and may be configured in ways that are difficult to
+// reproduce locally. For example some system run tests against
+// third-party code that we cannot access. Aborting (cf. assert) on
+// unimplemented functionality creates two problems. First, it produces
+// a service failure where none is needed. Second, it puts the
+// customer on the critical path for notifying us of a problem.
+// The alternative, skipping unimplemented functionality silently, is
+// arguably worse: neither the service provider nor the customer will
+// learn that unimplemented functionality may have compromised the test
+// results.
+// Logging invocations of unimplemented functionality is useful to both
+// service provider and the customer. The service provider can learn
+// that the functionality is needed. The customer learns that the test
+// results may be compromised.
+
+/**
+ * Enter the debugger with a memory fault iff debuggerd is set to capture this
+ * process. Otherwise return.
+ */
+void AndroidEnterDebugger();
+
+#define ASSERT(E) do { \
+ if (!(E)) { \
+ ALOGE("badness: assertion_failed %s in %s at %s:%d", #E, \
+ __FUNCTION__, __FILE__, __LINE__); \
+ AndroidEnterDebugger(); \
+ } \
+ } while(0)
+
+#undef assert
+#define assert(E) ASSERT(E)
+
+#define ERR(format, ...) \
+ do { \
+ ALOGE("badness: err %s %s:%d (" format ")", __FUNCTION__, __FILE__, \
+ __LINE__, ##__VA_ARGS__); \
+ AndroidEnterDebugger(); \
+ } while(0)
+
+#define FIXME(format, ...) \
+ do { \
+ ALOGE("badness: fixme %s %s:%d (" format ")", __FUNCTION__, __FILE__, \
+ __LINE__, ##__VA_ARGS__); \
+ AndroidEnterDebugger(); \
+ } while(0)
+
+// TODO: Handle __VA_ARGS__ (can be empty)
+#define UNIMPLEMENTED(...) do { \
+ ALOGE("badness: unimplemented: %s %s:%d", \
+ __FUNCTION__, __FILE__, __LINE__); \
+ AndroidEnterDebugger(); \
+ } while(0)
+
+#define UNREACHABLE(value) do { \
+ ALOGE("badness: unreachable case reached: %s %s:%d. %s: %d", \
+ __FUNCTION__, __FILE__, __LINE__, #value, value); \
+ AndroidEnterDebugger(); \
+ } while(0)
+
+#ifndef NDEBUG
+ #define TRACE(format, ...) \
+ ALOGV("%s %s:%d (" format ")", __FUNCTION__, __FILE__, \
+ __LINE__, ##__VA_ARGS__)
+#else
+ #define TRACE(...) ((void)0)
+#endif
+
+void trace(const char *format, ...);
+
+#endif // DebugAndroid_hpp
diff --git a/src/System/GrallocAndroid.cpp b/src/System/GrallocAndroid.cpp
new file mode 100644
index 0000000..c877e9933
--- /dev/null
+++ b/src/System/GrallocAndroid.cpp
@@ -0,0 +1,106 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "GrallocAndroid.hpp"
+#include "Debug.hpp"
+
+#ifdef HAVE_GRALLOC1
+#include <sync/sync.h>
+#endif
+
+GrallocModule *GrallocModule::getInstance()
+{
+ static GrallocModule instance;
+ return &instance;
+}
+
+GrallocModule::GrallocModule()
+{
+ const hw_module_t *module = nullptr;
+ hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+
+ m_major_version = (module->module_api_version >> 8) & 0xff;
+ switch(m_major_version)
+ {
+ case 0:
+ m_module = reinterpret_cast<const gralloc_module_t*>(module);
+ break;
+ case 1:
+#ifdef HAVE_GRALLOC1
+ gralloc1_open(module, &m_gralloc1_device);
+ m_gralloc1_lock = (GRALLOC1_PFN_LOCK) m_gralloc1_device->getFunction(m_gralloc1_device, GRALLOC1_FUNCTION_LOCK);
+ m_gralloc1_unlock = (GRALLOC1_PFN_UNLOCK)m_gralloc1_device->getFunction(m_gralloc1_device, GRALLOC1_FUNCTION_UNLOCK);
+ break;
+#endif
+ default:
+ TRACE("unknown gralloc major version (%d)", m_major_version);
+ break;
+ }
+}
+
+int GrallocModule::lock(buffer_handle_t handle, int usage, int left, int top, int width, int height, void **vaddr)
+{
+ switch(m_major_version)
+ {
+ case 0:
+ {
+ return m_module->lock(m_module, handle, usage, left, top, width, height, vaddr);
+ }
+ case 1:
+#ifdef HAVE_GRALLOC1
+ {
+ gralloc1_rect_t outRect{};
+ outRect.left = left;
+ outRect.top = top;
+ outRect.width = width;
+ outRect.height = height;
+ return m_gralloc1_lock(m_gralloc1_device, handle, usage, usage, &outRect, vaddr, -1);
+ }
+#endif
+ default:
+ {
+ TRACE("no gralloc module to lock");
+ return -1;
+ }
+ }
+}
+
+int GrallocModule::unlock(buffer_handle_t handle)
+{
+ switch(m_major_version)
+ {
+ case 0:
+ {
+ return m_module->unlock(m_module, handle);
+ }
+ case 1:
+#ifdef HAVE_GRALLOC1
+ {
+ int32_t fenceFd = -1;
+ int error = m_gralloc1_unlock(m_gralloc1_device, handle, &fenceFd);
+ if (!error)
+ {
+ sync_wait(fenceFd, -1);
+ close(fenceFd);
+ }
+ return error;
+ }
+#endif
+ default:
+ {
+ TRACE("no gralloc module to unlock");
+ return -1;
+ }
+ }
+}
diff --git a/src/System/GrallocAndroid.hpp b/src/System/GrallocAndroid.hpp
new file mode 100644
index 0000000..fe0b15a
--- /dev/null
+++ b/src/System/GrallocAndroid.hpp
@@ -0,0 +1,44 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef GRALLOC_ANDROID
+#define GRALLOC_ANDROID
+
+#include <hardware/gralloc.h>
+
+#ifdef HAVE_GRALLOC1
+#include <hardware/gralloc1.h>
+#endif
+
+#include <unistd.h> // for close()
+
+class GrallocModule
+{
+public:
+ static GrallocModule *getInstance();
+ int lock(buffer_handle_t handle, int usage, int left, int top, int width, int height, void **vaddr);
+ int unlock(buffer_handle_t handle);
+
+private:
+ GrallocModule();
+ uint8_t m_major_version;
+ const gralloc_module_t *m_module;
+#ifdef HAVE_GRALLOC1
+ gralloc1_device_t *m_gralloc1_device = nullptr;
+ GRALLOC1_PFN_LOCK m_gralloc1_lock = nullptr;
+ GRALLOC1_PFN_UNLOCK m_gralloc1_unlock = nullptr;
+#endif
+};
+
+#endif // GRALLOC_ANDROID
diff --git a/src/System/Half.cpp b/src/System/Half.cpp
new file mode 100644
index 0000000..cde8190
--- /dev/null
+++ b/src/System/Half.cpp
@@ -0,0 +1,102 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Half.hpp"
+
+namespace sw
+{
+ half::half(float fp32)
+ {
+ unsigned int fp32i = *(unsigned int*)&fp32;
+ unsigned int sign = (fp32i & 0x80000000) >> 16;
+ unsigned int abs = fp32i & 0x7FFFFFFF;
+
+ if(abs > 0x47FFEFFF) // Infinity
+ {
+ fp16i = sign | 0x7FFF;
+ }
+ else if(abs < 0x38800000) // Denormal
+ {
+ unsigned int mantissa = (abs & 0x007FFFFF) | 0x00800000;
+ int e = 113 - (abs >> 23);
+
+ if(e < 24)
+ {
+ abs = mantissa >> e;
+ }
+ else
+ {
+ abs = 0;
+ }
+
+ fp16i = sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13;
+ }
+ else
+ {
+ fp16i = sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13;
+ }
+ }
+
+ half::operator float() const
+ {
+ unsigned int fp32i;
+
+ int s = (fp16i >> 15) & 0x00000001;
+ int e = (fp16i >> 10) & 0x0000001F;
+ int m = fp16i & 0x000003FF;
+
+ if(e == 0)
+ {
+ if(m == 0)
+ {
+ fp32i = s << 31;
+
+ return (float&)fp32i;
+ }
+ else
+ {
+ while(!(m & 0x00000400))
+ {
+ m <<= 1;
+ e -= 1;
+ }
+
+ e += 1;
+ m &= ~0x00000400;
+ }
+ }
+
+ e = e + (127 - 15);
+ m = m << 13;
+
+ fp32i = (s << 31) | (e << 23) | m;
+
+ return (float&)fp32i;
+ }
+
+ half &half::operator=(half h)
+ {
+ fp16i = h.fp16i;
+
+ return *this;
+ }
+
+
+ half &half::operator=(float f)
+ {
+ *this = half(f);
+
+ return *this;
+ }
+}
diff --git a/src/System/Half.hpp b/src/System/Half.hpp
new file mode 100644
index 0000000..f2d378e
--- /dev/null
+++ b/src/System/Half.hpp
@@ -0,0 +1,93 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_Half_hpp
+#define sw_Half_hpp
+
+namespace sw
+{
+ class half
+ {
+ public:
+ half() = default;
+ explicit half(float f);
+
+ operator float() const;
+
+ half &operator=(half h);
+ half &operator=(float f);
+
+ private:
+ unsigned short fp16i;
+ };
+
+ inline half shortAsHalf(short s)
+ {
+ union
+ {
+ half h;
+ short s;
+ } hs;
+
+ hs.s = s;
+
+ return hs.h;
+ }
+
+ class RGB9E5
+ {
+ unsigned int R : 9;
+ unsigned int G : 9;
+ unsigned int B : 9;
+ unsigned int E : 5;
+
+ public:
+ void toRGB16F(half rgb[3]) const
+ {
+ constexpr int offset = 24; // Exponent bias (15) + number of mantissa bits per component (9) = 24
+
+ const float factor = (1u << E) * (1.0f / (1 << offset));
+ rgb[0] = half(R * factor);
+ rgb[1] = half(G * factor);
+ rgb[2] = half(B * factor);
+ }
+ };
+
+ class R11G11B10F
+ {
+ unsigned int R : 11;
+ unsigned int G : 11;
+ unsigned int B : 10;
+
+ static inline half float11ToFloat16(unsigned short fp11)
+ {
+ return shortAsHalf(fp11 << 4); // Sign bit 0
+ }
+
+ static inline half float10ToFloat16(unsigned short fp10)
+ {
+ return shortAsHalf(fp10 << 5); // Sign bit 0
+ }
+
+ public:
+ void toRGB16F(half rgb[3]) const
+ {
+ rgb[0] = float11ToFloat16(R);
+ rgb[1] = float11ToFloat16(G);
+ rgb[2] = float10ToFloat16(B);
+ }
+ };
+}
+
+#endif // sw_Half_hpp
diff --git a/src/System/Math.cpp b/src/System/Math.cpp
new file mode 100644
index 0000000..290d4ab
--- /dev/null
+++ b/src/System/Math.cpp
@@ -0,0 +1,49 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Math.hpp"
+
+namespace sw
+{
+ inline uint64_t FNV_1a(uint64_t hash, unsigned char data)
+ {
+ return (hash ^ data) * 1099511628211;
+ }
+
+ uint64_t FNV_1a(const unsigned char *data, int size)
+ {
+ int64_t hash = 0xCBF29CE484222325;
+
+ for(int i = 0; i < size; i++)
+ {
+ hash = FNV_1a(hash, data[i]);
+ }
+
+ return hash;
+ }
+
+ unsigned char sRGB8toLinear8(unsigned char value)
+ {
+ static unsigned char sRGBtoLinearTable[256] = { 255 };
+ if(sRGBtoLinearTable[0] == 255)
+ {
+ for(int i = 0; i < 256; i++)
+ {
+ sRGBtoLinearTable[i] = static_cast<unsigned char>(sw::sRGBtoLinear(static_cast<float>(i) / 255.0f) * 255.0f + 0.5f);
+ }
+ }
+
+ return sRGBtoLinearTable[value];
+ }
+}
diff --git a/src/System/Math.hpp b/src/System/Math.hpp
new file mode 100644
index 0000000..a35d2e0
--- /dev/null
+++ b/src/System/Math.hpp
@@ -0,0 +1,385 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_Math_hpp
+#define sw_Math_hpp
+
+#include "Types.hpp"
+#include "Half.hpp"
+
+#include <cmath>
+#if defined(_MSC_VER)
+ #include <intrin.h>
+#endif
+
+namespace sw
+{
+ using std::abs;
+
+ #undef min
+ #undef max
+
+ template<class T>
+ inline T max(T a, T b)
+ {
+ return a > b ? a : b;
+ }
+
+ template<class T>
+ inline T min(T a, T b)
+ {
+ return a < b ? a : b;
+ }
+
+ template<class T>
+ inline T max(T a, T b, T c)
+ {
+ return max(max(a, b), c);
+ }
+
+ template<class T>
+ inline T min(T a, T b, T c)
+ {
+ return min(min(a, b), c);
+ }
+
+ template<class T>
+ inline T max(T a, T b, T c, T d)
+ {
+ return max(max(a, b), max(c, d));
+ }
+
+ template<class T>
+ inline T min(T a, T b, T c, T d)
+ {
+ return min(min(a, b), min(c, d));
+ }
+
+ template<class T>
+ inline void swap(T &a, T &b)
+ {
+ T t = a;
+ a = b;
+ b = t;
+ }
+
+ template <typename destType, typename sourceType>
+ destType bitCast(const sourceType &source)
+ {
+ union
+ {
+ sourceType s;
+ destType d;
+ } sd;
+ sd.s = source;
+ return sd.d;
+ }
+
+ inline int iround(float x)
+ {
+ return (int)floor(x + 0.5f);
+ // return _mm_cvtss_si32(_mm_load_ss(&x)); // FIXME: Demands SSE support
+ }
+
+ inline int ifloor(float x)
+ {
+ return (int)floor(x);
+ }
+
+ inline int ceilFix4(int x)
+ {
+ return (x + 0xF) & 0xFFFFFFF0;
+ }
+
+ inline int ceilInt4(int x)
+ {
+ return (x + 0xF) >> 4;
+ }
+
+ #define BITS(x) ( \
+ !!((x) & 0x80000000) + \
+ !!((x) & 0xC0000000) + \
+ !!((x) & 0xE0000000) + \
+ !!((x) & 0xF0000000) + \
+ !!((x) & 0xF8000000) + \
+ !!((x) & 0xFC000000) + \
+ !!((x) & 0xFE000000) + \
+ !!((x) & 0xFF000000) + \
+ !!((x) & 0xFF800000) + \
+ !!((x) & 0xFFC00000) + \
+ !!((x) & 0xFFE00000) + \
+ !!((x) & 0xFFF00000) + \
+ !!((x) & 0xFFF80000) + \
+ !!((x) & 0xFFFC0000) + \
+ !!((x) & 0xFFFE0000) + \
+ !!((x) & 0xFFFF0000) + \
+ !!((x) & 0xFFFF8000) + \
+ !!((x) & 0xFFFFC000) + \
+ !!((x) & 0xFFFFE000) + \
+ !!((x) & 0xFFFFF000) + \
+ !!((x) & 0xFFFFF800) + \
+ !!((x) & 0xFFFFFC00) + \
+ !!((x) & 0xFFFFFE00) + \
+ !!((x) & 0xFFFFFF00) + \
+ !!((x) & 0xFFFFFF80) + \
+ !!((x) & 0xFFFFFFC0) + \
+ !!((x) & 0xFFFFFFE0) + \
+ !!((x) & 0xFFFFFFF0) + \
+ !!((x) & 0xFFFFFFF8) + \
+ !!((x) & 0xFFFFFFFC) + \
+ !!((x) & 0xFFFFFFFE) + \
+ !!((x) & 0xFFFFFFFF))
+
+ #define MAX(x, y) ((x) > (y) ? (x) : (y))
+ #define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+ inline float exp2(float x)
+ {
+ return exp2f(x);
+ }
+
+ inline int exp2(int x)
+ {
+ return 1 << x;
+ }
+
+ inline unsigned long log2(int x)
+ {
+ #if defined(_MSC_VER)
+ unsigned long y;
+ _BitScanReverse(&y, x);
+ return y;
+ #else
+ return 31 - __builtin_clz(x);
+ #endif
+ }
+
+ inline int ilog2(float x)
+ {
+ unsigned int y = *(unsigned int*)&x;
+
+ return ((y & 0x7F800000) >> 23) - 127;
+ }
+
+ inline float log2(float x)
+ {
+ return logf(x) * 1.44269504f; // 1.0 / log[e](2)
+ }
+
+ inline bool isPow2(int x)
+ {
+ return (x & -x) == x;
+ }
+
+ template<class T>
+ inline T clamp(T x, T a, T b)
+ {
+ if(x < a) x = a;
+ if(x > b) x = b;
+
+ return x;
+ }
+
+ inline float clamp01(float x)
+ {
+ return clamp(x, 0.0f, 1.0f);
+ }
+
+ inline int ceilPow2(int x)
+ {
+ int i = 1;
+
+ while(i < x)
+ {
+ i <<= 1;
+ }
+
+ return i;
+ }
+
+ inline int floorDiv(int a, int b)
+ {
+ return a / b + ((a % b) >> 31);
+ }
+
+ inline int floorMod(int a, int b)
+ {
+ int r = a % b;
+ return r + ((r >> 31) & b);
+ }
+
+ inline int ceilDiv(int a, int b)
+ {
+ return a / b - (-(a % b) >> 31);
+ }
+
+ inline int ceilMod(int a, int b)
+ {
+ int r = a % b;
+ return r - ((-r >> 31) & b);
+ }
+
+ template<const int n>
+ inline unsigned int unorm(float x)
+ {
+ static const unsigned int max = 0xFFFFFFFF >> (32 - n);
+ static const float maxf = static_cast<float>(max);
+
+ if(x >= 1.0f)
+ {
+ return max;
+ }
+ else if(x <= 0.0f)
+ {
+ return 0;
+ }
+ else
+ {
+ return static_cast<unsigned int>(maxf * x + 0.5f);
+ }
+ }
+
+ template<const int n>
+ inline int snorm(float x)
+ {
+ static const unsigned int min = 0x80000000 >> (32 - n);
+ static const unsigned int max = 0xFFFFFFFF >> (32 - n + 1);
+ static const float maxf = static_cast<float>(max);
+ static const unsigned int range = 0xFFFFFFFF >> (32 - n);
+
+ if(x >= 0.0f)
+ {
+ if(x >= 1.0f)
+ {
+ return max;
+ }
+ else
+ {
+ return static_cast<int>(maxf * x + 0.5f);
+ }
+ }
+ else
+ {
+ if(x <= -1.0f)
+ {
+ return min;
+ }
+ else
+ {
+ return static_cast<int>(maxf * x - 0.5f) & range;
+ }
+ }
+ }
+
+ template<const int n>
+ inline unsigned int ucast(float x)
+ {
+ static const unsigned int max = 0xFFFFFFFF >> (32 - n);
+ static const float maxf = static_cast<float>(max);
+
+ if(x >= maxf)
+ {
+ return max;
+ }
+ else if(x <= 0.0f)
+ {
+ return 0;
+ }
+ else
+ {
+ return static_cast<unsigned int>(x + 0.5f);
+ }
+ }
+
+ template<const int n>
+ inline int scast(float x)
+ {
+ static const unsigned int min = 0x80000000 >> (32 - n);
+ static const unsigned int max = 0xFFFFFFFF >> (32 - n + 1);
+ static const float maxf = static_cast<float>(max);
+ static const float minf = static_cast<float>(min);
+ static const unsigned int range = 0xFFFFFFFF >> (32 - n);
+
+ if(x > 0.0f)
+ {
+ if(x >= maxf)
+ {
+ return max;
+ }
+ else
+ {
+ return static_cast<int>(x + 0.5f);
+ }
+ }
+ else
+ {
+ if(x <= -minf)
+ {
+ return min;
+ }
+ else
+ {
+ return static_cast<int>(x - 0.5f) & range;
+ }
+ }
+ }
+
+ inline float sRGBtoLinear(float c)
+ {
+ if(c <= 0.04045f)
+ {
+ return c * 0.07739938f; // 1.0f / 12.92f;
+ }
+ else
+ {
+ return powf((c + 0.055f) * 0.9478673f, 2.4f); // 1.0f / 1.055f
+ }
+ }
+
+ inline float linearToSRGB(float c)
+ {
+ if(c <= 0.0031308f)
+ {
+ return c * 12.92f;
+ }
+ else
+ {
+ return 1.055f * powf(c, 0.4166667f) - 0.055f; // 1.0f / 2.4f
+ }
+ }
+
+ unsigned char sRGB8toLinear8(unsigned char value);
+
+ uint64_t FNV_1a(const unsigned char *data, int size); // Fowler-Noll-Vo hash function
+
+ // Round up to the next multiple of alignment
+ template<typename T>
+ inline T align(T value, unsigned int alignment)
+ {
+ return ((value + alignment - 1) / alignment) * alignment;
+ }
+
+ template<unsigned int alignment, typename T>
+ inline T align(T value)
+ {
+ return ((value + alignment - 1) / alignment) * alignment;
+ }
+
+ inline int clampToSignedInt(unsigned int x)
+ {
+ return static_cast<int>(min(x, 0x7FFFFFFFu));
+ }
+}
+
+#endif // sw_Math_hpp
diff --git a/src/System/Memory.cpp b/src/System/Memory.cpp
new file mode 100644
index 0000000..45fef40
--- /dev/null
+++ b/src/System/Memory.cpp
@@ -0,0 +1,262 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Memory.hpp"
+
+#include "Types.hpp"
+#include "Debug.hpp"
+
+#if defined(_WIN32)
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #include <windows.h>
+ #include <intrin.h>
+#else
+ #include <errno.h>
+ #include <sys/mman.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+#endif
+
+#include <memory.h>
+
+#undef allocate
+#undef deallocate
+
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined (_M_X64)) && !defined(__x86__)
+#define __x86__
+#endif
+
+namespace sw
+{
+namespace
+{
+struct Allocation
+{
+// size_t bytes;
+ unsigned char *block;
+};
+
+void *allocateRaw(size_t bytes, size_t alignment)
+{
+ ASSERT((alignment & (alignment - 1)) == 0); // Power of 2 alignment.
+
+ #if defined(LINUX_ENABLE_NAMED_MMAP)
+ void *allocation;
+ int result = posix_memalign(&allocation, alignment, bytes);
+ if(result != 0)
+ {
+ errno = result;
+ allocation = nullptr;
+ }
+ return allocation;
+ #else
+ unsigned char *block = new unsigned char[bytes + sizeof(Allocation) + alignment];
+ unsigned char *aligned = nullptr;
+
+ if(block)
+ {
+ aligned = (unsigned char*)((uintptr_t)(block + sizeof(Allocation) + alignment - 1) & -(intptr_t)alignment);
+ Allocation *allocation = (Allocation*)(aligned - sizeof(Allocation));
+
+ // allocation->bytes = bytes;
+ allocation->block = block;
+ }
+
+ return aligned;
+ #endif
+}
+
+#if defined(LINUX_ENABLE_NAMED_MMAP)
+// Create a file descriptor for anonymous memory with the given
+// name. Returns -1 on failure.
+// TODO: remove once libc wrapper exists.
+int memfd_create(const char* name, unsigned int flags)
+{
+ #if __aarch64__
+ #define __NR_memfd_create 279
+ #elif __arm__
+ #define __NR_memfd_create 279
+ #elif __powerpc64__
+ #define __NR_memfd_create 360
+ #elif __i386__
+ #define __NR_memfd_create 356
+ #elif __x86_64__
+ #define __NR_memfd_create 319
+ #endif /* __NR_memfd_create__ */
+ #ifdef __NR_memfd_create
+ // In the event of no system call this returns -1 with errno set
+ // as ENOSYS.
+ return syscall(__NR_memfd_create, name, flags);
+ #else
+ return -1;
+ #endif
+}
+
+// Returns a file descriptor for use with an anonymous mmap, if
+// memfd_create fails, -1 is returned. Note, the mappings should be
+// MAP_PRIVATE so that underlying pages aren't shared.
+int anonymousFd()
+{
+ static int fd = memfd_create("SwiftShader JIT", 0);
+ return fd;
+}
+
+// Ensure there is enough space in the "anonymous" fd for length.
+void ensureAnonFileSize(int anonFd, size_t length)
+{
+ static size_t fileSize = 0;
+ if(length > fileSize)
+ {
+ ftruncate(anonFd, length);
+ fileSize = length;
+ }
+}
+#endif // defined(LINUX_ENABLE_NAMED_MMAP)
+
+} // anonymous namespace
+
+size_t memoryPageSize()
+{
+ static int pageSize = 0;
+
+ if(pageSize == 0)
+ {
+ #if defined(_WIN32)
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ pageSize = systemInfo.dwPageSize;
+ #else
+ pageSize = sysconf(_SC_PAGESIZE);
+ #endif
+ }
+
+ return pageSize;
+}
+
+void *allocate(size_t bytes, size_t alignment)
+{
+ void *memory = allocateRaw(bytes, alignment);
+
+ if(memory)
+ {
+ memset(memory, 0, bytes);
+ }
+
+ return memory;
+}
+
+void deallocate(void *memory)
+{
+ #if defined(LINUX_ENABLE_NAMED_MMAP)
+ free(memory);
+ #else
+ if(memory)
+ {
+ unsigned char *aligned = (unsigned char*)memory;
+ Allocation *allocation = (Allocation*)(aligned - sizeof(Allocation));
+
+ delete[] allocation->block;
+ }
+ #endif
+}
+
+void *allocateExecutable(size_t bytes)
+{
+ size_t pageSize = memoryPageSize();
+ size_t length = (bytes + pageSize - 1) & ~(pageSize - 1);
+ void *mapping;
+
+ #if defined(LINUX_ENABLE_NAMED_MMAP)
+ // Try to name the memory region for the executable code,
+ // to aid profilers.
+ int anonFd = anonymousFd();
+ if(anonFd == -1)
+ {
+ mapping = mmap(nullptr, length, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ }
+ else
+ {
+ ensureAnonFileSize(anonFd, length);
+ mapping = mmap(nullptr, length, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, anonFd, 0);
+ }
+
+ if(mapping == MAP_FAILED)
+ {
+ mapping = nullptr;
+ }
+ #else
+ mapping = allocate(length, pageSize);
+ #endif
+
+ return mapping;
+}
+
+void markExecutable(void *memory, size_t bytes)
+{
+ #if defined(_WIN32)
+ unsigned long oldProtection;
+ VirtualProtect(memory, bytes, PAGE_EXECUTE_READ, &oldProtection);
+ #else
+ mprotect(memory, bytes, PROT_READ | PROT_EXEC);
+ #endif
+}
+
+void deallocateExecutable(void *memory, size_t bytes)
+{
+ #if defined(_WIN32)
+ unsigned long oldProtection;
+ VirtualProtect(memory, bytes, PAGE_READWRITE, &oldProtection);
+ deallocate(memory);
+ #elif defined(LINUX_ENABLE_NAMED_MMAP)
+ size_t pageSize = memoryPageSize();
+ size_t length = (bytes + pageSize - 1) & ~(pageSize - 1);
+ munmap(memory, length);
+ #else
+ mprotect(memory, bytes, PROT_READ | PROT_WRITE);
+ deallocate(memory);
+ #endif
+}
+
+void clear(uint16_t *memory, uint16_t element, size_t count)
+{
+ #if defined(_MSC_VER) && defined(__x86__) && !defined(MEMORY_SANITIZER)
+ __stosw(memory, element, count);
+ #elif defined(__GNUC__) && defined(__x86__) && !defined(MEMORY_SANITIZER)
+ __asm__("rep stosw" : : "D"(memory), "a"(element), "c"(count));
+ #else
+ for(size_t i = 0; i < count; i++)
+ {
+ memory[i] = element;
+ }
+ #endif
+}
+
+void clear(uint32_t *memory, uint32_t element, size_t count)
+{
+ #if defined(_MSC_VER) && defined(__x86__) && !defined(MEMORY_SANITIZER)
+ __stosd((unsigned long*)memory, element, count);
+ #elif defined(__GNUC__) && defined(__x86__) && !defined(MEMORY_SANITIZER)
+ __asm__("rep stosl" : : "D"(memory), "a"(element), "c"(count));
+ #else
+ for(size_t i = 0; i < count; i++)
+ {
+ memory[i] = element;
+ }
+ #endif
+}
+}
diff --git a/src/System/Memory.hpp b/src/System/Memory.hpp
new file mode 100644
index 0000000..8d3a159
--- /dev/null
+++ b/src/System/Memory.hpp
@@ -0,0 +1,36 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef Memory_hpp
+#define Memory_hpp
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace sw
+{
+size_t memoryPageSize();
+
+void *allocate(size_t bytes, size_t alignment = 16);
+void deallocate(void *memory);
+
+void *allocateExecutable(size_t bytes); // Allocates memory that can be made executable using markExecutable()
+void markExecutable(void *memory, size_t bytes);
+void deallocateExecutable(void *memory, size_t bytes);
+
+void clear(uint16_t *memory, uint16_t element, size_t count);
+void clear(uint32_t *memory, uint32_t element, size_t count);
+}
+
+#endif // Memory_hpp
diff --git a/src/System/MutexLock.hpp b/src/System/MutexLock.hpp
new file mode 100644
index 0000000..65e9fa4
--- /dev/null
+++ b/src/System/MutexLock.hpp
@@ -0,0 +1,199 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_MutexLock_hpp
+#define sw_MutexLock_hpp
+
+#include "Thread.hpp"
+
+#if defined(__linux__)
+// Use a pthread mutex on Linux. Since many processes may use SwiftShader
+// at the same time it's best to just have the scheduler overhead.
+#include <pthread.h>
+
+namespace sw
+{
+ class MutexLock
+ {
+ public:
+ MutexLock()
+ {
+ pthread_mutex_init(&mutex, NULL);
+ }
+
+ ~MutexLock()
+ {
+ pthread_mutex_destroy(&mutex);
+ }
+
+ bool attemptLock()
+ {
+ return pthread_mutex_trylock(&mutex) == 0;
+ }
+
+ void lock()
+ {
+ pthread_mutex_lock(&mutex);
+ }
+
+ void unlock()
+ {
+ pthread_mutex_unlock(&mutex);
+ }
+
+ private:
+ pthread_mutex_t mutex;
+ };
+}
+
+#else // !__linux__
+
+#include <atomic>
+
+namespace sw
+{
+ class BackoffLock
+ {
+ public:
+ BackoffLock()
+ {
+ mutex = 0;
+ }
+
+ bool attemptLock()
+ {
+ if(!isLocked())
+ {
+ if(mutex.exchange(true) == false)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void lock()
+ {
+ int backoff = 1;
+
+ while(!attemptLock())
+ {
+ if(backoff <= 64)
+ {
+ for(int i = 0; i < backoff; i++)
+ {
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ }
+
+ backoff *= 2;
+ }
+ else
+ {
+ Thread::yield();
+
+ backoff = 1;
+ }
+ };
+ }
+
+ void unlock()
+ {
+ mutex.store(false, std::memory_order_release);
+ }
+
+ bool isLocked()
+ {
+ return mutex.load(std::memory_order_acquire);
+ }
+
+ private:
+ struct
+ {
+ // Ensure that the mutex variable is on its own 64-byte cache line to avoid false sharing
+ // Padding must be public to avoid compiler warnings
+ volatile int padding1[16];
+ std::atomic<bool> mutex;
+ volatile int padding2[15];
+ };
+ };
+
+ using MutexLock = BackoffLock;
+}
+
+#endif // !__ANDROID__
+
+class LockGuard
+{
+public:
+ explicit LockGuard(sw::MutexLock &mutex) : mutex(&mutex)
+ {
+ mutex.lock();
+ }
+
+ explicit LockGuard(sw::MutexLock *mutex) : mutex(mutex)
+ {
+ if (mutex) mutex->lock();
+ }
+
+ ~LockGuard()
+ {
+ if (mutex) mutex->unlock();
+ }
+
+protected:
+ sw::MutexLock *mutex;
+};
+
+#endif // sw_MutexLock_hpp
diff --git a/src/System/Resource.cpp b/src/System/Resource.cpp
new file mode 100644
index 0000000..3a63810
--- /dev/null
+++ b/src/System/Resource.cpp
@@ -0,0 +1,184 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Resource.hpp"
+
+#include "Memory.hpp"
+#include "Debug.hpp"
+
+namespace sw
+{
+ Resource::Resource(size_t bytes) : size(bytes)
+ {
+ blocked = 0;
+
+ accessor = PUBLIC;
+ count = 0;
+ orphaned = false;
+
+ buffer = allocate(bytes);
+ }
+
+ Resource::~Resource()
+ {
+ deallocate(buffer);
+ }
+
+ void *Resource::lock(Accessor claimer)
+ {
+ criticalSection.lock();
+
+ while(count > 0 && accessor != claimer)
+ {
+ blocked++;
+ criticalSection.unlock();
+
+ unblock.wait();
+
+ criticalSection.lock();
+ blocked--;
+ }
+
+ accessor = claimer;
+ count++;
+
+ criticalSection.unlock();
+
+ return buffer;
+ }
+
+ void *Resource::lock(Accessor relinquisher, Accessor claimer)
+ {
+ criticalSection.lock();
+
+ // Release
+ while(count > 0 && accessor == relinquisher)
+ {
+ count--;
+
+ if(count == 0)
+ {
+ if(blocked)
+ {
+ unblock.signal();
+ }
+ else if(orphaned)
+ {
+ criticalSection.unlock();
+
+ delete this;
+
+ return 0;
+ }
+ }
+ }
+
+ // Acquire
+ while(count > 0 && accessor != claimer)
+ {
+ blocked++;
+ criticalSection.unlock();
+
+ unblock.wait();
+
+ criticalSection.lock();
+ blocked--;
+ }
+
+ accessor = claimer;
+ count++;
+
+ criticalSection.unlock();
+
+ return buffer;
+ }
+
+ void Resource::unlock()
+ {
+ criticalSection.lock();
+ ASSERT(count > 0);
+
+ count--;
+
+ if(count == 0)
+ {
+ if(blocked)
+ {
+ unblock.signal();
+ }
+ else if(orphaned)
+ {
+ criticalSection.unlock();
+
+ delete this;
+
+ return;
+ }
+ }
+
+ criticalSection.unlock();
+ }
+
+ void Resource::unlock(Accessor relinquisher)
+ {
+ criticalSection.lock();
+ ASSERT(count > 0);
+
+ while(count > 0 && accessor == relinquisher)
+ {
+ count--;
+
+ if(count == 0)
+ {
+ if(blocked)
+ {
+ unblock.signal();
+ }
+ else if(orphaned)
+ {
+ criticalSection.unlock();
+
+ delete this;
+
+ return;
+ }
+ }
+ }
+
+ criticalSection.unlock();
+ }
+
+ void Resource::destruct()
+ {
+ criticalSection.lock();
+
+ if(count == 0 && !blocked)
+ {
+ criticalSection.unlock();
+
+ delete this;
+
+ return;
+ }
+
+ orphaned = true;
+
+ criticalSection.unlock();
+ }
+
+ const void *Resource::data() const
+ {
+ return buffer;
+ }
+}
diff --git a/src/System/Resource.hpp b/src/System/Resource.hpp
new file mode 100644
index 0000000..0acfa48
--- /dev/null
+++ b/src/System/Resource.hpp
@@ -0,0 +1,60 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_Resource_hpp
+#define sw_Resource_hpp
+
+#include "MutexLock.hpp"
+
+namespace sw
+{
+ enum Accessor
+ {
+ PUBLIC, // Application/API access
+ PRIVATE, // Renderer access, shared by multiple threads if read-only
+ MANAGED, // Renderer access, shared read/write access if partitioned
+ EXCLUSIVE
+ };
+
+ class Resource
+ {
+ public:
+ Resource(size_t bytes);
+
+ void destruct(); // Asynchronous destructor
+
+ void *lock(Accessor claimer);
+ void *lock(Accessor relinquisher, Accessor claimer);
+ void unlock();
+ void unlock(Accessor relinquisher);
+
+ const void *data() const;
+ const size_t size;
+
+ private:
+ ~Resource(); // Always call destruct() instead
+
+ MutexLock criticalSection;
+ Event unblock;
+ volatile int blocked;
+
+ volatile Accessor accessor;
+ volatile int count;
+ bool orphaned;
+
+ void *buffer;
+ };
+}
+
+#endif // sw_Resource_hpp
diff --git a/src/System/SharedLibrary.hpp b/src/System/SharedLibrary.hpp
new file mode 100644
index 0000000..8a8c3a1
--- /dev/null
+++ b/src/System/SharedLibrary.hpp
@@ -0,0 +1,171 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SharedLibrary_hpp
+#define SharedLibrary_hpp
+
+#if defined(_WIN32)
+ #include <Windows.h>
+#else
+ #include <dlfcn.h>
+#endif
+
+#include <string>
+
+void *getLibraryHandle(const char *path);
+void *loadLibrary(const char *path);
+void freeLibrary(void *library);
+void *getProcAddress(void *library, const char *name);
+
+template<int n>
+void *loadLibrary(const std::string &libraryDirectory, const char *(&names)[n], const char *mustContainSymbol = nullptr)
+{
+ for(const char *libraryName : names)
+ {
+ std::string libraryPath = libraryDirectory + libraryName;
+ void *library = getLibraryHandle(libraryPath.c_str());
+
+ if(library)
+ {
+ if(!mustContainSymbol || getProcAddress(library, mustContainSymbol))
+ {
+ return library;
+ }
+
+ freeLibrary(library);
+ }
+ }
+
+ for(const char *libraryName : names)
+ {
+ std::string libraryPath = libraryDirectory + libraryName;
+ void *library = loadLibrary(libraryPath.c_str());
+
+ if(library)
+ {
+ if(!mustContainSymbol || getProcAddress(library, mustContainSymbol))
+ {
+ return library;
+ }
+
+ freeLibrary(library);
+ }
+ }
+
+ return nullptr;
+}
+
+#if defined(_WIN32)
+ inline void *loadLibrary(const char *path)
+ {
+ return (void*)LoadLibrary(path);
+ }
+
+ inline void *getLibraryHandle(const char *path)
+ {
+ HMODULE module = NULL;
+ GetModuleHandleEx(0, path, &module);
+ return (void*)module;
+ }
+
+ inline void freeLibrary(void *library)
+ {
+ FreeLibrary((HMODULE)library);
+ }
+
+ inline void *getProcAddress(void *library, const char *name)
+ {
+ return (void*)GetProcAddress((HMODULE)library, name);
+ }
+
+ inline std::string getModuleDirectory()
+ {
+ static int dummy_symbol = 0;
+
+ HMODULE module = NULL;
+ GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&dummy_symbol, &module);
+
+ char filename[1024];
+ if(module && (GetModuleFileName(module, filename, sizeof(filename)) != 0))
+ {
+ std::string directory(filename);
+ return directory.substr(0, directory.find_last_of("\\/") + 1).c_str();
+ }
+ else
+ {
+ return "";
+ }
+ }
+#else
+ inline void *loadLibrary(const char *path)
+ {
+ return dlopen(path, RTLD_LAZY | RTLD_LOCAL);
+ }
+
+ inline void *getLibraryHandle(const char *path)
+ {
+ #ifdef __ANDROID__
+ // bionic doesn't support RTLD_NOLOAD before L
+ return dlopen(path, RTLD_NOW | RTLD_LOCAL);
+ #else
+ void *resident = dlopen(path, RTLD_LAZY | RTLD_NOLOAD | RTLD_LOCAL);
+
+ if(resident)
+ {
+ return dlopen(path, RTLD_LAZY | RTLD_LOCAL); // Increment reference count
+ }
+
+ return nullptr;
+ #endif
+ }
+
+ inline void freeLibrary(void *library)
+ {
+ if(library)
+ {
+ dlclose(library);
+ }
+ }
+
+ inline void *getProcAddress(void *library, const char *name)
+ {
+ void *symbol = dlsym(library, name);
+
+ if(!symbol)
+ {
+ const char *reason = dlerror(); // Silence the error
+ (void)reason;
+ }
+
+ return symbol;
+ }
+
+ inline std::string getModuleDirectory()
+ {
+ static int dummy_symbol = 0;
+
+ Dl_info dl_info;
+ if(dladdr(&dummy_symbol, &dl_info) != 0)
+ {
+ std::string directory(dl_info.dli_fname);
+ return directory.substr(0, directory.find_last_of("\\/") + 1).c_str();
+ }
+ else
+ {
+ return "";
+ }
+ }
+#endif
+
+#endif // SharedLibrary_hpp
diff --git a/src/System/Socket.cpp b/src/System/Socket.cpp
new file mode 100644
index 0000000..b098031
--- /dev/null
+++ b/src/System/Socket.cpp
@@ -0,0 +1,110 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Socket.hpp"
+
+#if defined(_WIN32)
+ #include <ws2tcpip.h>
+#else
+ #include <unistd.h>
+ #include <netdb.h>
+ #include <netinet/in.h>
+ #include <sys/select.h>
+#endif
+
+namespace sw
+{
+ Socket::Socket(SOCKET socket) : socket(socket)
+ {
+ }
+
+ Socket::Socket(const char *address, const char *port)
+ {
+ #if defined(_WIN32)
+ socket = INVALID_SOCKET;
+ #else
+ socket = -1;
+ #endif
+
+ addrinfo hints = {};
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = AI_PASSIVE;
+
+ addrinfo *info = 0;
+ getaddrinfo(address, port, &hints, &info);
+
+ if(info)
+ {
+ socket = ::socket(info->ai_family, info->ai_socktype, info->ai_protocol);
+ bind(socket, info->ai_addr, (int)info->ai_addrlen);
+ }
+ }
+
+ Socket::~Socket()
+ {
+ #if defined(_WIN32)
+ closesocket(socket);
+ #else
+ close(socket);
+ #endif
+ }
+
+ void Socket::listen(int backlog)
+ {
+ ::listen(socket, backlog);
+ }
+
+ bool Socket::select(int us)
+ {
+ fd_set sockets;
+ FD_ZERO(&sockets);
+ FD_SET(socket, &sockets);
+
+ timeval timeout = {us / 1000000, us % 1000000};
+
+ return ::select(FD_SETSIZE, &sockets, 0, 0, &timeout) >= 1;
+ }
+
+ Socket *Socket::accept()
+ {
+ return new Socket(::accept(socket, 0, 0));
+ }
+
+ int Socket::receive(char *buffer, int length)
+ {
+ return recv(socket, buffer, length, 0);
+ }
+
+ void Socket::send(const char *buffer, int length)
+ {
+ ::send(socket, buffer, length, 0);
+ }
+
+ void Socket::startup()
+ {
+ #if defined(_WIN32)
+ WSADATA winsockData;
+ WSAStartup(MAKEWORD(2, 2), &winsockData);
+ #endif
+ }
+
+ void Socket::cleanup()
+ {
+ #if defined(_WIN32)
+ WSACleanup();
+ #endif
+ }
+}
diff --git a/src/System/Socket.hpp b/src/System/Socket.hpp
new file mode 100644
index 0000000..b6b9abd
--- /dev/null
+++ b/src/System/Socket.hpp
@@ -0,0 +1,49 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_Socket_hpp
+#define sw_Socket_hpp
+
+#if defined(_WIN32)
+ #include <winsock2.h>
+#else
+ #include <sys/socket.h>
+ typedef int SOCKET;
+#endif
+
+namespace sw
+{
+ class Socket
+ {
+ public:
+ Socket(SOCKET socket);
+ Socket(const char *address, const char *port);
+ ~Socket();
+
+ void listen(int backlog = 1);
+ bool select(int us);
+ Socket *accept();
+
+ int receive(char *buffer, int length);
+ void send(const char *buffer, int length);
+
+ static void startup();
+ static void cleanup();
+
+ private:
+ SOCKET socket;
+ };
+}
+
+#endif // sw_Socket_hpp
diff --git a/src/System/Thread.cpp b/src/System/Thread.cpp
new file mode 100644
index 0000000..df9a0b7
--- /dev/null
+++ b/src/System/Thread.cpp
@@ -0,0 +1,91 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Thread.hpp"
+
+namespace sw
+{
+ Thread::Thread(void (*threadFunction)(void *parameters), void *parameters)
+ {
+ Event init;
+ Entry entry = {threadFunction, parameters, &init};
+
+ #if defined(_WIN32)
+ handle = CreateThread(NULL, 1024 * 1024, startFunction, &entry, 0, NULL);
+ #else
+ pthread_create(&handle, NULL, startFunction, &entry);
+ #endif
+
+ init.wait();
+ }
+
+ Thread::~Thread()
+ {
+ join(); // Make threads exit before deleting them to not block here
+ }
+
+ void Thread::join()
+ {
+ if(!hasJoined)
+ {
+ #if defined(_WIN32)
+ WaitForSingleObject(handle, INFINITE);
+ CloseHandle(handle);
+ #else
+ pthread_join(handle, NULL);
+ #endif
+
+ hasJoined = true;
+ }
+ }
+
+ #if defined(_WIN32)
+ unsigned long __stdcall Thread::startFunction(void *parameters)
+ {
+ Entry entry = *(Entry*)parameters;
+ entry.init->signal();
+ entry.threadFunction(entry.threadParameters);
+ return 0;
+ }
+ #else
+ void *Thread::startFunction(void *parameters)
+ {
+ Entry entry = *(Entry*)parameters;
+ entry.init->signal();
+ entry.threadFunction(entry.threadParameters);
+ return nullptr;
+ }
+ #endif
+
+ Event::Event()
+ {
+ #if defined(_WIN32)
+ handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+ #else
+ pthread_cond_init(&handle, NULL);
+ pthread_mutex_init(&mutex, NULL);
+ signaled = false;
+ #endif
+ }
+
+ Event::~Event()
+ {
+ #if defined(_WIN32)
+ CloseHandle(handle);
+ #else
+ pthread_cond_destroy(&handle);
+ pthread_mutex_destroy(&mutex);
+ #endif
+ }
+}
diff --git a/src/System/Thread.hpp b/src/System/Thread.hpp
new file mode 100644
index 0000000..b8280f1
--- /dev/null
+++ b/src/System/Thread.hpp
@@ -0,0 +1,338 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_Thread_hpp
+#define sw_Thread_hpp
+
+#if defined(_WIN32)
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #include <windows.h>
+ #include <intrin.h>
+#else
+ #include <pthread.h>
+ #include <sched.h>
+ #include <unistd.h>
+ #define TLS_OUT_OF_INDEXES (pthread_key_t)(~0)
+#endif
+
+#include <stdlib.h>
+
+#if defined(__clang__)
+#if __has_include(<atomic>) // clang has an explicit check for the availability of atomic
+#define USE_STD_ATOMIC 1
+#endif
+// atomic is available in C++11 or newer, and in Visual Studio 2012 or newer
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
+#define USE_STD_ATOMIC 1
+#endif
+
+#if USE_STD_ATOMIC
+#include <atomic>
+#endif
+
+namespace sw
+{
+ class Event;
+
+ class Thread
+ {
+ public:
+ Thread(void (*threadFunction)(void *parameters), void *parameters);
+
+ ~Thread();
+
+ void join();
+
+ static void yield();
+ static void sleep(int milliseconds);
+
+ #if defined(_WIN32)
+ typedef DWORD LocalStorageKey;
+ #else
+ typedef pthread_key_t LocalStorageKey;
+ #endif
+
+ static LocalStorageKey allocateLocalStorageKey(void (*destructor)(void *storage) = free);
+ static void freeLocalStorageKey(LocalStorageKey key);
+ static void *allocateLocalStorage(LocalStorageKey key, size_t size);
+ static void *getLocalStorage(LocalStorageKey key);
+ static void freeLocalStorage(LocalStorageKey key);
+
+ private:
+ struct Entry
+ {
+ void (*const threadFunction)(void *parameters);
+ void *threadParameters;
+ Event *init;
+ };
+
+ #if defined(_WIN32)
+ static unsigned long __stdcall startFunction(void *parameters);
+ HANDLE handle;
+ #else
+ static void *startFunction(void *parameters);
+ pthread_t handle;
+ #endif
+
+ bool hasJoined = false;
+ };
+
+ class Event
+ {
+ friend class Thread;
+
+ public:
+ Event();
+
+ ~Event();
+
+ void signal();
+ void wait();
+
+ private:
+ #if defined(_WIN32)
+ HANDLE handle;
+ #else
+ pthread_cond_t handle;
+ pthread_mutex_t mutex;
+ volatile bool signaled;
+ #endif
+ };
+
+ #if PERF_PROFILE
+ int64_t atomicExchange(int64_t volatile *target, int64_t value);
+ int atomicExchange(int volatile *target, int value);
+ #endif
+
+ int atomicIncrement(int volatile *value);
+ int atomicDecrement(int volatile *value);
+ int atomicAdd(int volatile *target, int value);
+ void nop();
+}
+
+namespace sw
+{
+ inline void Thread::yield()
+ {
+ #if defined(_WIN32)
+ Sleep(0);
+ #elif defined(__APPLE__)
+ pthread_yield_np();
+ #else
+ sched_yield();
+ #endif
+ }
+
+ inline void Thread::sleep(int milliseconds)
+ {
+ #if defined(_WIN32)
+ Sleep(milliseconds);
+ #else
+ usleep(1000 * milliseconds);
+ #endif
+ }
+
+ inline Thread::LocalStorageKey Thread::allocateLocalStorageKey(void (*destructor)(void *storage))
+ {
+ #if defined(_WIN32)
+ return TlsAlloc();
+ #else
+ LocalStorageKey key;
+ pthread_key_create(&key, destructor);
+ return key;
+ #endif
+ }
+
+ inline void Thread::freeLocalStorageKey(LocalStorageKey key)
+ {
+ #if defined(_WIN32)
+ TlsFree(key);
+ #else
+ pthread_key_delete(key); // Using an invalid key is an error but not undefined behavior.
+ #endif
+ }
+
+ inline void *Thread::allocateLocalStorage(LocalStorageKey key, size_t size)
+ {
+ if(key == TLS_OUT_OF_INDEXES)
+ {
+ return nullptr;
+ }
+
+ freeLocalStorage(key);
+
+ void *storage = malloc(size);
+
+ #if defined(_WIN32)
+ TlsSetValue(key, storage);
+ #else
+ pthread_setspecific(key, storage);
+ #endif
+
+ return storage;
+ }
+
+ inline void *Thread::getLocalStorage(LocalStorageKey key)
+ {
+ #if defined(_WIN32)
+ return TlsGetValue(key);
+ #else
+ if(key == TLS_OUT_OF_INDEXES) // Avoid undefined behavior.
+ {
+ return nullptr;
+ }
+
+ return pthread_getspecific(key);
+ #endif
+ }
+
+ inline void Thread::freeLocalStorage(LocalStorageKey key)
+ {
+ free(getLocalStorage(key));
+
+ #if defined(_WIN32)
+ TlsSetValue(key, nullptr);
+ #else
+ pthread_setspecific(key, nullptr);
+ #endif
+ }
+
+ inline void Event::signal()
+ {
+ #if defined(_WIN32)
+ SetEvent(handle);
+ #else
+ pthread_mutex_lock(&mutex);
+ signaled = true;
+ pthread_cond_signal(&handle);
+ pthread_mutex_unlock(&mutex);
+ #endif
+ }
+
+ inline void Event::wait()
+ {
+ #if defined(_WIN32)
+ WaitForSingleObject(handle, INFINITE);
+ #else
+ pthread_mutex_lock(&mutex);
+ while(!signaled) pthread_cond_wait(&handle, &mutex);
+ signaled = false;
+ pthread_mutex_unlock(&mutex);
+ #endif
+ }
+
+ #if PERF_PROFILE
+ inline int64_t atomicExchange(volatile int64_t *target, int64_t value)
+ {
+ #if defined(_WIN32)
+ return InterlockedExchange64(target, value);
+ #else
+ int ret;
+ __asm__ __volatile__("lock; xchg8 %x0,(%x1)" : "=r" (ret) :"r" (target), "0" (value) : "memory" );
+ return ret;
+ #endif
+ }
+
+ inline int atomicExchange(volatile int *target, int value)
+ {
+ #if defined(_WIN32)
+ return InterlockedExchange((volatile long*)target, (long)value);
+ #else
+ int ret;
+ __asm__ __volatile__("lock; xchgl %x0,(%x1)" : "=r" (ret) :"r" (target), "0" (value) : "memory" );
+ return ret;
+ #endif
+ }
+ #endif
+
+ inline int atomicIncrement(volatile int *value)
+ {
+ #if defined(_WIN32)
+ return InterlockedIncrement((volatile long*)value);
+ #else
+ return __sync_add_and_fetch(value, 1);
+ #endif
+ }
+
+ inline int atomicDecrement(volatile int *value)
+ {
+ #if defined(_WIN32)
+ return InterlockedDecrement((volatile long*)value);
+ #else
+ return __sync_sub_and_fetch(value, 1);
+ #endif
+ }
+
+ inline int atomicAdd(volatile int* target, int value)
+ {
+ #if defined(_WIN32)
+ return InterlockedExchangeAdd((volatile long*)target, value) + value;
+ #else
+ return __sync_add_and_fetch(target, value);
+ #endif
+ }
+
+ inline void nop()
+ {
+ #if defined(_WIN32)
+ __nop();
+ #else
+ __asm__ __volatile__ ("nop");
+ #endif
+ }
+
+ #if USE_STD_ATOMIC
+ class AtomicInt
+ {
+ public:
+ AtomicInt() : ai() {}
+ AtomicInt(int i) : ai(i) {}
+
+ inline operator int() const { return ai.load(std::memory_order_acquire); }
+ inline void operator=(const AtomicInt& i) { ai.store(i.ai.load(std::memory_order_acquire), std::memory_order_release); }
+ inline void operator=(int i) { ai.store(i, std::memory_order_release); }
+ inline void operator--() { ai.fetch_sub(1, std::memory_order_acq_rel); }
+ inline void operator++() { ai.fetch_add(1, std::memory_order_acq_rel); }
+ inline int operator--(int) { return ai.fetch_sub(1, std::memory_order_acq_rel) - 1; }
+ inline int operator++(int) { return ai.fetch_add(1, std::memory_order_acq_rel) + 1; }
+ inline void operator-=(int i) { ai.fetch_sub(i, std::memory_order_acq_rel); }
+ inline void operator+=(int i) { ai.fetch_add(i, std::memory_order_acq_rel); }
+ private:
+ std::atomic<int> ai;
+ };
+ #else
+ class AtomicInt
+ {
+ public:
+ AtomicInt() {}
+ AtomicInt(int i) : vi(i) {}
+
+ inline operator int() const { return vi; } // Note: this isn't a guaranteed atomic operation
+ inline void operator=(const AtomicInt& i) { sw::atomicExchange(&vi, i.vi); }
+ inline void operator=(int i) { sw::atomicExchange(&vi, i); }
+ inline void operator--() { sw::atomicDecrement(&vi); }
+ inline void operator++() { sw::atomicIncrement(&vi); }
+ inline int operator--(int) { return sw::atomicDecrement(&vi); }
+ inline int operator++(int) { return sw::atomicIncrement(&vi); }
+ inline void operator-=(int i) { sw::atomicAdd(&vi, -i); }
+ inline void operator+=(int i) { sw::atomicAdd(&vi, i); }
+ private:
+ volatile int vi;
+ };
+ #endif
+}
+
+#endif // sw_Thread_hpp
diff --git a/src/System/Timer.cpp b/src/System/Timer.cpp
new file mode 100644
index 0000000..8ff2cf3
--- /dev/null
+++ b/src/System/Timer.cpp
@@ -0,0 +1,95 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Timer.hpp"
+
+#if !defined(__i386__) && defined(_M_IX86)
+ #define __i386__ 1
+#endif
+
+#if !defined(__x86_64__) && (defined(_M_AMD64) || defined (_M_X64))
+ #define __x86_64__ 1
+#endif
+
+#if defined(_WIN32)
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #include <windows.h>
+ #include <intrin.h>
+#else
+ #include <sys/time.h>
+ #if defined(__i386__) || defined(__x86_64__)
+ #include <x86intrin.h>
+ #endif
+#endif
+
+namespace sw
+{
+ Timer::Timer()
+ {
+ }
+
+ Timer::~Timer()
+ {
+ }
+
+ double Timer::seconds()
+ {
+ #if defined(_WIN32)
+ return (double)counter() / (double)frequency();
+ #else
+ timeval t;
+ gettimeofday(&t, 0);
+ return (double)t.tv_sec + (double)t.tv_usec * 1.0e-6;
+ #endif
+ }
+
+ int64_t Timer::ticks()
+ {
+ #if defined(_WIN32)
+ return __rdtsc();
+ #elif defined(__i386__) || defined(__x86_64__)
+ int64_t tsc;
+ __asm volatile("rdtsc": "=A" (tsc));
+ return tsc;
+ #else
+ return 0;
+ #endif
+ }
+
+ int64_t Timer::counter()
+ {
+ #if defined(_WIN32)
+ int64_t counter;
+ QueryPerformanceCounter((LARGE_INTEGER*)&counter);
+ return counter;
+ #else
+ timeval t;
+ gettimeofday(&t, 0);
+ return t.tv_sec * 1000000 + t.tv_usec;
+ #endif
+ }
+
+ int64_t Timer::frequency()
+ {
+ #if defined(_WIN32)
+ int64_t frequency;
+ QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
+ return frequency;
+ #else
+ return 1000000; // gettimeofday uses microsecond resolution
+ #endif
+ }
+}
diff --git a/src/System/Timer.hpp b/src/System/Timer.hpp
new file mode 100644
index 0000000..977c877
--- /dev/null
+++ b/src/System/Timer.hpp
@@ -0,0 +1,37 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_Timer_hpp
+#define sw_Timer_hpp
+
+#include "Types.hpp"
+
+namespace sw
+{
+ class Timer
+ {
+ public:
+ Timer();
+
+ ~Timer();
+
+ static double seconds();
+ static int64_t ticks();
+
+ static int64_t counter();
+ static int64_t frequency();
+ };
+}
+
+#endif // sw_Timer_hpp
diff --git a/src/System/Types.hpp b/src/System/Types.hpp
new file mode 100644
index 0000000..cd08ed5
--- /dev/null
+++ b/src/System/Types.hpp
@@ -0,0 +1,157 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_Types_hpp
+#define sw_Types_hpp
+
+#include <limits>
+#include <type_traits>
+
+// GCC warns against bitfields not fitting the entire range of an enum with a fixed underlying type of unsigned int, which gets promoted to an error with -Werror and cannot be suppressed.
+// However, GCC already defaults to using unsigned int as the underlying type of an unscoped enum without a fixed underlying type. So we can just omit it.
+#if defined(__GNUC__) && !defined(__clang__)
+namespace {enum E {}; static_assert(!std::numeric_limits<std::underlying_type<E>::type>::is_signed, "expected unscoped enum whose underlying type is not fixed to be unsigned");}
+#define ENUM_UNDERLYING_TYPE_UNSIGNED_INT
+#else
+#define ENUM_UNDERLYING_TYPE_UNSIGNED_INT : unsigned int
+#endif
+
+#if defined(_MSC_VER)
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef signed __int64 int64_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+ typedef unsigned __int64 uint64_t;
+ #define ALIGN(bytes, type) __declspec(align(bytes)) type
+#else
+ #include <stdint.h>
+ #define ALIGN(bytes, type) type __attribute__((aligned(bytes)))
+#endif
+
+namespace sw
+{
+ typedef ALIGN(1, uint8_t) byte;
+ typedef ALIGN(2, uint16_t) word;
+ typedef ALIGN(4, uint32_t) dword;
+ typedef ALIGN(8, uint64_t) qword;
+ typedef ALIGN(16, uint64_t) qword2[2];
+ typedef ALIGN(4, uint8_t) byte4[4];
+ typedef ALIGN(8, uint8_t) byte8[8];
+ typedef ALIGN(16, uint8_t) byte16[16];
+ typedef ALIGN(8, uint16_t) word4[4];
+ typedef ALIGN(8, uint32_t) dword2[2];
+ typedef ALIGN(16, uint32_t) dword4[4];
+ typedef ALIGN(16, uint64_t) xword[2];
+
+ typedef ALIGN(1, int8_t) sbyte;
+ typedef ALIGN(4, int8_t) sbyte4[4];
+ typedef ALIGN(8, int8_t) sbyte8[8];
+ typedef ALIGN(16, int8_t) sbyte16[16];
+ typedef ALIGN(8, short) short4[4];
+ typedef ALIGN(8, unsigned short) ushort4[4];
+ typedef ALIGN(16, short) short8[8];
+ typedef ALIGN(16, unsigned short) ushort8[8];
+ typedef ALIGN(8, int) int2[2];
+ typedef ALIGN(8, unsigned int) uint2[2];
+ typedef ALIGN(16, unsigned int) uint4[4];
+
+ typedef ALIGN(8, float) float2[2];
+
+ ALIGN(16, struct int4
+ {
+ int x;
+ int y;
+ int z;
+ int w;
+
+ int &operator[](int i)
+ {
+ return (&x)[i];
+ }
+
+ const int &operator[](int i) const
+ {
+ return (&x)[i];
+ }
+
+ bool operator!=(const int4 &rhs)
+ {
+ return x != rhs.x || y != rhs.y || z != rhs.z || w != rhs.w;
+ }
+
+ bool operator==(const int4 &rhs)
+ {
+ return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w;
+ }
+ });
+
+ ALIGN(16, struct float4
+ {
+ float x;
+ float y;
+ float z;
+ float w;
+
+ float &operator[](int i)
+ {
+ return (&x)[i];
+ }
+
+ const float &operator[](int i) const
+ {
+ return (&x)[i];
+ }
+
+ bool operator!=(const float4 &rhs)
+ {
+ return x != rhs.x || y != rhs.y || z != rhs.z || w != rhs.w;
+ }
+
+ bool operator==(const float4 &rhs)
+ {
+ return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w;
+ }
+ });
+
+ inline float4 vector(float x, float y, float z, float w)
+ {
+ float4 v;
+
+ v.x = x;
+ v.y = y;
+ v.z = z;
+ v.w = w;
+
+ return v;
+ }
+
+ inline float4 replicate(float f)
+ {
+ float4 v;
+
+ v.x = f;
+ v.y = f;
+ v.z = f;
+ v.w = f;
+
+ return v;
+ }
+
+ #define OFFSET(s,m) (int)(size_t)&reinterpret_cast<const volatile char&>((((s*)0)->m))
+}
+
+#endif // sw_Types_hpp
diff --git a/src/System/Version.h b/src/System/Version.h
new file mode 100644
index 0000000..72bd15d
--- /dev/null
+++ b/src/System/Version.h
@@ -0,0 +1,24 @@
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#define MAJOR_VERSION 4
+#define MINOR_VERSION 1
+#define BUILD_VERSION 0
+#define BUILD_REVISION 2
+
+#define STRINGIFY(x) #x
+#define MACRO_STRINGIFY(x) STRINGIFY(x)
+
+#define REVISION_STRING MACRO_STRINGIFY(BUILD_REVISION)
+#define VERSION_STRING MACRO_STRINGIFY(MAJOR_VERSION) "." MACRO_STRINGIFY(MINOR_VERSION) "." MACRO_STRINGIFY(BUILD_VERSION) "." MACRO_STRINGIFY(BUILD_REVISION)