diff --git a/.gitattributes b/.gitattributes index 406780d20a..4a06c4288a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10,6 +10,7 @@ *.json text *.js text *.qml text +*.qrc text *.slf text *.slh text *.slv text diff --git a/.gitignore b/.gitignore index d6227f1f30..8aa82865a4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,11 @@ ext/ Makefile *.user +# Android Studio +*.iml +local.properties +android/libraries + # Xcode *.xcodeproj *.xcworkspace diff --git a/BUILD_ANDROID.md b/BUILD_ANDROID.md index d69d20ee8a..cc51e58b1d 100644 --- a/BUILD_ANDROID.md +++ b/BUILD_ANDROID.md @@ -1,19 +1,56 @@ Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Android specific instructions are found in this file. -### Android Dependencies +# Android Dependencies You will need the following tools to build our Android targets. -* [cmake](http://www.cmake.org/download/) ~> 3.5.1 -* [Qt](http://www.qt.io/download-open-source/#) ~> 5.6.2 -* [ant](http://ant.apache.org/bindownload.cgi) ~> 1.9.4 -* [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html) ~> r10d -* [Android SDK](http://developer.android.com/sdk/installing/index.html) ~> 24.4.1.1 - * Install the latest Platform-tools - * Install the latest Build-tools - * Install the SDK Platform for API Level 19 - * Install Sources for Android SDK for API Level 19 - * Install the ARM EABI v7a System Image if you want to run an emulator. +* [Qt](http://www.qt.io/download-open-source/#) ~> 5.9.1 +* [Android Studio](https://developer.android.com/studio/index.html) +* [Google VR SDK](https://github.com/googlevr/gvr-android-sdk/releases) +* [Gradle](https://gradle.org/releases/) + +### Qt + +Download the Qt online installer. Run the installer and select the android_armv7 binaries. Installing to the default path is recommended + +### Android Studio + +Download the Android Studio installer and run it. Once installed, at the welcome screen, click configure in the lower right corner and select SDK manager + +From the SDK Platforms tab, select API level 26. + +* Install the ARM EABI v7a System Image if you want to run an emulator. + +From the SDK Tools tab select the following + +* Android SDK Build-Tools +* GPU Debugging Tools +* CMake (even if you have a separate CMake installation) +* LLDB +* Android SDK Platform-Tools +* Android SDK Tools +* Android SDK Tools +* NDK (even if you have the NDK installed separately) + +### Google VR SDK + +Download the 1.8 Google VR SDK [release](https://github.com/googlevr/gvr-android-sdk/archive/v1.80.0.zip). Unzip the archive to a location on your drive. + +### Gradle + +Download [Gradle 4.1](https://services.gradle.org/distributions/gradle-4.1-all.zip) and unzip it on your local drive. You may wish to add the location of the bin directory within the archive to your path + +#### Set up machine specific Gradle properties + +Create a `gradle.properties` file in ~/.gradle. Edit the file to contain the following + + QT5_ROOT=C\:\\Qt\\5.9.1\\android_armv7 + GVR_ROOT=C\:\\Android\\gvr-android-sdk + +Replace the paths with your local installations of Qt5 and the Google VR SDK + + +# TODO fix the rest You will also need to cross-compile the dependencies required for all platforms for Android, and help CMake find these compiled libraries on your machine. diff --git a/CMakeLists.txt b/CMakeLists.txt index be513abddb..9d3296a168 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,16 @@ -if (WIN32) +# If we're running under the gradle build, HIFI_ANDROID will be set here, but +# ANDROID will not be set until after the `project` statement. This is the *ONLY* +# place you need to use `HIFI_ANDROID` instead of `ANDROID` +if (WIN32 AND NOT HIFI_ANDROID) cmake_minimum_required(VERSION 3.7) else() cmake_minimum_required(VERSION 3.2) endif() -include("cmake/init.cmake") - project(hifi) +include("cmake/init.cmake") + include("cmake/compiler.cmake") if (NOT DEFINED SERVER_ONLY) @@ -54,11 +57,13 @@ endif() file(GLOB_RECURSE CMAKE_SRC cmake/*.cmake cmake/CMakeLists.txt) add_custom_target(cmake SOURCES ${CMAKE_SRC}) GroupSources("cmake") +unset(CMAKE_SRC) file(GLOB_RECURSE JS_SRC scripts/*.js unpublishedScripts/*.js) add_custom_target(js SOURCES ${JS_SRC}) GroupSources("scripts") GroupSources("unpublishedScripts") +unset(JS_SRC) # Locate the required Qt build on the filesystem setup_qt() @@ -77,6 +82,12 @@ option(USE_NSIGHT "Attempt to find the nSight libraries" 1) set_packaging_parameters() +# FIXME hack to work on the proper Android toolchain +if (ANDROID) + add_subdirectory(android/app) + return() +endif() + # add subdirectories for all targets if (BUILD_SERVER) add_subdirectory(assignment-client) diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt new file mode 100644 index 0000000000..2d6df925e9 --- /dev/null +++ b/android/app/CMakeLists.txt @@ -0,0 +1,8 @@ +set(TARGET_NAME native-lib) +setup_hifi_library() +link_hifi_libraries(shared networking gl gpu gpu-gles render-utils) +autoscribe_shader_lib(gpu model render render-utils) +target_opengl() +target_link_libraries(native-lib android log m) +target_include_directories(native-lib PRIVATE "${GVR_ROOT}/libraries/headers") +target_link_libraries(native-lib "C:/Users/bdavis/Git/hifi/android/libraries/jni/armeabi-v7a/libgvr.so") diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000000..bd1c596bf3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,57 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 26 + buildToolsVersion "26.0.1" + defaultConfig { + applicationId "org.saintandreas.testapp" + minSdkVersion 24 + targetSdkVersion 26 + versionCode 1 + versionName "1.0" + ndk { abiFilters 'armeabi-v7a' } + externalNativeBuild { + cmake { + arguments '-DHIFI_ANDROID=1', + '-DANDROID_PLATFORM=android-24', + '-DANDROID_TOOLCHAIN=clang', + '-DANDROID_STL=gnustl_shared', + '-DGVR_ROOT=' + GVR_ROOT, + '-DNATIVE_SCRIBE=c:/bin/scribe.exe', + "-DHIFI_ANDROID_PRECOMPILED=${project.rootDir}/libraries/jni/armeabi-v7a" + } + } + jackOptions { enabled true } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + sourceSets { + main { + jniLibs.srcDirs += '../libraries/jni'; + } + } + externalNativeBuild { + cmake { + path '../../CMakeLists.txt' + } + } +} + +dependencies { + compile fileTree(dir: "${project.rootDir}/libraries/jar", include: 'QtAndroid-bundled.jar') + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.google.vr:sdk-audio:1.80.0' + compile 'com.google.vr:sdk-base:1.80.0' +} + +build.dependsOn(':extractQt5') diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000000..b3c0078513 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Android\SDK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..05547bd5ae --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/cpp/GoogleVRHelpers.h b/android/app/src/main/cpp/GoogleVRHelpers.h new file mode 100644 index 0000000000..10c46b036f --- /dev/null +++ b/android/app/src/main/cpp/GoogleVRHelpers.h @@ -0,0 +1,50 @@ +#include +#include +#include + +namespace googlevr { + + // Convert a GVR matrix to GLM matrix + glm::mat4 toGlm(const gvr::Mat4f &matrix) { + glm::mat4 result; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + result[j][i] = matrix.m[i][j]; + } + } + return result; + } + + // Given a field of view in degrees, compute the corresponding projection +// matrix. + glm::mat4 perspectiveMatrixFromView(const gvr::Rectf& fov, float z_near, float z_far) { + const float x_left = -std::tan(fov.left * M_PI / 180.0f) * z_near; + const float x_right = std::tan(fov.right * M_PI / 180.0f) * z_near; + const float y_bottom = -std::tan(fov.bottom * M_PI / 180.0f) * z_near; + const float y_top = std::tan(fov.top * M_PI / 180.0f) * z_near; + const float Y = (2 * z_near) / (y_top - y_bottom); + const float A = (x_right + x_left) / (x_right - x_left); + const float B = (y_top + y_bottom) / (y_top - y_bottom); + const float C = (z_near + z_far) / (z_near - z_far); + const float D = (2 * z_near * z_far) / (z_near - z_far); + + glm::mat4 result { 0 }; + result[2][0] = A; + result[1][1] = Y; + result[2][1] = B; + result[2][2] = C; + result[3][2] = D; + result[2][3] = -1; + return result; + } + + glm::quat toGlm(const gvr::ControllerQuat& q) { + glm::quat result; + result.w = q.qw; + result.x = q.qx; + result.y = q.qy; + result.z = q.qz; + return result; + } + +} diff --git a/android/app/src/main/cpp/native-lib.cpp b/android/app/src/main/cpp/native-lib.cpp new file mode 100644 index 0000000000..156d43d849 --- /dev/null +++ b/android/app/src/main/cpp/native-lib.cpp @@ -0,0 +1,78 @@ +#include + +#include +#include + +#include "renderer.h" + +int QtMsgTypeToAndroidPriority(QtMsgType type) { + int priority = ANDROID_LOG_UNKNOWN; + switch (type) { + case QtDebugMsg: priority = ANDROID_LOG_DEBUG; break; + case QtWarningMsg: priority = ANDROID_LOG_WARN; break; + case QtCriticalMsg: priority = ANDROID_LOG_ERROR; break; + case QtFatalMsg: priority = ANDROID_LOG_FATAL; break; + case QtInfoMsg: priority = ANDROID_LOG_INFO; break; + default: break; + } + return priority; +} + +void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { + __android_log_write(QtMsgTypeToAndroidPriority(type), "Interface", message.toStdString().c_str()); +} + +static jlong toJni(NativeRenderer *renderer) { + return reinterpret_cast(renderer); +} + +static NativeRenderer *fromJni(jlong renderer) { + return reinterpret_cast(renderer); +} + +#define JNI_METHOD(r, name) JNIEXPORT r JNICALL Java_org_saintandreas_testapp_MainActivity_##name + +extern "C" { + +JNI_METHOD(jlong, nativeCreateRenderer) +(JNIEnv *env, jclass clazz, jobject class_loader, jobject android_context, jlong native_gvr_api) { + qInstallMessageHandler(messageHandler); +#if defined(GVR) + auto gvrContext = reinterpret_cast(native_gvr_api); + return toJni(new NativeRenderer(gvrContext)); +#else + return toJni(new NativeRenderer(nullptr)); +#endif +} + +JNI_METHOD(void, nativeDestroyRenderer) +(JNIEnv *env, jclass clazz, jlong renderer) { + delete fromJni(renderer); +} + +JNI_METHOD(void, nativeInitializeGl) +(JNIEnv *env, jobject obj, jlong renderer) { + fromJni(renderer)->InitializeGl(); +} + +JNI_METHOD(void, nativeDrawFrame) +(JNIEnv *env, jobject obj, jlong renderer) { + fromJni(renderer)->DrawFrame(); +} + +JNI_METHOD(void, nativeOnTriggerEvent) +(JNIEnv *env, jobject obj, jlong renderer) { + fromJni(renderer)->OnTriggerEvent(); +} + +JNI_METHOD(void, nativeOnPause) +(JNIEnv *env, jobject obj, jlong renderer) { + fromJni(renderer)->OnPause(); +} + +JNI_METHOD(void, nativeOnResume) +(JNIEnv *env, jobject obj, jlong renderer) { + fromJni(renderer)->OnResume(); +} + +} // extern "C" diff --git a/android/app/src/main/cpp/renderer.cpp b/android/app/src/main/cpp/renderer.cpp new file mode 100644 index 0000000000..a877ebd777 --- /dev/null +++ b/android/app/src/main/cpp/renderer.cpp @@ -0,0 +1,636 @@ +#include "renderer.h" + +#include + +#include +#include + +#include "GoogleVRHelpers.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if 0 +#include +#include +#include +#include +#include +#include +#include +#include +#endif + + +template +void withFrameBuffer(gvr::Frame& frame, int32_t index, F f) { + frame.BindBuffer(index); + f(); + frame.Unbind(); +} + + +static const uint64_t kPredictionTimeWithoutVsyncNanos = 50000000; + +// Each shader has two variants: a single-eye ES 2.0 variant, and a multiview +// ES 3.0 variant. The multiview vertex shaders use transforms defined by +// arrays of mat4 uniforms, using gl_ViewID_OVR to determine the array index. + +#define UNIFORM_LIGHT_POS 20 +#define UNIFORM_M 16 +#define UNIFORM_MV 8 +#define UNIFORM_MVP 0 + +#if 0 +uniform Transform { // API uses “Transform[2]” to refer to instance 2 + mat4 u_MVP[2]; + mat4 u_MVMatrix[2]; + mat4 u_Model; + vec3 u_LightPos[2]; +}; +static const char *kDiffuseLightingVertexShader = R"glsl( +#version 300 es +#extension GL_OVR_multiview2 : enable + +layout(num_views=2) in; + +layout(location = 0) uniform mat4 u_MVP[2]; +layout(location = 8) uniform mat4 u_MVMatrix[2]; +layout(location = 16) uniform mat4 u_Model; +layout(location = 20) uniform vec3 u_LightPos[2]; + +layout(location = 0) in vec4 a_Position; +layout(location = 1) in vec4 a_Color; +layout(location = 2) in vec3 a_Normal; + +out vec4 v_Color; +out vec3 v_Grid; + +void main() { + mat4 mvp = u_MVP[gl_ViewID_OVR]; + mat4 modelview = u_MVMatrix[gl_ViewID_OVR]; + vec3 lightpos = u_LightPos[gl_ViewID_OVR]; + v_Grid = vec3(u_Model * a_Position); + vec3 modelViewVertex = vec3(modelview * a_Position); + vec3 modelViewNormal = vec3(modelview * vec4(a_Normal, 0.0)); + float distance = length(lightpos - modelViewVertex); + vec3 lightVector = normalize(lightpos - modelViewVertex); + float diffuse = max(dot(modelViewNormal, lightVector), 0.5); + diffuse = diffuse * (1.0 / (1.0 + (0.00001 * distance * distance))); + v_Color = vec4(a_Color.rgb * diffuse, a_Color.a); + gl_Position = mvp * a_Position; +} +)glsl"; +#endif + + +static const char *kSimepleVertexShader = R"glsl( +#version 300 es +#extension GL_OVR_multiview2 : enable + +layout(num_views=2) in; + +layout(location = 0) in vec4 a_Position; + +out vec4 v_Color; + +void main() { + v_Color = vec4(a_Position.xyz, 1.0); + gl_Position = vec4(a_Position.xyz, 1.0); +} +)glsl"; + + +static const char *kPassthroughFragmentShader = R"glsl( +#version 300 es +precision mediump float; +in vec4 v_Color; +out vec4 FragColor; + +void main() { FragColor = v_Color; } +)glsl"; + +static void CheckGLError(const char* label) { + int gl_error = glGetError(); + if (gl_error != GL_NO_ERROR) { + qWarning("GL error @ %s: %d", label, gl_error); + // Crash immediately to make OpenGL errors obvious. + abort(); + } +} + +// Contains vertex, normal and other data. +namespace cube { + const std::array CUBE_COORDS{{ + // Front face + -1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + + // Right face + 1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, -1.0f, + 1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + + // Back face + 1.0f, 1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + + // Left face + -1.0f, 1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + + // Top face + -1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, -1.0f, + + // Bottom face + 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, 1.0f, + -1.0f, -1.0f, 1.0f, + -1.0f, -1.0f, -1.0f + }}; + + const std::array CUBE_COLORS{{ + // front, green + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + + // right, blue + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + + // back, also green + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + 0.0f, 0.5273f, 0.2656f, + + // left, also blue + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + 0.0f, 0.3398f, 0.9023f, + + // top, red + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f, + + // bottom, also red + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f, + 0.8359375f, 0.17578125f, 0.125f + }}; + + const std::array CUBE_NORMALS{{ + // Front face + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + + // Right face + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + + // Back face + 0.0f, 0.0f, -1.0f, + 0.0f, 0.0f, -1.0f, + 0.0f, 0.0f, -1.0f, + 0.0f, 0.0f, -1.0f, + 0.0f, 0.0f, -1.0f, + 0.0f, 0.0f, -1.0f, + + // Left face + -1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + + // Top face + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + + // Bottom face + 0.0f, -1.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, -1.0f, 0.0f + }}; +} + +namespace triangle { + static std::array TRIANGLE_VERTS {{ + -0.5f, -0.5f, 0.0f, + 0.5f, -0.5f, 0.0f, + 0.0f, 0.5f, 0.0f + }}; +} + +std::array buildViewports(const std::unique_ptr &gvrapi) { + return { {gvrapi->CreateBufferViewport(), gvrapi->CreateBufferViewport()} }; +}; + +const std::string VERTEX_SHADER_DEFINES{ R"GLSL( +#version 300 es +#extension GL_EXT_clip_cull_distance : enable +#define GPU_VERTEX_SHADER +#define GPU_SSBO_TRANSFORM_OBJECT 1 +#define GPU_TRANSFORM_IS_STEREO +#define GPU_TRANSFORM_STEREO_CAMERA +#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED +#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN +)GLSL" }; + +const std::string PIXEL_SHADER_DEFINES{ R"GLSL( +#version 300 es +precision mediump float; +#define GPU_PIXEL_SHADER +#define GPU_TRANSFORM_IS_STEREO +#define GPU_TRANSFORM_STEREO_CAMERA +#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED +#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN +)GLSL" }; + + +#if defined(GVR) +NativeRenderer::NativeRenderer(gvr_context *vrContext) : + _gvrapi(new gvr::GvrApi(vrContext, false)), + _viewports(buildViewports(_gvrapi)), + _gvr_viewer_type(_gvrapi->GetViewerType()) +#else +NativeRenderer::NativeRenderer(void *vrContext) +#endif +{ + start = std::chrono::system_clock::now(); + qDebug() << "QQQ" << __FUNCTION__; +} + + +/** + * Converts a raw text file, saved as a resource, into an OpenGL ES shader. + * + * @param type The type of shader we will be creating. + * @param resId The resource ID of the raw text file. + * @return The shader object handler. + */ +int LoadGLShader(int type, const char *shadercode) { + GLuint result = 0; + std::string shaderError; + static const std::string SHADER_DEFINES; + if (!gl::compileShader(type, shadercode, SHADER_DEFINES, result, shaderError)) { + qWarning() << "QQQ" << __FUNCTION__ << "Shader compile failure" << shaderError.c_str(); + } + return result; +} + +// Computes a texture size that has approximately half as many pixels. This is +// equivalent to scaling each dimension by approximately sqrt(2)/2. +static gvr::Sizei HalfPixelCount(const gvr::Sizei &in) { + // Scale each dimension by sqrt(2)/2 ~= 7/10ths. + gvr::Sizei out; + out.width = (7 * in.width) / 10; + out.height = (7 * in.height) / 10; + return out; +} + + +#if defined(GVR) +void NativeRenderer::InitializeVR() { + _gvrapi->InitializeGl(); + bool multiviewEnabled = _gvrapi->IsFeatureSupported(GVR_FEATURE_MULTIVIEW); + qWarning() << "QQQ" << __FUNCTION__ << "Multiview enabled " << multiviewEnabled; + // Because we are using 2X MSAA, we can render to half as many pixels and + // achieve similar quality. + _renderSize = HalfPixelCount(_gvrapi->GetMaximumEffectiveRenderTargetSize()); + + std::vector specs; + specs.push_back(_gvrapi->CreateBufferSpec()); + specs[0].SetColorFormat(GVR_COLOR_FORMAT_RGBA_8888); + specs[0].SetDepthStencilFormat(GVR_DEPTH_STENCIL_FORMAT_DEPTH_16); + specs[0].SetSamples(2); + gvr::Sizei half_size = {_renderSize.width / 2, _renderSize.height}; + specs[0].SetMultiviewLayers(2); + specs[0].SetSize(half_size); + + _swapchain.reset(new gvr::SwapChain(_gvrapi->CreateSwapChain(specs))); + _viewportlist.reset(new gvr::BufferViewportList(_gvrapi->CreateEmptyBufferViewportList())); +} +void NativeRenderer::PrepareFramebuffer() { + const gvr::Sizei recommended_size = HalfPixelCount( + _gvrapi->GetMaximumEffectiveRenderTargetSize()); + if (_renderSize.width != recommended_size.width || + _renderSize.height != recommended_size.height) { + // We need to resize the framebuffer. Note that multiview uses two texture + // layers, each with half the render width. + gvr::Sizei framebuffer_size = recommended_size; + framebuffer_size.width /= 2; + _swapchain->ResizeBuffer(0, framebuffer_size); + _renderSize = recommended_size; + } +} +#endif + +void testShaderBuild(const char* vs_src, const char * fs_src) { + std::string error; + GLuint vs, fs; + if (!gl::compileShader(GL_VERTEX_SHADER, vs_src, VERTEX_SHADER_DEFINES, vs, error) || + !gl::compileShader(GL_FRAGMENT_SHADER, fs_src, PIXEL_SHADER_DEFINES, fs, error)) { + throw std::runtime_error("Failed to compile shader"); + } + auto pr = gl::compileProgram({ vs, fs }, error); + if (!pr) { + throw std::runtime_error("Failed to link shader"); + } +} + +void NativeRenderer::InitializeGl() { + qDebug() << "QQQ" << __FUNCTION__; + //gl::initModuleGl(); +#if defined(GVR) + InitializeVR(); +#endif + + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + + + const uint32_t vertShader = LoadGLShader(GL_VERTEX_SHADER, kSimepleVertexShader); + //const uint32_t vertShader = LoadGLShader(GL_VERTEX_SHADER, kDiffuseLightingVertexShader); + const uint32_t fragShader = LoadGLShader(GL_FRAGMENT_SHADER, kPassthroughFragmentShader); + std::string error; + _cubeProgram = gl::compileProgram({ vertShader, fragShader }, error); + CheckGLError("build program"); + + glGenBuffers(1, &_cubeBuffer); + glBindBuffer(GL_ARRAY_BUFFER, _cubeBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 9, triangle::TRIANGLE_VERTS.data(), GL_STATIC_DRAW); + /* + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 3, NULL, GL_STATIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 0, sizeof(float) * 108, cube::CUBE_COORDS.data()); + glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 1, sizeof(float) * 108, cube::CUBE_COLORS.data()); + glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 2, sizeof(float) * 108, cube::CUBE_NORMALS.data()); + */ + glBindBuffer(GL_ARRAY_BUFFER, 0); + CheckGLError("upload vertices"); + + glGenVertexArrays(1, &_cubeVao); + glBindBuffer(GL_ARRAY_BUFFER, _cubeBuffer); + glBindVertexArray(_cubeVao); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + /* + glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, (const void*)(sizeof(float) * 108 * 1) ); + glEnableVertexAttribArray(1); + glVertexAttribPointer(2, 3, GL_FLOAT, false, 0, (const void*)(sizeof(float) * 108 * 2)); + glEnableVertexAttribArray(2); + */ + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + CheckGLError("build vao "); + + static std::once_flag once; + std::call_once(once, [&]{ + testShaderBuild(sdf_text3D_vert, sdf_text3D_frag); + + testShaderBuild(DrawTransformUnitQuad_vert, DrawTexture_frag); + testShaderBuild(DrawTexcoordRectTransformUnitQuad_vert, DrawTexture_frag); + testShaderBuild(DrawViewportQuadTransformTexcoord_vert, DrawTexture_frag); + testShaderBuild(DrawTransformUnitQuad_vert, DrawTextureOpaque_frag); + testShaderBuild(DrawTransformUnitQuad_vert, DrawColoredTexture_frag); + + testShaderBuild(simple_vert, simple_frag); + testShaderBuild(simple_vert, simple_textured_frag); + testShaderBuild(simple_vert, simple_textured_unlit_frag); + testShaderBuild(deferred_light_vert, directional_ambient_light_frag); + testShaderBuild(deferred_light_vert, directional_skybox_light_frag); + testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag); + testShaderBuild(standardTransformPNTC_vert, DrawTextureOpaque_frag); + + testShaderBuild(model_vert, model_frag); + testShaderBuild(model_normal_map_vert, model_normal_map_frag); + testShaderBuild(model_vert, model_specular_map_frag); + testShaderBuild(model_normal_map_vert, model_normal_specular_map_frag); + testShaderBuild(model_vert, model_translucent_frag); + testShaderBuild(model_normal_map_vert, model_translucent_frag); + testShaderBuild(model_lightmap_vert, model_lightmap_frag); + testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_map_frag); + testShaderBuild(model_lightmap_vert, model_lightmap_specular_map_frag); + testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_specular_map_frag); + + testShaderBuild(skin_model_vert, model_frag); + testShaderBuild(skin_model_normal_map_vert, model_normal_map_frag); + testShaderBuild(skin_model_vert, model_specular_map_frag); + testShaderBuild(skin_model_normal_map_vert, model_normal_specular_map_frag); + testShaderBuild(skin_model_vert, model_translucent_frag); + testShaderBuild(skin_model_normal_map_vert, model_translucent_frag); + + testShaderBuild(model_shadow_vert, model_shadow_frag); + + testShaderBuild(overlay3D_vert, overlay3D_frag); + +#if 0 + testShaderBuild(textured_particle_vert, textured_particle_frag); + testShaderBuild(skybox_vert, skybox_frag); + testShaderBuild(paintStroke_vert,paintStroke_frag); + testShaderBuild(polyvox_vert, polyvox_frag); +#endif + + }); + + qDebug() << "done"; +} + +static const float kZNear = 1.0f; +static const float kZFar = 100.0f; +static const gvr_rectf fullscreen = {0, 1, 0, 1}; + +void NativeRenderer::DrawFrame() { + auto now = std::chrono::duration_cast( + std::chrono::system_clock::now() - start); + glm::vec3 v; + v.r = (float) (now.count() % 1000) / 1000.0f; + v.g = 1.0f - v.r; + v.b = 1.0f; + + PrepareFramebuffer(); + + // A client app does its rendering here. + gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); + target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; + + using namespace googlevr; + using namespace bilateral; + const auto gvrHeadPose = _gvrapi->GetHeadSpaceFromStartSpaceRotation(target_time); + _head_view = toGlm(gvrHeadPose); + _viewportlist->SetToRecommendedBufferViewports(); + + glm::mat4 eye_views[2]; + for_each_side([&](bilateral::Side side) { + int eye = index(side); + const gvr::Eye gvr_eye = eye == 0 ? GVR_LEFT_EYE : GVR_RIGHT_EYE; + const auto& eyeView = eye_views[eye] = toGlm(_gvrapi->GetEyeFromHeadMatrix(gvr_eye)) * _head_view; + auto& viewport = _viewports[eye]; + + _viewportlist->GetBufferViewport(eye, &viewport); + viewport.SetSourceUv(fullscreen); + viewport.SetSourceLayer(eye); + _viewportlist->SetBufferViewport(eye, viewport); + const auto &mvc = _modelview_cube[eye] = eyeView * _model_cube; + const auto &mvf = _modelview_floor[eye] = eyeView * _model_floor; + const gvr_rectf fov = viewport.GetSourceFov(); + const glm::mat4 perspective = perspectiveMatrixFromView(fov, kZNear, kZFar); + _modelview_projection_cube[eye] = perspective * mvc; + _modelview_projection_floor[eye] = perspective * mvf; + _light_pos_eye_space[eye] = glm::vec3(eyeView * _light_pos_world_space); + }); + + + gvr::Frame frame = _swapchain->AcquireFrame(); + withFrameBuffer(frame, 0, [&]{ + glClearColor(v.r, v.g, v.b, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, _renderSize.width / 2, _renderSize.height); + glUseProgram(_cubeProgram); + glBindVertexArray(_cubeVao); + glDrawArrays(GL_TRIANGLES, 0, 3); + /* + float* fp; + fp = (float*)&_light_pos_eye_space[0]; + glUniform3fv(UNIFORM_LIGHT_POS, 2, fp); + fp = (float*)&_modelview_cube[0]; + glUniformMatrix4fv(UNIFORM_MV, 2, GL_FALSE, fp); + fp = (float*)&_modelview_projection_cube[0]; + glUniformMatrix4fv(UNIFORM_MVP, 2, GL_FALSE, fp); + fp = (float*)&_model_cube; + glUniformMatrix4fv(UNIFORM_M, 1, GL_FALSE, fp); + glDrawArrays(GL_TRIANGLES, 0, 36); + */ + glBindVertexArray(0); + }); + + frame.Submit(*_viewportlist, gvrHeadPose); + CheckGLError("onDrawFrame"); + +} + +void NativeRenderer::OnTriggerEvent() { + qDebug() << "QQQ" << __FUNCTION__; +} + +void NativeRenderer::OnPause() { + qDebug() << "QQQ" << __FUNCTION__; + _gvrapi->PauseTracking(); +} + +void NativeRenderer::OnResume() { + qDebug() << "QQQ" << __FUNCTION__; + _gvrapi->ResumeTracking(); + _gvrapi->RefreshViewerProfile(); +} diff --git a/android/app/src/main/cpp/renderer.h b/android/app/src/main/cpp/renderer.h new file mode 100644 index 0000000000..df7c51cab4 --- /dev/null +++ b/android/app/src/main/cpp/renderer.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include + +#define GVR + +#if defined(GVR) +#include +#endif + +class NativeRenderer { +public: + +#if defined(GVR) + NativeRenderer(gvr_context* vrContext); +#else + NativeRenderer(void* vrContext); +#endif + + void InitializeGl(); + void DrawFrame(); + void OnTriggerEvent(); + void OnPause(); + void OnResume(); + +private: + + + std::chrono::time_point start; +#if defined(GVR) + void InitializeVR(); + void PrepareFramebuffer(); + + std::unique_ptr _gvrapi; + gvr::ViewerType _gvr_viewer_type; + std::unique_ptr _viewportlist; + std::unique_ptr _swapchain; + std::array _viewports; + gvr::Sizei _renderSize; +#endif + + uint32_t _cubeBuffer { 0 }; + uint32_t _cubeVao { 0 }; + uint32_t _cubeProgram { 0 }; + + glm::mat4 _head_view; + glm::mat4 _model_cube; + glm::mat4 _camera; + glm::mat4 _view; + glm::mat4 _model_floor; + + std::array _modelview_cube; + std::array _modelview_floor; + std::array _modelview_projection_cube; + std::array _modelview_projection_floor; + std::array _light_pos_eye_space; + const glm::vec4 _light_pos_world_space{ 0, 2, 0, 1}; +}; diff --git a/android/app/src/main/java/org/saintandreas/testapp/MainActivity.java b/android/app/src/main/java/org/saintandreas/testapp/MainActivity.java new file mode 100644 index 0000000000..7eea14dce9 --- /dev/null +++ b/android/app/src/main/java/org/saintandreas/testapp/MainActivity.java @@ -0,0 +1,105 @@ +package org.saintandreas.testapp; + +import android.app.Activity; +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.os.Bundle; +import android.view.View; + +import com.google.vr.ndk.base.AndroidCompat; +import com.google.vr.ndk.base.GvrLayout; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +public class MainActivity extends Activity { + private final static int IMMERSIVE_STICKY_VIEW_FLAGS = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + + static { + System.loadLibrary("gvr"); + System.loadLibrary("native-lib"); + } + + private long nativeRenderer; + private GvrLayout gvrLayout; + private GLSurfaceView surfaceView; + + private native long nativeCreateRenderer(ClassLoader appClassLoader, Context context, long nativeGvrContext); + private native void nativeDestroyRenderer(long renderer); + private native void nativeInitializeGl(long renderer); + private native void nativeDrawFrame(long renderer); + private native void nativeOnTriggerEvent(long renderer); + private native void nativeOnPause(long renderer); + private native void nativeOnResume(long renderer); + + class NativeRenderer implements GLSurfaceView.Renderer { + @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { nativeInitializeGl(nativeRenderer); } + @Override public void onSurfaceChanged(GL10 gl, int width, int height) { } + @Override public void onDrawFrame(GL10 gl) { + nativeDrawFrame(nativeRenderer); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setImmersiveSticky(); + getWindow() + .getDecorView() + .setOnSystemUiVisibilityChangeListener((int visibility)->{ + if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { setImmersiveSticky(); } + }); + + gvrLayout = new GvrLayout(this); + nativeRenderer = nativeCreateRenderer( + getClass().getClassLoader(), + getApplicationContext(), + gvrLayout.getGvrApi().getNativeGvrContext()); + + surfaceView = new GLSurfaceView(this); + surfaceView.setEGLContextClientVersion(3); + surfaceView.setEGLConfigChooser(8, 8, 8, 0, 0, 0); + surfaceView.setPreserveEGLContextOnPause(true); + surfaceView.setRenderer(new NativeRenderer()); + + gvrLayout.setPresentationView(surfaceView); + setContentView(gvrLayout); + if (gvrLayout.setAsyncReprojectionEnabled(true)) { + AndroidCompat.setSustainedPerformanceMode(this, true); + } + AndroidCompat.setVrModeEnabled(this, true); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + gvrLayout.shutdown(); + nativeDestroyRenderer(nativeRenderer); + nativeRenderer = 0; + } + + @Override + protected void onPause() { + surfaceView.queueEvent(()->nativeOnPause(nativeRenderer)); + surfaceView.onPause(); + gvrLayout.onPause(); + super.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + gvrLayout.onResume(); + surfaceView.onResume(); + surfaceView.queueEvent(()->nativeOnResume(nativeRenderer)); + } + + private void setImmersiveSticky() { + getWindow().getDecorView().setSystemUiVisibility(IMMERSIVE_STICKY_VIEW_FLAGS); + } +} diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..cde69bccce Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000..9a078e3e1a Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..c133a0cbd3 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000..efc028a636 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..bfa42f0e7b Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..3af2608a44 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..324e72cdd7 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..9bec2e6231 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..aee44e1384 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..34947cd6bb Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000000..344907f039 --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #ffffff + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000000..5d6a4c1b99 --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + TestApp + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000..033324ac58 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000000..77c3dd498c --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,91 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.3.3' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +task extractQt5jars(type: Copy) { + from fileTree(QT5_ROOT + "/jar") + into("${project.rootDir}/libraries/jar") + include("*.jar") +} + +task extractQt5so(type: Copy) { + from fileTree(QT5_ROOT + "/lib") + into("${project.rootDir}/libraries/jni/armeabi-v7a/") + include("libQt5AndroidExtras.so") + include("libQt5Concurrent.so") + include("libQt5Core.so") + include("libQt5Gamepad.so") + include("libQt5Gui.so") + include("libQt5Location.so") + include("libQt5Multimedia.so") + include("libQt5MultimediaQuick_p.so") + include("libQt5Network.so") + include("libQt5NetworkAuth.so") + include("libQt5OpenGL.so") + include("libQt5Positioning.so") + include("libQt5Qml.so") + include("libQt5Quick.so") + include("libQt5QuickControls2.so") + include("libQt5QuickParticles.so") + include("libQt5QuickTemplates2.so") + include("libQt5QuickWidgets.so") + include("libQt5Script.so") + include("libQt5ScriptTools.so") + include("libQt5Sensors.so") + include("libQt5Svg.so") + include("libQt5WebChannel.so") + include("libQt5WebSockets.so") + include("libQt5WebView.so") + include("libQt5Widgets.so") + include("libQt5Xml.so") + include("libQt5XmlPatterns.so") +} + +task extractAudioSo(type: Copy) { + from zipTree(GVR_ROOT + "/libraries/sdk-audio-1.80.0.aar") + into "${project.rootDir}/libraries/" + include "jni/armeabi-v7a/libgvr_audio.so" +} + +task extractGvrSo(type: Copy) { + from zipTree(GVR_ROOT + "/libraries/sdk-base-1.80.0.aar") + into "${project.rootDir}/libraries/" + include "jni/armeabi-v7a/libgvr.so" +} + +task extractNdk { } +extractNdk.dependsOn extractAudioSo +extractNdk.dependsOn extractGvrSo + +task extractQt5 { } +extractQt5.dependsOn extractQt5so +extractQt5.dependsOn extractQt5jars + +task extractBinaries { } +extractBinaries.dependsOn extractQt5 +extractBinaries.dependsOn extractNdk + +task deleteBinaries(type: Delete) { + delete "${project.rootDir}/libraries/jni" +} + +//clean.dependsOn(deleteBinaries) diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000000..aac7c9b461 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,17 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000000..e7b4def49c --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/cmake/android/AndroidManifest.xml.in b/cmake/android/AndroidManifest.xml.in deleted file mode 100755 index aa834f3384..0000000000 --- a/cmake/android/AndroidManifest.xml.in +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${ANDROID_EXTRA_ACTIVITY_XML} - - - - - - ${ANDROID_EXTRA_APPLICATION_XML} - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/cmake/android/QtCreateAPK.cmake b/cmake/android/QtCreateAPK.cmake deleted file mode 100644 index 30ee2f57bd..0000000000 --- a/cmake/android/QtCreateAPK.cmake +++ /dev/null @@ -1,159 +0,0 @@ -# -# QtCreateAPK.cmake -# -# Created by Stephen Birarda on 11/18/14. -# Copyright 2013 High Fidelity, Inc. -# -# Distributed under the Apache License, Version 2.0. -# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# - -# -# OPTIONS -# These options will modify how QtCreateAPK behaves. May be useful if somebody wants to fork. -# For High Fidelity purposes these should not need to be changed. -# -set(ANDROID_THIS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) # Directory this CMake file is in - -if (POLICY CMP0026) - cmake_policy(SET CMP0026 OLD) -endif () - -macro(qt_create_apk) - if(ANDROID_APK_FULLSCREEN) - set(ANDROID_APK_THEME "android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\"") - else() - set(ANDROID_APK_THEME "") - endif() - - if (UPPER_CMAKE_BUILD_TYPE MATCHES RELEASE) - set(ANDROID_APK_DEBUGGABLE "false") - set(ANDROID_APK_RELEASE_LOCAL ${ANDROID_APK_RELEASE}) - else () - set(ANDROID_APK_DEBUGGABLE "true") - set(ANDROID_APK_RELEASE_LOCAL "0") - endif () - - # Create "AndroidManifest.xml" - configure_file("${ANDROID_THIS_DIRECTORY}/AndroidManifest.xml.in" "${ANDROID_APK_BUILD_DIR}/AndroidManifest.xml") - - # create "strings.xml" - configure_file("${ANDROID_THIS_DIRECTORY}/strings.xml.in" "${ANDROID_APK_BUILD_DIR}/res/values/strings.xml") - - # find androiddeployqt - find_program(ANDROID_DEPLOY_QT androiddeployqt HINTS "${QT_DIR}/bin") - - # set the path to our app shared library - set(EXECUTABLE_DESTINATION_PATH "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}/lib${TARGET_NAME}.so") - - # add our dependencies to the deployment file - get_property(_DEPENDENCIES TARGET ${TARGET_NAME} PROPERTY INTERFACE_LINK_LIBRARIES) - - foreach(_IGNORE_COPY IN LISTS IGNORE_COPY_LIBS) - list(REMOVE_ITEM _DEPENDENCIES ${_IGNORE_COPY}) - endforeach() - - foreach(_DEP IN LISTS _DEPENDENCIES) - if (NOT TARGET ${_DEP}) - list(APPEND _DEPS_LIST ${_DEP}) - else () - if(NOT _DEP MATCHES "Qt5::.*") - get_property(_DEP_LOCATION TARGET ${_DEP} PROPERTY "LOCATION_${CMAKE_BUILD_TYPE}") - - # recurisvely add libraries which are dependencies of this target - get_property(_DEP_DEPENDENCIES TARGET ${_DEP} PROPERTY INTERFACE_LINK_LIBRARIES) - - foreach(_SUB_DEP IN LISTS _DEP_DEPENDENCIES) - if (NOT TARGET ${_SUB_DEP} AND NOT _SUB_DEP MATCHES "Qt5::.*") - list(APPEND _DEPS_LIST ${_SUB_DEP}) - endif() - endforeach() - - list(APPEND _DEPS_LIST ${_DEP_LOCATION}) - endif() - endif () - endforeach() - - list(REMOVE_DUPLICATES _DEPS_LIST) - - # just copy static libs to apk libs folder - don't add to deps list - foreach(_LOCATED_DEP IN LISTS _DEPS_LIST) - if (_LOCATED_DEP MATCHES "\\.a$") - add_custom_command( - TARGET ${TARGET_NAME} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${_LOCATED_DEP} "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}" - ) - list(REMOVE_ITEM _DEPS_LIST ${_LOCATED_DEP}) - endif () - endforeach() - - string(REPLACE ";" "," _DEPS "${_DEPS_LIST}") - - configure_file("${ANDROID_THIS_DIRECTORY}/deployment-file.json.in" "${TARGET_NAME}-deployment.json") - - # copy the res folder from the target to the apk build dir - add_custom_target( - ${TARGET_NAME}-copy-res - COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/res" "${ANDROID_APK_BUILD_DIR}/res" - ) - - # copy the assets folder from the target to the apk build dir - add_custom_target( - ${TARGET_NAME}-copy-assets - COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/assets" "${ANDROID_APK_BUILD_DIR}/assets" - ) - - # copy the java folder from src to the apk build dir - add_custom_target( - ${TARGET_NAME}-copy-java - COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/src/java" "${ANDROID_APK_BUILD_DIR}/src" - ) - - # copy the libs folder from src to the apk build dir - add_custom_target( - ${TARGET_NAME}-copy-libs - COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/libs" "${ANDROID_APK_BUILD_DIR}/libs" - ) - - # handle setup for ndk-gdb - add_custom_target(${TARGET_NAME}-gdb DEPENDS ${TARGET_NAME}) - - if (ANDROID_APK_DEBUGGABLE) - get_property(TARGET_LOCATION TARGET ${TARGET_NAME} PROPERTY LOCATION) - - set(GDB_SOLIB_PATH ${ANDROID_APK_BUILD_DIR}/obj/local/${ANDROID_NDK_ABI_NAME}/) - - # generate essential Android Makefiles - file(WRITE ${ANDROID_APK_BUILD_DIR}/jni/Android.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n") - file(WRITE ${ANDROID_APK_BUILD_DIR}/jni/Application.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n") - - # create gdb.setup - get_directory_property(PROJECT_INCLUDES DIRECTORY ${PROJECT_SOURCE_DIR} INCLUDE_DIRECTORIES) - string(REGEX REPLACE ";" " " PROJECT_INCLUDES "${PROJECT_INCLUDES}") - file(WRITE ${ANDROID_APK_BUILD_DIR}/libs/${ANDROID_NDK_ABI_NAME}/gdb.setup "set solib-search-path ${GDB_SOLIB_PATH}\n") - file(APPEND ${ANDROID_APK_BUILD_DIR}/libs/${ANDROID_NDK_ABI_NAME}/gdb.setup "directory ${PROJECT_INCLUDES}\n") - - # copy lib to obj - add_custom_command(TARGET ${TARGET_NAME}-gdb PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${GDB_SOLIB_PATH}) - add_custom_command(TARGET ${TARGET_NAME}-gdb PRE_BUILD COMMAND cp ${TARGET_LOCATION} ${GDB_SOLIB_PATH}) - - # strip symbols - add_custom_command(TARGET ${TARGET_NAME}-gdb PRE_BUILD COMMAND ${CMAKE_STRIP} ${TARGET_LOCATION}) - endif () - - # use androiddeployqt to create the apk - add_custom_target(${TARGET_NAME}-apk - COMMAND ${ANDROID_DEPLOY_QT} --input "${TARGET_NAME}-deployment.json" --output "${ANDROID_APK_OUTPUT_DIR}" --android-platform android-${ANDROID_API_LEVEL} ${ANDROID_DEPLOY_QT_INSTALL} --verbose --deployment bundled "\\$(ARGS)" - DEPENDS ${TARGET_NAME} ${TARGET_NAME}-copy-res ${TARGET_NAME}-copy-assets ${TARGET_NAME}-copy-java ${TARGET_NAME}-copy-libs ${TARGET_NAME}-gdb - ) - - # rename the APK if the caller asked us to - if (ANDROID_APK_CUSTOM_NAME) - add_custom_command( - TARGET ${TARGET_NAME}-apk - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename "${ANDROID_APK_OUTPUT_DIR}/bin/QtApp-debug.apk" "${ANDROID_APK_OUTPUT_DIR}/bin/${ANDROID_APK_CUSTOM_NAME}" - ) - endif () -endmacro() \ No newline at end of file diff --git a/cmake/android/android.toolchain.cmake b/cmake/android/android.toolchain.cmake deleted file mode 100755 index 806cef6b18..0000000000 --- a/cmake/android/android.toolchain.cmake +++ /dev/null @@ -1,1725 +0,0 @@ -# Copyright (c) 2010-2011, Ethan Rublee -# Copyright (c) 2011-2014, Andrey Kamaev -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -# ------------------------------------------------------------------------------ -# Android CMake toolchain file, for use with the Android NDK r5-r10d -# Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended). -# See home page: https://github.com/taka-no-me/android-cmake -# -# Usage Linux: -# $ export ANDROID_NDK=/absolute/path/to/the/android-ndk -# $ mkdir build && cd build -# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake .. -# $ make -j8 -# -# Usage Windows: -# You need native port of make to build your project. -# Android NDK r7 (and newer) already has make.exe on board. -# For older NDK you have to install it separately. -# For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm -# -# $ SET ANDROID_NDK=C:\absolute\path\to\the\android-ndk -# $ mkdir build && cd build -# $ cmake.exe -G"MinGW Makefiles" -# -DCMAKE_TOOLCHAIN_FILE=path\to\the\android.toolchain.cmake -# -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows\bin\make.exe" .. -# $ cmake.exe --build . -# -# -# Options (can be set as cmake parameters: -D=): -# ANDROID_NDK=/opt/android-ndk - path to the NDK root. -# Can be set as environment variable. Can be set only at first cmake run. -# -# ANDROID_ABI=armeabi-v7a - specifies the target Application Binary -# Interface (ABI). This option nearly matches to the APP_ABI variable -# used by ndk-build tool from Android NDK. -# -# Possible targets are: -# "armeabi" - ARMv5TE based CPU with software floating point operations -# "armeabi-v7a" - ARMv7 based devices with hardware FPU instructions -# this ABI target is used by default -# "armeabi-v7a with NEON" - same as armeabi-v7a, but -# sets NEON as floating-point unit -# "armeabi-v7a with VFPV3" - same as armeabi-v7a, but -# sets VFPV3 as floating-point unit (has 32 registers instead of 16) -# "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP -# "x86" - IA-32 instruction set -# "mips" - MIPS32 instruction set -# -# 64-bit ABIs for NDK r10 and newer: -# "arm64-v8a" - ARMv8 AArch64 instruction set -# "x86_64" - Intel64 instruction set (r1) -# "mips64" - MIPS64 instruction set (r6) -# -# ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. -# Option is read-only when standalone toolchain is used. -# Note: building for "android-L" requires explicit configuration. -# -# ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 - the name of compiler -# toolchain to be used. The list of possible values depends on the NDK -# version. For NDK r10c the possible values are: -# -# * aarch64-linux-android-4.9 -# * aarch64-linux-android-clang3.4 -# * aarch64-linux-android-clang3.5 -# * arm-linux-androideabi-4.6 -# * arm-linux-androideabi-4.8 -# * arm-linux-androideabi-4.9 (default) -# * arm-linux-androideabi-clang3.4 -# * arm-linux-androideabi-clang3.5 -# * mips64el-linux-android-4.9 -# * mips64el-linux-android-clang3.4 -# * mips64el-linux-android-clang3.5 -# * mipsel-linux-android-4.6 -# * mipsel-linux-android-4.8 -# * mipsel-linux-android-4.9 -# * mipsel-linux-android-clang3.4 -# * mipsel-linux-android-clang3.5 -# * x86-4.6 -# * x86-4.8 -# * x86-4.9 -# * x86-clang3.4 -# * x86-clang3.5 -# * x86_64-4.9 -# * x86_64-clang3.4 -# * x86_64-clang3.5 -# -# ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions -# instead of Thumb. Is not available for "armeabi-v6 with VFP" -# (is forced to be ON) ABI. -# -# ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker -# errors even if they are not used. -# -# ANDROID_SO_UNDEFINED=OFF - set ON to allow undefined symbols in shared -# libraries. Automatically turned for NDK r5x and r6x due to GLESv2 -# problems. -# -# ANDROID_STL=gnustl_static - specify the runtime to use. -# -# Possible values are: -# none -> Do not configure the runtime. -# system -> Use the default minimal system C++ runtime library. -# Implies -fno-rtti -fno-exceptions. -# Is not available for standalone toolchain. -# system_re -> Use the default minimal system C++ runtime library. -# Implies -frtti -fexceptions. -# Is not available for standalone toolchain. -# gabi++_static -> Use the GAbi++ runtime as a static library. -# Implies -frtti -fno-exceptions. -# Available for NDK r7 and newer. -# Is not available for standalone toolchain. -# gabi++_shared -> Use the GAbi++ runtime as a shared library. -# Implies -frtti -fno-exceptions. -# Available for NDK r7 and newer. -# Is not available for standalone toolchain. -# stlport_static -> Use the STLport runtime as a static library. -# Implies -fno-rtti -fno-exceptions for NDK before r7. -# Implies -frtti -fno-exceptions for NDK r7 and newer. -# Is not available for standalone toolchain. -# stlport_shared -> Use the STLport runtime as a shared library. -# Implies -fno-rtti -fno-exceptions for NDK before r7. -# Implies -frtti -fno-exceptions for NDK r7 and newer. -# Is not available for standalone toolchain. -# gnustl_static -> Use the GNU STL as a static library. -# Implies -frtti -fexceptions. -# gnustl_shared -> Use the GNU STL as a shared library. -# Implies -frtti -fno-exceptions. -# Available for NDK r7b and newer. -# Silently degrades to gnustl_static if not available. -# c++_static -> Use the LLVM libc++ runtime as a static library. -# c++_shared -> Use the LLVM libc++ runtime as a shared library. -# -# ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on -# chosen runtime. If disabled, then the user is responsible for settings -# these options. -# -# What?: -# android-cmake toolchain searches for NDK/toolchain in the following order: -# ANDROID_NDK - cmake parameter -# ANDROID_NDK - environment variable -# ANDROID_STANDALONE_TOOLCHAIN - cmake parameter -# ANDROID_STANDALONE_TOOLCHAIN - environment variable -# ANDROID_NDK - default locations -# ANDROID_STANDALONE_TOOLCHAIN - default locations -# -# Make sure to do the following in your scripts: -# SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" ) -# SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" ) -# The flags will be prepopulated with critical flags, so don't loose them. -# Also be aware that toolchain also sets configuration-specific compiler -# flags and linker flags. -# -# ANDROID and BUILD_ANDROID will be set to true, you may test any of these -# variables to make necessary Android-specific configuration changes. -# -# Also ARMEABI or ARMEABI_V7A or X86 or MIPS or ARM64_V8A or X86_64 or MIPS64 -# will be set true, mutually exclusive. NEON option will be set true -# if VFP is set to NEON. -# -# ------------------------------------------------------------------------------ - -cmake_minimum_required( VERSION 2.6.3 ) - -if( DEFINED CMAKE_CROSSCOMPILING ) - # subsequent toolchain loading is not really needed - return() -endif() - -if( CMAKE_TOOLCHAIN_FILE ) - # touch toolchain variable to suppress "unused variable" warning -endif() - -# inherit settings in recursive loads -get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE ) -if( _CMAKE_IN_TRY_COMPILE ) - include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL ) -endif() - -# this one is important -if( CMAKE_VERSION VERSION_GREATER "3.0.99" ) - set( CMAKE_SYSTEM_NAME Android ) -else() - set( CMAKE_SYSTEM_NAME Linux ) -endif() - -# this one not so much -set( CMAKE_SYSTEM_VERSION 1 ) - -# rpath makes low sense for Android -set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" ) -set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) - -# NDK search paths -set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) -if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS ) - if( CMAKE_HOST_WIN32 ) - file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) - set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" ) - else() - file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS ) - set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" ) - endif() -endif() -if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) - set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain ) -endif() - -# known ABIs -set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" ) -set( ANDROID_SUPPORTED_ABIS_arm64 "arm64-v8a" ) -set( ANDROID_SUPPORTED_ABIS_x86 "x86" ) -set( ANDROID_SUPPORTED_ABIS_x86_64 "x86_64" ) -set( ANDROID_SUPPORTED_ABIS_mips "mips" ) -set( ANDROID_SUPPORTED_ABIS_mips64 "mips64" ) - -# API level defaults -set( ANDROID_DEFAULT_NDK_API_LEVEL 8 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 21 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 21 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 ) - - -macro( __LIST_FILTER listvar regex ) - if( ${listvar} ) - foreach( __val ${${listvar}} ) - if( __val MATCHES "${regex}" ) - list( REMOVE_ITEM ${listvar} "${__val}" ) - endif() - endforeach() - endif() -endmacro() - -macro( __INIT_VARIABLE var_name ) - set( __test_path 0 ) - foreach( __var ${ARGN} ) - if( __var STREQUAL "PATH" ) - set( __test_path 1 ) - break() - endif() - endforeach() - - if( __test_path AND NOT EXISTS "${${var_name}}" ) - unset( ${var_name} CACHE ) - endif() - - if( " ${${var_name}}" STREQUAL " " ) - set( __values 0 ) - foreach( __var ${ARGN} ) - if( __var STREQUAL "VALUES" ) - set( __values 1 ) - elseif( NOT __var STREQUAL "PATH" ) - if( __var MATCHES "^ENV_.*$" ) - string( REPLACE "ENV_" "" __var "${__var}" ) - set( __value "$ENV{${__var}}" ) - elseif( DEFINED ${__var} ) - set( __value "${${__var}}" ) - elseif( __values ) - set( __value "${__var}" ) - else() - set( __value "" ) - endif() - - if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") ) - set( ${var_name} "${__value}" ) - break() - endif() - endif() - endforeach() - unset( __value ) - unset( __values ) - endif() - - if( __test_path ) - file( TO_CMAKE_PATH "${${var_name}}" ${var_name} ) - endif() - unset( __test_path ) -endmacro() - -macro( __DETECT_NATIVE_API_LEVEL _var _path ) - set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" ) - file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" ) - if( NOT __apiFileContent ) - message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." ) - endif() - string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" ) - unset( __apiFileContent ) - unset( __ndkApiLevelRegex ) -endmacro() - -macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root ) - if( EXISTS "${_root}" ) - file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" ) - __LIST_FILTER( __gccExePath "^[.].*" ) - list( LENGTH __gccExePath __gccExePathsCount ) - if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE ) - message( WARNING "Could not determine machine name for compiler from ${_root}" ) - set( ${_var} "" ) - else() - get_filename_component( __gccExeName "${__gccExePath}" NAME_WE ) - string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" ) - endif() - unset( __gccExePath ) - unset( __gccExePathsCount ) - unset( __gccExeName ) - else() - set( ${_var} "" ) - endif() -endmacro() - - -# fight against cygwin -set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools") -mark_as_advanced( ANDROID_FORBID_SYGWIN ) -if( ANDROID_FORBID_SYGWIN ) - if( CYGWIN ) - message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." ) - endif() - - if( CMAKE_HOST_WIN32 ) - # remove cygwin from PATH - set( __new_path "$ENV{PATH}") - __LIST_FILTER( __new_path "cygwin" ) - set(ENV{PATH} "${__new_path}") - unset(__new_path) - endif() -endif() - - -# detect current host platform -if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) - set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) - mark_as_advanced( ANDROID_NDK_HOST_X64 ) -endif() - -set( TOOL_OS_SUFFIX "" ) -if( CMAKE_HOST_APPLE ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" ) -elseif( CMAKE_HOST_WIN32 ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" ) - set( TOOL_OS_SUFFIX ".exe" ) -elseif( CMAKE_HOST_UNIX ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" ) -else() - message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) -endif() - -if( NOT ANDROID_NDK_HOST_X64 ) - set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) -endif() - -# see if we have path to Android NDK -if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN ) - __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) -endif() -if( NOT ANDROID_NDK ) - # see if we have path to Android standalone toolchain - __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN ) - - if( NOT ANDROID_STANDALONE_TOOLCHAIN ) - #try to find Android NDK in one of the the default locations - set( __ndkSearchPaths ) - foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} ) - foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} ) - list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" ) - endforeach() - endforeach() - __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} ) - unset( __ndkSearchPaths ) - - if( ANDROID_NDK ) - message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" ) - message( STATUS " If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" ) - else() - #try to find Android standalone toolchain in one of the the default locations - __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) - - if( ANDROID_STANDALONE_TOOLCHAIN ) - message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" ) - message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" ) - endif( ANDROID_STANDALONE_TOOLCHAIN ) - endif( ANDROID_NDK ) - endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) -endif( NOT ANDROID_NDK ) - -# remember found paths -if( ANDROID_NDK ) - get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) - set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE ) - set( BUILD_WITH_ANDROID_NDK True ) - if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" ) - file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX "r[0-9]+[a-z]?" ) - string( REGEX MATCH "r([0-9]+)([a-z]?)" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" ) - else() - set( ANDROID_NDK_RELEASE "r1x" ) - set( ANDROID_NDK_RELEASE_FULL "unreleased" ) - endif() - string( REGEX REPLACE "r([0-9]+)([a-z]?)" "\\1*1000" ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE}" ) - string( FIND " abcdefghijklmnopqastuvwxyz" "${CMAKE_MATCH_2}" __ndkReleaseLetterNum ) - math( EXPR ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE_NUM}+${__ndkReleaseLetterNum}" ) -elseif( ANDROID_STANDALONE_TOOLCHAIN ) - get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) - # try to detect change - if( CMAKE_AR ) - string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length ) - string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath ) - if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN ) - message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." ) - endif() - unset( __androidStandaloneToolchainPreviousPath ) - unset( __length ) - endif() - set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" FORCE ) - set( BUILD_WITH_STANDALONE_TOOLCHAIN True ) -else() - list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH) - message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolchain. - You should either set an environment variable: - export ANDROID_NDK=~/my-android-ndk - or - export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain - or put the toolchain or NDK in the default path: - sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk - sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) -endif() - -# android NDK layout -if( BUILD_WITH_ANDROID_NDK ) - if( NOT DEFINED ANDROID_NDK_LAYOUT ) - # try to automatically detect the layout - if( EXISTS "${ANDROID_NDK}/RELEASE.TXT") - set( ANDROID_NDK_LAYOUT "RELEASE" ) - elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" ) - set( ANDROID_NDK_LAYOUT "LINARO" ) - elseif( EXISTS "${ANDROID_NDK}/../../gcc/" ) - set( ANDROID_NDK_LAYOUT "ANDROID" ) - endif() - endif() - set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" ) - mark_as_advanced( ANDROID_NDK_LAYOUT ) - if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment - set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) - elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment - set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) - else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE" - set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" ) - endif() - get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE ) - - # try to detect change of NDK - if( CMAKE_AR ) - string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length ) - string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) - if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH ) - message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. - " ) - endif() - unset( __androidNdkPreviousPath ) - unset( __length ) - endif() -endif() - - -# get all the details about standalone toolchain -if( BUILD_WITH_STANDALONE_TOOLCHAIN ) - __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) - set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) - set( __availableToolchains "standalone" ) - __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" ) - if( NOT __availableToolchainMachines ) - message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." ) - endif() - if( __availableToolchainMachines MATCHES x86_64 ) - set( __availableToolchainArchs "x86_64" ) - elseif( __availableToolchainMachines MATCHES i686 ) - set( __availableToolchainArchs "x86" ) - elseif( __availableToolchainMachines MATCHES aarch64 ) - set( __availableToolchainArchs "arm64" ) - elseif( __availableToolchainMachines MATCHES arm ) - set( __availableToolchainArchs "arm" ) - elseif( __availableToolchainMachines MATCHES mips64el ) - set( __availableToolchainArchs "mips64" ) - elseif( __availableToolchainMachines MATCHES mipsel ) - set( __availableToolchainArchs "mips" ) - endif() - execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion - OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE ) - string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" ) - if( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${TOOL_OS_SUFFIX}" ) - list( APPEND __availableToolchains "standalone-clang" ) - list( APPEND __availableToolchainMachines ${__availableToolchainMachines} ) - list( APPEND __availableToolchainArchs ${__availableToolchainArchs} ) - list( APPEND __availableToolchainCompilerVersions ${__availableToolchainCompilerVersions} ) - endif() -endif() - -macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) - foreach( __toolchain ${${__availableToolchainsLst}} ) - if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) - SET( __toolchainVersionRegex "^TOOLCHAIN_VERSION[\t ]+:=[\t ]+(.*)$" ) - FILE( STRINGS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}/setup.mk" __toolchainVersionStr REGEX "${__toolchainVersionRegex}" ) - if( __toolchainVersionStr ) - string( REGEX REPLACE "${__toolchainVersionRegex}" "\\1" __toolchainVersionStr "${__toolchainVersionStr}" ) - string( REGEX REPLACE "-clang3[.][0-9]$" "-${__toolchainVersionStr}" __gcc_toolchain "${__toolchain}" ) - else() - string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) - endif() - unset( __toolchainVersionStr ) - unset( __toolchainVersionRegex ) - else() - set( __gcc_toolchain "${__toolchain}" ) - endif() - __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) - if( __machine ) - string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) - if( __machine MATCHES x86_64 ) - set( __arch "x86_64" ) - elseif( __machine MATCHES i686 ) - set( __arch "x86" ) - elseif( __machine MATCHES aarch64 ) - set( __arch "arm64" ) - elseif( __machine MATCHES arm ) - set( __arch "arm" ) - elseif( __machine MATCHES mips64el ) - set( __arch "mips64" ) - elseif( __machine MATCHES mipsel ) - set( __arch "mips" ) - else() - set( __arch "" ) - endif() - #message("machine: !${__machine}!\narch: !${__arch}!\nversion: !${__version}!\ntoolchain: !${__toolchain}!\n") - if (__arch) - list( APPEND __availableToolchainMachines "${__machine}" ) - list( APPEND __availableToolchainArchs "${__arch}" ) - list( APPEND __availableToolchainCompilerVersions "${__version}" ) - list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) - endif() - endif() - unset( __gcc_toolchain ) - endforeach() -endmacro() - -# get all the details about NDK -if( BUILD_WITH_ANDROID_NDK ) - file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" ) - string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" ) - set( __availableToolchains "" ) - set( __availableToolchainMachines "" ) - set( __availableToolchainArchs "" ) - set( __availableToolchainCompilerVersions "" ) - if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" ) - # do not go through all toolchains if we know the name - set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) - if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) - if( __availableToolchains ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) - endif() - endif() - endif() - if( NOT __availableToolchains ) - file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" ) - if( __availableToolchainsLst ) - list(SORT __availableToolchainsLst) # we need clang to go after gcc - endif() - __LIST_FILTER( __availableToolchainsLst "^[.]" ) - __LIST_FILTER( __availableToolchainsLst "llvm" ) - __LIST_FILTER( __availableToolchainsLst "renderscript" ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) - if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) - if( __availableToolchains ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) - endif() - endif() - endif() - if( NOT __availableToolchains ) - message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." ) - endif() -endif() - -# build list of available ABIs -set( ANDROID_SUPPORTED_ABIS "" ) -set( __uniqToolchainArchNames ${__availableToolchainArchs} ) -list( REMOVE_DUPLICATES __uniqToolchainArchNames ) -list( SORT __uniqToolchainArchNames ) -foreach( __arch ${__uniqToolchainArchNames} ) - list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) -endforeach() -unset( __uniqToolchainArchNames ) -if( NOT ANDROID_SUPPORTED_ABIS ) - message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) -endif() - -# choose target ABI -__INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} ) -# verify that target ABI is supported -list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx ) -if( __androidAbiIdx EQUAL -1 ) - string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) - message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain. - Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\" - " ) -endif() -unset( __androidAbiIdx ) - -# set target ABI options -if( ANDROID_ABI STREQUAL "x86" ) - set( X86 true ) - set( ANDROID_NDK_ABI_NAME "x86" ) - set( ANDROID_ARCH_NAME "x86" ) - set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" ) - set( CMAKE_SYSTEM_PROCESSOR "i686" ) -elseif( ANDROID_ABI STREQUAL "x86_64" ) - set( X86 true ) - set( X86_64 true ) - set( ANDROID_NDK_ABI_NAME "x86_64" ) - set( ANDROID_ARCH_NAME "x86_64" ) - set( CMAKE_SYSTEM_PROCESSOR "x86_64" ) - set( ANDROID_LLVM_TRIPLE "x86_64-none-linux-android" ) -elseif( ANDROID_ABI STREQUAL "mips64" ) - set( MIPS64 true ) - set( ANDROID_NDK_ABI_NAME "mips64" ) - set( ANDROID_ARCH_NAME "mips64" ) - set( ANDROID_LLVM_TRIPLE "mips64el-none-linux-android" ) - set( CMAKE_SYSTEM_PROCESSOR "mips64" ) -elseif( ANDROID_ABI STREQUAL "mips" ) - set( MIPS true ) - set( ANDROID_NDK_ABI_NAME "mips" ) - set( ANDROID_ARCH_NAME "mips" ) - set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" ) - set( CMAKE_SYSTEM_PROCESSOR "mips" ) -elseif( ANDROID_ABI STREQUAL "arm64-v8a" ) - set( ARM64_V8A true ) - set( ANDROID_NDK_ABI_NAME "arm64-v8a" ) - set( ANDROID_ARCH_NAME "arm64" ) - set( ANDROID_LLVM_TRIPLE "aarch64-none-linux-android" ) - set( CMAKE_SYSTEM_PROCESSOR "aarch64" ) - set( VFPV3 true ) - set( NEON true ) -elseif( ANDROID_ABI STREQUAL "armeabi" ) - set( ARMEABI true ) - set( ANDROID_NDK_ABI_NAME "armeabi" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv5te" ) -elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" ) - set( ARMEABI_V6 true ) - set( ANDROID_NDK_ABI_NAME "armeabi" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv6" ) - # need always fallback to older platform - set( ARMEABI true ) -elseif( ANDROID_ABI STREQUAL "armeabi-v7a") - set( ARMEABI_V7A true ) - set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) -elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" ) - set( ARMEABI_V7A true ) - set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) - set( VFPV3 true ) -elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" ) - set( ARMEABI_V7A true ) - set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) - set( VFPV3 true ) - set( NEON true ) -else() - message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." ) -endif() - -if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" ) - # really dirty hack - # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... - file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" ) -endif() - -if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 ) - __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF ) - set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE ) - mark_as_advanced( ANDROID_FORCE_ARM_BUILD ) -else() - unset( ANDROID_FORCE_ARM_BUILD CACHE ) -endif() - -# choose toolchain -if( ANDROID_TOOLCHAIN_NAME ) - list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx ) - if( __toolchainIdx EQUAL -1 ) - list( SORT __availableToolchains ) - string( REPLACE ";" "\n * " toolchains_list "${__availableToolchains}" ) - set( toolchains_list " * ${toolchains_list}") - message( FATAL_ERROR "Specified toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing in your NDK or broken. Please verify that your NDK is working or select another compiler toolchain. -To configure the toolchain set CMake variable ANDROID_TOOLCHAIN_NAME to one of the following values:\n${toolchains_list}\n" ) - endif() - list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch ) - if( NOT __toolchainArch STREQUAL ANDROID_ARCH_NAME ) - message( SEND_ERROR "Selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." ) - endif() -else() - set( __toolchainIdx -1 ) - set( __applicableToolchains "" ) - set( __toolchainMaxVersion "0.0.0" ) - list( LENGTH __availableToolchains __availableToolchainsCount ) - math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" ) - foreach( __idx RANGE ${__availableToolchainsCount} ) - list( GET __availableToolchainArchs ${__idx} __toolchainArch ) - if( __toolchainArch STREQUAL ANDROID_ARCH_NAME ) - list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion ) - string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}") - if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion ) - set( __toolchainMaxVersion "${__toolchainVersion}" ) - set( __toolchainIdx ${__idx} ) - endif() - endif() - endforeach() - unset( __availableToolchainsCount ) - unset( __toolchainMaxVersion ) - unset( __toolchainVersion ) -endif() -unset( __toolchainArch ) -if( __toolchainIdx EQUAL -1 ) - message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." ) -endif() -list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME ) -list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME ) -list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION ) - -unset( __toolchainIdx ) -unset( __availableToolchains ) -unset( __availableToolchainMachines ) -unset( __availableToolchainArchs ) -unset( __availableToolchainCompilerVersions ) - -# choose native API level -__INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) -string( REPLACE "android-" "" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) -string( STRIP "${ANDROID_NATIVE_API_LEVEL}" ANDROID_NATIVE_API_LEVEL ) -# adjust API level -set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} ) -foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) - if( (__level LESS ANDROID_NATIVE_API_LEVEL OR __level STREQUAL ANDROID_NATIVE_API_LEVEL) AND NOT __level LESS __real_api_level ) - set( __real_api_level ${__level} ) - endif() -endforeach() -if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL STREQUAL __real_api_level ) - message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'") - set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} ) -endif() -unset(__real_api_level) -# validate -list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) -if( __levelIdx EQUAL -1 ) - message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." ) -else() - if( BUILD_WITH_ANDROID_NDK ) - __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" ) - if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL AND NOT __realApiLevel GREATER 9000 ) - message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." ) - endif() - unset( __realApiLevel ) - endif() - set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE ) - set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} ) - if( CMAKE_VERSION VERSION_GREATER "2.8" ) - list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS ) - set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) - endif() -endif() -unset( __levelIdx ) - - -# remember target ABI -set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE ) -if( CMAKE_VERSION VERSION_GREATER "2.8" ) - list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME} ) - set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME}} ) -endif() - - -# runtime choice (STL, rtti, exceptions) -if( NOT ANDROID_STL ) - set( ANDROID_STL gnustl_static ) -endif() -set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" ) -set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" ) -mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES ) - -if( BUILD_WITH_ANDROID_NDK ) - if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared|c\\+\\+_static|c\\+\\+_shared)$") - message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". -The possible values are: - none -> Do not configure the runtime. - system -> Use the default minimal system C++ runtime library. - system_re -> Same as system but with rtti and exceptions. - gabi++_static -> Use the GAbi++ runtime as a static library. - gabi++_shared -> Use the GAbi++ runtime as a shared library. - stlport_static -> Use the STLport runtime as a static library. - stlport_shared -> Use the STLport runtime as a shared library. - gnustl_static -> (default) Use the GNU STL as a static library. - gnustl_shared -> Use the GNU STL as a shared library. - c++_static -> Use the LLVM libc++ runtime as a static library. - c++_shared -> Use the LLVM libc++ runtime as a shared library. -" ) - endif() -elseif( BUILD_WITH_STANDALONE_TOOLCHAIN ) - if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$") - message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". -The possible values are: - none -> Do not configure the runtime. - gnustl_static -> (default) Use the GNU STL as a static library. - gnustl_shared -> Use the GNU STL as a shared library. -" ) - endif() -endif() - -unset( ANDROID_RTTI ) -unset( ANDROID_EXCEPTIONS ) -unset( ANDROID_STL_INCLUDE_DIRS ) -unset( __libstl ) -unset( __libsupcxx ) - -if( NOT _CMAKE_IN_TRY_COMPILE AND ANDROID_NDK_RELEASE STREQUAL "r7b" AND ARMEABI_V7A AND NOT VFPV3 AND ANDROID_STL MATCHES "gnustl" ) - message( WARNING "The GNU STL armeabi-v7a binaries from NDK r7b can crash non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf). -You are strongly recommended to switch to another NDK release. -" ) -endif() - -if( NOT _CMAKE_IN_TRY_COMPILE AND X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" ) - message( WARNING "The x86 system header file from NDK r6 has incorrect definition for ptrdiff_t. You are recommended to upgrade to a newer NDK release or manually patch the header: -See https://android.googlesource.com/platform/development.git f907f4f9d4e56ccc8093df6fee54454b8bcab6c2 - diff --git a/ndk/platforms/android-9/arch-x86/include/machine/_types.h b/ndk/platforms/android-9/arch-x86/include/machine/_types.h - index 5e28c64..65892a1 100644 - --- a/ndk/platforms/android-9/arch-x86/include/machine/_types.h - +++ b/ndk/platforms/android-9/arch-x86/include/machine/_types.h - @@ -51,7 +51,11 @@ typedef long int ssize_t; - #endif - #ifndef _PTRDIFF_T - #define _PTRDIFF_T - -typedef long ptrdiff_t; - +# ifdef __ANDROID__ - + typedef int ptrdiff_t; - +# else - + typedef long ptrdiff_t; - +# endif - #endif -" ) -endif() - - -# setup paths and STL for standalone toolchain -if( BUILD_WITH_STANDALONE_TOOLCHAIN ) - set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) - set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) - set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) - - if( NOT ANDROID_STL STREQUAL "none" ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) - if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) - # old location ( pre r8c ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) - endif() - if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) - list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) - elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) - list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" ) - else() - list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" ) - endif() - # always search static GNU STL to get the location of libsupc++.a - if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" ) - elseif( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}" ) - elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" ) - elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" ) - endif() - if( __libstl ) - set( __libsupcxx "${__libstl}/libsupc++.a" ) - set( __libstl "${__libstl}/libstdc++.a" ) - endif() - if( NOT EXISTS "${__libsupcxx}" ) - message( FATAL_ERROR "The required libstdsupc++.a is missing in your standalone toolchain. - Usually it happens because of bug in make-standalone-toolchain.sh script from NDK r7, r7b and r7c. - You need to either upgrade to newer NDK or manually copy - $ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a - to - ${__libsupcxx} - " ) - endif() - if( ANDROID_STL STREQUAL "gnustl_shared" ) - if( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) - elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) - elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) - endif() - endif() - endif() -endif() - -# clang -if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" ) - set( ANDROID_COMPILER_IS_CLANG 1 ) - execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) - string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}") -elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" ) - string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}") - string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-${ANDROID_COMPILER_VERSION}" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) - if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" ) - message( FATAL_ERROR "Could not find the Clang compiler driver" ) - endif() - set( ANDROID_COMPILER_IS_CLANG 1 ) - set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) -else() - set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) - unset( ANDROID_COMPILER_IS_CLANG CACHE ) -endif() - -string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" ) -if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" ) - set( _clang_name "clang" ) -endif() - - -# setup paths and STL for NDK -if( BUILD_WITH_ANDROID_NDK ) - set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) - set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" ) - - if( ANDROID_STL STREQUAL "none" ) - # do nothing - elseif( ANDROID_STL STREQUAL "system" ) - set( ANDROID_RTTI OFF ) - set( ANDROID_EXCEPTIONS OFF ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) - elseif( ANDROID_STL STREQUAL "system_re" ) - set( ANDROID_RTTI ON ) - set( ANDROID_EXCEPTIONS ON ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) - elseif( ANDROID_STL MATCHES "gabi" ) - if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 - message( FATAL_ERROR "gabi++ is not available in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.") - endif() - set( ANDROID_RTTI ON ) - set( ANDROID_EXCEPTIONS OFF ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/gabi++/include" ) - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${ANDROID_NDK_ABI_NAME}/libgabi++_static.a" ) - elseif( ANDROID_STL MATCHES "stlport" ) - if( NOT ANDROID_NDK_RELEASE_NUM LESS 8004 ) # before r8d - set( ANDROID_EXCEPTIONS ON ) - else() - set( ANDROID_EXCEPTIONS OFF ) - endif() - if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 - set( ANDROID_RTTI OFF ) - else() - set( ANDROID_RTTI ON ) - endif() - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" ) - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}/libstlport_static.a" ) - elseif( ANDROID_STL MATCHES "gnustl" ) - set( ANDROID_EXCEPTIONS ON ) - set( ANDROID_RTTI ON ) - if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) - if( ARMEABI_V7A AND ANDROID_COMPILER_VERSION VERSION_EQUAL "4.7" AND ANDROID_NDK_RELEASE STREQUAL "r8d" ) - # gnustl binary for 4.7 compiler is buggy :( - # TODO: look for right fix - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.6" ) - else() - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) - endif() - else() - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" ) - endif() - set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" ) - if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) - set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) - else() - set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" ) - endif() - elseif( ANDROID_STL MATCHES "c\\+\\+_shared" OR ANDROID_STL MATCHES "c\\+\\+_static" ) - set( ANDROID_EXCEPTIONS ON ) - set( ANDROID_RTTI ON ) - set( ANDROID_CXX_ROOT "${ANDROID_NDK}/sources/cxx-stl/" ) - set( ANDROID_LLVM_ROOT "${ANDROID_CXX_ROOT}/llvm-libc++" ) - - if( X86 ) - set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/gabi++/include" ) - else() - set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/llvm-libc++abi/include" ) - endif() - - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_LLVM_ROOT}/libcxx/include" "${ANDROID_ABI_INCLUDE_DIRS}" ) - - # android support sfiles - include_directories ( SYSTEM ${ANDROID_NDK}/sources/android/support/include ) - - if(ANDROID_STL MATCHES "c\\+\\+_shared") - set ( LLVM_LIBRARY_NAME "libc++_shared.so") - else() - set ( LLVM_LIBRARY_NAME "libc++_static.a" ) - endif () - - if( EXISTS "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/${LLVM_LIBRARY_NAME}" ) - set( __libstl "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/${LLVM_LIBRARY_NAME}" ) - else() - message( FATAL_ERROR "Could not find libc++ library" ) - endif() - else() - message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" ) - endif() - # find libsupc++.a - rtti & exceptions - if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" ) - set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer - if( NOT EXISTS "${__libsupcxx}" ) - set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8 - endif() - if( NOT EXISTS "${__libsupcxx}" ) # before r7 - if( ARMEABI_V7A ) - if( ANDROID_FORCE_ARM_BUILD ) - set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" ) - else() - set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" ) - endif() - elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD ) - set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" ) - else() - set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" ) - endif() - endif() - if( NOT EXISTS "${__libsupcxx}") - message( ERROR "Could not find libsupc++.a for a chosen platform. Either your NDK is not supported or is broken.") - endif() - endif() -endif() - - -# case of shared STL linkage -if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) - string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) - # TODO: check if .so file exists before the renaming -endif() - - -# ccache support -__INIT_VARIABLE( _ndk_ccache NDK_CCACHE ENV_NDK_CCACHE ) -if( _ndk_ccache ) - if( DEFINED NDK_CCACHE AND NOT EXISTS NDK_CCACHE ) - unset( NDK_CCACHE CACHE ) - endif() - find_program( NDK_CCACHE "${_ndk_ccache}" DOC "The path to ccache binary") -else() - unset( NDK_CCACHE CACHE ) -endif() -unset( _ndk_ccache ) - - -# setup the cross-compiler -if( NOT CMAKE_C_COMPILER ) - if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) - set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" ) - set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" ) - if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_C_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") - set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") - else() - set( CMAKE_C_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") - set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") - endif() - else() - if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_C_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") - set( CMAKE_CXX_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") - else() - set( CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler" ) - set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler" ) - endif() - endif() - set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" ) - set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" ) - if( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" ) - # Use gcc-ar if we have it for better LTO support. - set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) - else() - set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) - endif() - set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" ) - set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" ) - set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" ) - set( CMAKE_OBJDUMP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" ) - set( CMAKE_RANLIB "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" ) -endif() - -set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" ) -if( CMAKE_VERSION VERSION_LESS 2.8.5 ) - set( CMAKE_ASM_COMPILER_ARG1 "-c" ) -endif() -if( APPLE ) - find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool ) - if( NOT CMAKE_INSTALL_NAME_TOOL ) - message( FATAL_ERROR "Could not find install_name_tool, please check your installation." ) - endif() - mark_as_advanced( CMAKE_INSTALL_NAME_TOOL ) -endif() - -# Force set compilers because standard identification works badly for us -include( CMakeForceCompiler ) -CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU ) -if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_C_COMPILER_ID Clang ) -endif() -set( CMAKE_C_PLATFORM_ID Linux ) -if( X86_64 OR MIPS64 OR ARM64_V8A ) - set( CMAKE_C_SIZEOF_DATA_PTR 8 ) -else() - set( CMAKE_C_SIZEOF_DATA_PTR 4 ) -endif() -set( CMAKE_C_HAS_ISYSROOT 1 ) -set( CMAKE_C_COMPILER_ABI ELF ) -CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU ) -if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_CXX_COMPILER_ID Clang) -endif() -set( CMAKE_CXX_PLATFORM_ID Linux ) -set( CMAKE_CXX_SIZEOF_DATA_PTR ${CMAKE_C_SIZEOF_DATA_PTR} ) -set( CMAKE_CXX_HAS_ISYSROOT 1 ) -set( CMAKE_CXX_COMPILER_ABI ELF ) -set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C ) -# force ASM compiler (required for CMake < 2.8.5) -set( CMAKE_ASM_COMPILER_ID_RUN TRUE ) -set( CMAKE_ASM_COMPILER_ID GNU ) -set( CMAKE_ASM_COMPILER_WORKS TRUE ) -set( CMAKE_ASM_COMPILER_FORCED TRUE ) -set( CMAKE_COMPILER_IS_GNUASM 1) -set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm ) - -foreach( lang C CXX ASM ) - if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} ) - else() - set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} ) - endif() -endforeach() - -# flags and definitions -remove_definitions( -DANDROID ) -add_definitions( -DANDROID ) - -if( ANDROID_SYSROOT MATCHES "[ ;\"]" ) - if( CMAKE_HOST_WIN32 ) - # try to convert path to 8.3 form - file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" ) - execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}" - OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE __result ERROR_QUIET ) - if( __result EQUAL 0 ) - file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT ) - set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) - else() - set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) - endif() - else() - set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" ) - endif() - if( NOT _CMAKE_IN_TRY_COMPILE ) - # quotes can break try_compile and compiler identification - message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n") - endif() -else() - set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) -endif() - -# NDK flags -if (ARM64_V8A ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) - set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) - endif() -elseif( ARMEABI OR ARMEABI_V7A) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) - if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) - set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" ) - endif() - else() - # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI - set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) - endif() - endif() -elseif( X86 OR X86_64 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) - endif() - set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) -elseif( MIPS OR MIPS64 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" ) - set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) - set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" ) - set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) - endif() -elseif() - set( ANDROID_CXX_FLAGS_RELEASE "" ) - set( ANDROID_CXX_FLAGS_DEBUG "" ) -endif() - -set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries - -if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) -endif() - -if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/ -endif() - -# ABI-specific flags -if( ARMEABI_V7A ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" ) - if( NEON ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" ) - elseif( VFPV3 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" ) - else() - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3-d16" ) - endif() -elseif( ARMEABI_V6 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2 -elseif( ARMEABI ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) -endif() - -if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) -else() - set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) -endif() - -# STL -if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) - if( EXISTS "${__libstl}" ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" ) - set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libstl}\"" ) - endif() - if( EXISTS "${__libsupcxx}" ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) - set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) - # C objects: - set( CMAKE_C_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_C_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_C_LINK_EXECUTABLE " -o " ) - set( CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) - set( CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) - set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) - endif() - if( ANDROID_STL MATCHES "gnustl" ) - if( NOT EXISTS "${ANDROID_LIBM_PATH}" ) - set( ANDROID_LIBM_PATH -lm ) - endif() - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" ) - set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" ) - endif() -endif() - -# variables controlling optional build flags -if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 - # libGLESv2.so in NDK's prior to r7 refers to missing external symbols. - # So this flag option is required for all projects using OpenGL from native. - __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON ) -else() - __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF ) -endif() -__INIT_VARIABLE( ANDROID_NO_UNDEFINED VALUES ON ) -__INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON ) -__INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON ) -__INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON ) -__INIT_VARIABLE( ANDROID_RELRO VALUES ON ) - -set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" ) -set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) -set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" ) -set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" ) -set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) -set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" ) -mark_as_advanced( ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ) - -# linker flags -set( ANDROID_LINKER_FLAGS "" ) - -if( ARMEABI_V7A ) - # this is *required* to use the following linker flags that routes around - # a CPU bug in some Cortex-A8 implementations: - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--fix-cortex-a8" ) -endif() - -if( ANDROID_NO_UNDEFINED ) - if( MIPS ) - # there is some sysroot-related problem in mips linker... - if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) - endif() - else() - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) - endif() -endif() - -if( ANDROID_SO_UNDEFINED ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" ) -endif() - -if( ANDROID_FUNCTION_LEVEL_LINKING ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--gc-sections" ) -endif() - -if( ANDROID_COMPILER_VERSION VERSION_EQUAL "4.6" ) - if( ANDROID_GOLD_LINKER AND (CMAKE_HOST_UNIX OR ANDROID_NDK_RELEASE_NUM GREATER 8002) AND (ARMEABI OR ARMEABI_V7A OR X86) ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=gold" ) - elseif( ANDROID_NDK_RELEASE_NUM GREATER 8002 ) # after r8b - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=bfd" ) - elseif( ANDROID_NDK_RELEASE STREQUAL "r8b" AND ARMEABI AND NOT _CMAKE_IN_TRY_COMPILE ) - message( WARNING "The default bfd linker from arm GCC 4.6 toolchain can fail with 'unresolvable R_ARM_THM_CALL relocation' error message. See https://code.google.com/p/android/issues/detail?id=35342 - On Linux and OS X host platform you can workaround this problem using gold linker (default). - Rerun cmake with -DANDROID_GOLD_LINKER=ON option in case of problems. -" ) - endif() -endif() # version 4.6 - -if( ANDROID_NOEXECSTACK ) - if( ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Xclang -mnoexecstack" ) - else() - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Wa,--noexecstack" ) - endif() - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,noexecstack" ) -endif() - -if( ANDROID_RELRO ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now" ) -endif() - -if( ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} -Qunused-arguments ${ANDROID_CXX_FLAGS}" ) - if( BUILD_WITH_ANDROID_NDK ) - set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" ) - endif() -endif() - -# cache flags -set( CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags" ) -set( CMAKE_C_FLAGS "" CACHE STRING "c flags" ) -set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c++ Release flags" ) -set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c Release flags" ) -set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" ) -set( CMAKE_C_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" ) -set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags" ) -set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" ) -set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" ) - -# put flags to cache (for debug purpose only) -set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" ) -set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" ) -set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) -set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) - -# finish flags -set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) -set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) -set( CMAKE_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}" ) -set( CMAKE_C_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}" ) -set( CMAKE_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}" ) -set( CMAKE_C_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}" ) -set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" ) -set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" ) -set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) - -if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" ) - set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) - set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) - set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) -endif() - -# pie/pic -if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8) ) - set( CMAKE_POSITION_INDEPENDENT_CODE TRUE ) - set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie") -else() - set( CMAKE_POSITION_INDEPENDENT_CODE FALSE ) - set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" ) - set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" ) -endif() - -# configure rtti -if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES ) - if( ANDROID_RTTI ) - set( CMAKE_CXX_FLAGS "-frtti ${CMAKE_CXX_FLAGS}" ) - else() - set( CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}" ) - endif() -endif() - -# configure exceptios -if( DEFINED ANDROID_EXCEPTIONS AND ANDROID_STL_FORCE_FEATURES ) - if( ANDROID_EXCEPTIONS ) - set( CMAKE_CXX_FLAGS "-fexceptions ${CMAKE_CXX_FLAGS}" ) - set( CMAKE_C_FLAGS "-fexceptions ${CMAKE_C_FLAGS}" ) - else() - set( CMAKE_CXX_FLAGS "-fno-exceptions ${CMAKE_CXX_FLAGS}" ) - set( CMAKE_C_FLAGS "-fno-exceptions ${CMAKE_C_FLAGS}" ) - endif() -endif() - -# global includes and link directories -include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) -get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning -link_directories( "${__android_install_path}" ) - -# detect if need link crtbegin_so.o explicitly -if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) - set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" ) - string( REPLACE "" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" ) - string( REPLACE "" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" ) - string( REPLACE "" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" ) - string( REPLACE "" "" __cmd "${__cmd}" ) - string( REPLACE "" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" ) - string( REPLACE "" "-shared" __cmd "${__cmd}" ) - string( REPLACE "" "" __cmd "${__cmd}" ) - string( REPLACE "" "" __cmd "${__cmd}" ) - string( REPLACE "" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" ) - string( REPLACE "" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" ) - string( REPLACE "" "" __cmd "${__cmd}" ) - separate_arguments( __cmd ) - foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN ) - if( ${__var} ) - set( __tmp "${${__var}}" ) - separate_arguments( __tmp ) - string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}") - endif() - endforeach() - string( REPLACE "'" "" __cmd "${__cmd}" ) - string( REPLACE "\"" "" __cmd "${__cmd}" ) - execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET ) - if( __cmd_result EQUAL 0 ) - set( ANDROID_EXPLICIT_CRT_LINK ON ) - else() - set( ANDROID_EXPLICIT_CRT_LINK OFF ) - endif() -endif() - -if( ANDROID_EXPLICIT_CRT_LINK ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) -endif() - -# setup output directories -set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) - -if( DEFINED LIBRARY_OUTPUT_PATH_ROOT - OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml" - OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") ) - set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" ) - if( NOT _CMAKE_IN_TRY_COMPILE ) - if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) - set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" ) - else() - set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" ) - endif() - set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" ) - endif() -endif() - -# copy shaed stl library to build directory -if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH ) - get_filename_component( __libstlname "${__libstl}" NAME ) - execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) - if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") - message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) - endif() - unset( __fileCopyProcess ) - unset( __libstlname ) -endif() - - -# set these global flags for cmake client scripts to change behavior -set( ANDROID True ) -set( BUILD_ANDROID True ) - -# where is the target environment -set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" ) - -# only search for libraries and includes in the ndk toolchain -set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) -set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) -set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) - - -# macro to find packages on the host OS -macro( find_host_package ) - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) - set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) - if( CMAKE_HOST_WIN32 ) - SET( WIN32 1 ) - SET( UNIX ) - elseif( CMAKE_HOST_APPLE ) - SET( APPLE 1 ) - SET( UNIX ) - endif() - find_package( ${ARGN} ) - SET( WIN32 ) - SET( APPLE ) - SET( UNIX 1 ) - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) - set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) -endmacro() - - -# macro to find programs on the host OS -macro( find_host_program ) - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) - set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) - if( CMAKE_HOST_WIN32 ) - SET( WIN32 1 ) - SET( UNIX ) - elseif( CMAKE_HOST_APPLE ) - SET( APPLE 1 ) - SET( UNIX ) - endif() - find_program( ${ARGN} ) - SET( WIN32 ) - SET( APPLE ) - SET( UNIX 1 ) - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) - set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) -endmacro() - - -# export toolchain settings for the try_compile() command -if( NOT _CMAKE_IN_TRY_COMPILE ) - set( __toolchain_config "") - foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN - ANDROID_NDK_HOST_X64 - ANDROID_NDK - ANDROID_NDK_LAYOUT - ANDROID_STANDALONE_TOOLCHAIN - ANDROID_TOOLCHAIN_NAME - ANDROID_ABI - ANDROID_NATIVE_API_LEVEL - ANDROID_STL - ANDROID_STL_FORCE_FEATURES - ANDROID_FORCE_ARM_BUILD - ANDROID_NO_UNDEFINED - ANDROID_SO_UNDEFINED - ANDROID_FUNCTION_LEVEL_LINKING - ANDROID_GOLD_LINKER - ANDROID_NOEXECSTACK - ANDROID_RELRO - ANDROID_LIBM_PATH - ANDROID_EXPLICIT_CRT_LINK - ANDROID_APP_PIE - ) - if( DEFINED ${__var} ) - if( ${__var} MATCHES " ") - set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" ) - else() - set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" ) - endif() - endif() - endforeach() - file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" ) - unset( __toolchain_config ) -endif() - - -# force cmake to produce / instead of \ in build commands for Ninja generator -if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) - # it is a bad hack after all - # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW - set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW - set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion - enable_language( C ) - enable_language( CXX ) - # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it - unset( MINGW ) -endif() - - -# Variables controlling behavior or set by cmake toolchain: -# ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64" -# ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version) -# ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none -# ANDROID_FORBID_SYGWIN : ON/OFF -# ANDROID_NO_UNDEFINED : ON/OFF -# ANDROID_SO_UNDEFINED : OFF/ON (default depends on NDK version) -# ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF -# ANDROID_GOLD_LINKER : ON/OFF -# ANDROID_NOEXECSTACK : ON/OFF -# ANDROID_RELRO : ON/OFF -# ANDROID_FORCE_ARM_BUILD : ON/OFF -# ANDROID_STL_FORCE_FEATURES : ON/OFF -# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product//obj/lib/libm.so) to workaround unresolved `sincos` -# Can be set only at the first run: -# ANDROID_NDK : path to your NDK install -# NDK_CCACHE : path to your ccache executable -# ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain -# ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems) -# ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID) -# LIBRARY_OUTPUT_PATH_ROOT : -# ANDROID_STANDALONE_TOOLCHAIN -# -# Primary read-only variables: -# ANDROID : always TRUE -# ARMEABI : TRUE for arm v6 and older devices -# ARMEABI_V6 : TRUE for arm v6 -# ARMEABI_V7A : TRUE for arm v7a -# ARM64_V8A : TRUE for arm64-v8a -# NEON : TRUE if NEON unit is enabled -# VFPV3 : TRUE if VFP version 3 is enabled -# X86 : TRUE if configured for x86 -# X86_64 : TRUE if configured for x86_64 -# MIPS : TRUE if configured for mips -# MIPS64 : TRUE if configured for mips64 -# BUILD_WITH_ANDROID_NDK : TRUE if NDK is used -# BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used -# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform -# ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI -# ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK -# ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor) -# ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI -# ANDROID_SYSROOT : path to the compiler sysroot -# TOOL_OS_SUFFIX : "" or ".exe" depending on host platform -# ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used -# -# Secondary (less stable) read-only variables: -# ANDROID_COMPILER_VERSION : GCC version used (not Clang version) -# ANDROID_CLANG_VERSION : version of clang compiler if clang is used -# ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform -# ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI -# ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux" -# ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK) -# ANDROID_CLANG_TOOLCHAIN_ROOT : path to clang tools -# ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK -# ANDROID_STL_INCLUDE_DIRS : stl include paths -# ANDROID_RTTI : if rtti is enabled by the runtime -# ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime -# ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used -# -# Defaults: -# ANDROID_DEFAULT_NDK_API_LEVEL -# ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH} -# ANDROID_NDK_SEARCH_PATHS -# ANDROID_SUPPORTED_ABIS_${ARCH} -# ANDROID_SUPPORTED_NDK_VERSIONS diff --git a/cmake/android/deployment-file.json.in b/cmake/android/deployment-file.json.in deleted file mode 100644 index 81ed8a6ecc..0000000000 --- a/cmake/android/deployment-file.json.in +++ /dev/null @@ -1,13 +0,0 @@ -{ - "qt": "@QT_DIR@", - "sdk": "@ANDROID_SDK_ROOT@", - "ndk": "@ANDROID_NDK@", - "toolchain-prefix": "@ANDROID_TOOLCHAIN_MACHINE_NAME@", - "tool-prefix": "@ANDROID_TOOLCHAIN_MACHINE_NAME@", - "toolchain-version": "@ANDROID_COMPILER_VERSION@", - "ndk-host": "@ANDROID_NDK_HOST_SYSTEM_NAME@", - "target-architecture": "@ANDROID_ABI@", - "application-binary": "@EXECUTABLE_DESTINATION_PATH@", - "android-extra-libs": "@_DEPS@", - "android-package-source-directory": "@ANDROID_APK_BUILD_DIR@" -} diff --git a/cmake/android/strings.xml.in b/cmake/android/strings.xml.in deleted file mode 100644 index 6e6ce7b12e..0000000000 --- a/cmake/android/strings.xml.in +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - ${ANDROID_APP_DISPLAY_NAME} - - Can\'t find Ministro service.\nThe application can\'t start. - This application requires Ministro service. Would you like to install it? - Your application encountered a fatal error and cannot continue. - diff --git a/cmake/externals/glm/CMakeLists.txt b/cmake/externals/glm/CMakeLists.txt index 79a44fa48e..bc8089074f 100644 --- a/cmake/externals/glm/CMakeLists.txt +++ b/cmake/externals/glm/CMakeLists.txt @@ -6,7 +6,7 @@ ExternalProject_Add( URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.zip URL_MD5 579ac77a3110befa3244d68c0ceb7281 BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= ${EXTERNAL_ARGS} LOG_DOWNLOAD 1 LOG_CONFIGURE 1 LOG_BUILD 1 diff --git a/cmake/externals/tbb/CMakeLists.txt b/cmake/externals/tbb/CMakeLists.txt index 71d7b94597..9664fe7250 100644 --- a/cmake/externals/tbb/CMakeLists.txt +++ b/cmake/externals/tbb/CMakeLists.txt @@ -8,9 +8,6 @@ if (WIN32) elseif (APPLE) set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb2017_20170604oss_mac_slim.tar.gz) set(DOWNLOAD_MD5 62bde626b396f8e1a85c6a8ded1d8105) -elseif (ANDROID) - set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb2017_20170604oss_and_slim.tar.gz) - set(DOWNLOAD_MD5 04d50b64e1d81245a1be5f75f34d64c7) else () set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb2017_20170604oss_lin_slim.tar.gz) set(DOWNLOAD_MD5 2a5c721f40fa3503ffc12c18dd00011c) @@ -107,3 +104,4 @@ endif () if (DEFINED ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE) set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE "List of tbb include directories") endif () + diff --git a/cmake/init.cmake b/cmake/init.cmake index 75fb3a4b52..9d7b0fd94c 100644 --- a/cmake/init.cmake +++ b/cmake/init.cmake @@ -34,10 +34,23 @@ file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake") foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS}) include(${CUSTOM_MACRO}) endforeach() +unset(HIFI_CUSTOM_MACROS) if (ANDROID) - file(GLOB ANDROID_CUSTOM_MACROS "cmake/android/*.cmake") - foreach(CUSTOM_MACRO ${ANDROID_CUSTOM_MACROS}) - include(${CUSTOM_MACRO}) - endforeach() + set(BUILD_SHARED_LIBS ON) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) + + string(REGEX REPLACE "\\\\" "/" ANDROID_NDK ${ANDROID_NDK}) + string(REGEX REPLACE "\\\\" "/" CMAKE_TOOLCHAIN_FILE ${CMAKE_TOOLCHAIN_FILE}) + string(REGEX REPLACE "\\\\" "/" ANDROID_TOOLCHAIN ${ANDROID_TOOLCHAIN}) + string(REGEX REPLACE "\\\\" "/" CMAKE_MAKE_PROGRAM ${CMAKE_MAKE_PROGRAM}) + list(APPEND EXTERNAL_ARGS -DANDROID_ABI=${ANDROID_ABI}) + list(APPEND EXTERNAL_ARGS -DANDROID_NDK=${ANDROID_NDK}) + list(APPEND EXTERNAL_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) + list(APPEND EXTERNAL_ARGS -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}) + list(APPEND EXTERNAL_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) + list(APPEND EXTERNAL_ARGS -DHIFI_ANDROID=${HIFI_ANDROID}) + list(APPEND EXTERNAL_ARGS -DANDROID_PLATFORM=${ANDROID_PLATFORM}) + list(APPEND EXTERNAL_ARGS -DANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN}) + list(APPEND EXTERNAL_ARGS -DANDROID_STL=${ANDROID_STL}) endif () diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index c43ade45d2..c5b35b7e90 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -62,7 +62,9 @@ function(AUTOSCRIBE_SHADER SHADER_FILE) # since it's unrunnable by the cross-compiling build machine # so, we require the compiling user to point us at a compiled executable version for their native toolchain - find_program(NATIVE_SCRIBE scribe PATHS ${SCRIBE_PATH} ENV SCRIBE_PATH) + if (NOT NATIVE_SCRIBE) + find_program(NATIVE_SCRIBE scribe PATHS ${SCRIBE_PATH} ENV SCRIBE_PATH) + endif() if (NOT NATIVE_SCRIBE) message(FATAL_ERROR "The High Fidelity scribe tool is required for shader pre-processing. \ diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 8458d53f68..8faa4e6d96 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -162,5 +162,6 @@ macro(SET_PACKAGING_PARAMETERS) # create a header file our targets can use to find out the application version file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/includes") configure_file("${HF_CMAKE_DIR}/templates/BuildInfo.h.in" "${CMAKE_BINARY_DIR}/includes/BuildInfo.h") + include_directories("${CMAKE_BINARY_DIR}/includes") endmacro(SET_PACKAGING_PARAMETERS) diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index d0fc58af0c..04687e2c84 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -12,7 +12,7 @@ macro(SETUP_HIFI_LIBRARY) project(${TARGET_NAME}) # grab the implementation and header files - file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c") + file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c" "src/*.qrc") list(APPEND ${TARGET_NAME}_SRCS ${LIB_SRCS}) # add compiler flags to AVX source files @@ -65,7 +65,7 @@ macro(SETUP_HIFI_LIBRARY) list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core) # find these Qt modules and link them to our own target - find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED) + find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES}) target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) diff --git a/cmake/macros/SetupQt.cmake b/cmake/macros/SetupQt.cmake index b2a89f81e5..ece8607b9b 100644 --- a/cmake/macros/SetupQt.cmake +++ b/cmake/macros/SetupQt.cmake @@ -28,7 +28,7 @@ function(calculate_default_qt_dir _RESULT_NAME) set(QT_DEFAULT_ARCH "gcc_64") endif() - if (WIN32) + if (WIN32 OR (ANDROID AND ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows"))) set(QT_DEFAULT_ROOT "c:/Qt") else() set(QT_DEFAULT_ROOT "$ENV{HOME}/Qt") diff --git a/cmake/macros/TargetGlew.cmake b/cmake/macros/TargetGlew.cmake index 5f71f021ec..bc4d5cb033 100644 --- a/cmake/macros/TargetGlew.cmake +++ b/cmake/macros/TargetGlew.cmake @@ -6,9 +6,11 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # macro(TARGET_GLEW) - add_dependency_external_projects(glew) - find_package(GLEW REQUIRED) - add_definitions(-DGLEW_STATIC) - target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY}) + if (NOT ANDROID) + add_definitions(-DGLEW_STATIC) + add_dependency_external_projects(glew) + find_package(GLEW REQUIRED) + target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY}) + endif() endmacro() \ No newline at end of file diff --git a/cmake/macros/TargetOpenGL.cmake b/cmake/macros/TargetOpenGL.cmake index 73c92e651a..6ad92259bb 100644 --- a/cmake/macros/TargetOpenGL.cmake +++ b/cmake/macros/TargetOpenGL.cmake @@ -6,15 +6,13 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # macro(TARGET_OPENGL) - add_definitions(-DGLEW_STATIC) if (APPLE) # link in required OS X frameworks and include the right GL headers find_library(OpenGL OpenGL) target_link_libraries(${TARGET_NAME} ${OpenGL}) elseif(ANDROID) - target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL") + target_link_libraries(${TARGET_NAME} GLESv3 EGL) else() - target_nsight() find_package(OpenGL REQUIRED) if (${OPENGL_INCLUDE_DIR}) include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}") @@ -22,4 +20,6 @@ macro(TARGET_OPENGL) target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}") target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR}) endif() + target_nsight() + target_glew() endmacro() diff --git a/cmake/macros/TargetOpenSSL.cmake b/cmake/macros/TargetOpenSSL.cmake new file mode 100644 index 0000000000..7ee0283a48 --- /dev/null +++ b/cmake/macros/TargetOpenSSL.cmake @@ -0,0 +1,32 @@ +# +# Copyright 2015 High Fidelity, Inc. +# Created by Bradley Austin Davis on 2015/10/10 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_OPENSSL) + + if (ANDROID) + + # FIXME use a distributable binary + set(OPENSSL_INSTALL_DIR C:/Android/openssl) + set(OPENSSL_INCLUDE_DIR "${OPENSSL_INSTALL_DIR}/include" CACHE TYPE INTERNAL) + set(OPENSSL_LIBRARIES "${OPENSSL_INSTALL_DIR}/lib/libcrypto.a;${OPENSSL_INSTALL_DIR}/lib/libssl.a" CACHE TYPE INTERNAL) + + else() + + find_package(OpenSSL REQUIRED) + + if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include") + # this is a user on OS X using system OpenSSL, which is going to throw warnings since they're deprecating for their common crypto + message(WARNING "The found version of OpenSSL is the OS X system version. This will produce deprecation warnings." + "\nWe recommend you install a newer version (at least 1.0.1h) in a different directory and set OPENSSL_ROOT_DIR in your env so Cmake can find it.") + endif() + + endif() + + include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") + target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES}) + +endmacro() diff --git a/cmake/macros/TargetTBB.cmake b/cmake/macros/TargetTBB.cmake new file mode 100644 index 0000000000..e9c4639c3d --- /dev/null +++ b/cmake/macros/TargetTBB.cmake @@ -0,0 +1,24 @@ +# +# Copyright 2015 High Fidelity, Inc. +# Created by Bradley Austin Davis on 2015/10/10 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_TBB) + +if (ANDROID) + set(TBB_INSTALL_DIR C:/tbb-2018/built) + set(TBB_LIBRARY ${HIFI_ANDROID_PRECOMPILED}/libtbb.so CACHE FILEPATH "TBB library location") + set(TBB_MALLOC_LIBRARY ${HIFI_ANDROID_PRECOMPILED}/libtbbmalloc.so CACHE FILEPATH "TBB malloc library location") + set(TBB_INCLUDE_DIRS ${TBB_INSTALL_DIR}/include CACHE TYPE "List of tbb include directories" CACHE FILEPATH "TBB includes location") + set(TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY}) +else() + add_dependency_external_projects(tbb) + find_package(TBB REQUIRED) +endif() + +target_link_libraries(${TARGET_NAME} ${TBB_LIBRARIES}) +target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${TBB_INCLUDE_DIRS}) + +endmacro() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 43e50c6d33..305a6475f6 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -171,8 +171,6 @@ else () add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) endif () -target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes") - if (WIN32) # These are external plugins, but we need to do the 'add dependency' here so that their # binary directories get added to the fixup path @@ -214,10 +212,6 @@ target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries target_bullet() target_opengl() -if (NOT ANDROID) - target_glew() -endif () - # perform standard include and linking for found externals foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 4e7cc08919..621b1a3e72 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1503,6 +1503,11 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes); _inputRingBuffer.resizeForFrameSize(numFrameSamples); +#if defined(Q_OS_ANDROID) + if (_audioInput) { + connect(_audioInput, SIGNAL(stateChanged(QAudio::State)), this, SLOT(audioInputStateChanged(QAudio::State))); + } +#endif _inputDevice = _audioInput->start(); if (_inputDevice) { @@ -1541,6 +1546,31 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn return supportedFormat; } +#if defined(Q_OS_ANDROID) +void AudioClient::audioInputStateChanged(QAudio::State state) { + switch (state) { + case QAudio::StoppedState: + if (!_audioInput) { + break; + } + // Stopped on purpose + if (_shouldRestartInputSetup) { + Lock lock(_deviceMutex); + _inputDevice = _audioInput->start(); + lock.unlock(); + if (_inputDevice) { + connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleMicAudioInput())); + } + } + break; + case QAudio::ActiveState: + break; + default: + break; + } +} +#endif + void AudioClient::outputNotify() { int recentUnfulfilled = _audioOutputIODevice.getRecentUnfulfilledReads(); if (recentUnfulfilled > 0) { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index ff0ea968a8..01a487455c 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -173,6 +173,9 @@ public slots: void sendDownstreamAudioStatsPacket() { _stats.publish(); } void handleMicAudioInput(); +#if defined(Q_OS_ANDROID) + void audioInputStateChanged(QAudio::State state); +#endif void handleDummyAudioInput(); void handleRecordedAudioInput(const QByteArray& audio); void reset(); @@ -403,6 +406,10 @@ private: RateCounter<> _silentInbound; RateCounter<> _audioInbound; +#if defined(Q_OS_ANDROID) + bool _shouldRestartInputSetup { true }; // Should we restart the input device because of an unintended stop? +#endif + QTimer* _checkDevicesTimer { nullptr }; QTimer* _checkPeakValuesTimer { nullptr }; }; diff --git a/libraries/audio/src/AudioGate.cpp b/libraries/audio/src/AudioGate.cpp index a4d731a447..5b2561da07 100644 --- a/libraries/audio/src/AudioGate.cpp +++ b/libraries/audio/src/AudioGate.cpp @@ -6,11 +6,12 @@ // Copyright 2017 High Fidelity, Inc. // +#include "AudioGate.h" + #include #include - +#include #include "AudioDynamics.h" -#include "AudioGate.h" // log2 domain headroom bits above 0dB (int32_t) static const int LOG2_HEADROOM_Q30 = 1; @@ -417,7 +418,7 @@ void GateMono::process(int16_t* input, int16_t* output, int numFrames) { _dc.process(x); // peak detect - int32_t peak = abs(x); + int32_t peak = std::abs(x); // convert to log2 domain peak = fixlog2(peak); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1baf649e64..278ef25445 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -103,7 +103,7 @@ AvatarData::~AvatarData() { QUrl AvatarData::_defaultFullAvatarModelUrl = {}; // In C++, if this initialization were in the AvatarInfo, every file would have it's own copy, even for class vars. const QUrl& AvatarData::defaultFullAvatarModelUrl() { if (_defaultFullAvatarModelUrl.isEmpty()) { - _defaultFullAvatarModelUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst"); + _defaultFullAvatarModelUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "/meshes/defaultAvatar_full.fst"); } return _defaultFullAvatarModelUrl; } diff --git a/libraries/controllers/CMakeLists.txt b/libraries/controllers/CMakeLists.txt index 6b1ab72c60..9c6bbf4aae 100644 --- a/libraries/controllers/CMakeLists.txt +++ b/libraries/controllers/CMakeLists.txt @@ -8,7 +8,3 @@ link_hifi_libraries(shared) include_hifi_library_headers(networking) GroupSources("src/controllers") - -add_dependency_external_projects(glm) -find_package(GLM REQUIRED) -target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS} "${CMAKE_BINARY_DIR}/includes") diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp index 3e090dc7b3..da226d146b 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp @@ -28,11 +28,14 @@ DisplayPluginList getDisplayPlugins() { #ifdef DEBUG new NullDisplayPlugin(), #endif + +#if !defined(Q_OS_ANDROID) // Stereo modes // SBS left/right new SideBySideStereoDisplayPlugin(), // Interleaved left/right new InterleavedStereoDisplayPlugin(), +#endif nullptr }; diff --git a/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp index 1e0e7e6c1f..6e397efbe5 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.cpp @@ -40,14 +40,6 @@ bool DebugHmdDisplayPlugin::beginFrameRender(uint32_t frameIndex) { return Parent::beginFrameRender(frameIndex); } -// DLL based display plugins MUST initialize GLEW inside the DLL code. -void DebugHmdDisplayPlugin::customizeContext() { - glewExperimental = true; - glewInit(); - glGetError(); // clear the potential error from glewExperimental - Parent::customizeContext(); -} - bool DebugHmdDisplayPlugin::internalActivate() { _ipd = 0.0327499993f * 2.0f; _eyeProjections[0][0] = vec4{ 0.759056330, 0.000000000, 0.000000000, 0.000000000 }; @@ -61,7 +53,7 @@ bool DebugHmdDisplayPlugin::internalActivate() { _eyeInverseProjections[0] = glm::inverse(_eyeProjections[0]); _eyeInverseProjections[1] = glm::inverse(_eyeProjections[1]); _eyeOffsets[0][3] = vec4{ -0.0327499993, 0.0, 0.0149999997, 1.0 }; - _eyeOffsets[0][3] = vec4{ 0.0327499993, 0.0, 0.0149999997, 1.0 }; + _eyeOffsets[1][3] = vec4{ 0.0327499993, 0.0, 0.0149999997, 1.0 }; _renderTargetSize = { 3024, 1680 }; _cullingProjection = _eyeProjections[0]; // This must come after the initialization, so that the values calculated diff --git a/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.h index 9bb82b1836..cd6fdd44b9 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/DebugHmdDisplayPlugin.h @@ -26,7 +26,6 @@ protected: void updatePresentPose() override; void hmdPresent() override {} bool isHmdMounted() const override { return true; } - void customizeContext() override; bool internalActivate() override; private: static const QString NAME; diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index bfbe6d7e5a..ccf2057e09 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -38,7 +38,7 @@ void main(void) { int frontCondition = 1 -int(gl_FrontFacing) * 2; vec3 color = varColor.rgb; packDeferredFragmentTranslucent( - interpolatedNormal * frontCondition, + float(frontCondition) * interpolatedNormal, texel.a * varColor.a, polyline.color * texel.rgb, vec3(0.01, 0.01, 0.01), diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f91bc14fe4..c6b5bc953b 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -659,22 +659,22 @@ QVector EntityScriptingInterface::findEntitiesInFrustum(QVariantMap frust } QVector EntityScriptingInterface::findEntitiesByType(const QString entityType, const glm::vec3& center, float radius) const { - EntityTypes::EntityType type = EntityTypes::getEntityTypeFromName(entityType); + EntityTypes::EntityType type = EntityTypes::getEntityTypeFromName(entityType); - QVector result; - if (_entityTree) { - QVector entities; - _entityTree->withReadLock([&] { - _entityTree->findEntities(center, radius, entities); - }); + QVector result; + if (_entityTree) { + QVector entities; + _entityTree->withReadLock([&] { + _entityTree->findEntities(center, radius, entities); + }); - foreach(EntityItemPointer entity, entities) { - if (entity->getType() == type) { - result << entity->getEntityItemID(); - } - } - } - return result; + foreach(EntityItemPointer entity, entities) { + if (entity->getType() == type) { + result << entity->getEntityItemID(); + } + } + } + return result; } RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 9b2b6360f3..7248c1f851 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -215,12 +215,12 @@ public slots: /// this function will not find any models in script engine contexts which don't have access to entities Q_INVOKABLE QVector findEntitiesInFrustum(QVariantMap frustum) const; - /// finds entities of the indicated type within a sphere given by the center point and radius - /// @param {QString} string representation of entity type - /// @param {vec3} center point - /// @param {float} radius to search - /// this function will not find any entities in script engine contexts which don't have access to entities - Q_INVOKABLE QVector findEntitiesByType(const QString entityType, const glm::vec3& center, float radius) const; + /// finds entities of the indicated type within a sphere given by the center point and radius + /// @param {QString} string representation of entity type + /// @param {vec3} center point + /// @param {float} radius to search + /// this function will not find any entities in script engine contexts which don't have access to entities + Q_INVOKABLE QVector findEntitiesByType(const QString entityType, const glm::vec3& center, float radius) const; /// If the scripting context has visible entities, this will determine a ray intersection, the results /// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index cf5babdb1a..08acf9b058 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -590,7 +590,7 @@ bool EntityTree::findNearPointOperation(const OctreeElementPointer& element, voi bool findRayIntersectionOp(const OctreeElementPointer& element, void* extraData) { RayArgs* args = static_cast(extraData); bool keepSearching = true; - EntityTreeElementPointer entityTreeElementPointer = std::dynamic_pointer_cast(element); + EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast(element); if (entityTreeElementPointer->findRayIntersection(args->origin, args->direction, keepSearching, args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude, args->entityIdsToDiscard, args->visibleOnly, args->collidableOnly, args->intersectedObject, args->precisionPicking)) { diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 4860e3d4a4..3e482fcd60 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -89,17 +89,17 @@ class PolyLineEntityItem : public EntityItem { BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override { return false; } - // disable these external interfaces as PolyLineEntities caculate their own dimensions based on the points they contain - virtual void setRegistrationPoint(const glm::vec3& value) override {}; - virtual void setScale(const glm::vec3& scale) override {}; - virtual void setScale(float value) override {}; + // disable these external interfaces as PolyLineEntities caculate their own dimensions based on the points they contain + virtual void setRegistrationPoint(const glm::vec3& value) override {}; + virtual void setScale(const glm::vec3& scale) override {}; + virtual void setScale(float value) override {}; virtual void debugDump() const override; static const float DEFAULT_LINE_WIDTH; static const int MAX_POINTS_PER_LINE; private: - void calculateScaleAndRegistrationPoint(); - + void calculateScaleAndRegistrationPoint(); + protected: rgbColor _color; float _lineWidth { DEFAULT_LINE_WIDTH }; diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 9d74662e7c..586344ee81 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -223,7 +223,7 @@ void ShapeEntityItem::debugDump() const { qCDebug(entities) << " position:" << debugTreeVector(getPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); - qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; + qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; } void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 3099782588..e0c2efd72e 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -28,6 +28,7 @@ #include "FBXReader.h" #include "ModelFormatLogging.h" +#include QHash COMMENT_SCALE_HINTS = {{"This file uses centimeters as units", 1.0f / 100.0f}, {"This file uses millimeters as units", 1.0f / 1000.0f}}; @@ -51,6 +52,10 @@ const QByteArray OBJTokenizer::getLineAsDatum() { return _device->readLine().trimmed(); } +float OBJTokenizer::getFloat() { + return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data()); +} + int OBJTokenizer::nextToken() { if (_pushedBackToken != NO_PUSHBACKED_TOKEN) { int token = _pushedBackToken; @@ -125,7 +130,7 @@ glm::vec3 OBJTokenizer::getVec3() { } bool OBJTokenizer::getVertex(glm::vec3& vertex, glm::vec3& vertexColor) { // Used for vertices which may also have a vertex color (RGB [0,1]) to follow. - // NOTE: Returns true if there is a vertex color. + // NOTE: Returns true if there is a vertex color. auto x = getFloat(); // N.B.: getFloat() has side-effect auto y = getFloat(); // And order of arguments is different on Windows/Linux. auto z = getFloat(); @@ -168,7 +173,7 @@ void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID) { } // OBJFace -// NOTE (trent, 7/20/17): The vertexColors vector being passed-in isn't necessary here, but I'm just +// NOTE (trent, 7/20/17): The vertexColors vector being passed-in isn't necessary here, but I'm just // pairing it with the vertices vector for consistency. bool OBJFace::add(const QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex, const QVector& vertices, const QVector& vertexColors) { bool ok; @@ -544,9 +549,9 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, fbxMeshParts.append(FBXMeshPart()); FBXMeshPart& meshPartNew = fbxMeshParts.last(); - meshPartNew.quadIndices = QVector(meshPart.quadIndices); // Copy over quad indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway]. + meshPartNew.quadIndices = QVector(meshPart.quadIndices); // Copy over quad indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway]. meshPartNew.quadTrianglesIndices = QVector(meshPart.quadTrianglesIndices); // Copy over quad triangulated indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway]. - meshPartNew.triangleIndices = QVector(meshPart.triangleIndices); // Copy over triangle indices. + meshPartNew.triangleIndices = QVector(meshPart.triangleIndices); // Copy over triangle indices. // Do some of the material logic (which previously lived below) now. // All the faces in the same group will have the same name and material. diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index 9a32871590..fb250833cf 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -22,7 +22,7 @@ public: glm::vec3 getVec3(); bool getVertex(glm::vec3& vertex, glm::vec3& vertexColor); glm::vec2 getVec2(); - float getFloat() { return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data()); } + float getFloat(); private: QIODevice* _device; diff --git a/libraries/gl/CMakeLists.txt b/libraries/gl/CMakeLists.txt index fd3197410b..9fc7a0c10f 100644 --- a/libraries/gl/CMakeLists.txt +++ b/libraries/gl/CMakeLists.txt @@ -1,9 +1,5 @@ set(TARGET_NAME gl) setup_hifi_library(OpenGL Qml Quick) -link_hifi_libraries(shared networking) - +link_hifi_libraries(shared) target_opengl() -if (NOT ANDROID) - target_glew() -endif () diff --git a/libraries/gl/src/gl/Config.cpp b/libraries/gl/src/gl/Config.cpp new file mode 100644 index 0000000000..1f29fe21b1 --- /dev/null +++ b/libraries/gl/src/gl/Config.cpp @@ -0,0 +1,35 @@ +// +// GPUConfig.h +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 12/4/14. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Config.h" + +#include + +#if defined(Q_OS_ANDROID) +PFNGLQUERYCOUNTEREXTPROC glQueryCounterEXT = NULL; +PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64vEXT = NULL; +PFNGLFRAMEBUFFERTEXTUREEXTPROC glFramebufferTextureEXT = NULL; +#endif + +void gl::initModuleGl() { + static std::once_flag once; + std::call_once(once, [] { +#if defined(Q_OS_ANDROID) + glQueryCounterEXT = (PFNGLQUERYCOUNTEREXTPROC)eglGetProcAddress("glQueryCounterEXT"); + glGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC)eglGetProcAddress("glGetQueryObjectui64vEXT"); + glFramebufferTextureEXT = (PFNGLFRAMEBUFFERTEXTUREEXTPROC)eglGetProcAddress("glFramebufferTextureEXT"); +#else + glewExperimental = true; + glewInit(); +#endif + }); +} + diff --git a/libraries/gl/src/gl/Config.h b/libraries/gl/src/gl/Config.h index 9efae96f2a..ff282a1ca0 100644 --- a/libraries/gl/src/gl/Config.h +++ b/libraries/gl/src/gl/Config.h @@ -12,25 +12,67 @@ #ifndef hifi_gpu_GPUConfig_h #define hifi_gpu_GPUConfig_h -#define GL_GLEXT_PROTOTYPES 1 +#include +#if defined(QT_OPENGL_ES_3_1) +// Minimum GL ES version required is 3.1 +#define GL_MIN_VERSION_MAJOR 0x03 +#define GL_MIN_VERSION_MINOR 0x01 +#define GL_DEFAULT_VERSION_MAJOR GL_MIN_VERSION_MAJOR +#define GL_DEFAULT_VERSION_MINOR GL_MIN_VERSION_MINOR +#else +// Minimum desktop GL version required is 4.1 +#define GL_MIN_VERSION_MAJOR 0x04 +#define GL_MIN_VERSION_MINOR 0x01 +#define GL_DEFAULT_VERSION_MAJOR 0x04 +#define GL_DEFAULT_VERSION_MINOR 0x05 +#endif + +#define MINIMUM_GL_VERSION ((GL_MIN_VERSION_MAJOR << 8) | GL_MIN_VERSION_MINOR) + +#if defined(Q_OS_ANDROID) + +#include +#include + +#define GL_DEPTH_COMPONENT32_OES 0x81A7 +#define GL_TIME_ELAPSED_EXT 0x88BF +#define GL_TIMESTAMP_EXT 0x8E28 +#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 +#define GL_TEXTURE_BORDER_COLOR_EXT 0x1004 +#define GL_CLAMP_TO_BORDER_EXT 0x812D +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF + + +// Add some additional extensions missing from GLES 3.1 +extern "C" { + typedef void (GL_APIENTRYP PFNGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target); + typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params); + typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); + extern PFNGLQUERYCOUNTEREXTPROC glQueryCounterEXT; + extern PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64vEXT; + extern PFNGLFRAMEBUFFERTEXTUREEXTPROC glFramebufferTextureEXT; +} + +#else // !defined(Q_OS_ANDROID) + +#define GL_GLEXT_PROTOTYPES 1 #include -#if defined(__APPLE__) - +#if defined(Q_OS_DARWIN) #include #include #include - -#endif - -#if defined(WIN32) - +#elif defined(Q_OS_WIN64) #include - -// Uncomment this define and recompile to be able to avoid code path preventing to be able to run nsight graphics debug -//#define HIFI_ENABLE_NSIGHT_DEBUG 1 - #endif +#endif // !defined(Q_OS_ANDROID) + +// Platform specific code to load the GL functions +namespace gl { + void initModuleGl(); +} + #endif // hifi_gpu_GPUConfig_h diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index 28982703dd..ed0594135a 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -28,6 +28,13 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() { static QSurfaceFormat format; static std::once_flag once; std::call_once(once, [] { +#if defined(QT_OPENGL_ES_3_1) + format.setRenderableType(QSurfaceFormat::OpenGLES); + format.setRedBufferSize(8); + format.setGreenBufferSize(8); + format.setBlueBufferSize(8); + format.setAlphaBufferSize(8); +#endif // Qt Quick may need a depth and stencil buffer. Always make sure these are available. format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS); format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS); diff --git a/libraries/gl/src/gl/GLHelpers.h b/libraries/gl/src/gl/GLHelpers.h index 84229b97d2..80fc2c5f70 100644 --- a/libraries/gl/src/gl/GLHelpers.h +++ b/libraries/gl/src/gl/GLHelpers.h @@ -25,7 +25,12 @@ class QSurfaceFormat; class QGLFormat; template -void setGLFormatVersion(F& format, int major = 4, int minor = 5) { format.setVersion(major, minor); } +#if defined(QT_OPENGL_ES_3_1) +void setGLFormatVersion(F& format, int major = 3, int minor = 1) +#else +void setGLFormatVersion(F& format, int major = 4, int minor = 5) +#endif + { format.setVersion(major, minor); } size_t evalGLFormatSwapchainPixelSize(const QSurfaceFormat& format); diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index 3f1d629638..b974564705 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -59,7 +59,7 @@ bool OffscreenGLCanvas::create(QOpenGLContext* sharedContext) { bool OffscreenGLCanvas::makeCurrent() { bool result = _context->makeCurrent(_offscreenSurface); - std::call_once(_reportOnce, [this]{ + std::call_once(_reportOnce, []{ qCDebug(glLogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); qCDebug(glLogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); qCDebug(glLogging) << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR)); diff --git a/libraries/gl/src/gl/OpenGLVersionChecker.cpp b/libraries/gl/src/gl/OpenGLVersionChecker.cpp index f24a9bb932..771a8b9a75 100644 --- a/libraries/gl/src/gl/OpenGLVersionChecker.cpp +++ b/libraries/gl/src/gl/OpenGLVersionChecker.cpp @@ -21,9 +21,6 @@ #include "GLHelpers.h" -// Minimum gl version required is 4.1 -#define MINIMUM_GL_VERSION 0x0401 - OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) : QApplication(argc, argv) { diff --git a/libraries/gpu-gl/CMakeLists.txt b/libraries/gpu-gl/CMakeLists.txt index 65130d6d07..dc744e73f2 100644 --- a/libraries/gpu-gl/CMakeLists.txt +++ b/libraries/gpu-gl/CMakeLists.txt @@ -5,10 +5,5 @@ if (UNIX) target_link_libraries(${TARGET_NAME} pthread) endif(UNIX) GroupSources("src") - target_opengl() -target_nsight() -if (NOT ANDROID) - target_glew() -endif () diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp index b5a8dcb7a9..ff9ddaae63 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp @@ -7,9 +7,9 @@ // #include "GL41Backend.h" #include "../gl/GLShader.h" -//#include using namespace gpu; +using namespace gpu::gl; using namespace gpu::gl41; // GLSL version @@ -84,7 +84,7 @@ int GL41Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::Binding return ssboCount; } -void GL41Backend::makeProgramBindings(gl::ShaderObject& shaderObject) { +void GL41Backend::makeProgramBindings(ShaderObject& shaderObject) { if (!shaderObject.glprogram) { return; } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp index 8a5e8d0064..c2490524ae 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp @@ -10,6 +10,7 @@ //#include using namespace gpu; +using namespace gpu::gl; using namespace gpu::gl45; // GLSL version @@ -132,7 +133,7 @@ int GL45Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::Binding return ssboCount;*/ } -void GL45Backend::makeProgramBindings(gl::ShaderObject& shaderObject) { +void GL45Backend::makeProgramBindings(ShaderObject& shaderObject) { if (!shaderObject.glprogram) { return; } diff --git a/libraries/gpu-gles/CMakeLists.txt b/libraries/gpu-gles/CMakeLists.txt new file mode 100644 index 0000000000..55ec53b184 --- /dev/null +++ b/libraries/gpu-gles/CMakeLists.txt @@ -0,0 +1,11 @@ +set(TARGET_NAME gpu-gles) +setup_hifi_library(OpenGL) +link_hifi_libraries(shared gl gpu) +GroupSources("src") + +target_opengl() +target_nsight() + +if (NOT ANDROID) + target_glew() +endif () diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp new file mode 100644 index 0000000000..1d66618703 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp @@ -0,0 +1,722 @@ +// +// GLBackend.cpp +// libraries/gpu-gl-android/src/gpu/gl +// +// Created by Cristian Duarte & Gabriel Calero on 9/21/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLBackend.h" + +#include +#include +#include +#include +#include + +#include "../gles/GLESBackend.h" + +#if defined(NSIGHT_FOUND) +#include "nvToolsExt.h" +#endif + +#include +#include +#include + +#include "GLTexture.h" +#include "GLShader.h" +using namespace gpu; +using namespace gpu::gl; + +static GLBackend* INSTANCE{ nullptr }; +static const char* GL_BACKEND_PROPERTY_NAME = "com.highfidelity.gl.backend"; + +BackendPointer GLBackend::createBackend() { + // FIXME provide a mechanism to override the backend for testing + // Where the gpuContext is initialized and where the TRUE Backend is created and assigned + auto version = QOpenGLContextWrapper::currentContextVersion(); + std::shared_ptr result; + + qDebug() << "Using OpenGL ES backend"; + result = std::make_shared(); + + result->initInput(); + result->initTransform(); + + INSTANCE = result.get(); + void* voidInstance = &(*result); + qApp->setProperty(GL_BACKEND_PROPERTY_NAME, QVariant::fromValue(voidInstance)); + + gl::GLTexture::initTextureTransferHelper(); + return result; +} + +GLBackend& getBackend() { + if (!INSTANCE) { + INSTANCE = static_cast(qApp->property(GL_BACKEND_PROPERTY_NAME).value()); + } + return *INSTANCE; +} + +bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) { + return GLShader::makeProgram(getBackend(), shader, slotBindings); +} + +std::array commandNames = { + {QString("draw"),QString("drawIndexed"),QString("drawInstanced"),QString("drawIndexedInstanced"),QString("multiDrawIndirect"),QString("multiDrawIndexedIndirect"),QString("setInputFormat"),QString("setInputBuffer"),QString("setIndexBuffer"),QString("setIndirectBuffer"),QString("setModelTransform"),QString("setViewTransform"),QString("setProjectionTransform"),QString("setViewportTransform"),QString("setDepthRangeTransform"),QString("setPipeline"),QString("setStateBlendFactor"),QString("setStateScissorRect"),QString("setUniformBuffer"),QString("setResourceTexture"),QString("setFramebuffer"),QString("clearFramebuffer"),QString("blit"),QString("generateTextureMips"),QString("beginQuery"),QString("endQuery"),QString("getQuery"),QString("resetStages"),QString("runLambda"),QString("startNamedCall"),QString("stopNamedCall"),QString("glUniform1i"),QString("glUniform1f"),QString("glUniform2f"),QString("glUniform3f"),QString("glUniform4f"),QString("glUniform3fv"),QString("glUniform4fv"),QString("glUniform4iv"),QString("glUniformMatrix3fv"),QString("glUniformMatrix4fv"),QString("glColor4f"),QString("pushProfileRange"),QString("popProfileRange"),QString("NUM_COMMANDS")} +}; + +GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = +{ + (&::gpu::gl::GLBackend::do_draw), + (&::gpu::gl::GLBackend::do_drawIndexed), + (&::gpu::gl::GLBackend::do_drawInstanced), + (&::gpu::gl::GLBackend::do_drawIndexedInstanced), + (&::gpu::gl::GLBackend::do_multiDrawIndirect), + (&::gpu::gl::GLBackend::do_multiDrawIndexedIndirect), + + (&::gpu::gl::GLBackend::do_setInputFormat), + (&::gpu::gl::GLBackend::do_setInputBuffer), + (&::gpu::gl::GLBackend::do_setIndexBuffer), + (&::gpu::gl::GLBackend::do_setIndirectBuffer), + + (&::gpu::gl::GLBackend::do_setModelTransform), + (&::gpu::gl::GLBackend::do_setViewTransform), + (&::gpu::gl::GLBackend::do_setProjectionTransform), + (&::gpu::gl::GLBackend::do_setViewportTransform), + (&::gpu::gl::GLBackend::do_setDepthRangeTransform), + + (&::gpu::gl::GLBackend::do_setPipeline), + (&::gpu::gl::GLBackend::do_setStateBlendFactor), + (&::gpu::gl::GLBackend::do_setStateScissorRect), + + (&::gpu::gl::GLBackend::do_setUniformBuffer), + (&::gpu::gl::GLBackend::do_setResourceTexture), + + (&::gpu::gl::GLBackend::do_setFramebuffer), + (&::gpu::gl::GLBackend::do_clearFramebuffer), + (&::gpu::gl::GLBackend::do_blit), + (&::gpu::gl::GLBackend::do_generateTextureMips), + + (&::gpu::gl::GLBackend::do_beginQuery), + (&::gpu::gl::GLBackend::do_endQuery), + (&::gpu::gl::GLBackend::do_getQuery), + + (&::gpu::gl::GLBackend::do_resetStages), + + (&::gpu::gl::GLBackend::do_runLambda), + + (&::gpu::gl::GLBackend::do_startNamedCall), + (&::gpu::gl::GLBackend::do_stopNamedCall), + + (&::gpu::gl::GLBackend::do_glUniform1i), + (&::gpu::gl::GLBackend::do_glUniform1f), + (&::gpu::gl::GLBackend::do_glUniform2f), + (&::gpu::gl::GLBackend::do_glUniform3f), + (&::gpu::gl::GLBackend::do_glUniform4f), + (&::gpu::gl::GLBackend::do_glUniform3fv), + (&::gpu::gl::GLBackend::do_glUniform4fv), + (&::gpu::gl::GLBackend::do_glUniform4iv), + (&::gpu::gl::GLBackend::do_glUniformMatrix3fv), + (&::gpu::gl::GLBackend::do_glUniformMatrix4fv), + + (&::gpu::gl::GLBackend::do_glColor4f), + + (&::gpu::gl::GLBackend::do_pushProfileRange), + (&::gpu::gl::GLBackend::do_popProfileRange), +}; + +void GLBackend::init() { + static std::once_flag once; + std::call_once(once, [] { + QString vendor{ (const char*)glGetString(GL_VENDOR) }; + QString renderer{ (const char*)glGetString(GL_RENDERER) }; + qCDebug(gpugllogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); + qCDebug(gpugllogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); + qCDebug(gpugllogging) << "GL Vendor: " << vendor; + qCDebug(gpugllogging) << "GL Renderer: " << renderer; + GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer); + // From here on, GPUIdent::getInstance()->getMumble() should efficiently give the same answers. + qCDebug(gpugllogging) << "GPU:"; + qCDebug(gpugllogging) << "\tcard:" << gpu->getName(); + qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver(); + qCDebug(gpugllogging) << "\tdedicated memory:" << gpu->getMemory() << "MB"; + + /*glewExperimental = true; + GLenum err = glewInit(); + glGetError(); // clear the potential error from glewExperimental + if (GLEW_OK != err) { + // glewInit failed, something is seriously wrong. + qCDebug(gpugllogging, "Error: %s\n", glewGetErrorString(err)); + } + qCDebug(gpugllogging, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); + */ + + }); +} + +GLBackend::GLBackend() { + _pipeline._cameraCorrectionBuffer._buffer->flush(); + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment); +} + + +GLBackend::~GLBackend() { + resetStages(); + + killInput(); + killTransform(); +} + +void GLBackend::renderPassTransfer(const Batch& batch) { + const size_t numCommands = batch.getCommands().size(); + const Batch::Commands::value_type* command = batch.getCommands().data(); + const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data(); + + _inRenderTransferPass = true; + { // Sync all the buffers + ANDROID_PROFILE(render, "syncGPUBuffer", 0xffaaffaa, 1) + + for (auto& cached : batch._buffers._items) { + if (cached._data) { + syncGPUObject(*cached._data); + } + } + } + + { // Sync all the buffers + ANDROID_PROFILE(render, "syncCPUTransform", 0xffaaaaff, 1) + _transform._cameras.clear(); + _transform._cameraOffsets.clear(); + + for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) { + switch (*command) { + case Batch::COMMAND_draw: + case Batch::COMMAND_drawIndexed: + case Batch::COMMAND_drawInstanced: + case Batch::COMMAND_drawIndexedInstanced: + case Batch::COMMAND_multiDrawIndirect: + case Batch::COMMAND_multiDrawIndexedIndirect: + _transform.preUpdate(_commandIndex, _stereo); + break; + + case Batch::COMMAND_setViewportTransform: + case Batch::COMMAND_setViewTransform: + case Batch::COMMAND_setProjectionTransform: { + ANDROID_PROFILE_COMMAND(render, (int)(*command), 0xffeeaaff, 1) + CommandCall call = _commandCalls[(*command)]; + (this->*(call))(batch, *offset); + break; + } + + default: + break; + } + command++; + offset++; + } + } + + { // Sync the transform buffers + //PROFILE_RANGE(render_gpu_gl, "transferTransformState"); + ANDROID_PROFILE(render, "transferTransformState", 0xff0000ff, 1) + transferTransformState(batch); + } + + _inRenderTransferPass = false; +} + +void GLBackend::renderPassDraw(const Batch& batch) { + _currentDraw = -1; + _transform._camerasItr = _transform._cameraOffsets.begin(); + const size_t numCommands = batch.getCommands().size(); + const Batch::Commands::value_type* command = batch.getCommands().data(); + const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data(); + for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) { + switch (*command) { + // Ignore these commands on this pass, taken care of in the transfer pass + // Note we allow COMMAND_setViewportTransform to occur in both passes + // as it both updates the transform object (and thus the uniforms in the + // UBO) as well as executes the actual viewport call + case Batch::COMMAND_setModelTransform: + case Batch::COMMAND_setViewTransform: + case Batch::COMMAND_setProjectionTransform: + break; + + case Batch::COMMAND_draw: + case Batch::COMMAND_drawIndexed: + case Batch::COMMAND_drawInstanced: + case Batch::COMMAND_drawIndexedInstanced: + case Batch::COMMAND_multiDrawIndirect: + case Batch::COMMAND_multiDrawIndexedIndirect: { + // updates for draw calls + ++_currentDraw; + updateInput(); + updateTransform(batch); + updatePipeline(); + {ANDROID_PROFILE_COMMAND(render, (int)(*command), 0xff0000ff, 1) + CommandCall call = _commandCalls[(*command)]; + (this->*(call))(batch, *offset); + } + break; + } + default: { + ANDROID_PROFILE_COMMAND(render, (int)(*command), 0xffff00ff, 1) + CommandCall call = _commandCalls[(*command)]; + (this->*(call))(batch, *offset); + break; + } + } + + command++; + offset++; + } +} + +void GLBackend::render(const Batch& batch) { + ANDROID_PROFILE(render, "GLBackendRender", 0xffff00ff, 1) + _transform._skybox = _stereo._skybox = batch.isSkyboxEnabled(); + // Allow the batch to override the rendering stereo settings + // for things like full framebuffer copy operations (deferred lighting passes) + bool savedStereo = _stereo._enable; + if (!batch.isStereoEnabled()) { + _stereo._enable = false; + } + + { + //PROFILE_RANGE(render_gpu_gl, "Transfer"); + ANDROID_PROFILE(render, "Transfer", 0xff0000ff, 1) + renderPassTransfer(batch); + } + + { + //PROFILE_RANGE(render_gpu_gl, _stereo._enable ? "Render Stereo" : "Render"); + ANDROID_PROFILE(render, "RenderPassDraw", 0xff00ddff, 1) + renderPassDraw(batch); + } + + // Restore the saved stereo state for the next batch + _stereo._enable = savedStereo; +} + + +void GLBackend::syncCache() { + syncTransformStateCache(); + syncPipelineStateCache(); + syncInputStateCache(); + syncOutputStateCache(); + + //glEnable(GL_LINE_SMOOTH); + qDebug() << "TODO: GLBackend.cpp:syncCache GL_LINE_SMOOTH"; +} + +void GLBackend::setupStereoSide(int side) { + ivec4 vp = _transform._viewport; + vp.z /= 2; + glViewport(vp.x + side * vp.z, vp.y, vp.z, vp.w); + +#ifdef GPU_STEREO_CAMERA_BUFFER +#ifdef GPU_STEREO_DRAWCALL_DOUBLED + //glVertexAttribI1i(14, side); + glVertexAttribI4i(14, side, 0, 0, 0); + +#endif +#else + _transform.bindCurrentCamera(side); +#endif +} + +void GLBackend::do_resetStages(const Batch& batch, size_t paramOffset) { + resetStages(); +} + +void GLBackend::do_runLambda(const Batch& batch, size_t paramOffset) { + std::function f = batch._lambdas.get(batch._params[paramOffset]._uint); + f(); +} + +void GLBackend::do_startNamedCall(const Batch& batch, size_t paramOffset) { + batch._currentNamedCall = batch._names.get(batch._params[paramOffset]._uint); + _currentDraw = -1; +} + +void GLBackend::do_stopNamedCall(const Batch& batch, size_t paramOffset) { + batch._currentNamedCall.clear(); +} + +void GLBackend::resetStages() { + resetInputStage(); + resetPipelineStage(); + resetTransformStage(); + resetUniformStage(); + resetResourceStage(); + resetOutputStage(); + resetQueryStage(); + + (void) CHECK_GL_ERROR(); +} + + +void GLBackend::do_pushProfileRange(const Batch& batch, size_t paramOffset) { + auto name = batch._profileRanges.get(batch._params[paramOffset]._uint); + profileRanges.push_back(name); +#if defined(NSIGHT_FOUND) + nvtxRangePush(name.c_str()); +#endif +} + +void GLBackend::do_popProfileRange(const Batch& batch, size_t paramOffset) { + profileRanges.pop_back(); +#if defined(NSIGHT_FOUND) + nvtxRangePop(); +#endif +} + +// TODO: As long as we have gl calls explicitely issued from interface +// code, we need to be able to record and batch these calls. THe long +// term strategy is to get rid of any GL calls in favor of the HIFI GPU API + +// As long as we don;t use several versions of shaders we can avoid this more complex code path +// #define GET_UNIFORM_LOCATION(shaderUniformLoc) _pipeline._programShader->getUniformLocation(shaderUniformLoc, isStereo()); +#define GET_UNIFORM_LOCATION(shaderUniformLoc) shaderUniformLoc + +void GLBackend::do_glUniform1i(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + + glUniform1f( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int), + batch._params[paramOffset + 0]._int); + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glUniform1f(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + + glUniform1f( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int), + batch._params[paramOffset + 0]._float); + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glUniform2f(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + glUniform2f( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int), + batch._params[paramOffset + 1]._float, + batch._params[paramOffset + 0]._float); + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glUniform3f(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + glUniform3f( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int), + batch._params[paramOffset + 2]._float, + batch._params[paramOffset + 1]._float, + batch._params[paramOffset + 0]._float); + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glUniform4f(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + glUniform4f( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 4]._int), + batch._params[paramOffset + 3]._float, + batch._params[paramOffset + 2]._float, + batch._params[paramOffset + 1]._float, + batch._params[paramOffset + 0]._float); + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glUniform3fv(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + glUniform3fv( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int), + batch._params[paramOffset + 1]._uint, + (const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint)); + + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glUniform4fv(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + + GLint location = GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int); + GLsizei count = batch._params[paramOffset + 1]._uint; + const GLfloat* value = (const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint); + glUniform4fv(location, count, value); + + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glUniform4iv(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + glUniform4iv( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int), + batch._params[paramOffset + 1]._uint, + (const GLint*)batch.readData(batch._params[paramOffset + 0]._uint)); + + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glUniformMatrix3fv(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + + glUniformMatrix3fv( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int), + batch._params[paramOffset + 2]._uint, + batch._params[paramOffset + 1]._uint, + (const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint)); + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glUniformMatrix4fv(const Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + + glUniformMatrix4fv( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int), + batch._params[paramOffset + 2]._uint, + batch._params[paramOffset + 1]._uint, + (const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint)); + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_glColor4f(const Batch& batch, size_t paramOffset) { + + glm::vec4 newColor( + batch._params[paramOffset + 3]._float, + batch._params[paramOffset + 2]._float, + batch._params[paramOffset + 1]._float, + batch._params[paramOffset + 0]._float); + + if (_input._colorAttribute != newColor) { + _input._colorAttribute = newColor; + glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r); + } + (void)CHECK_GL_ERROR(); +} + +void GLBackend::releaseBuffer(GLuint id, Size size) const { + Lock lock(_trashMutex); + _buffersTrash.push_back({ id, size }); +} + +void GLBackend::releaseExternalTexture(GLuint id, const Texture::ExternalRecycler& recycler) const { + Lock lock(_trashMutex); + _externalTexturesTrash.push_back({ id, recycler }); +} + +void GLBackend::releaseTexture(GLuint id, Size size) const { + Lock lock(_trashMutex); + _texturesTrash.push_back({ id, size }); +} + +void GLBackend::releaseFramebuffer(GLuint id) const { + Lock lock(_trashMutex); + _framebuffersTrash.push_back(id); +} + +void GLBackend::releaseShader(GLuint id) const { + Lock lock(_trashMutex); + _shadersTrash.push_back(id); +} + +void GLBackend::releaseProgram(GLuint id) const { + Lock lock(_trashMutex); + _programsTrash.push_back(id); +} + +void GLBackend::releaseQuery(GLuint id) const { + Lock lock(_trashMutex); + _queriesTrash.push_back(id); +} + +void GLBackend::queueLambda(const std::function lambda) const { + Lock lock(_trashMutex); + _lambdaQueue.push_back(lambda); +} + +void GLBackend::recycle() const { + { + std::list> lamdbasTrash; + { + Lock lock(_trashMutex); + std::swap(_lambdaQueue, lamdbasTrash); + } + for (auto lambda : lamdbasTrash) { + lambda(); + } + } + + { + std::vector ids; + std::list> buffersTrash; + { + Lock lock(_trashMutex); + std::swap(_buffersTrash, buffersTrash); + } + ids.reserve(buffersTrash.size()); + for (auto pair : buffersTrash) { + ids.push_back(pair.first); + } + if (!ids.empty()) { + glDeleteBuffers((GLsizei)ids.size(), ids.data()); + } + } + + { + std::vector ids; + std::list framebuffersTrash; + { + Lock lock(_trashMutex); + std::swap(_framebuffersTrash, framebuffersTrash); + } + ids.reserve(framebuffersTrash.size()); + for (auto id : framebuffersTrash) { + ids.push_back(id); + } + if (!ids.empty()) { + glDeleteFramebuffers((GLsizei)ids.size(), ids.data()); + } + } + + { + std::vector ids; + std::list> texturesTrash; + { + Lock lock(_trashMutex); + std::swap(_texturesTrash, texturesTrash); + } + ids.reserve(texturesTrash.size()); + for (auto pair : texturesTrash) { + ids.push_back(pair.first); + } + if (!ids.empty()) { + glDeleteTextures((GLsizei)ids.size(), ids.data()); + } + } + + { + std::list> externalTexturesTrash; + { + Lock lock(_trashMutex); + std::swap(_externalTexturesTrash, externalTexturesTrash); + } + if (!externalTexturesTrash.empty()) { + std::vector fences; + fences.resize(externalTexturesTrash.size()); + for (size_t i = 0; i < externalTexturesTrash.size(); ++i) { + fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + } + // External texture fences will be read in another thread/context, so we need a flush + glFlush(); + size_t index = 0; + for (auto pair : externalTexturesTrash) { + auto fence = fences[index++]; + pair.second(pair.first, fence); + } + } + } + + { + std::list programsTrash; + { + Lock lock(_trashMutex); + std::swap(_programsTrash, programsTrash); + } + for (auto id : programsTrash) { + glDeleteProgram(id); + } + } + + { + std::list shadersTrash; + { + Lock lock(_trashMutex); + std::swap(_shadersTrash, shadersTrash); + } + for (auto id : shadersTrash) { + glDeleteShader(id); + } + } + + { + std::vector ids; + std::list queriesTrash; + { + Lock lock(_trashMutex); + std::swap(_queriesTrash, queriesTrash); + } + ids.reserve(queriesTrash.size()); + for (auto id : queriesTrash) { + ids.push_back(id); + } + if (!ids.empty()) { + glDeleteQueries((GLsizei)ids.size(), ids.data()); + } + } + +#ifndef THREADED_TEXTURE_TRANSFER + gl::GLTexture::_textureTransferHelper->process(); +#endif +} + +void GLBackend::setCameraCorrection(const Mat4& correction) { + _transform._correction.correction = correction; + _transform._correction.correctionInverse = glm::inverse(correction); + _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); + _pipeline._cameraCorrectionBuffer._buffer->flush(); +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackend.h b/libraries/gpu-gles/src/gpu/gl/GLBackend.h new file mode 100644 index 0000000000..f8f307bc17 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBackend.h @@ -0,0 +1,427 @@ +// +// Created by Cristian Duarte & Gabriel Calero on 09/21/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gles_Backend_h +#define hifi_gpu_gles_Backend_h + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include "GLShared.h" + + +// Different versions for the stereo drawcall +// Current preferred is "instanced" which draw the shape twice but instanced and rely on clipping plane to draw left/right side only +//#define GPU_STEREO_TECHNIQUE_DOUBLED_SMARTER +//#define GPU_STEREO_TECHNIQUE_INSTANCED + +#ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SMARTER +#define GPU_STEREO_DRAWCALL_DOUBLED +#define GPU_STEREO_CAMERA_BUFFER +#endif + +#ifdef GPU_STEREO_TECHNIQUE_INSTANCED +#define GPU_STEREO_DRAWCALL_INSTANCED +#define GPU_STEREO_CAMERA_BUFFER +#endif + +//#define ANDROID_INTENSIVE_INSTRUMENTATION 1 + +#ifdef ANDROID_INTENSIVE_INSTRUMENTATION +#define ANDROID_PROFILE_COMMAND(category, commandIndex, argbColor, payload, ...) PROFILE_RANGE_EX(category, commandNames[commandIndex], argbColor, payload, ##__VA_ARGS__); +#define ANDROID_PROFILE(category, name, argbColor, payload, ...) PROFILE_RANGE_EX(category, name, argbColor, payload, ##__VA_ARGS__); +#else +#define ANDROID_PROFILE_COMMAND(category, commandIndex, argbColor, payload, ...) +#define ANDROID_PROFILE(category, name, argbColor, payload, ...) +#endif +namespace gpu { namespace gl { + + class GLBackend : public Backend, public std::enable_shared_from_this { + // Context Backend static interface required + friend class gpu::Context; + static void init(); + static BackendPointer createBackend(); + + protected: + explicit GLBackend(bool syncCache); + GLBackend(); + public: + static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet()); + + ~GLBackend(); + + void setCameraCorrection(const Mat4& correction); + void render(const Batch& batch) final override; + + // This call synchronize the Full Backend cache with the current GLState + // THis is only intended to be used when mixing raw gl calls with the gpu api usage in order to sync + // the gpu::Backend state with the true gl state which has probably been messed up by these ugly naked gl calls + // Let's try to avoid to do that as much as possible! + void syncCache() final override; + + // This is the ugly "download the pixels to sysmem for taking a snapshot" + // Just avoid using it, it's ugly and will break performances + virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, + const Vec4i& region, QImage& destImage) final override; + + + // this is the maximum numeber of available input buffers + size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); } + + // this is the maximum per shader stage on the low end apple + // TODO make it platform dependant at init time + static const int MAX_NUM_UNIFORM_BUFFERS = 12; + size_t getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; } + + // this is the maximum per shader stage on the low end apple + // TODO make it platform dependant at init time + static const int MAX_NUM_RESOURCE_TEXTURES = 16; + size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } + + // Draw Stage + virtual void do_draw(const Batch& batch, size_t paramOffset) = 0; + virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0; + virtual void do_drawInstanced(const Batch& batch, size_t paramOffset) = 0; + virtual void do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) = 0; + virtual void do_multiDrawIndirect(const Batch& batch, size_t paramOffset) = 0; + virtual void do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffset) = 0; + + // Input Stage + virtual void do_setInputFormat(const Batch& batch, size_t paramOffset) final; + virtual void do_setInputBuffer(const Batch& batch, size_t paramOffset) final; + virtual void do_setIndexBuffer(const Batch& batch, size_t paramOffset) final; + virtual void do_setIndirectBuffer(const Batch& batch, size_t paramOffset) final; + virtual void do_generateTextureMips(const Batch& batch, size_t paramOffset) final; + + // Transform Stage + virtual void do_setModelTransform(const Batch& batch, size_t paramOffset) final; + virtual void do_setViewTransform(const Batch& batch, size_t paramOffset) final; + virtual void do_setProjectionTransform(const Batch& batch, size_t paramOffset) final; + virtual void do_setViewportTransform(const Batch& batch, size_t paramOffset) final; + virtual void do_setDepthRangeTransform(const Batch& batch, size_t paramOffset) final; + + // Uniform Stage + virtual void do_setUniformBuffer(const Batch& batch, size_t paramOffset) final; + + // Resource Stage + virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final; + + // Pipeline Stage + virtual void do_setPipeline(const Batch& batch, size_t paramOffset) final; + + // Output stage + virtual void do_setFramebuffer(const Batch& batch, size_t paramOffset) final; + virtual void do_clearFramebuffer(const Batch& batch, size_t paramOffset) final; + virtual void do_blit(const Batch& batch, size_t paramOffset) = 0; + + // Query section + virtual void do_beginQuery(const Batch& batch, size_t paramOffset) final; + virtual void do_endQuery(const Batch& batch, size_t paramOffset) final; + virtual void do_getQuery(const Batch& batch, size_t paramOffset) final; + + // Reset stages + virtual void do_resetStages(const Batch& batch, size_t paramOffset) final; + + virtual void do_runLambda(const Batch& batch, size_t paramOffset) final; + + virtual void do_startNamedCall(const Batch& batch, size_t paramOffset) final; + virtual void do_stopNamedCall(const Batch& batch, size_t paramOffset) final; + + static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS; + // The drawcall Info attribute channel is reserved and is the upper bound for the number of availables Input buffers + static const int MAX_NUM_INPUT_BUFFERS = Stream::DRAW_CALL_INFO; + + virtual void do_pushProfileRange(const Batch& batch, size_t paramOffset) final; + virtual void do_popProfileRange(const Batch& batch, size_t paramOffset) final; + + // TODO: As long as we have gl calls explicitely issued from interface + // code, we need to be able to record and batch these calls. THe long + // term strategy is to get rid of any GL calls in favor of the HIFI GPU API + virtual void do_glUniform1i(const Batch& batch, size_t paramOffset) final; + virtual void do_glUniform1f(const Batch& batch, size_t paramOffset) final; + virtual void do_glUniform2f(const Batch& batch, size_t paramOffset) final; + virtual void do_glUniform3f(const Batch& batch, size_t paramOffset) final; + virtual void do_glUniform4f(const Batch& batch, size_t paramOffset) final; + virtual void do_glUniform3fv(const Batch& batch, size_t paramOffset) final; + virtual void do_glUniform4fv(const Batch& batch, size_t paramOffset) final; + virtual void do_glUniform4iv(const Batch& batch, size_t paramOffset) final; + virtual void do_glUniformMatrix3fv(const Batch& batch, size_t paramOffset) final; + virtual void do_glUniformMatrix4fv(const Batch& batch, size_t paramOffset) final; + + virtual void do_glColor4f(const Batch& batch, size_t paramOffset) final; + + // The State setters called by the GLState::Commands when a new state is assigned + virtual void do_setStateFillMode(int32 mode) final; + virtual void do_setStateCullMode(int32 mode) final; + virtual void do_setStateFrontFaceClockwise(bool isClockwise) final; + virtual void do_setStateDepthClampEnable(bool enable) final; + virtual void do_setStateScissorEnable(bool enable) final; + virtual void do_setStateMultisampleEnable(bool enable) final; + virtual void do_setStateAntialiasedLineEnable(bool enable) final; + virtual void do_setStateDepthBias(Vec2 bias) final; + virtual void do_setStateDepthTest(State::DepthTest test) final; + virtual void do_setStateStencil(State::StencilActivation activation, State::StencilTest frontTest, State::StencilTest backTest) final; + virtual void do_setStateAlphaToCoverageEnable(bool enable) final; + virtual void do_setStateSampleMask(uint32 mask) final; + virtual void do_setStateBlend(State::BlendFunction blendFunction) final; + virtual void do_setStateColorWriteMask(uint32 mask) final; + virtual void do_setStateBlendFactor(const Batch& batch, size_t paramOffset) final; + virtual void do_setStateScissorRect(const Batch& batch, size_t paramOffset) final; + + virtual GLuint getFramebufferID(const FramebufferPointer& framebuffer) = 0; + virtual GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) = 0; + virtual GLuint getBufferID(const Buffer& buffer) = 0; + virtual GLuint getQueryID(const QueryPointer& query) = 0; + virtual bool isTextureReady(const TexturePointer& texture); + + virtual void releaseBuffer(GLuint id, Size size) const; + virtual void releaseExternalTexture(GLuint id, const Texture::ExternalRecycler& recycler) const; + virtual void releaseTexture(GLuint id, Size size) const; + virtual void releaseFramebuffer(GLuint id) const; + virtual void releaseShader(GLuint id) const; + virtual void releaseProgram(GLuint id) const; + virtual void releaseQuery(GLuint id) const; + virtual void queueLambda(const std::function lambda) const; + + bool isTextureManagementSparseEnabled() const override { return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures()); } + + protected: + + void recycle() const override; + virtual GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) = 0; + virtual GLBuffer* syncGPUObject(const Buffer& buffer) = 0; + virtual GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) = 0; + virtual GLQuery* syncGPUObject(const Query& query) = 0; + + static const size_t INVALID_OFFSET = (size_t)-1; + bool _inRenderTransferPass { false }; + int32_t _uboAlignment { 0 }; + int _currentDraw { -1 }; + + std::list profileRanges; + mutable Mutex _trashMutex; + mutable std::list> _buffersTrash; + mutable std::list> _texturesTrash; + mutable std::list> _externalTexturesTrash; + mutable std::list _framebuffersTrash; + mutable std::list _shadersTrash; + mutable std::list _programsTrash; + mutable std::list _queriesTrash; + mutable std::list> _lambdaQueue; + + void renderPassTransfer(const Batch& batch); + void renderPassDraw(const Batch& batch); + void setupStereoSide(int side); + + virtual void initInput() final; + virtual void killInput() final; + virtual void syncInputStateCache() final; + virtual void resetInputStage(); + virtual void updateInput(); + + struct InputStageState { + bool _invalidFormat { true }; + Stream::FormatPointer _format; + std::string _formatKey; + + typedef std::bitset ActivationCache; + ActivationCache _attributeActivation { 0 }; + + typedef std::bitset BuffersState; + + BuffersState _invalidBuffers{ 0 }; + BuffersState _attribBindingBuffers{ 0 }; + + Buffers _buffers; + Offsets _bufferOffsets; + Offsets _bufferStrides; + std::vector _bufferVBOs; + + glm::vec4 _colorAttribute{ 0.0f }; + + BufferPointer _indexBuffer; + Offset _indexBufferOffset { 0 }; + Type _indexBufferType { UINT32 }; + + BufferPointer _indirectBuffer; + Offset _indirectBufferOffset{ 0 }; + Offset _indirectBufferStride{ 0 }; + + GLuint _defaultVAO { 0 }; + + InputStageState() : + _invalidFormat(true), + _format(0), + _formatKey(), + _attributeActivation(0), + _buffers(_invalidBuffers.size(), BufferPointer(0)), + _bufferOffsets(_invalidBuffers.size(), 0), + _bufferStrides(_invalidBuffers.size(), 0), + _bufferVBOs(_invalidBuffers.size(), 0) {} + } _input; + + virtual void initTransform() = 0; + void killTransform(); + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void syncTransformStateCache(); + void updateTransform(const Batch& batch); + void resetTransformStage(); + + // Allows for correction of the camera pose to account for changes + // between the time when a was recorded and the time(s) when it is + // executed + struct CameraCorrection { + Mat4 correction; + Mat4 correctionInverse; + }; + + struct TransformStageState { +#ifdef GPU_STEREO_CAMERA_BUFFER + struct Cameras { + TransformCamera _cams[2]; + + Cameras() {}; + Cameras(const TransformCamera& cam) { memcpy(_cams, &cam, sizeof(TransformCamera)); }; + Cameras(const TransformCamera& camL, const TransformCamera& camR) { memcpy(_cams, &camL, sizeof(TransformCamera)); memcpy(_cams + 1, &camR, sizeof(TransformCamera)); }; + }; + + using CameraBufferElement = Cameras; +#else + using CameraBufferElement = TransformCamera; +#endif + using TransformCameras = std::vector; + + TransformCamera _camera; + TransformCameras _cameras; + + mutable std::map _drawCallInfoOffsets; + + GLuint _objectBuffer { 0 }; + GLuint _cameraBuffer { 0 }; + GLuint _drawCallInfoBuffer { 0 }; + GLuint _objectBufferTexture { 0 }; + size_t _cameraUboSize { 0 }; + bool _viewIsCamera{ false }; + bool _skybox { false }; + Transform _view; + CameraCorrection _correction; + + Mat4 _projection; + Vec4i _viewport { 0, 0, 1, 1 }; + Vec2 _depthRange { 0.0f, 1.0f }; + bool _invalidView { false }; + bool _invalidProj { false }; + bool _invalidViewport { false }; + + bool _enabledDrawcallInfoBuffer{ false }; + + using Pair = std::pair; + using List = std::list; + List _cameraOffsets; + mutable List::const_iterator _camerasItr; + mutable size_t _currentCameraOffset{ INVALID_OFFSET }; + + void preUpdate(size_t commandIndex, const StereoState& stereo); + void update(size_t commandIndex, const StereoState& stereo) const; + void bindCurrentCamera(int stereoSide) const; + } _transform; + + virtual void transferTransformState(const Batch& batch) const = 0; + + struct UniformStageState { + std::array _buffers; + //Buffers _buffers { }; + } _uniform; + + void releaseUniformBuffer(uint32_t slot); + void resetUniformStage(); + + // update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s + void releaseResourceTexture(uint32_t slot); + + void resetResourceStage(); + + struct ResourceStageState { + std::array _textures; + //Textures _textures { { MAX_NUM_RESOURCE_TEXTURES } }; + int findEmptyTextureSlot() const; + } _resource; + + size_t _commandIndex{ 0 }; + + // Standard update pipeline check that the current Program and current State or good to go for a + void updatePipeline(); + // Force to reset all the state fields indicated by the 'toBeReset" signature + void resetPipelineState(State::Signature toBeReset); + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void syncPipelineStateCache(); + void resetPipelineStage(); + + struct PipelineStageState { + PipelinePointer _pipeline; + + GLuint _program { 0 }; + GLint _cameraCorrectionLocation { -1 }; + GLShader* _programShader { nullptr }; + bool _invalidProgram { false }; + + BufferView _cameraCorrectionBuffer { gpu::BufferView(std::make_shared(sizeof(CameraCorrection), nullptr )) }; + + State::Data _stateCache{ State::DEFAULT }; + State::Signature _stateSignatureCache { 0 }; + + GLState* _state { nullptr }; + bool _invalidState { false }; + + PipelineStageState() { + _cameraCorrectionBuffer.edit() = CameraCorrection(); + } + } _pipeline; + + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void syncOutputStateCache(); + void resetOutputStage(); + + struct OutputStageState { + FramebufferPointer _framebuffer { nullptr }; + GLuint _drawFBO { 0 }; + } _output; + + void resetQueryStage(); + struct QueryStageState { + uint32_t _rangeQueryDepth { 0 }; + } _queryStage; + + void resetStages(); + + struct TextureManagementStageState { + bool _sparseCapable { false }; + } _textureManagement; + virtual void initTextureManagementStage() {} + + typedef void (GLBackend::*CommandCall)(const Batch&, size_t); + static CommandCall _commandCalls[Batch::NUM_COMMANDS]; + friend class GLState; + friend class GLTexture; + }; + + } } + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendInput.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendInput.cpp new file mode 100644 index 0000000000..057682584d --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBackendInput.cpp @@ -0,0 +1,338 @@ +// +// GLBackendInput.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLBackend.h" +#include "GLShared.h" +#include "GLInputFormat.h" + +using namespace gpu; +using namespace gpu::gl; + +void GLBackend::do_setInputFormat(const Batch& batch, size_t paramOffset) { + Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint); + if (format != _input._format) { + _input._format = format; + if (format) { + auto inputFormat = GLInputFormat::sync((*format)); + assert(inputFormat); + if (_input._formatKey != inputFormat->key) { + _input._formatKey = inputFormat->key; + _input._invalidFormat = true; + } + } else { + _input._formatKey.clear(); + _input._invalidFormat = true; + } + } +} + +void GLBackend::do_setInputBuffer(const Batch& batch, size_t paramOffset) { + Offset stride = batch._params[paramOffset + 0]._uint; + Offset offset = batch._params[paramOffset + 1]._uint; + BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); + uint32 channel = batch._params[paramOffset + 3]._uint; + + if (channel < getNumInputBuffers()) { + bool isModified = false; + if (_input._buffers[channel] != buffer) { + _input._buffers[channel] = buffer; + + GLuint vbo = 0; + if (buffer) { + vbo = getBufferID((*buffer)); + } + _input._bufferVBOs[channel] = vbo; + + isModified = true; + } + + if (_input._bufferOffsets[channel] != offset) { + _input._bufferOffsets[channel] = offset; + isModified = true; + } + + if (_input._bufferStrides[channel] != stride) { + _input._bufferStrides[channel] = stride; + isModified = true; + } + + if (isModified) { + _input._invalidBuffers.set(channel); + } + } +} + +void GLBackend::initInput() { + if(!_input._defaultVAO) { + glGenVertexArrays(1, &_input._defaultVAO); + } + qDebug() << "glBindVertexArray(" << _input._defaultVAO << ")"; + glBindVertexArray(_input._defaultVAO); + (void) CHECK_GL_ERROR(); +} + +void GLBackend::killInput() { + qDebug() << "glBindVertexArray(0)"; + glBindVertexArray(0); + if(_input._defaultVAO) { + glDeleteVertexArrays(1, &_input._defaultVAO); + } + (void) CHECK_GL_ERROR(); +} + +void GLBackend::syncInputStateCache() { + for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) { + GLint active = 0; + glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &active); + _input._attributeActivation[i] = active; + } + //_input._defaultVAO + qDebug() << "glBindVertexArray("<<_input._defaultVAO<< ")"; + glBindVertexArray(_input._defaultVAO); +} + +void GLBackend::resetInputStage() { + // Reset index buffer + _input._indexBufferType = UINT32; + _input._indexBufferOffset = 0; + _input._indexBuffer.reset(); + //qDebug() << "GLBackend::resetInputStage glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);"; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + (void) CHECK_GL_ERROR(); + + // Reset vertex buffer and format + _input._format.reset(); + _input._formatKey.clear(); + _input._invalidFormat = false; + _input._attributeActivation.reset(); + + for (uint32_t i = 0; i < _input._buffers.size(); i++) { + _input._buffers[i].reset(); + _input._bufferOffsets[i] = 0; + _input._bufferStrides[i] = 0; + _input._bufferVBOs[i] = 0; + } + _input._invalidBuffers.reset(); + + // THe vertex array binding MUST be reset in the specific Backend versions as they use different techniques +} + +void GLBackend::do_setIndexBuffer(const Batch& batch, size_t paramOffset) { + _input._indexBufferType = (Type)batch._params[paramOffset + 2]._uint; + _input._indexBufferOffset = batch._params[paramOffset + 0]._uint; + + BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint); + if (indexBuffer != _input._indexBuffer) { + _input._indexBuffer = indexBuffer; + if (indexBuffer) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer)); + } else { + // FIXME do we really need this? Is there ever a draw call where we care that the element buffer is null? + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + } + (void) CHECK_GL_ERROR(); +} + +void GLBackend::do_setIndirectBuffer(const Batch& batch, size_t paramOffset) { + _input._indirectBufferOffset = batch._params[paramOffset + 1]._uint; + _input._indirectBufferStride = batch._params[paramOffset + 2]._uint; + + BufferPointer buffer = batch._buffers.get(batch._params[paramOffset]._uint); + if (buffer != _input._indirectBuffer) { + _input._indirectBuffer = buffer; + if (buffer) { + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferID(*buffer)); + } else { + // FIXME do we really need this? Is there ever a draw call where we care that the element buffer is null? + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); + } + } + + (void)CHECK_GL_ERROR(); +} + + +// Core 41 doesn't expose the features to really separate the vertex format from the vertex buffers binding +// Core 43 does :) +// FIXME crashing problem with glVertexBindingDivisor / glVertexAttribFormat +// Once resolved, break this up into the GL 4.1 and 4.5 backends +#if 1 || (GPU_INPUT_PROFILE == GPU_CORE_41) +#define NO_SUPPORT_VERTEX_ATTRIB_FORMAT +#else +#define SUPPORT_VERTEX_ATTRIB_FORMAT +#endif + +void GLBackend::updateInput() { +#if defined(SUPPORT_VERTEX_ATTRIB_FORMAT) + if (_input._invalidFormat) { + + InputStageState::ActivationCache newActivation; + + // Assign the vertex format required + if (_input._format) { + for (auto& it : _input._format->getAttributes()) { + const Stream::Attribute& attrib = (it).second; + + GLuint slot = attrib._slot; + GLuint count = attrib._element.getLocationScalarCount(); + uint8_t locationCount = attrib._element.getLocationCount(); + GLenum type = _elementTypeToGL41Type[attrib._element.getType()]; + GLuint offset = attrib._offset;; + GLboolean isNormalized = attrib._element.isNormalized(); + + GLenum perLocationSize = attrib._element.getLocationSize(); + + for (size_t locNum = 0; locNum < locationCount; ++locNum) { + newActivation.set(slot + locNum); + glVertexAttribFormat(slot + locNum, count, type, isNormalized, offset + locNum * perLocationSize); + glVertexAttribBinding(slot + locNum, attrib._channel); + } + glVertexBindingDivisor(attrib._channel, attrib._frequency); + } + (void)CHECK_GL_ERROR(); + } + + // Manage Activation what was and what is expected now + for (size_t i = 0; i < newActivation.size(); i++) { + bool newState = newActivation[i]; + if (newState != _input._attributeActivation[i]) { + if (newState) { + glEnableVertexAttribArray(i); + } else { + glDisableVertexAttribArray(i); + } + _input._attributeActivation.flip(i); + } + } + (void)CHECK_GL_ERROR(); + + _input._invalidFormat = false; + _stats._ISNumFormatChanges++; + } + + if (_input._invalidBuffers.any()) { + int numBuffers = _input._buffers.size(); + auto buffer = _input._buffers.data(); + auto vbo = _input._bufferVBOs.data(); + auto offset = _input._bufferOffsets.data(); + auto stride = _input._bufferStrides.data(); + + for (int bufferNum = 0; bufferNum < numBuffers; bufferNum++) { + if (_input._invalidBuffers.test(bufferNum)) { + glBindVertexBuffer(bufferNum, (*vbo), (*offset), (*stride)); + } + buffer++; + vbo++; + offset++; + stride++; + } + _input._invalidBuffers.reset(); + (void)CHECK_GL_ERROR(); + } +#else + if (_input._invalidFormat || _input._invalidBuffers.any()) { + + if (_input._invalidFormat) { + InputStageState::ActivationCache newActivation; + + _stats._ISNumFormatChanges++; + + // Check expected activation + if (_input._format) { + for (auto& it : _input._format->getAttributes()) { + const Stream::Attribute& attrib = (it).second; + uint8_t locationCount = attrib._element.getLocationCount(); + for (int i = 0; i < locationCount; ++i) { + newActivation.set(attrib._slot + i); + } + } + } + + // Manage Activation what was and what is expected now + for (unsigned int i = 0; i < newActivation.size(); i++) { + bool newState = newActivation[i]; + if (newState != _input._attributeActivation[i]) { + + if (newState) { + glEnableVertexAttribArray(i); + } else { + glDisableVertexAttribArray(i); + } + (void)CHECK_GL_ERROR(); + + _input._attributeActivation.flip(i); + } + } + } + + // now we need to bind the buffers and assign the attrib pointers + if (_input._format) { + const Buffers& buffers = _input._buffers; + const Offsets& offsets = _input._bufferOffsets; + const Offsets& strides = _input._bufferStrides; + + const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); + auto& inputChannels = _input._format->getChannels(); + _stats._ISNumInputBufferChanges++; + + GLuint boundVBO = 0; + for (auto& channelIt : inputChannels) { + const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second; + if ((channelIt).first < buffers.size()) { + int bufferNum = (channelIt).first; + + if (_input._invalidBuffers.test(bufferNum) || _input._invalidFormat) { + // GLuint vbo = gpu::GL41Backend::getBufferID((*buffers[bufferNum])); + GLuint vbo = _input._bufferVBOs[bufferNum]; + if (boundVBO != vbo) { + //qDebug() << "GLBackend::updateInput glBindBuffer(GL_ARRAY_BUFFER, " << vbo <<")"; + glBindBuffer(GL_ARRAY_BUFFER, vbo); + (void)CHECK_GL_ERROR(); + boundVBO = vbo; + } + _input._invalidBuffers[bufferNum] = false; + + for (unsigned int i = 0; i < channel._slots.size(); i++) { + const Stream::Attribute& attrib = attributes.at(channel._slots[i]); + GLuint slot = attrib._slot; + GLuint count = attrib._element.getLocationScalarCount(); + uint8_t locationCount = attrib._element.getLocationCount(); + GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()]; + // GLenum perLocationStride = strides[bufferNum]; + GLenum perLocationStride = attrib._element.getLocationSize(); + GLuint stride = (GLuint)strides[bufferNum]; + GLuint pointer = (GLuint)(attrib._offset + offsets[bufferNum]); + GLboolean isNormalized = attrib._element.isNormalized(); + + for (size_t locNum = 0; locNum < locationCount; ++locNum) { + glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride, + reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency * (isStereo() ? 2 : 1)); +#else + glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency); +#endif + } + + // TODO: Support properly the IAttrib version + + (void)CHECK_GL_ERROR(); + } + } + } + } + } + // everything format related should be in sync now + _input._invalidFormat = false; + } +#endif +} + diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendOutput.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendOutput.cpp new file mode 100644 index 0000000000..6fddb810ee --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBackendOutput.cpp @@ -0,0 +1,169 @@ +// +// GLBackendTexture.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 1/19/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLBackend.h" +#include "GLShared.h" +#include "GLFramebuffer.h" + +#include + +using namespace gpu; +using namespace gpu::gl; + +void GLBackend::syncOutputStateCache() { + GLint currentFBO; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO); + + _output._drawFBO = currentFBO; + _output._framebuffer.reset(); +} + +void GLBackend::resetOutputStage() { + if (_output._framebuffer) { + _output._framebuffer.reset(); + _output._drawFBO = 0; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + } + + glEnable(GL_FRAMEBUFFER_SRGB_EXT); +} + +void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) { + auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); + if (_output._framebuffer != framebuffer) { + auto newFBO = getFramebufferID(framebuffer); + if (_output._drawFBO != newFBO) { + _output._drawFBO = newFBO; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, newFBO); + } + _output._framebuffer = framebuffer; + } +} + +void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) { + if (_stereo._enable && !_pipeline._stateCache.scissorEnable) { + //qWarning("Clear without scissor in stereo mode"); + } + + uint32 masks = batch._params[paramOffset + 7]._uint; + Vec4 color; + color.x = batch._params[paramOffset + 6]._float; + color.y = batch._params[paramOffset + 5]._float; + color.z = batch._params[paramOffset + 4]._float; + color.w = batch._params[paramOffset + 3]._float; + float depth = batch._params[paramOffset + 2]._float; + int stencil = batch._params[paramOffset + 1]._int; + int useScissor = batch._params[paramOffset + 0]._int; + + GLuint glmask = 0; + if (masks & Framebuffer::BUFFER_STENCIL) { + glClearStencil(stencil); + glmask |= GL_STENCIL_BUFFER_BIT; + // TODO: we will probably need to also check the write mask of stencil like we do + // for depth buffer, but as would say a famous Fez owner "We'll cross that bridge when we come to it" + } + + bool restoreDepthMask = false; + if (masks & Framebuffer::BUFFER_DEPTH) { + glClearDepthf(depth); + + glmask |= GL_DEPTH_BUFFER_BIT; + + bool cacheDepthMask = _pipeline._stateCache.depthTest.getWriteMask(); + if (!cacheDepthMask) { + restoreDepthMask = true; + glDepthMask(GL_TRUE); + } + } + + std::vector drawBuffers; + if (masks & Framebuffer::BUFFER_COLORS) { + if (_output._framebuffer) { + for (unsigned int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) { + if (masks & (1 << i)) { + drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i); + } + } + + if (!drawBuffers.empty()) { + glDrawBuffers((GLsizei)drawBuffers.size(), drawBuffers.data()); + glClearColor(color.x, color.y, color.z, color.w); + glmask |= GL_COLOR_BUFFER_BIT; + + (void) CHECK_GL_ERROR(); + } + } else { + glClearColor(color.x, color.y, color.z, color.w); + glmask |= GL_COLOR_BUFFER_BIT; + } + + // Force the color mask cache to WRITE_ALL if not the case + do_setStateColorWriteMask(State::ColorMask::WRITE_ALL); + } + + // Apply scissor if needed and if not already on + bool doEnableScissor = (useScissor && (!_pipeline._stateCache.scissorEnable)); + if (doEnableScissor) { + glEnable(GL_SCISSOR_TEST); + } + + // Clear! + glClear(glmask); + + // Restore scissor if needed + if (doEnableScissor) { + glDisable(GL_SCISSOR_TEST); + } + + // Restore write mask meaning turn back off + if (restoreDepthMask) { + glDepthMask(GL_FALSE); + } + + // Restore the color draw buffers only if a frmaebuffer is bound + if (_output._framebuffer && !drawBuffers.empty()) { + auto glFramebuffer = syncGPUObject(*_output._framebuffer); + if (glFramebuffer) { + glDrawBuffers((GLsizei)glFramebuffer->_colorBuffers.size(), glFramebuffer->_colorBuffers.data()); + } + } + + (void) CHECK_GL_ERROR(); +} + +void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) { + auto readFBO = getFramebufferID(srcFramebuffer); + if (srcFramebuffer && readFBO) { + if ((srcFramebuffer->getWidth() < (region.x + region.z)) || (srcFramebuffer->getHeight() < (region.y + region.w))) { + qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : srcFramebuffer is too small to provide the region queried"; + return; + } + } + + if ((destImage.width() < region.z) || (destImage.height() < region.w)) { + qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : destImage is too small to receive the region of the framebuffer"; + return; + } + + GLenum format = GL_RGBA; + //GLenum format = GL_BGRA; + qDebug() << "TODO: GLBackendOutput.cpp:do_clearFramebuffer GL_BGRA"; + + if (destImage.format() != QImage::Format_ARGB32) { + qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : destImage format must be FORMAT_ARGB32 to receive the region of the framebuffer"; + return; + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, getFramebufferID(srcFramebuffer)); + glReadPixels(region.x, region.y, region.z, region.w, format, GL_UNSIGNED_BYTE, destImage.bits()); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + (void) CHECK_GL_ERROR(); +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendPipeline.cpp new file mode 100644 index 0000000000..c35966d440 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBackendPipeline.cpp @@ -0,0 +1,250 @@ +// +// GLBackendPipeline.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLBackend.h" +#include "GLShared.h" +#include "GLPipeline.h" +#include "GLShader.h" +#include "GLState.h" +#include "GLBuffer.h" +#include "GLTexture.h" + +using namespace gpu; +using namespace gpu::gl; + +void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) { + PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint); + + if (_pipeline._pipeline == pipeline) { + return; + } + + // A true new Pipeline + _stats._PSNumSetPipelines++; + + // null pipeline == reset + if (!pipeline) { + qDebug() << " null pipeline"; + _pipeline._pipeline.reset(); + + _pipeline._program = 0; + _pipeline._cameraCorrectionLocation = -1; + _pipeline._programShader = nullptr; + _pipeline._invalidProgram = true; + + _pipeline._state = nullptr; + _pipeline._invalidState = true; + } else { + auto pipelineObject = GLPipeline::sync(*this, *pipeline); + if (!pipelineObject) { + return; + } + + // check the program cache + // pick the program version + // check the program cache + // pick the program version +#ifdef GPU_STEREO_CAMERA_BUFFER + GLuint glprogram = pipelineObject->_program->getProgram((GLShader::Version) isStereo()); +#else + GLuint glprogram = pipelineObject->_program->getProgram(); +#endif + + if (_pipeline._program != glprogram) { + _pipeline._program = glprogram; + _pipeline._programShader = pipelineObject->_program; + _pipeline._invalidProgram = true; + _pipeline._cameraCorrectionLocation = pipelineObject->_cameraCorrection; + } + + // Now for the state + if (_pipeline._state != pipelineObject->_state) { + _pipeline._state = pipelineObject->_state; + _pipeline._invalidState = true; + } + + // Remember the new pipeline + _pipeline._pipeline = pipeline; + } + + // THis should be done on Pipeline::update... + if (_pipeline._invalidProgram) { + glUseProgram(_pipeline._program); + if (_pipeline._cameraCorrectionLocation != -1) { + auto cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBuffer._buffer); + glBindBufferRange(GL_UNIFORM_BUFFER, _pipeline._cameraCorrectionLocation, cameraCorrectionBuffer->_id, 0, sizeof(CameraCorrection)); + } + (void) CHECK_GL_ERROR(); + _pipeline._invalidProgram = false; + } +} + +void GLBackend::updatePipeline() { + if (_pipeline._invalidProgram) { + // doing it here is aproblem for calls to glUniform.... so will do it on assing... + glUseProgram(_pipeline._program); + (void) CHECK_GL_ERROR(); + _pipeline._invalidProgram = false; + } + + if (_pipeline._invalidState) { + if (_pipeline._state) { + // first reset to default what should be + // the fields which were not to default and are default now + resetPipelineState(_pipeline._state->_signature); + + // Update the signature cache with what's going to be touched + _pipeline._stateSignatureCache |= _pipeline._state->_signature; + + // And perform + for (auto command: _pipeline._state->_commands) { + command->run(this); + } + } else { + // No state ? anyway just reset everything + resetPipelineState(0); + } + _pipeline._invalidState = false; + } +} + +void GLBackend::resetPipelineStage() { + // First reset State to default + State::Signature resetSignature(0); + resetPipelineState(resetSignature); + _pipeline._state = nullptr; + _pipeline._invalidState = false; + + // Second the shader side + _pipeline._invalidProgram = false; + _pipeline._program = 0; + _pipeline._programShader = nullptr; + _pipeline._pipeline.reset(); + glUseProgram(0); +} + +void GLBackend::releaseUniformBuffer(uint32_t slot) { + auto& buf = _uniform._buffers[slot]; + if (buf) { + auto* object = Backend::getGPUObject(*buf); + if (object) { + glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE + (void) CHECK_GL_ERROR(); + } + buf.reset(); + } +} + +void GLBackend::resetUniformStage() { + for (uint32_t i = 0; i < _uniform._buffers.size(); i++) { + releaseUniformBuffer(i); + } +} + +void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) { + GLuint slot = batch._params[paramOffset + 3]._uint; + BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); + GLintptr rangeStart = batch._params[paramOffset + 1]._uint; + GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint; + + if (!uniformBuffer) { + releaseUniformBuffer(slot); + return; + } + + // check cache before thinking + if (_uniform._buffers[slot] == uniformBuffer) { + return; + } + + // Sync BufferObject + auto* object = syncGPUObject(*uniformBuffer); + if (object) { + glBindBufferRange(GL_UNIFORM_BUFFER, slot, object->_buffer, rangeStart, rangeSize); + + _uniform._buffers[slot] = uniformBuffer; + (void) CHECK_GL_ERROR(); + } else { + releaseUniformBuffer(slot); + return; + } +} + +void GLBackend::releaseResourceTexture(uint32_t slot) { + auto& tex = _resource._textures[slot]; + if (tex) { + auto* object = Backend::getGPUObject(*tex); + if (object) { + GLuint target = object->_target; + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(target, 0); // RELEASE + (void) CHECK_GL_ERROR(); + } + tex.reset(); + } +} + +void GLBackend::resetResourceStage() { + for (uint32_t i = 0; i < _resource._textures.size(); i++) { + releaseResourceTexture(i); + } +} + +void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) { + GLuint slot = batch._params[paramOffset + 1]._uint; + if (slot >= (GLuint) MAX_NUM_RESOURCE_TEXTURES) { + // "GLBackend::do_setResourceTexture: Trying to set a resource Texture at slot #" + slot + " which doesn't exist. MaxNumResourceTextures = " + getMaxNumResourceTextures()); + return; + } + + TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + + if (!resourceTexture) { + releaseResourceTexture(slot); + return; + } + // check cache before thinking + if (_resource._textures[slot] == resourceTexture) { + return; + } + + // One more True texture bound + _stats._RSNumTextureBounded++; + + // Always make sure the GLObject is in sync + GLTexture* object = syncGPUObject(resourceTexture); + if (object) { + GLuint to = object->_texture; + GLuint target = object->_target; + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(target, to); + + (void) CHECK_GL_ERROR(); + + _resource._textures[slot] = resourceTexture; + + _stats._RSAmountTextureMemoryBounded += object->size(); + + } else { + releaseResourceTexture(slot); + return; + } +} + +int GLBackend::ResourceStageState::findEmptyTextureSlot() const { + // start from the end of the slots, try to find an empty one that can be used + for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) { + if (!_textures[i]) { + return i; + } + } + return -1; +} + diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendQuery.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendQuery.cpp new file mode 100644 index 0000000000..530e01d8ff --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBackendQuery.cpp @@ -0,0 +1,93 @@ +// +// GLBackendQuery.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 7/7/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLBackend.h" +#include "GLQuery.h" +#include "GLShared.h" + +using namespace gpu; +using namespace gpu::gl; + +// Eventually, we want to test with TIME_ELAPSED instead of TIMESTAMP +#ifdef Q_OS_MAC +const uint32_t MAX_RANGE_QUERY_DEPTH = 1; +static bool timeElapsed = true; +#else +const uint32_t MAX_RANGE_QUERY_DEPTH = 10000; +static bool timeElapsed = false; +#endif + +void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) { + auto query = batch._queries.get(batch._params[paramOffset]._uint); + GLQuery* glquery = syncGPUObject(*query); + if (glquery) { + //glGetInteger64v(GL_TIMESTAMP_EXT, (GLint64*)&glquery->_batchElapsedTime); + glquery->_batchElapsedTime = 1; + if (timeElapsed) { + glBeginQuery(GL_TIME_ELAPSED_EXT, glquery->_endqo); + } else { + if (glQueryCounterEXT != NULL) { + glQueryCounterEXT(glquery->_beginqo, GL_TIMESTAMP_EXT); + } + } + glquery->_rangeQueryDepth = _queryStage._rangeQueryDepth; + (void)CHECK_GL_ERROR(); + } +} + +void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) { + auto query = batch._queries.get(batch._params[paramOffset]._uint); + GLQuery* glquery = syncGPUObject(*query); + if (glquery) { + if (timeElapsed) { + glEndQuery(GL_TIME_ELAPSED_EXT); + } else { + if (glQueryCounterEXT != NULL) { + glQueryCounterEXT(glquery->_endqo, GL_TIMESTAMP_EXT); + } + } + + --_queryStage._rangeQueryDepth; + GLint64 now; + //glGetInteger64v(GL_TIMESTAMP_EXT, &now); + //glquery->_batchElapsedTime = now - glquery->_batchElapsedTime; + now = 1; + glquery->_batchElapsedTime = 1; + + PROFILE_RANGE_END(render_gpu_gl, glquery->_profileRangeId); + + (void)CHECK_GL_ERROR(); + } +} + +void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) { + auto query = batch._queries.get(batch._params[paramOffset]._uint); + if (glGetQueryObjectui64vEXT == NULL) + return; + GLQuery* glquery = syncGPUObject(*query); + if (glquery) { + glGetQueryObjectui64vEXT(glquery->_endqo, GL_QUERY_RESULT_AVAILABLE, &glquery->_result); + if (glquery->_result == GL_TRUE) { + if (timeElapsed) { + glGetQueryObjectui64vEXT(glquery->_endqo, GL_QUERY_RESULT, &glquery->_result); + } else { + GLuint64 start, end; + glGetQueryObjectui64vEXT(glquery->_beginqo, GL_QUERY_RESULT, &start); + glGetQueryObjectui64vEXT(glquery->_endqo, GL_QUERY_RESULT, &end); + glquery->_result = end - start; + } + query->triggerReturnHandler(glquery->_result, glquery->_batchElapsedTime); + } + (void)CHECK_GL_ERROR(); + } +} + +void GLBackend::resetQueryStage() { +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendState.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendState.cpp new file mode 100644 index 0000000000..27b8d23bf3 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBackendState.cpp @@ -0,0 +1,334 @@ +// +// GLBackendState.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/22/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLBackend.h" +#include "GLState.h" + +using namespace gpu; +using namespace gpu::gl; + +void GLBackend::resetPipelineState(State::Signature nextSignature) { + auto currentNotSignature = ~_pipeline._stateSignatureCache; + auto nextNotSignature = ~nextSignature; + auto fieldsToBeReset = currentNotSignature ^ (currentNotSignature | nextNotSignature); + if (fieldsToBeReset.any()) { + for (auto i = 0; i < State::NUM_FIELDS; i++) { + if (fieldsToBeReset[i]) { + GLState::_resetStateCommands[i]->run(this); + _pipeline._stateSignatureCache.reset(i); + } + } + } +} + +void GLBackend::syncPipelineStateCache() { + State::Data state; + + //glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + qDebug() << "TODO: GLBackendState.cpp:syncPipelineStateCache GL_TEXTURE_CUBE_MAP_SEAMLESS"; + + // Point size is always on + // FIXME CORE + //glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + //glEnable(GL_PROGRAM_POINT_SIZE_EXT); + qDebug() << "TODO: GLBackendState.cpp:syncPipelineStateCache GL_PROGRAM_POINT_SIZE_EXT"; + + //glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + qDebug() << "TODO: GLBackendState.cpp:syncPipelineStateCache GL_VERTEX_PROGRAM_POINT_SIZE"; + + // Default line width accross the board + glLineWidth(1.0f); + + getCurrentGLState(state); + State::Signature signature = State::evalSignature(state); + + _pipeline._stateCache = state; + _pipeline._stateSignatureCache = signature; +} + + +void GLBackend::do_setStateFillMode(int32 mode) { + if (_pipeline._stateCache.fillMode != mode) { + static GLenum GL_FILL_MODES[] = { /*GL_POINT, GL_LINE, GL_FILL*/ }; + qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode GL_POINT"; + qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode GL_LINE"; + qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode GL_FILL"; + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_MODES[mode]); + qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode glPolygonMode"; + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.fillMode = State::FillMode(mode); + } +} + +void GLBackend::do_setStateCullMode(int32 mode) { + if (_pipeline._stateCache.cullMode != mode) { + static GLenum GL_CULL_MODES[] = { GL_FRONT_AND_BACK, GL_FRONT, GL_BACK }; + if (mode == State::CULL_NONE) { + glDisable(GL_CULL_FACE); + glCullFace(GL_FRONT_AND_BACK); + } else { + glEnable(GL_CULL_FACE); + glCullFace(GL_CULL_MODES[mode]); + } + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.cullMode = State::CullMode(mode); + } +} + +void GLBackend::do_setStateFrontFaceClockwise(bool isClockwise) { + if (_pipeline._stateCache.frontFaceClockwise != isClockwise) { + static GLenum GL_FRONT_FACES[] = { GL_CCW, GL_CW }; + glFrontFace(GL_FRONT_FACES[isClockwise]); + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.frontFaceClockwise = isClockwise; + } +} + +void GLBackend::do_setStateDepthClampEnable(bool enable) { + if (_pipeline._stateCache.depthClampEnable != enable) { + if (enable) { + qDebug() << "TODO: GLBackendState.cpp:do_setStateDepthClampEnable GL_DEPTH_CLAMP"; + //glEnable(GL_DEPTH_CLAMP); + } else { + //glDisable(GL_DEPTH_CLAMP); + qDebug() << "TODO: GLBackendState.cpp:do_setStateDepthClampEnable GL_DEPTH_CLAMP"; + } + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.depthClampEnable = enable; + } +} + +void GLBackend::do_setStateScissorEnable(bool enable) { + if (_pipeline._stateCache.scissorEnable != enable) { + if (enable) { + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + } + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.scissorEnable = enable; + } +} + +void GLBackend::do_setStateMultisampleEnable(bool enable) { + if (_pipeline._stateCache.multisampleEnable != enable) { + if (enable) { + //glEnable(GL_MULTISAMPLE); + qDebug() << "TODO: GLBackendState.cpp:do_setStateMultisampleEnable GL_MULTISAMPLE"; + } else { + //glDisable(GL_MULTISAMPLE); + qDebug() << "TODO: GLBackendState.cpp:do_setStateMultisampleEnable GL_MULTISAMPLE"; + } + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.multisampleEnable = enable; + } +} + +void GLBackend::do_setStateAntialiasedLineEnable(bool enable) { + if (_pipeline._stateCache.antialisedLineEnable != enable) { + if (enable) { + //glEnable(GL_LINE_SMOOTH); + qDebug() << "TODO: GLBackendState.cpp:do_setStateAntialiasedLineEnable GL_LINE_SMOOTH"; + } else { + //glDisable(GL_LINE_SMOOTH); + qDebug() << "TODO: GLBackendState.cpp:do_setStateAntialiasedLineEnable GL_LINE_SMOOTH"; + } + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.antialisedLineEnable = enable; + } +} + +void GLBackend::do_setStateDepthBias(Vec2 bias) { + if ((bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) { + if ((bias.x != 0.0f) || (bias.y != 0.0f)) { + glEnable(GL_POLYGON_OFFSET_FILL); + //glEnable(GL_POLYGON_OFFSET_LINE); + qDebug() << "TODO: GLBackendState.cpp:do_setStateDepthBias GL_POLYGON_OFFSET_LINE"; + //glEnable(GL_POLYGON_OFFSET_POINT); + qDebug() << "TODO: GLBackendState.cpp:do_setStateDepthBias GL_POLYGON_OFFSET_POINT"; + glPolygonOffset(bias.x, bias.y); + } else { + glDisable(GL_POLYGON_OFFSET_FILL); + //glDisable(GL_POLYGON_OFFSET_LINE); + qDebug() << "TODO: GLBackendState.cpp:do_setStateDepthBias GL_POLYGON_OFFSET_LINE"; + //glDisable(GL_POLYGON_OFFSET_POINT); + qDebug() << "TODO: GLBackendState.cpp:do_setStateDepthBias GL_POLYGON_OFFSET_POINT"; + } + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.depthBias = bias.x; + _pipeline._stateCache.depthBiasSlopeScale = bias.y; + } +} + +void GLBackend::do_setStateDepthTest(State::DepthTest test) { + const auto& current = _pipeline._stateCache.depthTest; + if (current != test) { + if (test.isEnabled()) { + glEnable(GL_DEPTH_TEST); + } else { + glDisable(GL_DEPTH_TEST); + } + if (test.getWriteMask() != current.getWriteMask()) { + glDepthMask(test.getWriteMask()); + } + if (test.getFunction() != current.getFunction()) { + glDepthFunc(COMPARISON_TO_GL[test.getFunction()]); + } + if (CHECK_GL_ERROR()) { + qDebug() << "DepthTest" << (test.isEnabled() ? "Enabled" : "Disabled") + << "Mask=" << (test.getWriteMask() ? "Write" : "no Write") + << "Func=" << test.getFunction() + << "Raw=" << test.getRaw(); + } + _pipeline._stateCache.depthTest = test; + } +} + +void GLBackend::do_setStateStencil(State::StencilActivation activation, State::StencilTest testFront, State::StencilTest testBack) { + const auto& currentActivation = _pipeline._stateCache.stencilActivation; + const auto& currentTestFront = _pipeline._stateCache.stencilTestFront; + const auto& currentTestBack = _pipeline._stateCache.stencilTestBack; + if ((currentActivation != activation) + || (currentTestFront != testFront) + || (currentTestBack != testBack)) { + + if (activation.isEnabled()) { + glEnable(GL_STENCIL_TEST); + } else { + glDisable(GL_STENCIL_TEST); + } + + if (activation.getWriteMaskFront() != activation.getWriteMaskBack()) { + glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront()); + glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack()); + } else { + glStencilMask(activation.getWriteMaskFront()); + } + + static GLenum STENCIL_OPS[State::NUM_STENCIL_OPS] = { + GL_KEEP, + GL_ZERO, + GL_REPLACE, + GL_INCR_WRAP, + GL_DECR_WRAP, + GL_INVERT, + GL_INCR, + GL_DECR }; + + if (testFront != testBack) { + glStencilOpSeparate(GL_FRONT, STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getDepthFailOp()], STENCIL_OPS[testFront.getPassOp()]); + glStencilFuncSeparate(GL_FRONT, COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask()); + + glStencilOpSeparate(GL_BACK, STENCIL_OPS[testBack.getFailOp()], STENCIL_OPS[testBack.getDepthFailOp()], STENCIL_OPS[testBack.getPassOp()]); + glStencilFuncSeparate(GL_BACK, COMPARISON_TO_GL[testBack.getFunction()], testBack.getReference(), testBack.getReadMask()); + } else { + glStencilOp(STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getDepthFailOp()], STENCIL_OPS[testFront.getPassOp()]); + glStencilFunc(COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask()); + } + + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.stencilActivation = activation; + _pipeline._stateCache.stencilTestFront = testFront; + _pipeline._stateCache.stencilTestBack = testBack; + } +} + +void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) { + if (_pipeline._stateCache.alphaToCoverageEnable != enable) { + if (enable) { + glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } else { + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.alphaToCoverageEnable = enable; + } +} + +void GLBackend::do_setStateSampleMask(uint32 mask) { + if (_pipeline._stateCache.sampleMask != mask) { + if (mask == 0xFFFFFFFF) { + glDisable(GL_SAMPLE_MASK); + } else { + glEnable(GL_SAMPLE_MASK); + glSampleMaski(0, mask); + } + (void)CHECK_GL_ERROR(); + _pipeline._stateCache.sampleMask = mask; + } +} + +void GLBackend::do_setStateBlend(State::BlendFunction function) { + if (_pipeline._stateCache.blendFunction != function) { + if (function.isEnabled()) { + glEnable(GL_BLEND); + + glBlendEquationSeparate(BLEND_OPS_TO_GL[function.getOperationColor()], BLEND_OPS_TO_GL[function.getOperationAlpha()]); + (void)CHECK_GL_ERROR(); + + + glBlendFuncSeparate(BLEND_ARGS_TO_GL[function.getSourceColor()], BLEND_ARGS_TO_GL[function.getDestinationColor()], + BLEND_ARGS_TO_GL[function.getSourceAlpha()], BLEND_ARGS_TO_GL[function.getDestinationAlpha()]); + } else { + glDisable(GL_BLEND); + } + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.blendFunction = function; + } +} + +void GLBackend::do_setStateColorWriteMask(uint32 mask) { + if (_pipeline._stateCache.colorWriteMask != mask) { + glColorMask(mask & State::ColorMask::WRITE_RED, + mask & State::ColorMask::WRITE_GREEN, + mask & State::ColorMask::WRITE_BLUE, + mask & State::ColorMask::WRITE_ALPHA); + (void)CHECK_GL_ERROR(); + + _pipeline._stateCache.colorWriteMask = mask; + } +} + + +void GLBackend::do_setStateBlendFactor(const Batch& batch, size_t paramOffset) { + Vec4 factor(batch._params[paramOffset + 0]._float, + batch._params[paramOffset + 1]._float, + batch._params[paramOffset + 2]._float, + batch._params[paramOffset + 3]._float); + + glBlendColor(factor.x, factor.y, factor.z, factor.w); + (void)CHECK_GL_ERROR(); +} + +void GLBackend::do_setStateScissorRect(const Batch& batch, size_t paramOffset) { + Vec4i rect; + memcpy(&rect, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i)); + + if (_stereo._enable) { + rect.z /= 2; + if (_stereo._pass) { + rect.x += rect.z; + } + } + glScissor(rect.x, rect.y, rect.z, rect.w); + (void)CHECK_GL_ERROR(); +} + diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendTexture.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendTexture.cpp new file mode 100644 index 0000000000..4be7682a4f --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBackendTexture.cpp @@ -0,0 +1,40 @@ +// +// +// GLBackendTexture.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 1/19/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLBackend.h" +#include "GLTexture.h" + +using namespace gpu; +using namespace gpu::gl; + +bool GLBackend::isTextureReady(const TexturePointer& texture) { + // DO not transfer the texture, this call is expected for rendering texture + GLTexture* object = syncGPUObject(texture, true); + qDebug() << "GLBackendTexture isTextureReady syncGPUObject"; + return object && object->isReady(); +} + + +void GLBackend::do_generateTextureMips(const Batch& batch, size_t paramOffset) { + TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + if (!resourceTexture) { + return; + } + + // DO not transfer the texture, this call is expected for rendering texture + GLTexture* object = syncGPUObject(resourceTexture, false); + qDebug() << "GLBackendTexture do_generateTextureMips syncGPUObject"; + if (!object) { + return; + } + + object->generateMips(); +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendTransform.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendTransform.cpp new file mode 100644 index 0000000000..3068e24dac --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBackendTransform.cpp @@ -0,0 +1,212 @@ +// +// GLBackendTransform.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLBackend.h" + +using namespace gpu; +using namespace gpu::gl; + +// Transform Stage +void GLBackend::do_setModelTransform(const Batch& batch, size_t paramOffset) { + qDebug() << "do_setModelTransform"; +} + +void GLBackend::do_setViewTransform(const Batch& batch, size_t paramOffset) { + _transform._view = batch._transforms.get(batch._params[paramOffset]._uint); + _transform._viewIsCamera = batch._params[paramOffset + 1]._uint != 0; + _transform._invalidView = true; +} + +void GLBackend::do_setProjectionTransform(const Batch& batch, size_t paramOffset) { + memcpy(&_transform._projection, batch.readData(batch._params[paramOffset]._uint), sizeof(Mat4)); + _transform._invalidProj = true; +} + +void GLBackend::do_setViewportTransform(const Batch& batch, size_t paramOffset) { + memcpy(&_transform._viewport, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i)); + +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + { + ivec4& vp = _transform._viewport; + glViewport(vp.x, vp.y, vp.z, vp.w); + + // Where we assign the GL viewport + if (_stereo._enable) { + vp.z /= 2; + if (_stereo._pass) { + vp.x += vp.z; + } + } + } +#else + if (!_inRenderTransferPass && !isStereo()) { + ivec4& vp = _transform._viewport; + glViewport(vp.x, vp.y, vp.z, vp.w); + } +#endif + + // The Viewport is tagged invalid because the CameraTransformUBO is not up to date and will need update on next drawcall + _transform._invalidViewport = true; +} + +void GLBackend::do_setDepthRangeTransform(const Batch& batch, size_t paramOffset) { + + Vec2 depthRange(batch._params[paramOffset + 1]._float, batch._params[paramOffset + 0]._float); + + if ((depthRange.x != _transform._depthRange.x) || (depthRange.y != _transform._depthRange.y)) { + _transform._depthRange = depthRange; + + glDepthRangef(depthRange.x, depthRange.y); + } +} + +void GLBackend::killTransform() { + glDeleteBuffers(1, &_transform._objectBuffer); + glDeleteBuffers(1, &_transform._cameraBuffer); + glDeleteBuffers(1, &_transform._drawCallInfoBuffer); + glDeleteTextures(1, &_transform._objectBufferTexture); +} + +void GLBackend::syncTransformStateCache() { + _transform._invalidViewport = true; + _transform._invalidProj = true; + _transform._invalidView = true; + + glGetIntegerv(GL_VIEWPORT, (GLint*) &_transform._viewport); + + glGetFloatv(GL_DEPTH_RANGE, (GLfloat*)&_transform._depthRange); + + Mat4 modelView; + auto modelViewInv = glm::inverse(modelView); + _transform._view.evalFromRawMatrix(modelViewInv); + + glDisableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO); + _transform._enabledDrawcallInfoBuffer = false; +} + +void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const StereoState& stereo) { + // Check all the dirty flags and update the state accordingly + if (_invalidViewport) { + _camera._viewport = glm::vec4(_viewport); + } + + if (_invalidProj) { + _camera._projection = _projection; + } + + if (_invalidView) { + // Apply the correction + if (_viewIsCamera && _correction.correction != glm::mat4()) { + // FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out? + Transform result; + _view.mult(result, _view, _correction.correction); + if (_skybox) { + result.setTranslation(vec3()); + } + _view = result; + } + // This is when the _view matrix gets assigned + _view.getInverseMatrix(_camera._view); + } + + if (_invalidView || _invalidProj || _invalidViewport) { + size_t offset = _cameraUboSize * _cameras.size(); + _cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset)); + + if (stereo._enable) { +#ifdef GPU_STEREO_CAMERA_BUFFER + _cameras.push_back(CameraBufferElement(_camera.getEyeCamera(0, stereo, _view), _camera.getEyeCamera(1, stereo, _view))); +#else + _cameras.push_back((_camera.getEyeCamera(0, stereo, _view))); + _cameras.push_back((_camera.getEyeCamera(1, stereo, _view))); +#endif + } else { +#ifdef GPU_STEREO_CAMERA_BUFFER + _cameras.push_back(CameraBufferElement(_camera.recomputeDerived(_view))); +#else + _cameras.push_back((_camera.recomputeDerived(_view))); +#endif + } + } + + // Flags are clean + _invalidView = _invalidProj = _invalidViewport = false; +} + +void GLBackend::TransformStageState::update(size_t commandIndex, const StereoState& stereo) const { + size_t offset = INVALID_OFFSET; + while ((_camerasItr != _cameraOffsets.end()) && (commandIndex >= (*_camerasItr).first)) { + offset = (*_camerasItr).second; + _currentCameraOffset = offset; + ++_camerasItr; + } + + if (offset != INVALID_OFFSET) { +#ifdef GPU_STEREO_CAMERA_BUFFER + bindCurrentCamera(0); +#else + if (!stereo._enable) { + bindCurrentCamera(0); + } +#endif + } + (void)CHECK_GL_ERROR(); +} + +void GLBackend::TransformStageState::bindCurrentCamera(int eye) const { + if (_currentCameraOffset != INVALID_OFFSET) { + //qDebug() << "GLBackend::TransformStageState::bindCurrentCamera"; + glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _cameraBuffer, _currentCameraOffset + eye * _cameraUboSize, sizeof(CameraBufferElement)); + } +} + +void GLBackend::updateTransform(const Batch& batch) { + _transform.update(_commandIndex, _stereo); + + auto& drawCallInfoBuffer = batch.getDrawCallInfoBuffer(); + if (batch._currentNamedCall.empty()) { + (void)CHECK_GL_ERROR(); + auto& drawCallInfo = drawCallInfoBuffer[_currentDraw]; + glDisableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO); // Make sure attrib array is disabled + (void)CHECK_GL_ERROR(); + GLint current_vao, current_vbo, maxVertexAtribs; + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, ¤t_vao); + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤t_vbo); + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAtribs); + glVertexAttribI4i(gpu::Stream::DRAW_CALL_INFO, drawCallInfo.index, drawCallInfo.unused, 0, 0); + + //int values[] = {drawCallInfo.index, drawCallInfo.unused}; + //glVertexAttribIPointer(gpu::Stream::DRAW_CALL_INFO, 2, GL_INT, 0, (const GLvoid *) values); + + /* + //glDisableVertexAttribArray currentvao 1 current vbo 0 + GL_INVALID_OPERATION is generated + a non-zero vertex array object is bound, + zero is bound to the GL_ARRAY_BUFFER buffer object binding point and + the pointer argument is not NULL. TRUE + */ + //qDebug() << "GLBackend::updateTransform glVertexAttribIPointer done"; + (void)CHECK_GL_ERROR(); + + } else { + //qDebug() << "GLBackend::updateTransform else"; + glEnableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO); // Make sure attrib array is enabled + glBindBuffer(GL_ARRAY_BUFFER, _transform._drawCallInfoBuffer); + glVertexAttribIPointer(gpu::Stream::DRAW_CALL_INFO, 2, GL_UNSIGNED_SHORT, 0, + _transform._drawCallInfoOffsets[batch._currentNamedCall]); + glVertexAttribDivisor(gpu::Stream::DRAW_CALL_INFO, 1); + } + + (void)CHECK_GL_ERROR(); +} + +void GLBackend::resetTransformStage() { + +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLBuffer.cpp b/libraries/gpu-gles/src/gpu/gl/GLBuffer.cpp new file mode 100644 index 0000000000..4f7d0a8632 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBuffer.cpp @@ -0,0 +1,35 @@ +// +// Created by Gabriel Calero & Cristian Duarte on 09/27/2016 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLBuffer.h" +#include "GLBackend.h" + +using namespace gpu; +using namespace gpu::gl; + +GLBuffer::~GLBuffer() { + Backend::bufferCount.decrement(); + Backend::bufferGPUMemSize.update(_size, 0); + + if (_id) { + auto backend = _backend.lock(); + if (backend) { + backend->releaseBuffer(_id, _size); + } + } +} + +GLBuffer::GLBuffer(const std::weak_ptr& backend, const Buffer& buffer, GLuint id) : + GLObject(backend, buffer, id), + _size((GLuint)buffer._renderSysmem.getSize()), + _stamp(buffer._renderSysmem.getStamp()) +{ + Backend::bufferCount.increment(); + Backend::bufferGPUMemSize.update(0, _size); +} + diff --git a/libraries/gpu-gles/src/gpu/gl/GLBuffer.h b/libraries/gpu-gles/src/gpu/gl/GLBuffer.h new file mode 100644 index 0000000000..182014e764 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLBuffer.h @@ -0,0 +1,66 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLBuffer_h +#define hifi_gpu_gl_GLBuffer_h + +#include "GLShared.h" +#include "GLBackend.h" + +namespace gpu { namespace gl { + +class GLBuffer : public GLObject { +public: + template + static GLBufferType* sync(GLBackend& backend, const Buffer& buffer) { + if (buffer.getSysmem().getSize() != 0) { + if (buffer._getUpdateCount == 0) { + qWarning() << "Unsynced buffer"; + } + if (buffer._getUpdateCount < buffer._applyUpdateCount) { + qWarning() << "Unsynced buffer " << buffer._getUpdateCount << " " << buffer._applyUpdateCount; + } + } + GLBufferType* object = Backend::getGPUObject(buffer); + + // Has the storage size changed? + if (!object || object->_stamp != buffer._renderSysmem.getStamp()) { + object = new GLBufferType(backend.shared_from_this(), buffer, object); + } + + if (0 != (buffer._renderPages._flags & PageManager::DIRTY)) { + object->transfer(); + } + + return object; + } + + template + static GLuint getId(GLBackend& backend, const Buffer& buffer) { + GLBuffer* bo = sync(backend, buffer); + if (bo) { + return bo->_buffer; + } else { + return 0; + } + } + + const GLuint& _buffer { _id }; + const GLuint _size; + const Stamp _stamp; + + ~GLBuffer(); + + virtual void transfer() = 0; + +protected: + GLBuffer(const std::weak_ptr& backend, const Buffer& buffer, GLuint id); +}; + +} } + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLFramebuffer.cpp b/libraries/gpu-gles/src/gpu/gl/GLFramebuffer.cpp new file mode 100644 index 0000000000..150bb2be70 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLFramebuffer.cpp @@ -0,0 +1,48 @@ +// +// Created by Gabriel Calero & Cristian Duarte on 09/27/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLFramebuffer.h" +#include "GLBackend.h" + +using namespace gpu; +using namespace gpu::gl; + +GLFramebuffer::~GLFramebuffer() { + if (_id) { + auto backend = _backend.lock(); + if (backend) { + backend->releaseFramebuffer(_id); + } + } +} + +bool GLFramebuffer::checkStatus(GLenum target) const { + bool result = false; + switch (_status) { + case GL_FRAMEBUFFER_COMPLETE: + // Success ! + result = true; + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT."; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT."; + break; +/* TODO: case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER."; + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER."; + break; */ + case GL_FRAMEBUFFER_UNSUPPORTED: + qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED."; + break; + } + return result; +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLFramebuffer.h b/libraries/gpu-gles/src/gpu/gl/GLFramebuffer.h new file mode 100644 index 0000000000..a2fd0999f3 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLFramebuffer.h @@ -0,0 +1,77 @@ +// +// Created by Gabriel Calero & Cristian Duarte on 09/27/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLFramebuffer_h +#define hifi_gpu_gl_GLFramebuffer_h + +#include "GLShared.h" +#include "GLBackend.h" + +namespace gpu { namespace gl { + +class GLFramebuffer : public GLObject { +public: + template + static GLFramebufferType* sync(GLBackend& backend, const Framebuffer& framebuffer) { + GLFramebufferType* object = Backend::getGPUObject(framebuffer); + + bool needsUpate { false }; + if (!object || + framebuffer.getDepthStamp() != object->_depthStamp || + framebuffer.getColorStamps() != object->_colorStamps) { + needsUpate = true; + } + + // If GPU object already created and in sync + if (!needsUpate) { + return object; + } else if (framebuffer.isEmpty()) { + // NO framebuffer definition yet so let's avoid thinking + return nullptr; + } + + // need to have a gpu object? + if (!object) { + // All is green, assign the gpuobject to the Framebuffer + object = new GLFramebufferType(backend.shared_from_this(), framebuffer); + Backend::setGPUObject(framebuffer, object); + (void)CHECK_GL_ERROR(); + } + + object->update(); + return object; + } + + template + static GLuint getId(GLBackend& backend, const Framebuffer& framebuffer) { + GLFramebufferType* fbo = sync(backend, framebuffer); + if (fbo) { + return fbo->_id; + } else { + return 0; + } + } + + const GLuint& _fbo { _id }; + std::vector _colorBuffers; + Stamp _depthStamp { 0 }; + std::vector _colorStamps; + +protected: + GLenum _status { GL_FRAMEBUFFER_COMPLETE }; + virtual void update() = 0; + bool checkStatus(GLenum target) const; + + GLFramebuffer(const std::weak_ptr& backend, const Framebuffer& framebuffer, GLuint id) : GLObject(backend, framebuffer, id) {} + ~GLFramebuffer(); + +}; + +} } + + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLInputFormat.cpp b/libraries/gpu-gles/src/gpu/gl/GLInputFormat.cpp new file mode 100644 index 0000000000..7f42350c3b --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLInputFormat.cpp @@ -0,0 +1,33 @@ +// +// Created by Sam Gateau on 2016/07/21 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLInputFormat.h" +#include "GLBackend.h" + +using namespace gpu; +using namespace gpu::gl; + + +GLInputFormat::GLInputFormat() { +} + +GLInputFormat:: ~GLInputFormat() { + +} + +GLInputFormat* GLInputFormat::sync(const Stream::Format& inputFormat) { + GLInputFormat* object = Backend::getGPUObject(inputFormat); + + if (!object) { + object = new GLInputFormat(); + object->key = inputFormat.getKey(); + Backend::setGPUObject(inputFormat, object); + } + + return object; +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLInputFormat.h b/libraries/gpu-gles/src/gpu/gl/GLInputFormat.h new file mode 100644 index 0000000000..a14e3d4d91 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLInputFormat.h @@ -0,0 +1,29 @@ +// +// Created by Sam Gateau on 2016/07/21 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLInputFormat_h +#define hifi_gpu_gl_GLInputFormat_h + +#include "GLShared.h" + +namespace gpu { +namespace gl { + +class GLInputFormat : public GPUObject { + public: + static GLInputFormat* sync(const Stream::Format& inputFormat); + + GLInputFormat(); + ~GLInputFormat(); + + std::string key; +}; + +} +} + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLPipeline.cpp b/libraries/gpu-gles/src/gpu/gl/GLPipeline.cpp new file mode 100644 index 0000000000..09c09de353 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLPipeline.cpp @@ -0,0 +1,62 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLPipeline.h" + +#include "GLShader.h" +#include "GLState.h" + +using namespace gpu; +using namespace gpu::gl; + +GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) { + GLPipeline* object = Backend::getGPUObject(pipeline); + + // If GPU object already created then good + if (object) { + return object; + } + + // No object allocated yet, let's see if it's worth it... + ShaderPointer shader = pipeline.getProgram(); + + // If this pipeline's shader has already failed to compile, don't try again + if (shader->compilationHasFailed()) { + return nullptr; + } + + GLShader* programObject = GLShader::sync(backend, *shader); + if (programObject == nullptr) { + shader->setCompilationHasFailed(true); + return nullptr; + } + + StatePointer state = pipeline.getState(); + GLState* stateObject = GLState::sync(*state); + if (stateObject == nullptr) { + return nullptr; + } + + // Program and state are valid, we can create the pipeline object + if (!object) { + object = new GLPipeline(); + Backend::setGPUObject(pipeline, object); + } + + // Special case for view correction matrices, any pipeline that declares the correction buffer + // uniform will automatically have it provided without any client code necessary. + // Required for stable lighting in the HMD. + //CLIMAX_MERGE_START + //getbuffers() doesnt exist anymore.. use get uniformbuffers()? + object->_cameraCorrection = shader->getUniformBuffers().findLocation("cameraCorrectionBuffer"); + //CLIMAX_MERGE_END + object->_program = programObject; + object->_state = stateObject; + + return object; +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLPipeline.h b/libraries/gpu-gles/src/gpu/gl/GLPipeline.h new file mode 100644 index 0000000000..a298f149d9 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLPipeline.h @@ -0,0 +1,29 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLPipeline_h +#define hifi_gpu_gl_GLPipeline_h + +#include "GLShared.h" + +namespace gpu { namespace gl { + +class GLPipeline : public GPUObject { +public: + static GLPipeline* sync(GLBackend& backend, const Pipeline& pipeline); + + GLShader* _program { nullptr }; + GLState* _state { nullptr }; + // Bit of a hack, any pipeline can need the camera correction buffer at execution time, so + // we store whether a given pipeline has declared the uniform buffer for it. + int32 _cameraCorrection { -1 }; +}; + +} } + + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLQuery.h b/libraries/gpu-gles/src/gpu/gl/GLQuery.h new file mode 100644 index 0000000000..23b1f38621 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLQuery.h @@ -0,0 +1,67 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLQuery_h +#define hifi_gpu_gl_GLQuery_h + +#include "GLShared.h" +#include "GLBackend.h" + +namespace gpu { namespace gl { + +class GLQuery : public GLObject { + using Parent = gpu::gl::GLObject; +public: + template + static GLQueryType* sync(GLBackend& backend, const Query& query) { + GLQueryType* object = Backend::getGPUObject(query); + + // need to have a gpu object? + if (!object) { + // All is green, assign the gpuobject to the Query + object = new GLQueryType(backend.shared_from_this(), query); + (void)CHECK_GL_ERROR(); + Backend::setGPUObject(query, object); + } + + return object; + } + + template + static GLuint getId(GLBackend& backend, const QueryPointer& query) { + if (!query) { + return 0; + } + + GLQuery* object = sync(backend, *query); + if (!object) { + return 0; + } + + return object->_endqo; + } + + const GLuint& _endqo = { _id }; + const GLuint _beginqo = { 0 }; + GLuint64 _result { (GLuint64)-1 }; + GLuint64 _batchElapsedTime { (GLuint64) 0 }; + uint64_t _profileRangeId { 0 }; + uint32_t _rangeQueryDepth { 0 }; + +protected: + GLQuery(const std::weak_ptr& backend, const Query& query, GLuint endId, GLuint beginId) : Parent(backend, query, endId), _beginqo(beginId) {} + ~GLQuery() { + if (_id) { + GLuint ids[2] = { _endqo, _beginqo }; + glDeleteQueries(2, ids); + } + } +}; + +} } + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp new file mode 100644 index 0000000000..b728010470 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp @@ -0,0 +1,224 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLShader.h" +#include + +#include "GLBackend.h" + +using namespace gpu; +using namespace gpu::gl; + +GLShader::GLShader(const std::weak_ptr& backend) : _backend(backend) { +} + +GLShader::~GLShader() { + for (auto& so : _shaderObjects) { + auto backend = _backend.lock(); + if (backend) { + if (so.glshader != 0) { + backend->releaseShader(so.glshader); + } + if (so.glprogram != 0) { + backend->releaseProgram(so.glprogram); + } + } + } +} + +// GLSL version +static const std::string glslVersion { + "#version 310 es" +}; + +// Shader domain +static const size_t NUM_SHADER_DOMAINS = 3; + +// GL Shader type enums +// Must match the order of type specified in gpu::Shader::Type +static const std::array SHADER_DOMAINS { { + GL_VERTEX_SHADER, + GL_FRAGMENT_SHADER, + //GL_GEOMETRY_SHADER, +} }; + +// Domain specific defines +// Must match the order of type specified in gpu::Shader::Type +static const std::array DOMAIN_DEFINES { { + "#define GPU_VERTEX_SHADER", + "#define GPU_PIXEL_SHADER", + "#define GPU_GEOMETRY_SHADER", +} }; + +// Stereo specific defines +static const std::string stereoVersion { +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + "#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED\n#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN" +#endif +#ifdef GPU_STEREO_DRAWCALL_DOUBLED +#ifdef GPU_STEREO_CAMERA_BUFFER + "#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED" +#else + "#define GPU_TRANSFORM_IS_STEREO" +#endif +#endif +}; + +// Versions specific of the shader +static const std::array VERSION_DEFINES { { + "", + stereoVersion +} }; + +GLShader* compileBackendShader(GLBackend& backend, const Shader& shader) { + // Any GLSLprogram ? normally yes... + const std::string& shaderSource = shader.getSource().getCode(); + GLenum shaderDomain = SHADER_DOMAINS[shader.getType()]; + GLShader::ShaderObjects shaderObjects; + + for (int version = 0; version < GLShader::NumVersions; version++) { + auto& shaderObject = shaderObjects[version]; + std::string shaderDefines = glslVersion + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version] + + "\n" + "#extension GL_EXT_texture_buffer : enable" + + "\nprecision lowp float; // check precision 2" + + "\nprecision lowp samplerBuffer;" + + "\nprecision lowp sampler2DShadow;"; + // TODO Delete bool result = compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram); + std::string error; + + +#ifdef SEPARATE_PROGRAM + bool result = ::gl::compileShader(shaderDomain, shaderSource.c_str(), shaderDefines.c_str(), shaderObject.glshader, shaderObject.glprogram, error); +#else + bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, error); +#endif + if (!result) { + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << error.c_str(); + return nullptr; + } + } + + // So far so good, the shader is created successfully + GLShader* object = new GLShader(backend.shared_from_this()); + object->_shaderObjects = shaderObjects; + + return object; +} + +GLShader* compileBackendProgram(GLBackend& backend, const Shader& program) { + if (!program.isProgram()) { + return nullptr; + } + + GLShader::ShaderObjects programObjects; + + for (int version = 0; version < GLShader::NumVersions; version++) { + auto& programObject = programObjects[version]; + + // Let's go through every shaders and make sure they are ready to go + std::vector< GLuint > shaderGLObjects; + for (auto subShader : program.getShaders()) { + auto object = GLShader::sync(backend, *subShader); + if (object) { + shaderGLObjects.push_back(object->_shaderObjects[version].glshader); + } else { + qCDebug(gpugllogging) << "GLShader::compileBackendProgram - One of the shaders of the program is not compiled?"; + return nullptr; + } + } + + std::string error; + GLuint glprogram = ::gl::compileProgram(shaderGLObjects, error); + if (glprogram == 0) { + qCWarning(gpugllogging) << error.c_str(); + return nullptr; + } + + programObject.glprogram = glprogram; + + makeProgramBindings(programObject); + } + + // So far so good, the program versions have all been created successfully + GLShader* object = new GLShader(backend.shared_from_this()); + object->_shaderObjects = programObjects; + + return object; +} + +GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) { + GLShader* object = Backend::getGPUObject(shader); + + // If GPU object already created then good + if (object) { + return object; + } + // need to have a gpu object? + if (shader.isProgram()) { + GLShader* tempObject = compileBackendProgram(backend, shader); + if (tempObject) { + object = tempObject; + Backend::setGPUObject(shader, object); + } + } else if (shader.isDomain()) { + GLShader* tempObject = compileBackendShader(backend, shader); + if (tempObject) { + object = tempObject; + Backend::setGPUObject(shader, object); + } + } + + glFinish(); + return object; +} + +bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings) { + + // First make sure the Shader has been compiled + GLShader* object = sync(backend, shader); + if (!object) { + return false; + } + + // Apply bindings to all program versions and generate list of slots from default version + for (int version = 0; version < GLShader::NumVersions; version++) { + auto& shaderObject = object->_shaderObjects[version]; + if (shaderObject.glprogram) { + Shader::SlotSet buffers; + makeUniformBlockSlots(shaderObject.glprogram, slotBindings, buffers); + + Shader::SlotSet uniforms; + Shader::SlotSet textures; + Shader::SlotSet samplers; + makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers); + + Shader::SlotSet resourceBuffers; + makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers); + + Shader::SlotSet inputs; + makeInputSlots(shaderObject.glprogram, slotBindings, inputs); + + Shader::SlotSet outputs; + makeOutputSlots(shaderObject.glprogram, slotBindings, outputs); + + // Define the public slots only from the default version + if (version == 0) { + shader.defineSlots(uniforms, buffers, resourceBuffers, textures, samplers, inputs, outputs); + } // else + { + GLShader::UniformMapping mapping; + for (auto srcUniform : shader.getUniforms()) { + mapping[srcUniform._location] = uniforms.findLocation(srcUniform._name); + } + object->_uniformMappings.push_back(mapping); + } + } + } + + return true; +} + diff --git a/libraries/gpu-gles/src/gpu/gl/GLShader.h b/libraries/gpu-gles/src/gpu/gl/GLShader.h new file mode 100644 index 0000000000..e03b487a60 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLShader.h @@ -0,0 +1,59 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLShader_h +#define hifi_gpu_gl_GLShader_h + +#include "GLShared.h" + +namespace gpu { namespace gl { + +class GLShader : public GPUObject { +public: + static GLShader* sync(GLBackend& backend, const Shader& shader); + static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings); + + enum Version { + Mono = 0, + Stereo, + + NumVersions + }; + + using ShaderObject = gpu::gl::ShaderObject; + using ShaderObjects = std::array< ShaderObject, NumVersions >; + + using UniformMapping = std::map; + using UniformMappingVersions = std::vector; + + GLShader(const std::weak_ptr& backend); + ~GLShader(); + + ShaderObjects _shaderObjects; + UniformMappingVersions _uniformMappings; + + GLuint getProgram(Version version = Mono) const { + return _shaderObjects[version].glprogram; + } + + GLint getUniformLocation(GLint srcLoc, Version version = Mono) const { + // This check protect against potential invalid src location for this shader, if unknown then return -1. + const auto& mapping = _uniformMappings[version]; + auto found = mapping.find(srcLoc); + if (found == mapping.end()) { + return -1; + } + return found->second; + } + + const std::weak_ptr _backend; +}; + +} } + + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLShared.cpp b/libraries/gpu-gles/src/gpu/gl/GLShared.cpp new file mode 100644 index 0000000000..5d340889a6 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLShared.cpp @@ -0,0 +1,879 @@ +// +// Created by Bradley Austin Davis on 2016/05/14 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLShared.h" + +#include + +#include + +#include +#include +#include + +Q_LOGGING_CATEGORY(gpugllogging, "hifi.gpu.gl") +Q_LOGGING_CATEGORY(trace_render_gpu_gl, "trace.render.gpu.gl") + +namespace gpu { namespace gl { + +bool checkGLError(const char* name) { + GLenum error = glGetError(); + if (!error) { + return false; + } else { + switch (error) { + case GL_INVALID_ENUM: + qCDebug(gpugllogging) << "GLBackend::" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag."; + break; + case GL_INVALID_VALUE: + qCDebug(gpugllogging) << "GLBackend" << name << ": A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag"; + break; + case GL_INVALID_OPERATION: + qCDebug(gpugllogging) << "GLBackend" << name << ": The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag.."; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + qCDebug(gpugllogging) << "GLBackend" << name << ": The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag."; + break; + case GL_OUT_OF_MEMORY: + qCDebug(gpugllogging) << "GLBackend" << name << ": There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded."; + break; + default: + qCDebug(gpugllogging) << "GLBackend" << name << ": Unknown error: " << error; + break; + } + return true; + } +} + +bool checkGLErrorDebug(const char* name) { +#ifdef DEBUG + return checkGLError(name); +#else + Q_UNUSED(name); + return false; +#endif +} + +gpu::Size getFreeDedicatedMemory() { + Size result { 0 }; + static bool nvidiaMemorySupported { false }; + static bool atiMemorySupported { false }; + if (nvidiaMemorySupported) { + + GLint nvGpuMemory { 0 }; + qDebug() << "TODO: GLShared.cpp getFreeDedicatedMemory GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX"; + //glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &nvGpuMemory); + if (GL_NO_ERROR == glGetError()) { + result = KB_TO_BYTES(nvGpuMemory); + } else { + nvidiaMemorySupported = false; + } + } else if (atiMemorySupported) { + GLint atiGpuMemory[4]; + qDebug() << "TODO: GLShared.cpp getFreeDedicatedMemory GL_TEXTURE_FREE_MEMORY_ATI"; + // not really total memory, but close enough if called early enough in the application lifecycle + //glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, atiGpuMemory); + if (GL_NO_ERROR == glGetError()) { + result = KB_TO_BYTES(atiGpuMemory[0]); + } else { + atiMemorySupported = false; + } + } + return result; +} + +gpu::Size getDedicatedMemory() { + static Size dedicatedMemory { 0 }; + static std::once_flag once; + std::call_once(once, [&] { + if (!dedicatedMemory) { + GLint atiGpuMemory[4]; + // not really total memory, but close enough if called early enough in the application lifecycle + //glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, atiGpuMemory); + qDebug() << "TODO: GLShared.cpp.cpp:initInput GL_TEXTURE_FREE_MEMORY_ATI"; + if (GL_NO_ERROR == glGetError()) { + dedicatedMemory = KB_TO_BYTES(atiGpuMemory[0]); + } + } + + if (!dedicatedMemory) { + GLint nvGpuMemory { 0 }; + qDebug() << "TODO: GLShared.cpp.cpp:initInput GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX"; + //glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &nvGpuMemory); + if (GL_NO_ERROR == glGetError()) { + dedicatedMemory = KB_TO_BYTES(nvGpuMemory); + } + } + + if (!dedicatedMemory) { + auto gpuIdent = GPUIdent::getInstance(); + if (gpuIdent && gpuIdent->isValid()) { + dedicatedMemory = MB_TO_BYTES(gpuIdent->getMemory()); + } + } + }); + + return dedicatedMemory; +} + + + + +ComparisonFunction comparisonFuncFromGL(GLenum func) { + if (func == GL_NEVER) { + return NEVER; + } else if (func == GL_LESS) { + return LESS; + } else if (func == GL_EQUAL) { + return EQUAL; + } else if (func == GL_LEQUAL) { + return LESS_EQUAL; + } else if (func == GL_GREATER) { + return GREATER; + } else if (func == GL_NOTEQUAL) { + return NOT_EQUAL; + } else if (func == GL_GEQUAL) { + return GREATER_EQUAL; + } else if (func == GL_ALWAYS) { + return ALWAYS; + } + + return ALWAYS; +} + +State::StencilOp stencilOpFromGL(GLenum stencilOp) { + if (stencilOp == GL_KEEP) { + return State::STENCIL_OP_KEEP; + } else if (stencilOp == GL_ZERO) { + return State::STENCIL_OP_ZERO; + } else if (stencilOp == GL_REPLACE) { + return State::STENCIL_OP_REPLACE; + } else if (stencilOp == GL_INCR_WRAP) { + return State::STENCIL_OP_INCR_SAT; + } else if (stencilOp == GL_DECR_WRAP) { + return State::STENCIL_OP_DECR_SAT; + } else if (stencilOp == GL_INVERT) { + return State::STENCIL_OP_INVERT; + } else if (stencilOp == GL_INCR) { + return State::STENCIL_OP_INCR; + } else if (stencilOp == GL_DECR) { + return State::STENCIL_OP_DECR; + } + + return State::STENCIL_OP_KEEP; +} + +State::BlendOp blendOpFromGL(GLenum blendOp) { + if (blendOp == GL_FUNC_ADD) { + return State::BLEND_OP_ADD; + } else if (blendOp == GL_FUNC_SUBTRACT) { + return State::BLEND_OP_SUBTRACT; + } else if (blendOp == GL_FUNC_REVERSE_SUBTRACT) { + return State::BLEND_OP_REV_SUBTRACT; + } else if (blendOp == GL_MIN) { + return State::BLEND_OP_MIN; + } else if (blendOp == GL_MAX) { + return State::BLEND_OP_MAX; + } + + return State::BLEND_OP_ADD; +} + +State::BlendArg blendArgFromGL(GLenum blendArg) { + if (blendArg == GL_ZERO) { + return State::ZERO; + } else if (blendArg == GL_ONE) { + return State::ONE; + } else if (blendArg == GL_SRC_COLOR) { + return State::SRC_COLOR; + } else if (blendArg == GL_ONE_MINUS_SRC_COLOR) { + return State::INV_SRC_COLOR; + } else if (blendArg == GL_DST_COLOR) { + return State::DEST_COLOR; + } else if (blendArg == GL_ONE_MINUS_DST_COLOR) { + return State::INV_DEST_COLOR; + } else if (blendArg == GL_SRC_ALPHA) { + return State::SRC_ALPHA; + } else if (blendArg == GL_ONE_MINUS_SRC_ALPHA) { + return State::INV_SRC_ALPHA; + } else if (blendArg == GL_DST_ALPHA) { + return State::DEST_ALPHA; + } else if (blendArg == GL_ONE_MINUS_DST_ALPHA) { + return State::INV_DEST_ALPHA; + } else if (blendArg == GL_CONSTANT_COLOR) { + return State::FACTOR_COLOR; + } else if (blendArg == GL_ONE_MINUS_CONSTANT_COLOR) { + return State::INV_FACTOR_COLOR; + } else if (blendArg == GL_CONSTANT_ALPHA) { + return State::FACTOR_ALPHA; + } else if (blendArg == GL_ONE_MINUS_CONSTANT_ALPHA) { + return State::INV_FACTOR_ALPHA; + } + + return State::ONE; +} + +void getCurrentGLState(State::Data& state) { + { + GLint modes[2]; + //glGetIntegerv(GL_POLYGON_MODE, modes); + qDebug() << "TODO: GLShared.cpp:getCurrentGLState GL_POLYGON_MODE"; + qDebug() << "TODO: GLShared.cpp:getCurrentGLState GL_FILL"; + qDebug() << "TODO: GLShared.cpp:getCurrentGLState GL_LINE"; + + if (modes[0] == 0 /*GL_FILL*/) { + state.fillMode = State::FILL_FACE; + } else { + if (modes[0] == 0 /*GL_LINE*/) { + state.fillMode = State::FILL_LINE; + } else { + state.fillMode = State::FILL_POINT; + } + } + } + { + if (glIsEnabled(GL_CULL_FACE)) { + GLint mode; + glGetIntegerv(GL_CULL_FACE_MODE, &mode); + state.cullMode = (mode == GL_FRONT ? State::CULL_FRONT : State::CULL_BACK); + } else { + state.cullMode = State::CULL_NONE; + } + } + { + GLint winding; + glGetIntegerv(GL_FRONT_FACE, &winding); + state.frontFaceClockwise = (winding == GL_CW); + //state.depthClampEnable = glIsEnabled(GL_DEPTH_CLAMP); + qDebug() << "TODO: GLShared.cpp.cpp:getCurrentGLState GL_DEPTH_CLAMP"; + state.scissorEnable = glIsEnabled(GL_SCISSOR_TEST); + //state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE); + qDebug() << "TODO: GLShared.cpp.cpp:getCurrentGLState GL_MULTISAMPLE"; + + //state.antialisedLineEnable = glIsEnabled(GL_LINE_SMOOTH); + qDebug() << "TODO: GLShared.cpp.cpp:getCurrentGLState GL_LINE_SMOOTH"; + + } + { + if (glIsEnabled(GL_POLYGON_OFFSET_FILL)) { + glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &state.depthBiasSlopeScale); + glGetFloatv(GL_POLYGON_OFFSET_UNITS, &state.depthBias); + } + } + { + GLboolean isEnabled = glIsEnabled(GL_DEPTH_TEST); + GLboolean writeMask; + glGetBooleanv(GL_DEPTH_WRITEMASK, &writeMask); + GLint func; + glGetIntegerv(GL_DEPTH_FUNC, &func); + + state.depthTest = State::DepthTest(isEnabled, writeMask, comparisonFuncFromGL(func)); + } + { + GLboolean isEnabled = glIsEnabled(GL_STENCIL_TEST); + + GLint frontWriteMask; + GLint frontReadMask; + GLint frontRef; + GLint frontFail; + GLint frontDepthFail; + GLint frontPass; + GLint frontFunc; + glGetIntegerv(GL_STENCIL_WRITEMASK, &frontWriteMask); + glGetIntegerv(GL_STENCIL_VALUE_MASK, &frontReadMask); + glGetIntegerv(GL_STENCIL_REF, &frontRef); + glGetIntegerv(GL_STENCIL_FAIL, &frontFail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &frontDepthFail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &frontPass); + glGetIntegerv(GL_STENCIL_FUNC, &frontFunc); + + GLint backWriteMask; + GLint backReadMask; + GLint backRef; + GLint backFail; + GLint backDepthFail; + GLint backPass; + GLint backFunc; + glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &backWriteMask); + glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &backReadMask); + glGetIntegerv(GL_STENCIL_BACK_REF, &backRef); + glGetIntegerv(GL_STENCIL_BACK_FAIL, &backFail); + glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &backDepthFail); + glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &backPass); + glGetIntegerv(GL_STENCIL_BACK_FUNC, &backFunc); + + state.stencilActivation = State::StencilActivation(isEnabled, frontWriteMask, backWriteMask); + state.stencilTestFront = State::StencilTest(frontRef, frontReadMask, comparisonFuncFromGL(frontFunc), stencilOpFromGL(frontFail), stencilOpFromGL(frontDepthFail), stencilOpFromGL(frontPass)); + state.stencilTestBack = State::StencilTest(backRef, backReadMask, comparisonFuncFromGL(backFunc), stencilOpFromGL(backFail), stencilOpFromGL(backDepthFail), stencilOpFromGL(backPass)); + } + { + GLint mask = 0xFFFFFFFF; + if (glIsEnabled(GL_SAMPLE_MASK)) { + glGetIntegerv(GL_SAMPLE_MASK, &mask); + state.sampleMask = mask; + } + state.sampleMask = mask; + } + { + state.alphaToCoverageEnable = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + { + GLboolean isEnabled = glIsEnabled(GL_BLEND); + GLint srcRGB; + GLint srcA; + GLint dstRGB; + GLint dstA; + glGetIntegerv(GL_BLEND_SRC_RGB, &srcRGB); + glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcA); + glGetIntegerv(GL_BLEND_DST_RGB, &dstRGB); + glGetIntegerv(GL_BLEND_DST_ALPHA, &dstA); + + GLint opRGB; + GLint opA; + glGetIntegerv(GL_BLEND_EQUATION_RGB, &opRGB); + glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &opA); + + state.blendFunction = State::BlendFunction(isEnabled, + blendArgFromGL(srcRGB), blendOpFromGL(opRGB), blendArgFromGL(dstRGB), + blendArgFromGL(srcA), blendOpFromGL(opA), blendArgFromGL(dstA)); + } + { + GLboolean mask[4]; + glGetBooleanv(GL_COLOR_WRITEMASK, mask); + state.colorWriteMask = (mask[0] ? State::WRITE_RED : 0) + | (mask[1] ? State::WRITE_GREEN : 0) + | (mask[2] ? State::WRITE_BLUE : 0) + | (mask[3] ? State::WRITE_ALPHA : 0); + } + + (void)CHECK_GL_ERROR(); +} + + +class ElementResource { +public: + gpu::Element _element; + uint16 _resource; + + ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {} +}; + +ElementResource getFormatFromGLUniform(GLenum gltype) { + switch (gltype) { + case GL_FLOAT: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); + /* + case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); + */ + case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER); + case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER); + case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER); + case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER); + + case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER); +#if defined(Q_OS_WIN) + case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER); + case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER); + case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER); +#endif + + case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER); + case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER); + case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER); + case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER); + + + case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER); + + /* {GL_FLOAT_MAT2x3 mat2x3}, + {GL_FLOAT_MAT2x4 mat2x4}, + {GL_FLOAT_MAT3x2 mat3x2}, + {GL_FLOAT_MAT3x4 mat3x4}, + {GL_FLOAT_MAT4x2 mat4x2}, + {GL_FLOAT_MAT4x3 mat4x3}, + {GL_DOUBLE_MAT2 dmat2}, + {GL_DOUBLE_MAT3 dmat3}, + {GL_DOUBLE_MAT4 dmat4}, + {GL_DOUBLE_MAT2x3 dmat2x3}, + {GL_DOUBLE_MAT2x4 dmat2x4}, + {GL_DOUBLE_MAT3x2 dmat3x2}, + {GL_DOUBLE_MAT3x4 dmat3x4}, + {GL_DOUBLE_MAT4x2 dmat4x2}, + {GL_DOUBLE_MAT4x3 dmat4x3}, + */ + + //qDebug() << "TODO: GLShared.cpp.cpp:ElementResource GL_SAMPLER_1D"; + //case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D); + case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D); + + case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D); + case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE); + +#if defined(Q_OS_WIN) + case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY); + case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY); + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); +#endif + + case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D); +#if defined(Q_OS_WIN) + case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE); + + case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY); +#endif + + // {GL_SAMPLER_1D_SHADOW sampler1DShadow}, + // {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow}, + + // {GL_SAMPLER_BUFFER samplerBuffer}, + // {GL_SAMPLER_2D_RECT sampler2DRect}, + // {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow}, + +#if defined(Q_OS_WIN) + case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D); + case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D); + case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D); + case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE); + + case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); + case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); + + // {GL_INT_SAMPLER_BUFFER isamplerBuffer}, + // {GL_INT_SAMPLER_2D_RECT isampler2DRect}, + + case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D); + case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D); + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D); + case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE); + + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); +#endif + // {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer}, + // {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect}, + /* + {GL_IMAGE_1D image1D}, + {GL_IMAGE_2D image2D}, + {GL_IMAGE_3D image3D}, + {GL_IMAGE_2D_RECT image2DRect}, + {GL_IMAGE_CUBE imageCube}, + {GL_IMAGE_BUFFER imageBuffer}, + {GL_IMAGE_1D_ARRAY image1DArray}, + {GL_IMAGE_2D_ARRAY image2DArray}, + {GL_IMAGE_2D_MULTISAMPLE image2DMS}, + {GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray}, + {GL_INT_IMAGE_1D iimage1D}, + {GL_INT_IMAGE_2D iimage2D}, + {GL_INT_IMAGE_3D iimage3D}, + {GL_INT_IMAGE_2D_RECT iimage2DRect}, + {GL_INT_IMAGE_CUBE iimageCube}, + {GL_INT_IMAGE_BUFFER iimageBuffer}, + {GL_INT_IMAGE_1D_ARRAY iimage1DArray}, + {GL_INT_IMAGE_2D_ARRAY iimage2DArray}, + {GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS}, + {GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray}, + {GL_UNSIGNED_INT_IMAGE_1D uimage1D}, + {GL_UNSIGNED_INT_IMAGE_2D uimage2D}, + {GL_UNSIGNED_INT_IMAGE_3D uimage3D}, + {GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect}, + {GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot + + {GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer}, + {GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray}, + {GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray}, + {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS}, + {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray}, + {GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint} + */ + default: + return ElementResource(Element(), Resource::BUFFER); + } + +}; + +int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, + Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { + GLint uniformsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount); + + for (int i = 0; i < uniformsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + GLint location = glGetUniformLocation(glprogram, name); + const GLint INVALID_UNIFORM_LOCATION = -1; + + // Try to make sense of the gltype + auto elementResource = getFormatFromGLUniform(type); + + // The uniform as a standard var type + if (location != INVALID_UNIFORM_LOCATION) { + // Let's make sure the name doesn't contains an array element + std::string sname(name); + auto foundBracket = sname.find_first_of('['); + if (foundBracket != std::string::npos) { + // std::string arrayname = sname.substr(0, foundBracket); + + if (sname[foundBracket + 1] == '0') { + sname = sname.substr(0, foundBracket); + } else { + // skip this uniform since it's not the first element of an array + continue; + } + } + + if (elementResource._resource == Resource::BUFFER) { + uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource)); + } else { + // For texture/Sampler, the location is the actual binding value + GLint binding = -1; + glGetUniformiv(glprogram, location, &binding); + + auto requestedBinding = slotBindings.find(std::string(sname)); + if (requestedBinding != slotBindings.end()) { + if (binding != (*requestedBinding)._location) { + binding = (*requestedBinding)._location; + glProgramUniform1i(glprogram, location, binding); + } + } + + textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); + samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); + } + } + } + + return uniformsCount; +} + +const GLint UNUSED_SLOT = -1; +bool isUnusedSlot(GLint binding) { + return (binding == UNUSED_SLOT); +} + +int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) { + GLint buffersCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount); + + // fast exit + if (buffersCount == 0) { + return 0; + } + + GLint maxNumUniformBufferSlots = 0; + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots); + std::vector uniformBufferSlotMap(maxNumUniformBufferSlots, -1); + + struct UniformBlockInfo { + using Vector = std::vector; + const GLuint index{ 0 }; + const std::string name; + GLint binding{ -1 }; + GLint size{ 0 }; + + static std::string getName(GLuint glprogram, GLuint i) { + static const GLint NAME_LENGTH = 256; + GLint length = 0; + GLchar nameBuffer[NAME_LENGTH]; + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); + glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, nameBuffer); + return std::string(nameBuffer); + } + + UniformBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) { + glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_BINDING, &binding); + glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size); + } + }; + + UniformBlockInfo::Vector uniformBlocks; + uniformBlocks.reserve(buffersCount); + for (int i = 0; i < buffersCount; i++) { + uniformBlocks.push_back(UniformBlockInfo(glprogram, i)); + } + + for (auto& info : uniformBlocks) { + auto requestedBinding = slotBindings.find(info.name); + if (requestedBinding != slotBindings.end()) { + info.binding = (*requestedBinding)._location; + glUniformBlockBinding(glprogram, info.index, info.binding); + uniformBufferSlotMap[info.binding] = info.index; + } + } + + for (auto& info : uniformBlocks) { + if (slotBindings.count(info.name)) { + continue; + } + + // If the binding is 0, or the binding maps to an already used binding + if (info.binding == 0 || uniformBufferSlotMap[info.binding] != UNUSED_SLOT) { + // If no binding was assigned then just do it finding a free slot + auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), isUnusedSlot); + if (slotIt != uniformBufferSlotMap.end()) { + info.binding = slotIt - uniformBufferSlotMap.begin(); + glUniformBlockBinding(glprogram, info.index, info.binding); + } else { + // This should neve happen, an active ubo cannot find an available slot among the max available?! + info.binding = -1; + } + } + + uniformBufferSlotMap[info.binding] = info.index; + } + + for (auto& info : uniformBlocks) { + static const Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER); + buffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size)); + } + return buffersCount; +} +//CLIMAX_MERGE_START +//This has been copied over from gl45backendshader.cpp +int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) { + GLint buffersCount = 0; + glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &buffersCount); + + // fast exit + if (buffersCount == 0) { + return 0; + } + + GLint maxNumResourceBufferSlots = 0; + glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxNumResourceBufferSlots); + std::vector resourceBufferSlotMap(maxNumResourceBufferSlots, -1); + + struct ResourceBlockInfo { + using Vector = std::vector; + const GLuint index{ 0 }; + const std::string name; + GLint binding{ -1 }; + GLint size{ 0 }; + + static std::string getName(GLuint glprogram, GLuint i) { + static const GLint NAME_LENGTH = 256; + GLint length = 0; + GLchar nameBuffer[NAME_LENGTH]; + glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, i, NAME_LENGTH, &length, nameBuffer); + return std::string(nameBuffer); + } + + ResourceBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) { + GLenum props[2] = { GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE}; + glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, i, 2, props, 2, nullptr, &binding); + } + }; + + ResourceBlockInfo::Vector resourceBlocks; + resourceBlocks.reserve(buffersCount); + for (int i = 0; i < buffersCount; i++) { + resourceBlocks.push_back(ResourceBlockInfo(glprogram, i)); + } + + for (auto& info : resourceBlocks) { + auto requestedBinding = slotBindings.find(info.name); + if (requestedBinding != slotBindings.end()) { + info.binding = (*requestedBinding)._location; + glUniformBlockBinding(glprogram, info.index, info.binding); + resourceBufferSlotMap[info.binding] = info.index; + } + } + + for (auto& info : resourceBlocks) { + if (slotBindings.count(info.name)) { + continue; + } + + // If the binding is -1, or the binding maps to an already used binding + if (info.binding == -1 || !isUnusedSlot(resourceBufferSlotMap[info.binding])) { + // If no binding was assigned then just do it finding a free slot + auto slotIt = std::find_if(resourceBufferSlotMap.begin(), resourceBufferSlotMap.end(), isUnusedSlot); + if (slotIt != resourceBufferSlotMap.end()) { + info.binding = slotIt - resourceBufferSlotMap.begin(); + glUniformBlockBinding(glprogram, info.index, info.binding); + } else { + // This should never happen, an active ssbo cannot find an available slot among the max available?! + info.binding = -1; + } + } + + resourceBufferSlotMap[info.binding] = info.index; + } + + for (auto& info : resourceBlocks) { + static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER); + resourceBuffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size)); + } + return buffersCount; +} +//CLIMAX_MERGE_END + +int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) { + GLint inputsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount); + + for (int i = 0; i < inputsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + + GLint binding = glGetAttribLocation(glprogram, name); + + auto elementResource = getFormatFromGLUniform(type); + inputs.insert(Shader::Slot(name, binding, elementResource._element, -1)); + } + + return inputsCount; +} + +int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) { + /* GLint outputsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount); + + for (int i = 0; i < inputsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + + auto element = getFormatFromGLUniform(type); + outputs.insert(Shader::Slot(name, i, element)); + } + */ + return 0; //inputsCount; +} + +void makeProgramBindings(ShaderObject& shaderObject) { + if (!shaderObject.glprogram) { + return; + } + GLuint glprogram = shaderObject.glprogram; + GLint loc = -1; + + //Check for gpu specific attribute slotBindings + loc = glGetAttribLocation(glprogram, "inPosition"); + if (loc >= 0 && loc != gpu::Stream::POSITION) { + glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition"); + } + + loc = glGetAttribLocation(glprogram, "inNormal"); + if (loc >= 0 && loc != gpu::Stream::NORMAL) { + glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal"); + } + + loc = glGetAttribLocation(glprogram, "inColor"); + if (loc >= 0 && loc != gpu::Stream::COLOR) { + glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor"); + } + + loc = glGetAttribLocation(glprogram, "inTexCoord0"); + if (loc >= 0 && loc != gpu::Stream::TEXCOORD) { + glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0"); + } + + loc = glGetAttribLocation(glprogram, "inTangent"); + if (loc >= 0 && loc != gpu::Stream::TANGENT) { + glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent"); + } + + loc = glGetAttribLocation(glprogram, "inTexCoord1"); + if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) { + glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1"); + } + + loc = glGetAttribLocation(glprogram, "inSkinClusterIndex"); + if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) { + glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex"); + } + + loc = glGetAttribLocation(glprogram, "inSkinClusterWeight"); + if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) { + glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight"); + } + + loc = glGetAttribLocation(glprogram, "_drawCallInfo"); + if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) { + glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo"); + } + + // Link again to take into account the assigned attrib location + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + if (!linked) { + qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?"; + } + + // now assign the ubo binding, then DON't relink! + + //Check for gpu specific uniform slotBindings + loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer"); + if (loc >= 0) { + // FIXME GLES + // glShaderStorageBlockBinding(glprogram, loc, TRANSFORM_OBJECT_SLOT); + shaderObject.transformObjectSlot = TRANSFORM_OBJECT_SLOT; + } + + loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, TRANSFORM_CAMERA_SLOT); + shaderObject.transformCameraSlot = TRANSFORM_CAMERA_SLOT; + } + + (void)CHECK_GL_ERROR(); +} + +void serverWait() { + auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + assert(fence); + glWaitSync(fence, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(fence); +} + +void clientWait() { + auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + assert(fence); + auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0); + while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) { + // Minimum sleep + QThread::usleep(1); + result = glClientWaitSync(fence, 0, 0); + } + glDeleteSync(fence); +} + +} } + + +using namespace gpu; + + diff --git a/libraries/gpu-gles/src/gpu/gl/GLShared.h b/libraries/gpu-gles/src/gpu/gl/GLShared.h new file mode 100644 index 0000000000..54209b106d --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLShared.h @@ -0,0 +1,167 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_GLShared_h +#define hifi_gpu_GLShared_h + +#include +#include +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(gpugllogging) +Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl) + +namespace gpu { namespace gl { + + static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot + +// Create a fence and inject a GPU wait on the fence +void serverWait(); + +// Create a fence and synchronously wait on the fence +void clientWait(); + +gpu::Size getDedicatedMemory(); +gpu::Size getFreeDedicatedMemory(); +ComparisonFunction comparisonFuncFromGL(GLenum func); +State::StencilOp stencilOpFromGL(GLenum stencilOp); +State::BlendOp blendOpFromGL(GLenum blendOp); +State::BlendArg blendArgFromGL(GLenum blendArg); +void getCurrentGLState(State::Data& state); + +struct ShaderObject { + GLuint glshader { 0 }; + GLuint glprogram { 0 }; + GLint transformCameraSlot { -1 }; + GLint transformObjectSlot { -1 }; +}; + +int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, + Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers); +int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers); +int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs); +int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs); +//CLIMAX_MERGE_START +//makeResourceBufferSlots has been added to glbacked as a virtual function and is being used in gl42 and gl45 overrides. +//Since these files dont exist in the andoid version create a stub here. +int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& resourceBuffers); +//CLIMAX_MERGE_END +void makeProgramBindings(ShaderObject& shaderObject); + +enum GLSyncState { + // The object is currently undergoing no processing, although it's content + // may be out of date, or it's storage may be invalid relative to the + // owning GPU object + Idle, + // The object has been queued for transfer to the GPU + Pending, + // The object has been transferred to the GPU, but is awaiting + // any post transfer operations that may need to occur on the + // primary rendering thread + Transferred, +}; + +static const GLenum BLEND_OPS_TO_GL[State::NUM_BLEND_OPS] = { + GL_FUNC_ADD, + GL_FUNC_SUBTRACT, + GL_FUNC_REVERSE_SUBTRACT, + GL_MIN, + GL_MAX +}; + +static const GLenum BLEND_ARGS_TO_GL[State::NUM_BLEND_ARGS] = { + GL_ZERO, + GL_ONE, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA_SATURATE, + GL_CONSTANT_COLOR, + GL_ONE_MINUS_CONSTANT_COLOR, + GL_CONSTANT_ALPHA, + GL_ONE_MINUS_CONSTANT_ALPHA, +}; + +static const GLenum COMPARISON_TO_GL[gpu::NUM_COMPARISON_FUNCS] = { + GL_NEVER, + GL_LESS, + GL_EQUAL, + GL_LEQUAL, + GL_GREATER, + GL_NOTEQUAL, + GL_GEQUAL, + GL_ALWAYS +}; + +static const GLenum PRIMITIVE_TO_GL[gpu::NUM_PRIMITIVES] = { + GL_POINTS, + GL_LINES, + GL_LINE_STRIP, + GL_TRIANGLES, + GL_TRIANGLE_STRIP, + GL_TRIANGLE_FAN, +}; + +static const GLenum ELEMENT_TYPE_TO_GL[gpu::NUM_TYPES] = { + GL_FLOAT, + GL_INT, + GL_UNSIGNED_INT, + GL_HALF_FLOAT, + GL_SHORT, + GL_UNSIGNED_SHORT, + GL_BYTE, + GL_UNSIGNED_BYTE, + // Normalized values + GL_INT, + GL_UNSIGNED_INT, + GL_SHORT, + GL_UNSIGNED_SHORT, + GL_BYTE, + GL_UNSIGNED_BYTE +}; + +bool checkGLError(const char* name = nullptr); +bool checkGLErrorDebug(const char* name = nullptr); + +class GLBackend; + +template +struct GLObject : public GPUObject { +public: + GLObject(const std::weak_ptr& backend, const GPUType& gpuObject, GLuint id) : _gpuObject(gpuObject), _id(id), _backend(backend) {} + + virtual ~GLObject() { } + + const GPUType& _gpuObject; + const GLuint _id; +protected: + const std::weak_ptr _backend; +}; + +class GlBuffer; +class GLFramebuffer; +class GLPipeline; +class GLQuery; +class GLState; +class GLShader; +class GLTexture; + +} } // namespace gpu::gl + +#define CHECK_GL_ERROR() gpu::gl::checkGLErrorDebug(__FUNCTION__) + +#endif + + + diff --git a/libraries/gpu-gles/src/gpu/gl/GLState.cpp b/libraries/gpu-gles/src/gpu/gl/GLState.cpp new file mode 100644 index 0000000000..b6d917b928 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLState.cpp @@ -0,0 +1,248 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1 +#pragma GCC diagnostic ignored "-Wsuggest-override" +#endif +#endif + + +#include "GLState.h" + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + + +#include "GLBackend.h" + +using namespace gpu; +using namespace gpu::gl; + +typedef GLState::Command Command; +typedef GLState::CommandPointer CommandPointer; +typedef GLState::Command1 Command1U; +typedef GLState::Command1 Command1I; +typedef GLState::Command1 Command1B; +typedef GLState::Command1 CommandDepthBias; +typedef GLState::Command1 CommandDepthTest; +typedef GLState::Command3 CommandStencil; +typedef GLState::Command1 CommandBlend; + +const GLState::Commands makeResetStateCommands(); + +// NOTE: This must stay in sync with the ordering of the State::Field enum +const GLState::Commands makeResetStateCommands() { + // Since State::DEFAULT is a static defined in another .cpp the initialisation order is random + // and we have a 50/50 chance that State::DEFAULT is not yet initialized. + // Since State::DEFAULT = State::Data() it is much easier to not use the actual State::DEFAULT + // but another State::Data object with a default initialization. + const State::Data DEFAULT = State::Data(); + + auto depthBiasCommand = std::make_shared(&GLBackend::do_setStateDepthBias, + Vec2(DEFAULT.depthBias, DEFAULT.depthBiasSlopeScale)); + auto stencilCommand = std::make_shared(&GLBackend::do_setStateStencil, DEFAULT.stencilActivation, + DEFAULT.stencilTestFront, DEFAULT.stencilTestBack); + + // The state commands to reset to default, + // WARNING depending on the order of the State::Field enum + return { + std::make_shared(&GLBackend::do_setStateFillMode, DEFAULT.fillMode), + std::make_shared(&GLBackend::do_setStateCullMode, DEFAULT.cullMode), + std::make_shared(&GLBackend::do_setStateFrontFaceClockwise, DEFAULT.frontFaceClockwise), + std::make_shared(&GLBackend::do_setStateDepthClampEnable, DEFAULT.depthClampEnable), + std::make_shared(&GLBackend::do_setStateScissorEnable, DEFAULT.scissorEnable), + std::make_shared(&GLBackend::do_setStateMultisampleEnable, DEFAULT.multisampleEnable), + std::make_shared(&GLBackend::do_setStateAntialiasedLineEnable, DEFAULT.antialisedLineEnable), + + // Depth bias has 2 fields in State but really one call in GLBackend + CommandPointer(depthBiasCommand), + CommandPointer(depthBiasCommand), + + std::make_shared(&GLBackend::do_setStateDepthTest, DEFAULT.depthTest), + + // Depth bias has 3 fields in State but really one call in GLBackend + CommandPointer(stencilCommand), + CommandPointer(stencilCommand), + CommandPointer(stencilCommand), + + std::make_shared(&GLBackend::do_setStateSampleMask, DEFAULT.sampleMask), + + std::make_shared(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.alphaToCoverageEnable), + + std::make_shared(&GLBackend::do_setStateBlend, DEFAULT.blendFunction), + + std::make_shared(&GLBackend::do_setStateColorWriteMask, DEFAULT.colorWriteMask) + }; +} + +const GLState::Commands GLState::_resetStateCommands = makeResetStateCommands(); + + +void generateFillMode(GLState::Commands& commands, State::FillMode fillMode) { + commands.push_back(std::make_shared(&GLBackend::do_setStateFillMode, int32(fillMode))); +} + +void generateCullMode(GLState::Commands& commands, State::CullMode cullMode) { + commands.push_back(std::make_shared(&GLBackend::do_setStateCullMode, int32(cullMode))); +} + +void generateFrontFaceClockwise(GLState::Commands& commands, bool isClockwise) { + commands.push_back(std::make_shared(&GLBackend::do_setStateFrontFaceClockwise, isClockwise)); +} + +void generateDepthClampEnable(GLState::Commands& commands, bool enable) { + commands.push_back(std::make_shared(&GLBackend::do_setStateDepthClampEnable, enable)); +} + +void generateScissorEnable(GLState::Commands& commands, bool enable) { + commands.push_back(std::make_shared(&GLBackend::do_setStateScissorEnable, enable)); +} + +void generateMultisampleEnable(GLState::Commands& commands, bool enable) { + commands.push_back(std::make_shared(&GLBackend::do_setStateMultisampleEnable, enable)); +} + +void generateAntialiasedLineEnable(GLState::Commands& commands, bool enable) { + commands.push_back(std::make_shared(&GLBackend::do_setStateAntialiasedLineEnable, enable)); +} + +void generateDepthBias(GLState::Commands& commands, const State& state) { + commands.push_back(std::make_shared(&GLBackend::do_setStateDepthBias, Vec2(state.getDepthBias(), state.getDepthBiasSlopeScale()))); +} + +void generateDepthTest(GLState::Commands& commands, const State::DepthTest& test) { + commands.push_back(std::make_shared(&GLBackend::do_setStateDepthTest, int32(test.getRaw()))); +} + +void generateStencil(GLState::Commands& commands, const State& state) { + commands.push_back(std::make_shared(&GLBackend::do_setStateStencil, state.getStencilActivation(), state.getStencilTestFront(), state.getStencilTestBack())); +} + +void generateAlphaToCoverageEnable(GLState::Commands& commands, bool enable) { + commands.push_back(std::make_shared(&GLBackend::do_setStateAlphaToCoverageEnable, enable)); +} + +void generateSampleMask(GLState::Commands& commands, uint32 mask) { + commands.push_back(std::make_shared(&GLBackend::do_setStateSampleMask, mask)); +} + +void generateBlend(GLState::Commands& commands, const State& state) { + commands.push_back(std::make_shared(&GLBackend::do_setStateBlend, state.getBlendFunction())); +} + +void generateColorWriteMask(GLState::Commands& commands, uint32 mask) { + commands.push_back(std::make_shared(&GLBackend::do_setStateColorWriteMask, mask)); +} + +GLState* GLState::sync(const State& state) { + GLState* object = Backend::getGPUObject(state); + + // If GPU object already created then good + if (object) { + return object; + } + + // Else allocate and create the GLState + if (!object) { + object = new GLState(); + Backend::setGPUObject(state, object); + } + + // here, we need to regenerate something so let's do it all + object->_commands.clear(); + object->_stamp = state.getStamp(); + object->_signature = state.getSignature(); + + bool depthBias = false; + bool stencilState = false; + + // go thorugh the list of state fields in the State and record the corresponding gl command + for (int i = 0; i < State::NUM_FIELDS; i++) { + if (state.getSignature()[i]) { + switch (i) { + case State::FILL_MODE: { + generateFillMode(object->_commands, state.getFillMode()); + break; + } + case State::CULL_MODE: { + generateCullMode(object->_commands, state.getCullMode()); + break; + } + case State::DEPTH_BIAS: + case State::DEPTH_BIAS_SLOPE_SCALE: { + depthBias = true; + break; + } + case State::FRONT_FACE_CLOCKWISE: { + generateFrontFaceClockwise(object->_commands, state.isFrontFaceClockwise()); + break; + } + case State::DEPTH_CLAMP_ENABLE: { + generateDepthClampEnable(object->_commands, state.isDepthClampEnable()); + break; + } + case State::SCISSOR_ENABLE: { + generateScissorEnable(object->_commands, state.isScissorEnable()); + break; + } + case State::MULTISAMPLE_ENABLE: { + generateMultisampleEnable(object->_commands, state.isMultisampleEnable()); + break; + } + case State::ANTIALISED_LINE_ENABLE: { + generateAntialiasedLineEnable(object->_commands, state.isAntialiasedLineEnable()); + break; + } + case State::DEPTH_TEST: { + generateDepthTest(object->_commands, state.getDepthTest()); + break; + } + + case State::STENCIL_ACTIVATION: + case State::STENCIL_TEST_FRONT: + case State::STENCIL_TEST_BACK: { + stencilState = true; + break; + } + + case State::SAMPLE_MASK: { + generateSampleMask(object->_commands, state.getSampleMask()); + break; + } + case State::ALPHA_TO_COVERAGE_ENABLE: { + generateAlphaToCoverageEnable(object->_commands, state.isAlphaToCoverageEnabled()); + break; + } + + case State::BLEND_FUNCTION: { + generateBlend(object->_commands, state); + break; + } + + case State::COLOR_WRITE_MASK: { + generateColorWriteMask(object->_commands, state.getColorWriteMask()); + break; + } + } + } + } + + if (depthBias) { + generateDepthBias(object->_commands, state); + } + + if (stencilState) { + generateStencil(object->_commands, state); + } + + return object; +} + diff --git a/libraries/gpu-gles/src/gpu/gl/GLState.h b/libraries/gpu-gles/src/gpu/gl/GLState.h new file mode 100644 index 0000000000..82635db893 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLState.h @@ -0,0 +1,73 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLState_h +#define hifi_gpu_gl_GLState_h + +#include "GLShared.h" + +#include + +namespace gpu { namespace gl { + +class GLBackend; +class GLState : public GPUObject { +public: + static GLState* sync(const State& state); + + class Command { + public: + virtual void run(GLBackend* backend) = 0; + Command() {} + virtual ~Command() {}; + }; + + template class Command1 : public Command { + public: + typedef void (GLBackend::*GLFunction)(T); + void run(GLBackend* backend) { (backend->*(_func))(_param); } + Command1(GLFunction func, T param) : _func(func), _param(param) {}; + GLFunction _func; + T _param; + }; + template class Command2 : public Command { + public: + typedef void (GLBackend::*GLFunction)(T, U); + void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1); } + Command2(GLFunction func, T param0, U param1) : _func(func), _param0(param0), _param1(param1) {}; + GLFunction _func; + T _param0; + U _param1; + }; + + template class Command3 : public Command { + public: + typedef void (GLBackend::*GLFunction)(T, U, V); + void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1, _param2); } + Command3(GLFunction func, T param0, U param1, V param2) : _func(func), _param0(param0), _param1(param1), _param2(param2) {}; + GLFunction _func; + T _param0; + U _param1; + V _param2; + }; + + typedef std::shared_ptr< Command > CommandPointer; + typedef std::vector< CommandPointer > Commands; + + Commands _commands; + Stamp _stamp; + State::Signature _signature; + + // The state commands to reset to default, + static const Commands _resetStateCommands; + + friend class GLBackend; +}; + +} } + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLTexelFormat.cpp b/libraries/gpu-gles/src/gpu/gl/GLTexelFormat.cpp new file mode 100644 index 0000000000..6eec4b5292 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLTexelFormat.cpp @@ -0,0 +1,648 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLTexelFormat.h" + +using namespace gpu; +using namespace gpu::gl; + + +GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { +// qDebug() << "GLTexelFormat::evalGLTexelFormatInternal " << dstFormat.getDimension() << ", " << dstFormat.getSemantic() << ", " << dstFormat.getType(); + GLenum result = GL_RGBA8; + switch (dstFormat.getDimension()) { + case gpu::SCALAR: { + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + case gpu::SRGB: + case gpu::SRGBA: + switch (dstFormat.getType()) { + case gpu::UINT32: + result = GL_R32UI; + break; + case gpu::INT32: + result = GL_R32I; + break; + case gpu::NUINT32: + result = GL_R8; + break; + case gpu::NINT32: + result = GL_R8_SNORM; + break; + case gpu::FLOAT: + result = GL_R32F; + break; + case gpu::UINT16: + result = GL_R16UI; + break; + case gpu::INT16: + result = GL_R16I; + break; + case gpu::HALF: + result = GL_R16F; + break; + case gpu::UINT8: + result = GL_R8UI; + break; + case gpu::INT8: + result = GL_R8I; + break; + case gpu::NUINT8: + if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) { + //result = GL_SLUMINANCE8; + qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormatInternal GL_SLUMINANCE8"; + } else { + result = GL_R8; + } + break; + case gpu::NINT8: + result = GL_R8_SNORM; + break; + default: + qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormatInternal " << dstFormat.getType(); + Q_UNREACHABLE(); + break; + } + break; + case gpu::R11G11B10: + // the type should be float + result = GL_R11F_G11F_B10F; + break; + + case gpu::DEPTH: + result = GL_DEPTH_COMPONENT16; + switch (dstFormat.getType()) { + case gpu::FLOAT: + result = GL_DEPTH_COMPONENT32F; + break; + case gpu::UINT16: + case gpu::INT16: + case gpu::NUINT16: + case gpu::NINT16: + case gpu::HALF: + result = GL_DEPTH_COMPONENT16; + break; + case gpu::UINT8: + case gpu::INT8: + case gpu::NUINT8: + case gpu::NINT8: + result = GL_DEPTH_COMPONENT24; + break; + default: + Q_UNREACHABLE(); + break; + } + break; + + case gpu::DEPTH_STENCIL: + result = GL_DEPTH24_STENCIL8; + break; + + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + break; + } + + case gpu::VEC2: { + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + result = GL_RG8; + break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC3: { + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + result = GL_RGB8; + break; + case gpu::SRGB: + case gpu::SRGBA: + //result = GL_SRGB8; // standard 2.2 gamma correction color + result = GL_RGB8; // standard 2.2 gamma correction color + break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC4: { + switch (dstFormat.getSemantic()) { + case gpu::RGB: + result = GL_RGB8; + break; + case gpu::RGBA: + switch (dstFormat.getType()) { + case gpu::UINT32: + result = GL_RGBA32UI; + break; + case gpu::INT32: + result = GL_RGBA32I; + break; + case gpu::FLOAT: + result = GL_RGBA32F; + break; + case gpu::UINT16: + result = GL_RGBA16UI; + break; + case gpu::INT16: + result = GL_RGBA16I; + break; + case gpu::HALF: + result = GL_RGBA16F; + break; + case gpu::UINT8: + result = GL_RGBA8UI; + break; + case gpu::INT8: + result = GL_RGBA8I; + break; + case gpu::NUINT8: + result = GL_RGBA8; + break; + case gpu::NINT8: + result = GL_RGBA8_SNORM; + break; + case gpu::NUINT32: + case gpu::NINT32: + case gpu::NUM_TYPES: // quiet compiler + Q_UNREACHABLE(); + } + break; + case gpu::SRGB: + //result = GL_SRGB8; + result = GL_RGB8; + qDebug() << "SRGBA Here 2"; + break; + case gpu::SRGBA: + result = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color + break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + break; + } + + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + + //qDebug() << "GLTexelFormat::evalGLTexelFormatInternal result " << result; + + return result; +} + +GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) { +// qDebug() << "GLTexelFormat::evalGLTexelFormat dst.getDimension=" << dstFormat.getDimension() << " dst.getType=" << dstFormat.getType() << " dst.getSemantic=" << dstFormat.getSemantic(); +// qDebug() << "GLTexelFormat::evalGLTexelFormat src.getDimension=" << srcFormat.getDimension() << " src.getType=" << srcFormat.getType() << " src.getSemantic=" << srcFormat.getSemantic(); + + if (dstFormat != srcFormat) { + GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }; + + switch (dstFormat.getDimension()) { + case gpu::SCALAR: { + texel.format = GL_RED; + texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_R8; + break; + + //CLIMAX_MERGE_START + // case gpu::COMPRESSED_R: + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RED_RGTC1"; + // //texel.internalFormat = GL_COMPRESSED_RED_RGTC1; + // break; + //CLIMAX_MERGE_END + + case gpu::DEPTH: + texel.internalFormat = GL_DEPTH_COMPONENT32_OES; + break; + case gpu::DEPTH_STENCIL: + texel.type = GL_UNSIGNED_INT_24_8; + texel.format = GL_DEPTH_STENCIL; + texel.internalFormat = GL_DEPTH24_STENCIL8; + break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + break; + } + + case gpu::VEC2: { + texel.format = GL_RG; + texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RG8; + break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC3: { + texel.format = GL_RGB; + + texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RGB8; + break; + //CLIMAX_MERGE_START + //not needed? + // case gpu::COMPRESSED_RGB: + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RGB"; + // //texel.internalFormat = GL_COMPRESSED_RGB; + // break; + // case gpu::COMPRESSED_SRGB: + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_SRGB"; + // //texel.internalFormat = GL_COMPRESSED_SRGB; + // break; + //CLIMAX_MERGE_END + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC4: { + texel.format = GL_RGBA; + texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()]; + + switch (srcFormat.getSemantic()) { + case gpu::BGRA: + case gpu::SBGRA: + qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_BGRA"; + //texel.format = GL_BGRA; + break; + case gpu::RGB: + case gpu::RGBA: + case gpu::SRGB: + case gpu::SRGBA: + default: + break; + }; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + texel.internalFormat = GL_RGB8; + break; + case gpu::RGBA: + texel.internalFormat = GL_RGBA8; + break; + case gpu::SRGB: + //texel.internalFormat = GL_SRGB8; + texel.internalFormat = GL_RGB8; + qDebug() << "SRGBA Here 3"; + break; + case gpu::SRGBA: + texel.internalFormat = GL_SRGB8_ALPHA8; + break; + + //CLIMAX_MERGE_START + // case gpu::COMPRESSED_RGBA: + // //texel.internalFormat = GL_COMPRESSED_RGBA; + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RGBA"; + // break; + // case gpu::COMPRESSED_SRGBA: + // //texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA; + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_SRGB_ALPHA"; + // break; + //CLIMAX_MERGE_END + // FIXME: WE will want to support this later + /* + case gpu::COMPRESSED_BC3_RGBA: + texel.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case gpu::COMPRESSED_BC3_SRGBA: + texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + break; + + case gpu::COMPRESSED_BC7_RGBA: + texel.internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + break; + case gpu::COMPRESSED_BC7_SRGBA: + texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; + break; + */ + + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + break; + } + + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + return texel; + } else { + GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }; + + switch (dstFormat.getDimension()) { + case gpu::SCALAR: { + texel.format = GL_RED; + texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + //CLIMAX_MERGE_START + // case gpu::COMPRESSED_R: { + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RED_RGTC1"; + // //texel.internalFormat = GL_COMPRESSED_RED_RGTC1; + // break; + // } + case gpu::RGB: + case gpu::RGBA: + case gpu::SRGB: + case gpu::SRGBA: + texel.internalFormat = GL_RED; + switch (dstFormat.getType()) { + case gpu::UINT32: { + texel.internalFormat = GL_R32UI; + break; + } + case gpu::INT32: { + texel.internalFormat = GL_R32I; + break; + } + case gpu::NUINT32: { + texel.internalFormat = GL_R8; + break; + } + case gpu::NINT32: { + texel.internalFormat = GL_R8_SNORM; + break; + } + case gpu::FLOAT: { + texel.internalFormat = GL_R32F; + break; + } + case gpu::UINT16: { + texel.internalFormat = GL_R16UI; + break; + } + case gpu::INT16: { + texel.internalFormat = GL_R16I; + break; + } + case gpu::NUINT16: { + //texel.internalFormat = GL_R16; + qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_R16"; + break; + } + case gpu::NINT16: { + //texel.internalFormat = GL_R16_SNORM; + qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_R16_SNORM"; + break; + } + case gpu::HALF: { + texel.internalFormat = GL_R16F; + break; + } + case gpu::UINT8: { + texel.internalFormat = GL_R8UI; + break; + } + case gpu::INT8: { + texel.internalFormat = GL_R8I; + break; + } + case gpu::NUINT8: { + if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) { +// texel.internalFormat = GL_SLUMINANCE8; + qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_SLUMINANCE8"; + + } else { + texel.internalFormat = GL_R8; + } + break; + } + case gpu::NINT8: { + texel.internalFormat = GL_R8_SNORM; + break; + } + case gpu::NUM_TYPES: { // quiet compiler + Q_UNREACHABLE(); + } + + } + break; + + case gpu::R11G11B10: + texel.format = GL_RGB; + // the type should be float + texel.internalFormat = GL_R11F_G11F_B10F; + break; + + case gpu::DEPTH: + texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it + texel.internalFormat = GL_DEPTH_COMPONENT32_OES; + switch (dstFormat.getType()) { + case gpu::UINT32: + case gpu::INT32: + case gpu::NUINT32: + case gpu::NINT32: { + texel.internalFormat = GL_DEPTH_COMPONENT32_OES; + break; + } + case gpu::FLOAT: { + texel.internalFormat = GL_DEPTH_COMPONENT32F; + break; + } + case gpu::UINT16: + case gpu::INT16: + case gpu::NUINT16: + case gpu::NINT16: + case gpu::HALF: { + texel.internalFormat = GL_DEPTH_COMPONENT16; + break; + } + case gpu::UINT8: + case gpu::INT8: + case gpu::NUINT8: + case gpu::NINT8: { + texel.internalFormat = GL_DEPTH_COMPONENT24; + break; + } + case gpu::NUM_TYPES: { // quiet compiler + Q_UNREACHABLE(); + } + } + break; + case gpu::DEPTH_STENCIL: + texel.type = GL_UNSIGNED_INT_24_8; + texel.format = GL_DEPTH_STENCIL; + texel.internalFormat = GL_DEPTH24_STENCIL8; + break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC2: { + texel.format = GL_RG; + texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RG8; + break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC3: { + texel.format = GL_RGB; + + texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RGB8; + break; + case gpu::SRGB: + case gpu::SRGBA: + //texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color + texel.internalFormat = GL_RGB8; // standard 2.2 gamma correction color + break; + //CLIMAX_MERGE_START + // case gpu::COMPRESSED_RGB: + // //texel.internalFormat = GL_COMPRESSED_RGB; + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RGB"; + // break; + // case gpu::COMPRESSED_SRGB: + // //texel.internalFormat = GL_COMPRESSED_SRGB; + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_SRGB"; + // break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + break; + } + + case gpu::VEC4: { + texel.format = GL_RGBA; + texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()]; + + switch (dstFormat.getSemantic()) { + case gpu::RGB: + texel.internalFormat = GL_RGB8; + break; + case gpu::RGBA: + texel.internalFormat = GL_RGBA8; + switch (dstFormat.getType()) { + case gpu::UINT32: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA32UI; + break; + case gpu::INT32: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA32I; + break; + case gpu::FLOAT: + texel.internalFormat = GL_RGBA32F; + break; + case gpu::UINT16: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA16UI; + break; + case gpu::INT16: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA16I; + break; + case gpu::NUINT16: + texel.format = GL_RGBA; + //texel.internalFormat = GL_RGBA16; + qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_RGBA16"; + break; + case gpu::NINT16: + texel.format = GL_RGBA; + qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_RGBA16_SNORM"; + //texel.internalFormat = GL_RGBA16_SNORM; + break; + case gpu::HALF: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16F; + break; + case gpu::UINT8: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA8UI; + break; + case gpu::INT8: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA8I; + break; + case gpu::NUINT8: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA8; + break; + case gpu::NINT8: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA8_SNORM; + break; + case gpu::NUINT32: + case gpu::NINT32: + case gpu::NUM_TYPES: // quiet compiler + Q_UNREACHABLE(); + } + break; + case gpu::SRGB: + //texel.internalFormat = GL_SRGB8; + texel.internalFormat = GL_RGB8; // standard 2.2 gamma correction color + break; + case gpu::SRGBA: + texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color + break; + //CLIMAX_MERGE_START + // case gpu::COMPRESSED_RGBA: + // //texel.internalFormat = GL_COMPRESSED_RGBA; + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RGBA"; + // break; + // case gpu::COMPRESSED_SRGBA: + // qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_SRGB_ALPHA"; + // //texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA; + // break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + break; + } + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + //qDebug() << "GLTexelFormat::evalGLTexelFormat Texel.type " << texel.type << " - texel.format=" << texel.format << " texel.internalFormat=" << texel.internalFormat; + return texel; + } +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLTexelFormat.h b/libraries/gpu-gles/src/gpu/gl/GLTexelFormat.h new file mode 100644 index 0000000000..94ded3dc23 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLTexelFormat.h @@ -0,0 +1,32 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLTexelFormat_h +#define hifi_gpu_gl_GLTexelFormat_h + +#include "GLShared.h" + +namespace gpu { namespace gl { + +class GLTexelFormat { +public: + GLenum internalFormat; + GLenum format; + GLenum type; + + static GLTexelFormat evalGLTexelFormat(const Element& dstFormat) { + return evalGLTexelFormat(dstFormat, dstFormat); + } + static GLenum evalGLTexelFormatInternal(const Element& dstFormat); + + static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat); +}; + +} } + + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gles/src/gpu/gl/GLTexture.cpp new file mode 100644 index 0000000000..5f5e3a9be1 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLTexture.cpp @@ -0,0 +1,323 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLTexture.h" + +#include + +#include "GLTextureTransfer.h" +#include "GLBackend.h" + +using namespace gpu; +using namespace gpu::gl; + +std::shared_ptr GLTexture::_textureTransferHelper; + +// FIXME placeholder for texture memory over-use +#define DEFAULT_MAX_MEMORY_MB 256 +#define MIN_FREE_GPU_MEMORY_PERCENTAGE 0.25f +#define OVER_MEMORY_PRESSURE 2.0f + +const GLenum GLTexture::CUBE_FACE_LAYOUT[6] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; + +const GLenum GLTexture::WRAP_MODES[Sampler::NUM_WRAP_MODES] = { + GL_REPEAT, // WRAP_REPEAT, + GL_MIRRORED_REPEAT, // WRAP_MIRROR, + GL_CLAMP_TO_EDGE, // WRAP_CLAMP, + GL_CLAMP_TO_BORDER_EXT, // WRAP_BORDER, + + //GL_MIRROR_CLAMP_TO_EDGE_EXT // WRAP_MIRROR_ONCE, +// qDebug() << "TODO: GLTexture.cpp:WRAP_MODES GL_MIRROR_CLAMP_TO_EDGE_EXT"; +}; + +const GLFilterMode GLTexture::FILTER_MODES[Sampler::NUM_FILTERS] = { + { GL_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_POINT, + { GL_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR, + { GL_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT, + { GL_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR, + + { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT, + { GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_MAG_POINT_MIP_LINEAR, + { GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, + { GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_POINT_MAG_MIP_LINEAR, + { GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_MIP_POINT, + { GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, + { GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR_MIP_POINT, + { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_MIP_LINEAR, + { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR } //FILTER_ANISOTROPIC, +}; + +GLenum GLTexture::getGLTextureType(const Texture& texture) { + switch (texture.getType()) { + case Texture::TEX_2D: + return GL_TEXTURE_2D; + break; + + case Texture::TEX_CUBE: + return GL_TEXTURE_CUBE_MAP; + break; + + default: + qFatal("Unsupported texture type"); + } + Q_UNREACHABLE(); + return GL_TEXTURE_2D; +} + + +const std::vector& GLTexture::getFaceTargets(GLenum target) { + static std::vector cubeFaceTargets { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z + }; + static std::vector faceTargets { + GL_TEXTURE_2D + }; + switch (target) { + case GL_TEXTURE_2D: + return faceTargets; + case GL_TEXTURE_CUBE_MAP: + return cubeFaceTargets; + default: + Q_UNREACHABLE(); + break; + } + Q_UNREACHABLE(); + return faceTargets; +} + +// Default texture memory = GPU total memory - 2GB +#define GPU_MEMORY_RESERVE_BYTES MB_TO_BYTES(2048) +// Minimum texture memory = 1GB +#define TEXTURE_MEMORY_MIN_BYTES MB_TO_BYTES(1024) + + +float GLTexture::getMemoryPressure() { + // Check for an explicit memory limit + auto availableTextureMemory = Texture::getAllowedGPUMemoryUsage(); + + + // If no memory limit has been set, use a percentage of the total dedicated memory + if (!availableTextureMemory) { +#if 0 + auto totalMemory = getDedicatedMemory(); + if ((GPU_MEMORY_RESERVE_BYTES + TEXTURE_MEMORY_MIN_BYTES) > totalMemory) { + availableTextureMemory = TEXTURE_MEMORY_MIN_BYTES; + } else { + availableTextureMemory = totalMemory - GPU_MEMORY_RESERVE_BYTES; + } +#else + // Hardcode texture limit for sparse textures at 1 GB for now + availableTextureMemory = TEXTURE_MEMORY_MIN_BYTES; +#endif + } + + // Return the consumed texture memory divided by the available texture memory. + //CLIMAX_MERGE_START + //auto consumedGpuMemory = Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage(); + //float memoryPressure = (float)consumedGpuMemory / (float)availableTextureMemory; + //static Context::Size lastConsumedGpuMemory = 0; + //if (memoryPressure > 1.0f && lastConsumedGpuMemory != consumedGpuMemory) { + // lastConsumedGpuMemory = consumedGpuMemory; + // qCDebug(gpugllogging) << "Exceeded max allowed texture memory: " << consumedGpuMemory << " / " << availableTextureMemory; + //} + //return memoryPressure; + return 0; + +} + + +// Create the texture and allocate storage +GLTexture::GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id, bool transferrable) : + GLObject(backend, texture, id), + _external(false), + _source(texture.source()), + _storageStamp(texture.getStamp()), + _target(getGLTextureType(texture)), + _internalFormat(gl::GLTexelFormat::evalGLTexelFormatInternal(texture.getTexelFormat())), + _maxMip(texture.getMaxMip()), + _minMip(texture.getMinMip()), + _virtualSize(texture.evalTotalSize()), + _transferrable(transferrable) +{ + //qDebug() << "GLTexture::GLTexture building GLTexture with _internalFormat" << _internalFormat; + auto strongBackend = _backend.lock(); + strongBackend->recycle(); + //CLIMAX_MERGE_START + //Backend::incrementTextureGPUCount(); + //Backend::updateTextureGPUVirtualMemoryUsage(0, _virtualSize); + //CLIMAX_MERGE_END + Backend::setGPUObject(texture, this); +} + +GLTexture::GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id) : + GLObject(backend, texture, id), + _external(true), + _source(texture.source()), + _storageStamp(0), + _target(getGLTextureType(texture)), + _internalFormat(GL_RGBA8), + // FIXME force mips to 0? + _maxMip(texture.getMaxMip()), + _minMip(texture.getMinMip()), + _virtualSize(0), + _transferrable(false) +{ + Backend::setGPUObject(texture, this); + + // FIXME Is this necessary? + //withPreservedTexture([this] { + // syncSampler(); + // if (_gpuObject.isAutogenerateMips()) { + // generateMips(); + // } + //}); +} + +GLTexture::~GLTexture() { + auto backend = _backend.lock(); + if (backend) { + if (_external) { + auto recycler = _gpuObject.getExternalRecycler(); + if (recycler) { + backend->releaseExternalTexture(_id, recycler); + } else { + qWarning() << "No recycler available for texture " << _id << " possible leak"; + } + } else if (_id) { + // WARNING! Sparse textures do not use this code path. See GL45BackendTexture for + // the GL45Texture destructor for doing any required work tracking GPU stats + backend->releaseTexture(_id, _size); + } + + ////CLIMAX_MERGE_START + //if (!_external && !_transferrable) { + // Backend::updateTextureGPUFramebufferMemoryUsage(_size, 0); + //} + } + //Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0); + //CLIMAX_MERGE_END +} + +void GLTexture::createTexture() { + withPreservedTexture([&] { + allocateStorage(); + (void)CHECK_GL_ERROR(); + syncSampler(); + (void)CHECK_GL_ERROR(); + }); +} + +void GLTexture::withPreservedTexture(std::function f) const { + GLint boundTex = -1; + switch (_target) { + case GL_TEXTURE_2D: + glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); + break; + + case GL_TEXTURE_CUBE_MAP: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex); + break; + + default: + qFatal("Unsupported texture type"); + } + (void)CHECK_GL_ERROR(); + + glBindTexture(_target, _texture); + f(); + glBindTexture(_target, boundTex); + (void)CHECK_GL_ERROR(); +} + +void GLTexture::setSize(GLuint size) const { + ////CLIMAX_MERGE_START + //if (!_external && !_transferrable) { + // Backend::updateTextureGPUFramebufferMemoryUsage(_size, 0); + //} + //Backend::updateTextureGPUMemoryUsage(_size, size); + const_cast(_size) = size; +} + +bool GLTexture::isInvalid() const { + return _storageStamp < _gpuObject.getStamp(); +} + +bool GLTexture::isOutdated() const { + return GLSyncState::Idle == _syncState && _contentStamp < _gpuObject.getDataStamp(); +} + +bool GLTexture::isReady() const { + // If we have an invalid texture, we're never ready + if (isInvalid()) { + return false; + } + + auto syncState = _syncState.load(); + if (isOutdated() || Idle != syncState) { + return false; + } + + return true; +} + + +// Do any post-transfer operations that might be required on the main context / rendering thread +void GLTexture::postTransfer() { + //CLIMAX_MERGE_START + + // setSyncState(GLSyncState::Idle); + // ++_transferCount; + + // // At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory + // switch (_gpuObject.getType()) { + // case Texture::TEX_2D: + // for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) { + // if (_gpuObject.isStoredMipFaceAvailable(i)) { + // _gpuObject.notifyMipFaceGPULoaded(i); + // } + // } + // break; + + // case Texture::TEX_CUBE: + // // transfer pixels from each faces + // for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) { + // for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) { + // if (_gpuObject.isStoredMipFaceAvailable(i, f)) { + // _gpuObject.notifyMipFaceGPULoaded(i, f); + // } + // } + // } + // break; + + // default: + // qCWarning(gpugllogging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported"; + // break; + // } + //CLIMAX_MERGE_END +} + +void GLTexture::initTextureTransferHelper() { + _textureTransferHelper = std::make_shared(); +} + +void GLTexture::startTransfer() { + createTexture(); +} + +void GLTexture::finishTransfer() { + if (_gpuObject.isAutogenerateMips()) { + generateMips(); + } +} + diff --git a/libraries/gpu-gles/src/gpu/gl/GLTexture.h b/libraries/gpu-gles/src/gpu/gl/GLTexture.h new file mode 100644 index 0000000000..03353ae67d --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLTexture.h @@ -0,0 +1,233 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLTexture_h +#define hifi_gpu_gl_GLTexture_h + +#include "GLShared.h" +#include "GLTextureTransfer.h" +#include "GLBackend.h" +#include "GLTexelFormat.h" + +namespace gpu { namespace gl { + +struct GLFilterMode { + GLint minFilter; + GLint magFilter; +}; + + +class GLTexture : public GLObject { +public: + static const uint16_t INVALID_MIP { (uint16_t)-1 }; + static const uint8_t INVALID_FACE { (uint8_t)-1 }; + + static void initTextureTransferHelper(); + static std::shared_ptr _textureTransferHelper; + + template + static GLTexture* sync(GLBackend& backend, const TexturePointer& texturePointer, bool needTransfer) { + const Texture& texture = *texturePointer; + + // Special case external textures + //CLIMAX_MERGE_START + //Z:/HiFi_Android/HiFi_GIT/libraries/gpu-gl-android/src/gpu/gl/../gles/../gl/GLTexture.h:37:32: error: no member named 'isExternal' in 'gpu::Texture::Usage' + // The only instance of this being used again. replace. + // if (texture.getUsage().isExternal()) { + // Texture::ExternalUpdates updates = texture.getUpdates(); + // if (!updates.empty()) { + // Texture::ExternalRecycler recycler = texture.getExternalRecycler(); + // Q_ASSERT(recycler); + // // Discard any superfluous updates + // while (updates.size() > 1) { + // const auto& update = updates.front(); + // // Superfluous updates will never have been read, but we want to ensure the previous + // // writes to them are complete before they're written again, so return them with the + // // same fences they arrived with. This can happen on any thread because no GL context + // // work is involved + // recycler(update.first, update.second); + // updates.pop_front(); + // } + + // // The last texture remaining is the one we'll use to create the GLTexture + // const auto& update = updates.front(); + // // Check for a fence, and if it exists, inject a wait into the command stream, then destroy the fence + // if (update.second) { + // GLsync fence = static_cast(update.second); + // glWaitSync(fence, 0, GL_TIMEOUT_IGNORED); + // glDeleteSync(fence); + // } + + // // Create the new texture object (replaces any previous texture object) + // new GLTextureType(backend.shared_from_this(), texture, update.first); + // } + + + // Return the texture object (if any) associated with the texture, without extensive logic + // (external textures are + //return Backend::getGPUObject(texture); + //} + //CLIMAX_MERGE_END + if (!texture.isDefined()) { + // NO texture definition yet so let's avoid thinking + return nullptr; + } + + // If the object hasn't been created, or the object definition is out of date, drop and re-create + GLTexture* object = Backend::getGPUObject(texture); + + // Create the texture if need be (force re-creation if the storage stamp changes + // for easier use of immutable storage) + if (!object || object->isInvalid()) { + // This automatically any previous texture + object = new GLTextureType(backend.shared_from_this(), texture, needTransfer); + if (!object->_transferrable) { + object->createTexture(); + object->_contentStamp = texture.getDataStamp(); + object->updateSize(); + object->postTransfer(); + } + } + + // Object maybe doens't neet to be tranasferred after creation + if (!object->_transferrable) { + return object; + } + + // If we just did a transfer, return the object after doing post-transfer work + if (GLSyncState::Transferred == object->getSyncState()) { + object->postTransfer(); + } + + if (object->isOutdated()) { + // Object might be outdated, if so, start the transfer + // (outdated objects that are already in transfer will have reported 'true' for ready() + _textureTransferHelper->transferTexture(texturePointer); + return nullptr; + } + + if (!object->isReady()) { + return nullptr; + } + + ((GLTexture*)object)->updateMips(); + + return object; + } + + template + static GLuint getId(GLBackend& backend, const TexturePointer& texture, bool shouldSync) { + if (!texture) { + return 0; + } + GLTexture* object { nullptr }; + if (shouldSync) { + object = sync(backend, texture, shouldSync); + } else { + object = Backend::getGPUObject(*texture); + } + + if (!object) { + return 0; + } + + if (!shouldSync) { + return object->_id; + } + + // Don't return textures that are in transfer state + if ((object->getSyncState() != GLSyncState::Idle) || + // Don't return transferrable textures that have never completed transfer + (!object->_transferrable || 0 != object->_transferCount)) { + return 0; + } + + return object->_id; + } + + ~GLTexture(); + + // Is this texture generated outside the GPU library? + const bool _external; + const GLuint& _texture { _id }; + const std::string _source; + const Stamp _storageStamp; + const GLenum _target; + const GLenum _internalFormat; + const uint16 _maxMip; + uint16 _minMip; + const GLuint _virtualSize; // theoretical size as expected + Stamp _contentStamp { 0 }; + const bool _transferrable; + Size _transferCount { 0 }; + GLuint size() const { return _size; } + GLSyncState getSyncState() const { return _syncState; } + + // Is the storage out of date relative to the gpu texture? + bool isInvalid() const; + + // Is the content out of date relative to the gpu texture? + bool isOutdated() const; + + // Is the texture in a state where it can be rendered with no work? + bool isReady() const; + + // Execute any post-move operations that must occur only on the main thread + virtual void postTransfer(); + + uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; } + + static const size_t CUBE_NUM_FACES = 6; + static const GLenum CUBE_FACE_LAYOUT[6]; + static const GLFilterMode FILTER_MODES[Sampler::NUM_FILTERS]; + static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES]; + + // Return a floating point value indicating how much of the allowed + // texture memory we are currently consuming. A value of 0 indicates + // no texture memory usage, while a value of 1 indicates all available / allowed memory + // is consumed. A value above 1 indicates that there is a problem. + static float getMemoryPressure(); +protected: + + static const std::vector& getFaceTargets(GLenum textureType); + + static GLenum getGLTextureType(const Texture& texture); + + + const GLuint _size { 0 }; // true size as reported by the gl api + std::atomic _syncState { GLSyncState::Idle }; + + GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id, bool transferrable); + GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id); + + void setSyncState(GLSyncState syncState) { _syncState = syncState; } + + void createTexture(); + + virtual void updateMips() {} + virtual void allocateStorage() const = 0; + virtual void updateSize() const = 0; + virtual void syncSampler() const = 0; + virtual void generateMips() const = 0; + virtual void withPreservedTexture(std::function f) const; + +protected: + void setSize(GLuint size) const; + + virtual void startTransfer(); + // Returns true if this is the last block required to complete transfer + virtual bool continueTransfer() { return false; } + virtual void finishTransfer(); + +private: + friend class GLTextureTransferHelper; + friend class GLBackend; +}; + +} } + +#endif diff --git a/libraries/gpu-gles/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gles/src/gpu/gl/GLTextureTransfer.cpp new file mode 100644 index 0000000000..cec46cb90d --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLTextureTransfer.cpp @@ -0,0 +1,207 @@ +// +// Created by Bradley Austin Davis on 2016/04/03 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLTextureTransfer.h" + +#include +#include + +#include "GLShared.h" +#include "GLTexture.h" + +#ifdef HAVE_NSIGHT +#include "nvToolsExt.h" +std::unordered_map _map; +#endif + + +#ifdef TEXTURE_TRANSFER_PBOS +#define TEXTURE_TRANSFER_BLOCK_SIZE (64 * 1024) +#define TEXTURE_TRANSFER_PBO_COUNT 128 +#endif + +using namespace gpu; +using namespace gpu::gl; + +GLTextureTransferHelper::GLTextureTransferHelper() { +#ifdef THREADED_TEXTURE_TRANSFER + setObjectName("TextureTransferThread"); + _context.create(); + initialize(true, QThread::LowPriority); + // Clean shutdown on UNIX, otherwise _canvas is freed early + connect(qApp, &QCoreApplication::aboutToQuit, [&] { terminate(); }); +#else + initialize(false, QThread::LowPriority); +#endif +} + +GLTextureTransferHelper::~GLTextureTransferHelper() { +#ifdef THREADED_TEXTURE_TRANSFER + if (isStillRunning()) { + terminate(); + } +#else + terminate(); +#endif +} + +void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) { + GLTexture* object = Backend::getGPUObject(*texturePointer); + + //CLIMAX_MERGE_START + //Backend::incrementTextureGPUTransferCount(); + object->setSyncState(GLSyncState::Pending); + Lock lock(_mutex); + _pendingTextures.push_back(texturePointer); +} + +void GLTextureTransferHelper::setup() { +#ifdef THREADED_TEXTURE_TRANSFER + _context.makeCurrent(); + +#ifdef TEXTURE_TRANSFER_FORCE_DRAW + // FIXME don't use opengl 4.5 DSA functionality without verifying it's present + glCreateRenderbuffers(1, &_drawRenderbuffer); + glNamedRenderbufferStorage(_drawRenderbuffer, GL_RGBA8, 128, 128); + glCreateFramebuffers(1, &_drawFramebuffer); + glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _drawRenderbuffer); + glCreateFramebuffers(1, &_readFramebuffer); +#endif + +#ifdef TEXTURE_TRANSFER_PBOS + std::array pbos; + glCreateBuffers(TEXTURE_TRANSFER_PBO_COUNT, &pbos[0]); + for (uint32_t i = 0; i < TEXTURE_TRANSFER_PBO_COUNT; ++i) { + TextureTransferBlock newBlock; + newBlock._pbo = pbos[i]; + glNamedBufferStorage(newBlock._pbo, TEXTURE_TRANSFER_BLOCK_SIZE, 0, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + newBlock._mapped = glMapNamedBufferRange(newBlock._pbo, 0, TEXTURE_TRANSFER_BLOCK_SIZE, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + _readyQueue.push(newBlock); + } +#endif +#endif +} + +void GLTextureTransferHelper::shutdown() { +#ifdef THREADED_TEXTURE_TRANSFER + _context.makeCurrent(); +#endif + +#ifdef TEXTURE_TRANSFER_FORCE_DRAW + glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0); + glDeleteFramebuffers(1, &_drawFramebuffer); + _drawFramebuffer = 0; + glDeleteFramebuffers(1, &_readFramebuffer); + _readFramebuffer = 0; + + glNamedFramebufferTexture(_readFramebuffer, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0); + glDeleteRenderbuffers(1, &_drawRenderbuffer); + _drawRenderbuffer = 0; +#endif +} + +void GLTextureTransferHelper::queueExecution(VoidLambda lambda) { + Lock lock(_mutex); + _pendingCommands.push_back(lambda); +} + +#define MAX_TRANSFERS_PER_PASS 2 + +bool GLTextureTransferHelper::process() { + // Take any new textures or commands off the queue + VoidLambdaList pendingCommands; + TextureList newTransferTextures; + { + Lock lock(_mutex); + newTransferTextures.swap(_pendingTextures); + pendingCommands.swap(_pendingCommands); + } + + if (!pendingCommands.empty()) { + for (auto command : pendingCommands) { + command(); + } + glFlush(); + } + + if (!newTransferTextures.empty()) { + for (auto& texturePointer : newTransferTextures) { +#ifdef HAVE_NSIGHT + _map[texturePointer] = nvtxRangeStart("TextureTansfer"); +#endif + GLTexture* object = Backend::getGPUObject(*texturePointer); + object->startTransfer(); + _transferringTextures.push_back(texturePointer); + _textureIterator = _transferringTextures.begin(); + } + _transferringTextures.sort([](const gpu::TexturePointer& a, const gpu::TexturePointer& b)->bool { + return a->getSize() < b->getSize(); + }); + } + + // No transfers in progress, sleep + if (_transferringTextures.empty()) { +#ifdef THREADED_TEXTURE_TRANSFER + QThread::usleep(1); +#endif + return true; + } + + static auto lastReport = usecTimestampNow(); + auto now = usecTimestampNow(); + auto lastReportInterval = now - lastReport; + if (lastReportInterval > USECS_PER_SECOND * 4) { + lastReport = now; + qDebug() << "Texture list " << _transferringTextures.size(); + } + + size_t transferCount = 0; + for (_textureIterator = _transferringTextures.begin(); _textureIterator != _transferringTextures.end();) { + if (++transferCount > MAX_TRANSFERS_PER_PASS) { + break; + } + auto texture = *_textureIterator; + GLTexture* gltexture = Backend::getGPUObject(*texture); + if (gltexture->continueTransfer()) { + ++_textureIterator; + continue; + } + + gltexture->finishTransfer(); + +#ifdef TEXTURE_TRANSFER_FORCE_DRAW + // FIXME force a draw on the texture transfer thread before passing the texture to the main thread for use +#endif + +#ifdef THREADED_TEXTURE_TRANSFER + clientWait(); +#endif + gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp(); + gltexture->updateSize(); + gltexture->setSyncState(gpu::gl::GLSyncState::Transferred); + //CLIMAX_MERGE_START + //Backend::decrementTextureGPUTransferCount(); +#ifdef HAVE_NSIGHT + // Mark the texture as transferred + nvtxRangeEnd(_map[texture]); + _map.erase(texture); +#endif + _textureIterator = _transferringTextures.erase(_textureIterator); + } + +#ifdef THREADED_TEXTURE_TRANSFER + if (!_transferringTextures.empty()) { + // Don't saturate the GPU + clientWait(); + } else { + // Don't saturate the CPU + QThread::msleep(1); + } +#endif + + return true; +} diff --git a/libraries/gpu-gles/src/gpu/gl/GLTextureTransfer.h b/libraries/gpu-gles/src/gpu/gl/GLTextureTransfer.h new file mode 100644 index 0000000000..a23c282fd4 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gl/GLTextureTransfer.h @@ -0,0 +1,78 @@ +// +// Created by Bradley Austin Davis on 2016/04/03 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gl_GLTextureTransfer_h +#define hifi_gpu_gl_GLTextureTransfer_h + +#include +#include + +#include + +#include + +#include "GLShared.h" + +#ifdef Q_OS_WIN +#define THREADED_TEXTURE_TRANSFER +#endif + +#ifdef THREADED_TEXTURE_TRANSFER +// FIXME when sparse textures are enabled, it's harder to force a draw on the transfer thread +// also, the current draw code is implicitly using OpenGL 4.5 functionality +//#define TEXTURE_TRANSFER_FORCE_DRAW +// FIXME PBO's increase the complexity and don't seem to work reliably +//#define TEXTURE_TRANSFER_PBOS +#endif + +namespace gpu { namespace gl { + +using TextureList = std::list; +using TextureListIterator = TextureList::iterator; + +class GLTextureTransferHelper : public GenericThread { +public: + using VoidLambda = std::function; + using VoidLambdaList = std::list; + using Pointer = std::shared_ptr; + GLTextureTransferHelper(); + ~GLTextureTransferHelper(); + void transferTexture(const gpu::TexturePointer& texturePointer); + void queueExecution(VoidLambda lambda); + + void setup() override; + void shutdown() override; + bool process() override; + +private: +#ifdef THREADED_TEXTURE_TRANSFER + ::gl::OffscreenContext _context; +#endif + +#ifdef TEXTURE_TRANSFER_FORCE_DRAW + // Framebuffers / renderbuffers for forcing access to the texture on the transfer thread + GLuint _drawRenderbuffer { 0 }; + GLuint _drawFramebuffer { 0 }; + GLuint _readFramebuffer { 0 }; +#endif + + // A mutex for protecting items access on the render and transfer threads + Mutex _mutex; + // Commands that have been submitted for execution on the texture transfer thread + VoidLambdaList _pendingCommands; + // Textures that have been submitted for transfer + TextureList _pendingTextures; + // Textures currently in the transfer process + // Only used on the transfer thread + TextureList _transferringTextures; + TextureListIterator _textureIterator; + +}; + +} } + +#endif \ No newline at end of file diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp new file mode 100644 index 0000000000..8c843c1ce3 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp @@ -0,0 +1,197 @@ +// +// Created by Gabriel Calero & Cristian Duarte on 9/27/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLESBackend.h" + +#include +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(gpugleslogging, "hifi.gpu.gles") + +using namespace gpu; +using namespace gpu::gles; + +const std::string GLESBackend::GLES_VERSION { "GLES" }; + +void GLESBackend::do_draw(const Batch& batch, size_t paramOffset) { + Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numVertices = batch._params[paramOffset + 1]._uint; + uint32 startVertex = batch._params[paramOffset + 0]._uint; + + if (isStereo()) { +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + glDrawArraysInstanced(mode, startVertex, numVertices, 2); +#else + + setupStereoSide(0); + glDrawArrays(mode, startVertex, numVertices); + setupStereoSide(1); + glDrawArrays(mode, startVertex, numVertices); + +#endif + _stats._DSNumTriangles += 2 * numVertices / 3; + _stats._DSNumDrawcalls += 2; + + } else { + glDrawArrays(mode, startVertex, numVertices); + _stats._DSNumTriangles += numVertices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void) CHECK_GL_ERROR(); +} + +void GLESBackend::do_drawIndexed(const Batch& batch, size_t paramOffset) { + Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numIndices = batch._params[paramOffset + 1]._uint; + uint32 startIndex = batch._params[paramOffset + 0]._uint; + + GLenum glType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType]; + + auto typeByteSize = TYPE_SIZE[_input._indexBufferType]; + GLvoid* indexBufferByteOffset = reinterpret_cast(startIndex * typeByteSize + _input._indexBufferOffset); + + if (isStereo()) { +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + glDrawElementsInstanced(mode, numIndices, glType, indexBufferByteOffset, 2); +#else + setupStereoSide(0); + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); + setupStereoSide(1); + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); +#endif + _stats._DSNumTriangles += 2 * numIndices / 3; + _stats._DSNumDrawcalls += 2; + } else { + //qDebug() << "GLESBackend::do_drawIndexed glDrawElements " << numIndices; + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); + _stats._DSNumTriangles += numIndices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void) CHECK_GL_ERROR(); +} + +void GLESBackend::do_drawInstanced(const Batch& batch, size_t paramOffset) { + GLint numInstances = batch._params[paramOffset + 4]._uint; + Primitive primitiveType = (Primitive)batch._params[paramOffset + 3]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numVertices = batch._params[paramOffset + 2]._uint; + uint32 startVertex = batch._params[paramOffset + 1]._uint; + + + if (isStereo()) { + GLint trueNumInstances = 2 * numInstances; + +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + glDrawArraysInstanced(mode, startVertex, numVertices, trueNumInstances); +#else + setupStereoSide(0); + glDrawArraysInstanced(mode, startVertex, numVertices, numInstances); + setupStereoSide(1); + glDrawArraysInstanced(mode, startVertex, numVertices, numInstances); +#endif + _stats._DSNumTriangles += (trueNumInstances * numVertices) / 3; + _stats._DSNumDrawcalls += trueNumInstances; + } else { + //qDebug() << "GLESBackend::do_drawInstanced glDrawArraysInstancedEXT " << numVertices << "," << numInstances; + glDrawArraysInstanced(mode, startVertex, numVertices, numInstances); + _stats._DSNumTriangles += (numInstances * numVertices) / 3; + _stats._DSNumDrawcalls += numInstances; + } + _stats._DSNumAPIDrawcalls++; + + (void) CHECK_GL_ERROR(); +} + +void glbackend_glDrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance) { +//#if (GPU_INPUT_PROFILE == GPU_CORE_43) + //glDrawElementsInstancedBaseVertexBaseInstance(mode, count, type, indices, primcount, basevertex, baseinstance); +//#else + glDrawElementsInstanced(mode, count, type, indices, primcount); +//#endif +} + +void GLESBackend::do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) { + GLint numInstances = batch._params[paramOffset + 4]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 3]._uint]; + uint32 numIndices = batch._params[paramOffset + 2]._uint; + uint32 startIndex = batch._params[paramOffset + 1]._uint; + // FIXME glDrawElementsInstancedBaseVertexBaseInstance is only available in GL 4.3 + // and higher, so currently we ignore this field + uint32 startInstance = batch._params[paramOffset + 0]._uint; + GLenum glType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType]; + + auto typeByteSize = TYPE_SIZE[_input._indexBufferType]; + GLvoid* indexBufferByteOffset = reinterpret_cast(startIndex * typeByteSize + _input._indexBufferOffset); + + if (isStereo()) { + GLint trueNumInstances = 2 * numInstances; + +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, trueNumInstances, 0, startInstance); +#else + setupStereoSide(0); + glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); + setupStereoSide(1); + glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); +#endif + + _stats._DSNumTriangles += (trueNumInstances * numIndices) / 3; + _stats._DSNumDrawcalls += trueNumInstances; + } else { + //qDebug() << "GLESBackend::do_drawIndexedInstanced glbackend_glDrawElementsInstancedBaseVertexBaseInstance " << numInstances; + glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); + _stats._DSNumTriangles += (numInstances * numIndices) / 3; + _stats._DSNumDrawcalls += numInstances; + } + + _stats._DSNumAPIDrawcalls++; + + (void)CHECK_GL_ERROR(); +} + + +void GLESBackend::do_multiDrawIndirect(const Batch& batch, size_t paramOffset) { +#if (GPU_INPUT_PROFILE == GPU_CORE_43) + uint commandCount = batch._params[paramOffset + 0]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint]; + + //glMultiDrawArraysIndirect(mode, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); + qDebug() << "TODO: GLESBackend.cpp:do_multiDrawIndirect do_multiDrawIndirect"; + _stats._DSNumDrawcalls += commandCount; + _stats._DSNumAPIDrawcalls++; + +#else + // FIXME implement the slow path +#endif + (void)CHECK_GL_ERROR(); + +} + +void GLESBackend::do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffset) { +//#if (GPU_INPUT_PROFILE == GPU_CORE_43) + uint commandCount = batch._params[paramOffset + 0]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint]; + GLenum indexType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType]; + + //glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); + qDebug() << "TODO: GLESBackend.cpp:do_multiDrawIndexedIndirect glMultiDrawElementsIndirect"; + _stats._DSNumDrawcalls += commandCount; + _stats._DSNumAPIDrawcalls++; +//#else + // FIXME implement the slow path +//#endif + (void)CHECK_GL_ERROR(); +} diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h new file mode 100644 index 0000000000..69a417d952 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h @@ -0,0 +1,99 @@ +// +// GLESBackend.h +// libraries/gpu-gl-android/src/gpu/gles +// +// Created by Gabriel Calero & Cristian Duarte on 9/27/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_gles_GLESBackend_h +#define hifi_gpu_gles_GLESBackend_h + +#include + +#include "../gl/GLBackend.h" +#include "../gl/GLTexture.h" + + +namespace gpu { namespace gles { + +using namespace gpu::gl; + +class GLESBackend : public GLBackend { + using Parent = GLBackend; + // Context Backend static interface required + friend class Context; + +public: + explicit GLESBackend(bool syncCache) : Parent(syncCache) {} + GLESBackend() : Parent() {} + virtual ~GLESBackend() { + // call resetStages here rather than in ~GLBackend dtor because it will call releaseResourceBuffer + // which is pure virtual from GLBackend's dtor. + resetStages(); + } + + static const std::string GLES_VERSION; + const std::string& getVersion() const override { return GLES_VERSION; } + + + class GLESTexture : public GLTexture { + using Parent = GLTexture; + GLuint allocate(); + public: + GLESTexture(const std::weak_ptr& backend, const Texture& buffer, GLuint externalId); + GLESTexture(const std::weak_ptr& backend, const Texture& buffer, bool transferrable); + + protected: + void transferMip(uint16_t mipLevel, uint8_t face) const; + void startTransfer() override; + void allocateStorage() const override; + void updateSize() const override; + void syncSampler() const override; + void generateMips() const override; + }; + + +protected: + GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; + GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; + + GLuint getBufferID(const Buffer& buffer) override; + GLBuffer* syncGPUObject(const Buffer& buffer) override; + + GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) override; + GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override; + + GLuint getQueryID(const QueryPointer& query) override; + GLQuery* syncGPUObject(const Query& query) override; + + // Draw Stage + void do_draw(const Batch& batch, size_t paramOffset) override; + void do_drawIndexed(const Batch& batch, size_t paramOffset) override; + void do_drawInstanced(const Batch& batch, size_t paramOffset) override; + void do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) override; + void do_multiDrawIndirect(const Batch& batch, size_t paramOffset) override; + void do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffset) override; + + // Input Stage + void updateInput() override; + void resetInputStage() override; + + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void transferTransformState(const Batch& batch) const override; + void initTransform() override; + void updateTransform(const Batch& batch); + void resetTransformStage(); + + // Output stage + void do_blit(const Batch& batch, size_t paramOffset) override; +}; + +} } + +Q_DECLARE_LOGGING_CATEGORY(gpugleslogging) + + +#endif \ No newline at end of file diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendBuffer.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendBuffer.cpp new file mode 100644 index 0000000000..f6bdea45af --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendBuffer.cpp @@ -0,0 +1,69 @@ +// +// Created by Gabriel Calero & Cristian Duarte on 09/27/2016 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLESBackend.h" +#include "../gl/GLBuffer.h" + +namespace gpu { + namespace gles { + + class GLESBuffer : public gpu::gl::GLBuffer { + using Parent = gpu::gl::GLBuffer; + static GLuint allocate() { + GLuint result; + glGenBuffers(1, &result); + return result; + } + + public: + GLESBuffer(const std::weak_ptr& backend, const Buffer& buffer, GLESBuffer* original) : Parent(backend, buffer, allocate()) { + glBindBuffer(GL_ARRAY_BUFFER, _buffer); + glBufferData(GL_ARRAY_BUFFER, _size, nullptr, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if (original && original->_size) { + glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer); + glBindBuffer(GL_COPY_READ_BUFFER, original->_buffer); + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, original->_size); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); + glBindBuffer(GL_COPY_READ_BUFFER, 0); + (void)CHECK_GL_ERROR(); + } + Backend::setGPUObject(buffer, this); + } + + void transfer() override { + glBindBuffer(GL_ARRAY_BUFFER, _buffer); + (void)CHECK_GL_ERROR(); + Size offset; + Size size; + Size currentPage { 0 }; + auto data = _gpuObject._renderSysmem.readData(); + while (_gpuObject._renderPages.getNextTransferBlock(offset, size, currentPage)) { + glBufferSubData(GL_ARRAY_BUFFER, offset, size, data + offset); + (void)CHECK_GL_ERROR(); + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + (void)CHECK_GL_ERROR(); + _gpuObject._renderPages._flags &= ~PageManager::DIRTY; + } + }; + } +} + +using namespace gpu; +using namespace gpu::gl; +using namespace gpu::gles; + + +GLuint GLESBackend::getBufferID(const Buffer& buffer) { + return GLESBuffer::getId(*this, buffer); +} + +GLBuffer* GLESBackend::syncGPUObject(const Buffer& buffer) { + return GLESBuffer::sync(*this, buffer); +} diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendInput.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendInput.cpp new file mode 100644 index 0000000000..d37a01eb90 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendInput.cpp @@ -0,0 +1,29 @@ +// +// GLESBackendInput.cpp +// libraries/gpu-gl-android/src/gpu/gles +// +// Created by Cristian Duarte & Gabriel Calero on 10/7/2016. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLESBackend.h" + +using namespace gpu; +using namespace gpu::gles; + +void GLESBackend::updateInput() { + Parent::updateInput(); +} + + +void GLESBackend::resetInputStage() { + Parent::resetInputStage(); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) { + glDisableVertexAttribArray(i); + glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0); + } +} \ No newline at end of file diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp new file mode 100644 index 0000000000..8bf9267fde --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp @@ -0,0 +1,169 @@ +// +// GLESBackendOutput.cpp +// libraries/gpu-gl-android/src/gpu/gles +// +// Created by Gabriel Calero & Cristian Duarte on 9/27/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLESBackend.h" + +#include + +#include "../gl/GLFramebuffer.h" +#include "../gl/GLTexture.h" + +namespace gpu { namespace gles { + +class GLESFramebuffer : public gl::GLFramebuffer { + using Parent = gl::GLFramebuffer; + static GLuint allocate() { + GLuint result; + glGenFramebuffers(1, &result); + return result; + } +public: + void update() override { + GLint currentFBO = -1; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO); + glBindFramebuffer(GL_FRAMEBUFFER, _fbo); + gl::GLTexture* gltexture = nullptr; + TexturePointer surface; + if (_gpuObject.getColorStamps() != _colorStamps) { + if (_gpuObject.hasColor()) { + _colorBuffers.clear(); + static const GLenum colorAttachments[] = { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, + GL_COLOR_ATTACHMENT8, + GL_COLOR_ATTACHMENT9, + GL_COLOR_ATTACHMENT10, + GL_COLOR_ATTACHMENT11, + GL_COLOR_ATTACHMENT12, + GL_COLOR_ATTACHMENT13, + GL_COLOR_ATTACHMENT14, + GL_COLOR_ATTACHMENT15 }; + + int unit = 0; + for (auto& b : _gpuObject.getRenderBuffers()) { + surface = b._texture; + if (surface) { + gltexture = gl::GLTexture::sync(*_backend.lock().get(), surface, false); // Grab the gltexture and don't transfer + } else { + gltexture = nullptr; + } + + if (gltexture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); + _colorBuffers.push_back(colorAttachments[unit]); + } else { + glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, 0, 0); + } + unit++; + } + } + _colorStamps = _gpuObject.getColorStamps(); + } + + GLenum attachement = GL_DEPTH_STENCIL_ATTACHMENT; + if (!_gpuObject.hasStencil()) { + attachement = GL_DEPTH_ATTACHMENT; + } else if (!_gpuObject.hasDepth()) { + attachement = GL_STENCIL_ATTACHMENT; + } + + if (_gpuObject.getDepthStamp() != _depthStamp) { + auto surface = _gpuObject.getDepthStencilBuffer(); + if (_gpuObject.hasDepthStencil() && surface) { + gltexture = gl::GLTexture::sync(*_backend.lock().get(), surface, false); // Grab the gltexture and don't transfer + } + + if (gltexture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); + } else { + glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, 0, 0); + } + _depthStamp = _gpuObject.getDepthStamp(); + } + + + // Last but not least, define where we draw + if (!_colorBuffers.empty()) { + glDrawBuffers((GLsizei)_colorBuffers.size(), _colorBuffers.data()); + } else { + glDrawBuffers(1, {GL_NONE}); + } + + // Now check for completness + _status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + // restore the current framebuffer + if (currentFBO != -1) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO); + } + + checkStatus(GL_DRAW_FRAMEBUFFER); + } + + +public: + GLESFramebuffer(const std::weak_ptr& backend, const gpu::Framebuffer& framebuffer) + : Parent(backend, framebuffer, allocate()) { } +}; + +gl::GLFramebuffer* gpu::gles::GLESBackend::syncGPUObject(const Framebuffer& framebuffer) { + return GLESFramebuffer::sync(*this, framebuffer); +} + +GLuint GLESBackend::getFramebufferID(const FramebufferPointer& framebuffer) { + return framebuffer ? GLESFramebuffer::getId(*this, *framebuffer) : 0; +} + +void GLESBackend::do_blit(const Batch& batch, size_t paramOffset) { + auto srcframebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); + Vec4i srcvp; + for (auto i = 0; i < 4; ++i) { + srcvp[i] = batch._params[paramOffset + 1 + i]._int; + } + + auto dstframebuffer = batch._framebuffers.get(batch._params[paramOffset + 5]._uint); + Vec4i dstvp; + for (auto i = 0; i < 4; ++i) { + dstvp[i] = batch._params[paramOffset + 6 + i]._int; + } + + // Assign dest framebuffer if not bound already + auto newDrawFBO = getFramebufferID(dstframebuffer); + if (_output._drawFBO != newDrawFBO) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, newDrawFBO); + } + + // always bind the read fbo + glBindFramebuffer(GL_READ_FRAMEBUFFER, getFramebufferID(srcframebuffer)); + + // Blit! + glBlitFramebuffer(srcvp.x, srcvp.y, srcvp.z, srcvp.w, + dstvp.x, dstvp.y, dstvp.z, dstvp.w, + GL_COLOR_BUFFER_BIT, GL_LINEAR); + + // Always clean the read fbo to 0 + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + // Restore draw fbo if changed + if (_output._drawFBO != newDrawFBO) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _output._drawFBO); + } + + (void) CHECK_GL_ERROR(); +} + + +} } diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendQuery.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendQuery.cpp new file mode 100644 index 0000000000..db541b07bc --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendQuery.cpp @@ -0,0 +1,38 @@ +// +// GLESBackendQuery.cpp +// libraries/gpu-gl-android/src/gpu/gles +// +// Created by Gabriel Calero & Cristian Duarte on 9/27/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLESBackend.h" + +#include "../gl/GLQuery.h" + +using namespace gpu; +using namespace gpu::gl; +using namespace gpu::gles; + +class GLESQuery : public GLQuery { + using Parent = GLQuery; +public: + static GLuint allocateQuery() { + GLuint result; + glGenQueries(1, &result); + return result; + } + + GLESQuery(const std::weak_ptr& backend, const Query& query) + : Parent(backend, query, allocateQuery(), allocateQuery()) { } +}; + +GLQuery* GLESBackend::syncGPUObject(const Query& query) { + return GLESQuery::sync(*this, query); +} + +GLuint GLESBackend::getQueryID(const QueryPointer& query) { + return GLESQuery::getId(*this, query); +} diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp new file mode 100644 index 0000000000..31a98edd12 --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp @@ -0,0 +1,176 @@ +// +// GLESBackendTexture.cpp +// libraries/gpu-gl-android/src/gpu/gles +// +// Created by Gabriel Calero & Cristian Duarte on 9/27/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLESBackend.h" + +#include +#include +#include + +// #include "../gl/GLTexelFormat.h" + +using namespace gpu; +using namespace gpu::gl; +using namespace gpu::gles; + +//using GL41TexelFormat = GLTexelFormat; +using GLESTexture = GLESBackend::GLESTexture; + +GLuint GLESTexture::allocate() { + //CLIMAX_MERGE_START + //Backend::incrementTextureGPUCount(); + //CLIMAX_MERGE_END + GLuint result; + glGenTextures(1, &result); + return result; +} + +GLuint GLESBackend::getTextureID(const TexturePointer& texture, bool transfer) { + return GLESTexture::getId(*this, texture, transfer); +} + +GLTexture* GLESBackend::syncGPUObject(const TexturePointer& texture, bool transfer) { + return GLESTexture::sync(*this, texture, transfer); +} + +GLESTexture::GLESTexture(const std::weak_ptr& backend, const Texture& texture, GLuint externalId) + : GLTexture(backend, texture, externalId) { +} + +GLESTexture::GLESTexture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) + : GLTexture(backend, texture, allocate(), transferrable) { +} + +void GLESTexture::generateMips() const { + withPreservedTexture([&] { + glGenerateMipmap(_target); + }); + (void)CHECK_GL_ERROR(); +} + +void GLESTexture::allocateStorage() const { + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); + glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0); + (void)CHECK_GL_ERROR(); + glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); + (void)CHECK_GL_ERROR(); +/* if (GLEW_VERSION_4_2 && !_gpuObject.getTexelFormat().isCompressed()) { + // Get the dimensions, accounting for the downgrade level + Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip); + glTexStorage2D(_target, usedMipLevels(), texelFormat.internalFormat, dimensions.x, dimensions.y); + (void)CHECK_GL_ERROR(); + } else {*/ + for (uint16_t l = _minMip; l <= _maxMip; l++) { + // Get the mip level dimensions, accounting for the downgrade level + Vec3u dimensions = _gpuObject.evalMipDimensions(l); + for (GLenum target : getFaceTargets(_target)) { + glTexImage2D(target, l - _minMip, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, NULL); + (void)CHECK_GL_ERROR(); + } + } + //} +} + +void GLESTexture::updateSize() const { + setSize(_virtualSize); + if (!_id) { + return; + } + + if (_gpuObject.getTexelFormat().isCompressed()) { + GLenum proxyType = GL_TEXTURE_2D; + GLuint numFaces = 1; + if (_gpuObject.getType() == gpu::Texture::TEX_CUBE) { + proxyType = CUBE_FACE_LAYOUT[0]; + numFaces = (GLuint)CUBE_NUM_FACES; + } + GLint gpuSize{ 0 }; + glGetTexLevelParameteriv(proxyType, 0, GL_TEXTURE_COMPRESSED, &gpuSize); + (void)CHECK_GL_ERROR(); + + if (gpuSize) { + for (GLuint level = _minMip; level < _maxMip; level++) { + GLint levelSize{ 0 }; + //glGetTexLevelParameteriv(proxyType, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize); + //qDebug() << "TODO: GLBackendTexture.cpp:updateSize GL_TEXTURE_COMPRESSED_IMAGE_SIZE"; + levelSize *= numFaces; + + if (levelSize <= 0) { + break; + } + gpuSize += levelSize; + } + (void)CHECK_GL_ERROR(); + setSize(gpuSize); + return; + } + } +} + +// Move content bits from the CPU to the GPU for a given mip / face +void GLESTexture::transferMip(uint16_t mipLevel, uint8_t face) const { + auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat()); + //GLenum target = getFaceTargets()[face]; + GLenum target = _target == GL_TEXTURE_2D ? GL_TEXTURE_2D : CUBE_FACE_LAYOUT[face]; + auto size = _gpuObject.evalMipDimensions(mipLevel); + glTexSubImage2D(target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); + (void)CHECK_GL_ERROR(); +} + +void GLESTexture::startTransfer() { + PROFILE_RANGE(render_gpu_gl, __FUNCTION__); + Parent::startTransfer(); + + glBindTexture(_target, _id); + (void)CHECK_GL_ERROR(); + + // transfer pixels from each faces + uint8_t numFaces = (Texture::TEX_CUBE == _gpuObject.getType()) ? CUBE_NUM_FACES : 1; + for (uint8_t f = 0; f < numFaces; f++) { + for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) { + if (_gpuObject.isStoredMipFaceAvailable(i, f)) { + transferMip(i, f); + } + } + } +} + +void GLESBackend::GLESTexture::syncSampler() const { + const Sampler& sampler = _gpuObject.getSampler(); + const auto& fm = FILTER_MODES[sampler.getFilter()]; + glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); + + if (sampler.doComparison()) { + glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(_target, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); + } else { + glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + glTexParameteri(_target, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); + glTexParameteri(_target, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); + glTexParameteri(_target, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + + glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR_EXT, (const float*)&sampler.getBorderColor()); + + + glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset()); + glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); + glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + (void)CHECK_GL_ERROR(); + //qDebug() << "[GPU-GL-GLBackend] syncSampler 12 " << _target << "," << sampler.getMaxAnisotropy(); + //glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + //(void)CHECK_GL_ERROR(); + //qDebug() << "[GPU-GL-GLBackend] syncSampler end"; + +} + diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp new file mode 100644 index 0000000000..5050db6edd --- /dev/null +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp @@ -0,0 +1,67 @@ +// +// GLESBackendTransform.cpp +// libraries/gpu-gl-android/src/gpu/gles +// +// Created by Gabriel Calero & Cristian Duarte on 9/28/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GLESBackend.h" + +using namespace gpu; +using namespace gpu::gles; + +void GLESBackend::initTransform() { + glGenBuffers(1, &_transform._objectBuffer); + glGenBuffers(1, &_transform._cameraBuffer); + glGenBuffers(1, &_transform._drawCallInfoBuffer); + glGenTextures(1, &_transform._objectBufferTexture); + size_t cameraSize = sizeof(TransformStageState::CameraBufferElement); + while (_transform._cameraUboSize < cameraSize) { + _transform._cameraUboSize += _uboAlignment; + } +} + +void GLESBackend::transferTransformState(const Batch& batch) const { + // FIXME not thread safe + static std::vector bufferData; + if (!_transform._cameras.empty()) { + bufferData.resize(_transform._cameraUboSize * _transform._cameras.size()); + for (size_t i = 0; i < _transform._cameras.size(); ++i) { + memcpy(bufferData.data() + (_transform._cameraUboSize * i), &_transform._cameras[i], sizeof(TransformStageState::CameraBufferElement)); + } + glBindBuffer(GL_UNIFORM_BUFFER, _transform._cameraBuffer); + glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + + if (!batch._objects.empty()) { + glBindBuffer(GL_SHADER_STORAGE_BUFFER, _transform._objectBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, batch._objects.size() * sizeof(Batch::TransformObject), batch._objects.data(), GL_STREAM_DRAW); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + } + + if (!batch._namedData.empty()) { + bufferData.clear(); + for (auto& data : batch._namedData) { + auto currentSize = bufferData.size(); + auto bytesToCopy = data.second.drawCallInfos.size() * sizeof(Batch::DrawCallInfo); + bufferData.resize(currentSize + bytesToCopy); + memcpy(bufferData.data() + currentSize, data.second.drawCallInfos.data(), bytesToCopy); + _transform._drawCallInfoOffsets[data.first] = (GLvoid*)currentSize; + } + + glBindBuffer(GL_ARRAY_BUFFER, _transform._drawCallInfoBuffer); + glBufferData(GL_ARRAY_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._objectBuffer); + + CHECK_GL_ERROR(); + + // Make sure the current Camera offset is unknown before render Draw + _transform._currentCameraOffset = INVALID_OFFSET; +} diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h index c5df94235c..01cc652fd1 100644 --- a/libraries/gpu/src/gpu/Buffer.h +++ b/libraries/gpu/src/gpu/Buffer.h @@ -159,6 +159,7 @@ protected: friend class gl::GLBuffer; friend class gl41::GL41Buffer; friend class gl45::GL45Buffer; + friend class gles::GLESBuffer; }; using BufferUpdates = std::vector; diff --git a/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv b/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv index c9cc9e9dfa..1f788051bc 100755 --- a/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv +++ b/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv @@ -35,5 +35,5 @@ void main(void) { TransformObject obj = getTransformObject(); <$transformModelToClipPos(cam, obj, pos, gl_Position)$> - varTexCoord0 = ((pos.xy + 1) * 0.5) * texcoordRect.zw + texcoordRect.xy; + varTexCoord0 = ((pos.xy + 1.0) * 0.5) * texcoordRect.zw + texcoordRect.xy; } diff --git a/libraries/gpu/src/gpu/DrawTransformUnitQuad.slv b/libraries/gpu/src/gpu/DrawTransformUnitQuad.slv index f55abf1089..845cf0326d 100755 --- a/libraries/gpu/src/gpu/DrawTransformUnitQuad.slv +++ b/libraries/gpu/src/gpu/DrawTransformUnitQuad.slv @@ -32,5 +32,5 @@ void main(void) { TransformObject obj = getTransformObject(); <$transformModelToClipPos(cam, obj, pos, gl_Position)$> - varTexCoord0 = (pos.xy + 1) * 0.5; + varTexCoord0 = (pos.xy + 1.0) * 0.5; } diff --git a/libraries/gpu/src/gpu/DrawUnitQuadTexcoord.slv b/libraries/gpu/src/gpu/DrawUnitQuadTexcoord.slv index 1426ae48fd..289d8f96b1 100644 --- a/libraries/gpu/src/gpu/DrawUnitQuadTexcoord.slv +++ b/libraries/gpu/src/gpu/DrawUnitQuadTexcoord.slv @@ -23,7 +23,7 @@ void main(void) { ); vec4 pos = UNIT_QUAD[gl_VertexID]; - varTexCoord0 = (pos.xy + 1) * 0.5; + varTexCoord0 = (pos.xy + 1.0) * 0.5; gl_Position = pos; } diff --git a/libraries/gpu/src/gpu/DrawViewportQuadTransformTexcoord.slv b/libraries/gpu/src/gpu/DrawViewportQuadTransformTexcoord.slv index 1f9bc13700..554728417b 100755 --- a/libraries/gpu/src/gpu/DrawViewportQuadTransformTexcoord.slv +++ b/libraries/gpu/src/gpu/DrawViewportQuadTransformTexcoord.slv @@ -28,7 +28,7 @@ void main(void) { vec4 pos = UNIT_QUAD[gl_VertexID]; // standard transform but applied to the Texcoord - vec4 tc = vec4((pos.xy + 1) * 0.5, pos.zw); + vec4 tc = vec4((pos.xy + 1.0) * 0.5, pos.zw); TransformObject obj = getTransformObject(); <$transformModelToWorldPos(obj, tc, tc)$> diff --git a/libraries/gpu/src/gpu/Forward.h b/libraries/gpu/src/gpu/Forward.h index 88800652a5..8100efafaf 100644 --- a/libraries/gpu/src/gpu/Forward.h +++ b/libraries/gpu/src/gpu/Forward.h @@ -137,6 +137,11 @@ namespace gpu { class GL45Backend; class GL45Buffer; } + + namespace gles { + class GLESBackend; + class GLESBuffer; + } } #endif diff --git a/libraries/gpu/src/gpu/Frame.cpp b/libraries/gpu/src/gpu/Frame.cpp index 4854559d61..58ab7257f7 100644 --- a/libraries/gpu/src/gpu/Frame.cpp +++ b/libraries/gpu/src/gpu/Frame.cpp @@ -11,6 +11,10 @@ using namespace gpu; +Frame::Frame() { + batches.reserve(16); +} + Frame::~Frame() { if (framebuffer && framebufferRecycler) { framebufferRecycler(framebuffer); diff --git a/libraries/gpu/src/gpu/Frame.h b/libraries/gpu/src/gpu/Frame.h index bfebe85753..69872906e3 100644 --- a/libraries/gpu/src/gpu/Frame.h +++ b/libraries/gpu/src/gpu/Frame.h @@ -20,8 +20,8 @@ namespace gpu { friend class Context; public: + Frame(); virtual ~Frame(); - using Batches = std::vector; using FramebufferRecycler = std::function; using OverlayRecycler = std::function; diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index b49c681889..f1257e7c83 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -13,6 +13,7 @@ #include #include +#include #include using namespace gpu; diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index a65aaf765b..b3a500d68f 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -132,7 +132,11 @@ public: float getAspectRatio() const { return getWidth() / (float) getHeight() ; } +#ifndef ANDROID static const uint32 MAX_NUM_RENDER_BUFFERS = 8; +#else + static const uint32 MAX_NUM_RENDER_BUFFERS = 4; +#endif static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } const GPUObjectPointer gpuObject {}; diff --git a/libraries/gpu/src/gpu/Query.cpp b/libraries/gpu/src/gpu/Query.cpp index 38a9d6db8c..03312e0db9 100644 --- a/libraries/gpu/src/gpu/Query.cpp +++ b/libraries/gpu/src/gpu/Query.cpp @@ -45,8 +45,8 @@ void Query::triggerReturnHandler(uint64_t queryResult, uint64_t batchElapsedTime RangeTimer::RangeTimer(const std::string& name) : _name(name) { for (int i = 0; i < QUERY_QUEUE_SIZE; i++) { - _timerQueries.push_back(std::make_shared([&, i] (const Query& query) { - _tailIndex ++; + _timerQueries.push_back(std::make_shared([this] (const Query& query) { + _tailIndex++; _movingAverageGPU.addSample(query.getGPUElapsedTime()); _movingAverageBatch.addSample(query.getBatchElapsedTime()); diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index b786222198..9feca4a3c9 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -43,16 +43,21 @@ layout(location=14) in int _inStereoSide; flat out int _stereoSide; // In stereo drawcall mode Instances are drawn twice (left then right) hence the true InstanceID is the gl_InstanceID / 2 -int gpu_InstanceID = gl_InstanceID >> 1; +int gpu_InstanceID() { + return gl_InstanceID >> 1; +} #else -int gpu_InstanceID = gl_InstanceID; - +int gpu_InstanceID() { + return gl_InstanceID; +} #endif #else -int gpu_InstanceID = gl_InstanceID; +int gpu_InstanceID() { + return gl_InstanceID; +} #endif @@ -166,7 +171,7 @@ TransformObject getTransformObject() { #ifdef GPU_TRANSFORM_STEREO_SPLIT_SCREEN vec4 eyeClipEdge[2]= vec4[2](vec4(-1,0,0,1), vec4(1,0,0,1)); vec2 eyeOffsetScale = vec2(-0.5, +0.5); - uint eyeIndex = _stereoSide; + uint eyeIndex = uint(_stereoSide); gl_ClipDistance[0] = dot(<$clipPos$>, eyeClipEdge[eyeIndex]); float newClipPosX = <$clipPos$>.x * 0.5 + eyeOffsetScale[eyeIndex] * <$clipPos$>.w; <$clipPos$>.x = newClipPosX; diff --git a/libraries/image/CMakeLists.txt b/libraries/image/CMakeLists.txt index 85d3d8f1ae..442fa714b3 100644 --- a/libraries/image/CMakeLists.txt +++ b/libraries/image/CMakeLists.txt @@ -2,10 +2,10 @@ set(TARGET_NAME image) setup_hifi_library() link_hifi_libraries(shared gpu) -target_glm() - -add_dependency_external_projects(nvtt) -find_package(NVTT REQUIRED) -target_include_directories(${TARGET_NAME} PRIVATE ${NVTT_INCLUDE_DIRS}) -target_link_libraries(${TARGET_NAME} ${NVTT_LIBRARIES}) -add_paths_to_fixup_libs(${NVTT_DLL_PATH}) +if (NOT ANDROID) + add_dependency_external_projects(nvtt) + find_package(NVTT REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${NVTT_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${NVTT_LIBRARIES}) + add_paths_to_fixup_libs(${NVTT_DLL_PATH}) +endif() \ No newline at end of file diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index f274dc54f8..e9fb447e99 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -11,7 +11,8 @@ #include "Image.h" -#include +#include + #include #include @@ -28,7 +29,13 @@ using namespace gpu; +#if defined(Q_OS_ANDROID) +#define CPU_MIPMAPS 0 +#else #define CPU_MIPMAPS 1 +#include +#endif + static std::mutex settingsMutex; static Setting::Handle compressColorTextures("hifi.graphics.compressColorTextures", false); @@ -292,6 +299,7 @@ QImage processSourceImage(const QImage& srcImage, bool cubemap) { return srcImage; } +#if defined(NVTT_API) struct MyOutputHandler : public nvtt::OutputHandler { MyOutputHandler(gpu::Texture* texture, int face) : _texture(texture), _face(face) {} @@ -330,6 +338,7 @@ struct MyErrorHandler : public nvtt::ErrorHandler { qCWarning(imagelogging) << "Texture compression error:" << nvtt::errorString(e); } }; +#endif void generateMips(gpu::Texture* texture, QImage& image, int face = -1) { #if CPU_MIPMAPS @@ -450,7 +459,7 @@ void generateMips(gpu::Texture* texture, QImage& image, int face = -1) { nvtt::Compressor compressor; compressor.process(inputOptions, compressionOptions, outputOptions); #else - texture->autoGenerateMips(-1); + texture->setAutoGenerateMips(true); #endif } diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h index 02dcbe4664..c0cca200d7 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h @@ -30,7 +30,7 @@ public: TOUCH_AXIS_Y_NEG, }; - enum TouchGestureAxisChannel { + enum TouchGestureAxisChannel { TOUCH_GESTURE_PINCH_POS = TOUCH_AXIS_Y_NEG + 1, TOUCH_GESTURE_PINCH_NEG, }; diff --git a/libraries/ktx/CMakeLists.txt b/libraries/ktx/CMakeLists.txt index 967ea71eb6..efd8b76567 100644 --- a/libraries/ktx/CMakeLists.txt +++ b/libraries/ktx/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME ktx) setup_hifi_library() -include_hifi_library_headers(shared) \ No newline at end of file +link_hifi_libraries(shared) diff --git a/libraries/midi/src/Midi.h b/libraries/midi/src/Midi.h index 0ffa27986d..013ec056e3 100644 --- a/libraries/midi/src/Midi.h +++ b/libraries/midi/src/Midi.h @@ -66,7 +66,7 @@ Q_INVOKABLE void thruModeEnable(bool enable); public: Midi(); - virtual ~Midi(); + virtual ~Midi(); }; #endif // hifi_Midi_h diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 704455c981..2f29f47864 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -173,9 +173,9 @@ void GeometryReader::run() { QString urlname = _url.path().toLower(); if (!urlname.isEmpty() && !_url.path().isEmpty() && - (_url.path().toLower().endsWith(".fbx") || - _url.path().toLower().endsWith(".obj") || - _url.path().toLower().endsWith(".obj.gz"))) { + (_url.path().toLower().endsWith(".fbx") || + _url.path().toLower().endsWith(".obj") || + _url.path().toLower().endsWith(".obj.gz"))) { FBXGeometry::Pointer fbxGeometry; if (_url.path().toLower().endsWith(".fbx")) { @@ -185,15 +185,15 @@ void GeometryReader::run() { } } else if (_url.path().toLower().endsWith(".obj")) { fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _combineParts, _url)); - } else if (_url.path().toLower().endsWith(".obj.gz")) { - QByteArray uncompressedData; - if (gunzip(_data, uncompressedData)){ - fbxGeometry.reset(OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url)); - } else { - throw QString("failed to decompress .obj.gz" ); - } + } else if (_url.path().toLower().endsWith(".obj.gz")) { + QByteArray uncompressedData; + if (gunzip(_data, uncompressedData)){ + fbxGeometry.reset(OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url)); + } else { + throw QString("failed to decompress .obj.gz" ); + } - } else { + } else { throw QString("unsupported format"); } diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 67946abea0..093a87adc8 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -41,7 +41,7 @@ SphericalHarmonics getLightAmbientSphere(LightAmbient l) { return l._ambientSphe float getLightAmbientIntensity(LightAmbient l) { return l._ambient.x; } -bool getLightHasAmbientMap(LightAmbient l) { return l._ambient.y > 0; } +bool getLightHasAmbientMap(LightAmbient l) { return l._ambient.y > 0.0; } float getLightAmbientMapNumMips(LightAmbient l) { return l._ambient.y; } <@func declareLightBuffer(N)@> diff --git a/libraries/model/src/model/LightIrradiance.shared.slh b/libraries/model/src/model/LightIrradiance.shared.slh index 4a2ee40c9d..13d6cf4b93 100644 --- a/libraries/model/src/model/LightIrradiance.shared.slh +++ b/libraries/model/src/model/LightIrradiance.shared.slh @@ -37,7 +37,7 @@ float lightIrradiance_evalLightAttenuation(LightIrradiance li, float d) { // "Fade" the edges of light sources to make things look a bit more attractive. // Note: this tends to look a bit odd at lower exponents. - attenuation *= min(1, max(0, -(d - cutoff))); + attenuation *= min(1.0, max(0.0, -(d - cutoff))); return attenuation; } diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 288e98d5a5..c3592c5da2 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -2,44 +2,18 @@ set(TARGET_NAME networking) setup_hifi_library(Network) link_hifi_libraries(shared) -target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes") +target_openssl() +target_tbb() if (WIN32) - # we need ws2_32.lib on windows, but it's static so we don't bubble it up - target_link_libraries(${TARGET_NAME} ws2_32.lib) -endif () - -add_dependency_external_projects(tbb) - -# find required dependencies -find_package(OpenSSL REQUIRED) -find_package(TBB REQUIRED) - -if (APPLE) + # we need ws2_32.lib on windows, but it's static so we don't bubble it up + target_link_libraries(${TARGET_NAME} ws2_32.lib) +elseif(APPLE) + # IOKit is needed for getting machine fingerprint find_library(FRAMEWORK_IOKIT IOKit) find_library(CORE_FOUNDATION CoreFoundation) -endif () - -if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include") - # this is a user on OS X using system OpenSSL, which is going to throw warnings since they're deprecating for their common crypto - message(WARNING "The found version of OpenSSL is the OS X system version. This will produce deprecation warnings." - "\nWe recommend you install a newer version (at least 1.0.1h) in a different directory and set OPENSSL_ROOT_DIR in your env so Cmake can find it.") -endif () - -include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") - -# append OpenSSL to our list of libraries to link -target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES} ${TBB_LIBRARIES}) - -# IOKit is needed for getting machine fingerprint -if (APPLE) target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT} ${CORE_FOUNDATION}) -endif (APPLE) - -# libcrypto uses dlopen in libdl -if (UNIX) - target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) -endif (UNIX) - -# append tbb includes to our list of includes to bubble -target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${TBB_INCLUDE_DIRS}) +elseif(UNIX) + # libcrypto uses dlopen in libdl + target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) +endif () diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 99e1962387..2376a3b2b6 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -29,11 +29,15 @@ #include "UserActivityLogger.h" #include "udt/PacketHeaders.h" +#ifdef Q_OS_ANDROID +const QString DEFAULT_HIFI_ADDRESS = "hifi://android/0.0,0.0,-200"; +#else #if USE_STABLE_GLOBAL_SERVICES const QString DEFAULT_HIFI_ADDRESS = "hifi://welcome/hello"; #else const QString DEFAULT_HIFI_ADDRESS = "hifi://dev-welcome/hello"; #endif +#endif const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager"; const QString SETTINGS_CURRENT_ADDRESS_KEY = "address"; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index cb0b620a54..ea66d018e5 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -59,7 +59,11 @@ void AssetClient::init() { auto& networkAccessManager = NetworkAccessManager::getInstance(); if (!networkAccessManager.cache()) { if (_cacheDir.isEmpty()) { +#ifdef Q_OS_ANDROID + QString cachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); +#else QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); +#endif _cacheDir = !cachePath.isEmpty() ? cachePath : "interfaceCache"; } QNetworkDiskCache* cache = new QNetworkDiskCache(); diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index a41283cc0d..eb3a75d14f 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -187,7 +187,7 @@ void AssetResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytes emit progress(bytesReceived, bytesTotal); auto now = p_high_resolution_clock::now(); - + // Recording ATP bytes downloaded in stats DependencyManager::get()->updateStat(STAT_ATP_RESOURCE_TOTAL_BYTES, bytesReceived); diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index c6d0370a70..edba520bd5 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -201,11 +201,11 @@ void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesT _sendTimer->start(); emit progress(bytesReceived, bytesTotal); - + // Recording HTTP bytes downloaded in stats DependencyManager::get()->updateStat(STAT_HTTP_RESOURCE_TOTAL_BYTES, bytesReceived); - - + + } void HTTPResourceRequest::onTimeout() { diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 954b9685af..d0cb0109c7 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -668,7 +668,11 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t } // insert the new node and release our read lock +#ifdef Q_OS_ANDROID + _nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer)); +#else _nodeHash.emplace(newNode->getUUID(), newNodePointer); +#endif readLocker.unlock(); qCDebug(networking) << "Added" << *newNode; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 48e5c8a62c..fcf369f786 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -809,7 +809,7 @@ void NodeList::sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationN void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { // enumerate the nodes to send a reliable ignore packet to each that can leverage it if (!nodeID.isNull() && _sessionUUID != nodeID) { - eachMatchingNode([&nodeID](const SharedNodePointer& node)->bool { + eachMatchingNode([](const SharedNodePointer& node)->bool { if (node->getType() == NodeType::AudioMixer || node->getType() == NodeType::AvatarMixer) { return true; } else { diff --git a/libraries/networking/src/NodePermissions.cpp b/libraries/networking/src/NodePermissions.cpp index e94c43b6fb..67359ee862 100644 --- a/libraries/networking/src/NodePermissions.cpp +++ b/libraries/networking/src/NodePermissions.cpp @@ -9,9 +9,28 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "NodePermissions.h" + +#include #include #include -#include "NodePermissions.h" + + + +size_t std::hash::operator()(const NodePermissionsKey& key) const { + size_t result = qHash(key.first); + result <<= sizeof(size_t) / 2; + +#if (QT_POINTER_SIZE == 8) + const uint MASK = 0x00FF; +#else + const uint MASK = 0xFFFF; +#endif + + result |= (qHash(key.second) & MASK); + return result; +} + NodePermissionsKey NodePermissions::standardNameLocalhost = NodePermissionsKey("localhost", 0); NodePermissionsKey NodePermissions::standardNameLoggedIn = NodePermissionsKey("logged-in", 0); diff --git a/libraries/networking/src/NodePermissions.h b/libraries/networking/src/NodePermissions.h index 129d7e5c08..8f7bdaebfe 100644 --- a/libraries/networking/src/NodePermissions.h +++ b/libraries/networking/src/NodePermissions.h @@ -29,13 +29,8 @@ using NodePermissionsKeyList = QList>; namespace std { template<> - struct hash { - size_t operator()(const NodePermissionsKey& key) const { - size_t result = qHash(key.first); - result <<= 32; - result |= qHash(key.second); - return result; - } + struct hash { + size_t operator()(const NodePermissionsKey& key) const; }; } diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 3a93134a5e..e6a462651e 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -123,9 +123,9 @@ private: p_high_resolution_clock::time_point _lastRCTime = p_high_resolution_clock::now(); // last rate increase time - bool _slowStart { true }; // if in slow start phase + bool _slowStart { true }; // if in slow start phase SequenceNumber _lastACK; // last ACKed sequence number from previous - bool _loss { false }; // if loss happened since last rate increase + bool _loss { false }; // if loss happened since last rate increase SequenceNumber _lastDecreaseMaxSeq; // max pkt seq num sent out when last decrease happened double _lastDecreasePeriod { 1 }; // value of _packetSendPeriod when last decrease happened int _nakCount { 0 }; // number of NAKs in congestion epoch diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 0d5d3e8c25..6fdefd36f6 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -68,7 +68,7 @@ ControlPacket::ControlPacket(std::unique_ptr data, qint64 size, const Hi } ControlPacket::ControlPacket(ControlPacket&& other) : - BasePacket(std::move(other)) + BasePacket(std::move(other)) { _type = other._type; } diff --git a/libraries/physics/src/CharacterRayResult.h b/libraries/physics/src/CharacterRayResult.h index e8b0bb7f99..239ab9570a 100644 --- a/libraries/physics/src/CharacterRayResult.h +++ b/libraries/physics/src/CharacterRayResult.h @@ -26,19 +26,19 @@ public: protected: const CharacterGhostObject* _character; - // Note: Public data members inherited from ClosestRayResultCallback - // - // btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction - // btVector3 m_rayToWorld; - // btVector3 m_hitNormalWorld; - // btVector3 m_hitPointWorld; - // - // Note: Public data members inherited from RayResultCallback - // - // btScalar m_closestHitFraction; - // const btCollisionObject* m_collisionObject; - // short int m_collisionFilterGroup; - // short int m_collisionFilterMask; + // Note: Public data members inherited from ClosestRayResultCallback + // + // btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction + // btVector3 m_rayToWorld; + // btVector3 m_hitNormalWorld; + // btVector3 m_hitPointWorld; + // + // Note: Public data members inherited from RayResultCallback + // + // btScalar m_closestHitFraction; + // const btCollisionObject* m_collisionObject; + // short int m_collisionFilterGroup; + // short int m_collisionFilterMask; }; #endif // hifi_CharacterRayResult_h diff --git a/libraries/physics/src/CharacterSweepResult.cpp b/libraries/physics/src/CharacterSweepResult.cpp index a5c4092b1d..36e36185d3 100755 --- a/libraries/physics/src/CharacterSweepResult.cpp +++ b/libraries/physics/src/CharacterSweepResult.cpp @@ -25,7 +25,7 @@ CharacterSweepResult::CharacterSweepResult(const CharacterGhostObject* character } btScalar CharacterSweepResult::addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool useWorldFrame) { - // skip objects that we shouldn't collide with + // skip objects that we shouldn't collide with if (!convexResult.m_hitCollisionObject->hasContactResponse()) { return btScalar(1.0); } @@ -37,6 +37,6 @@ btScalar CharacterSweepResult::addSingleResult(btCollisionWorld::LocalConvexResu } void CharacterSweepResult::resetHitHistory() { - m_hitCollisionObject = nullptr; - m_closestHitFraction = btScalar(1.0f); + m_hitCollisionObject = nullptr; + m_closestHitFraction = btScalar(1.0f); } diff --git a/libraries/physics/src/CharacterSweepResult.h b/libraries/physics/src/CharacterSweepResult.h index 1e2898a3cf..3c7bb66282 100644 --- a/libraries/physics/src/CharacterSweepResult.h +++ b/libraries/physics/src/CharacterSweepResult.h @@ -22,13 +22,13 @@ class CharacterSweepResult : public btCollisionWorld::ClosestConvexResultCallbac public: CharacterSweepResult(const CharacterGhostObject* character); virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool useWorldFrame) override; - void resetHitHistory(); + void resetHitHistory(); protected: const CharacterGhostObject* _character; // NOTE: Public data members inherited from ClosestConvexResultCallback: // - // btVector3 m_convexFromWorld; // unused except by btClosestNotMeConvexResultCallback + // btVector3 m_convexFromWorld; // unused except by btClosestNotMeConvexResultCallback // btVector3 m_convexToWorld; // unused except by btClosestNotMeConvexResultCallback // btVector3 m_hitNormalWorld; // btVector3 m_hitPointWorld; diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index 6a6857a5ae..10b2440db2 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -21,7 +21,7 @@ class CollisionRenderMeshCache { public: - using Key = const void*; // must actually be a const btCollisionShape* + using Key = const void*; // must actually be a const btCollisionShape* CollisionRenderMeshCache(); ~CollisionRenderMeshCache(); diff --git a/libraries/procedural/CMakeLists.txt b/libraries/procedural/CMakeLists.txt index 3ebd0f3d14..daf6fefccc 100644 --- a/libraries/procedural/CMakeLists.txt +++ b/libraries/procedural/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME procedural) AUTOSCRIBE_SHADER_LIB(gpu model) setup_hifi_library() -link_hifi_libraries(shared gpu gpu-gl networking model model-networking ktx image) +link_hifi_libraries(shared gpu networking model model-networking ktx image) diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 0079ffae66..94232c81b2 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -3,7 +3,7 @@ AUTOSCRIBE_SHADER_LIB(gpu model render) # pull in the resources.qrc file qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") setup_hifi_library(Widgets OpenGL Network Qml Quick Script) -link_hifi_libraries(shared ktx gpu model model-networking render animation fbx entities image procedural) +link_hifi_libraries(shared ktx gpu model model-networking render animation fbx image procedural) include_hifi_library_headers(networking) include_hifi_library_headers(octree) include_hifi_library_headers(audio) diff --git a/libraries/render-utils/src/DeferredBufferRead.slh b/libraries/render-utils/src/DeferredBufferRead.slh index 315de30fea..fbca241bb9 100644 --- a/libraries/render-utils/src/DeferredBufferRead.slh +++ b/libraries/render-utils/src/DeferredBufferRead.slh @@ -90,7 +90,7 @@ DeferredFragment unpackDeferredFragmentNoPositionNoAmbient(vec2 texcoord) { vec4 diffuseVal; DeferredFragment frag; - frag.depthVal = -1; + frag.depthVal = -1.0; normalVal = texture(normalMap, texcoord); diffuseVal = texture(albedoMap, texcoord); diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index 4b4e401332..e4a7debd1e 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -47,8 +47,8 @@ private: glm::vec3 _lastBaseOffset { 0.f, 0.f, 0.f }; glm::vec3 _lastBaseInvSize { 1.f, 1.f, 1.f }; - explicit FadeEffect(); - virtual ~FadeEffect() { } + explicit FadeEffect(); + virtual ~FadeEffect() { } }; #endif // hifi_render_utils_FadeEffect_h diff --git a/libraries/render-utils/src/ForwardBuffer.slh b/libraries/render-utils/src/ForwardBuffer.slh new file mode 100644 index 0000000000..4d1dc89aa4 --- /dev/null +++ b/libraries/render-utils/src/ForwardBuffer.slh @@ -0,0 +1,68 @@ + +<@if not FORWARD_BUFFER_SLH@> +<@def FORWARD_BUFFER_SLH@> + +<@include gpu/PackedNormal.slh@> + +// Unpack the metallic-mode value +const float FRAG_PACK_SHADED_NON_METALLIC = 0.0; +const float FRAG_PACK_SHADED_METALLIC = 0.1; +const float FRAG_PACK_SHADED_RANGE_INV = 1.0 / (FRAG_PACK_SHADED_METALLIC - FRAG_PACK_SHADED_NON_METALLIC); + +const float FRAG_PACK_LIGHTMAPPED_NON_METALLIC = 0.2; +const float FRAG_PACK_LIGHTMAPPED_METALLIC = 0.3; +const float FRAG_PACK_LIGHTMAPPED_RANGE_INV = 1.0 / (FRAG_PACK_LIGHTMAPPED_METALLIC - FRAG_PACK_LIGHTMAPPED_NON_METALLIC); + +const float FRAG_PACK_SCATTERING_NON_METALLIC = 0.4; +const float FRAG_PACK_SCATTERING_METALLIC = 0.5; +const float FRAG_PACK_SCATTERING_RANGE_INV = 1.0 / (FRAG_PACK_SCATTERING_METALLIC - FRAG_PACK_SCATTERING_NON_METALLIC); + +const float FRAG_PACK_UNLIT = 0.6; + +const int FRAG_MODE_UNLIT = 0; +const int FRAG_MODE_SHADED = 1; +const int FRAG_MODE_LIGHTMAPPED = 2; +const int FRAG_MODE_SCATTERING = 3; + +void unpackModeMetallic(float rawValue, out int mode, out float metallic) { + if (rawValue <= FRAG_PACK_SHADED_METALLIC) { + mode = FRAG_MODE_SHADED; + metallic = clamp((rawValue - FRAG_PACK_SHADED_NON_METALLIC) * FRAG_PACK_SHADED_RANGE_INV, 0.0, 1.0); + } else if (rawValue <= FRAG_PACK_LIGHTMAPPED_METALLIC) { + mode = FRAG_MODE_LIGHTMAPPED; + metallic = clamp((rawValue - FRAG_PACK_LIGHTMAPPED_NON_METALLIC) * FRAG_PACK_LIGHTMAPPED_RANGE_INV, 0.0, 1.0); + } else if (rawValue <= FRAG_PACK_SCATTERING_METALLIC) { + mode = FRAG_MODE_SCATTERING; + metallic = clamp((rawValue - FRAG_PACK_SCATTERING_NON_METALLIC) * FRAG_PACK_SCATTERING_RANGE_INV, 0.0, 1.0); + } else if (rawValue >= FRAG_PACK_UNLIT) { + mode = FRAG_MODE_UNLIT; + metallic = 0.0; + } +} + +float packShadedMetallic(float metallic) { + return mix(FRAG_PACK_SHADED_NON_METALLIC, FRAG_PACK_SHADED_METALLIC, metallic); +} + +float packLightmappedMetallic(float metallic) { + return mix(FRAG_PACK_LIGHTMAPPED_NON_METALLIC, FRAG_PACK_LIGHTMAPPED_METALLIC, metallic); +} + +float packScatteringMetallic(float metallic) { + return mix(FRAG_PACK_SCATTERING_NON_METALLIC, FRAG_PACK_SCATTERING_METALLIC, metallic); +} + +float packUnlit() { + return FRAG_PACK_UNLIT; +} + +<@endif@> diff --git a/libraries/render-utils/src/ForwardBufferWrite.slh b/libraries/render-utils/src/ForwardBufferWrite.slh new file mode 100644 index 0000000000..873514d51f --- /dev/null +++ b/libraries/render-utils/src/ForwardBufferWrite.slh @@ -0,0 +1,63 @@ + +<@if not FORWARD_BUFFER_WRITE_SLH@> +<@def FORWARD_BUFFER_WRITE_SLH@> + +<@include ForwardBuffer.slh@> + + +layout(location = 0) out vec4 _fragColor0; + +// the alpha threshold +const float alphaThreshold = 0.5; +float evalOpaqueFinalAlpha(float alpha, float mapAlpha) { + return mix(alpha, 1.0 - alpha, step(mapAlpha, alphaThreshold)); +} + +const float DEFAULT_ROUGHNESS = 0.9; +const float DEFAULT_SHININESS = 10.0; +const float DEFAULT_METALLIC = 0.0; +const vec3 DEFAULT_SPECULAR = vec3(0.1); +const vec3 DEFAULT_EMISSIVE = vec3(0.0); +const float DEFAULT_OCCLUSION = 1.0; +const float DEFAULT_SCATTERING = 0.0; +const vec3 DEFAULT_FRESNEL = DEFAULT_EMISSIVE; + +void packForwardFragment(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 emissive, float occlusion, float scattering) { + if (alpha != 1.0) { + discard; + } + _fragColor0 = vec4(albedo, ((scattering > 0.0) ? packScatteringMetallic(metallic) : packShadedMetallic(metallic))); +} + +void packForwardFragmentLightmap(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 fresnel, vec3 lightmap) { + if (alpha != 1.0) { + discard; + } + + _fragColor0 = vec4(albedo, packLightmappedMetallic(metallic)); +} + +void packForwardFragmentUnlit(vec3 normal, float alpha, vec3 color) { + if (alpha != 1.0) { + discard; + } + _fragColor0 = vec4(color, packUnlit()); +} + +void packForwardFragmentTranslucent(vec3 normal, float alpha, vec3 albedo, vec3 fresnel, float roughness) { + if (alpha <= 0.0) { + discard; + } + _fragColor0 = vec4(albedo.rgb, alpha); +} + +<@endif@> diff --git a/libraries/render-utils/src/ForwardGlobalLight.slh b/libraries/render-utils/src/ForwardGlobalLight.slh new file mode 100644 index 0000000000..aba0498ef5 --- /dev/null +++ b/libraries/render-utils/src/ForwardGlobalLight.slh @@ -0,0 +1,198 @@ + +<@if not DEFERRED_GLOBAL_LIGHT_SLH@> +<@def DEFERRED_GLOBAL_LIGHT_SLH@> + +<@include model/Light.slh@> + +<@include LightingModel.slh@> +<$declareLightBuffer()$> +<$declareLightAmbientBuffer()$> + +<@include LightAmbient.slh@> +<@include LightDirectional.slh@> + + +<@func prepareGlobalLight(isScattering)@> + // prepareGlobalLight + // Transform directions to worldspace + vec3 fragNormal = vec3((normal)); + vec3 fragEyeVector = vec3(invViewMat * vec4(-1.0*position, 0.0)); + vec3 fragEyeDir = normalize(fragEyeVector); + + // Get light + Light light = getLight(); + LightAmbient lightAmbient = getLightAmbient(); + + vec3 lightDirection = getLightDirection(light); + vec3 lightIrradiance = getLightIrradiance(light); + + vec3 color = vec3(0.0); + +<@endfunc@> + + +<@func declareEvalAmbientGlobalColor()@> +vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float metallic, float roughness) { + <$prepareGlobalLight()$> + color += albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(lightAmbient); + return color; +} +<@endfunc@> + +<@func declareEvalAmbientSphereGlobalColor(supportScattering)@> + +<$declareLightingAmbient(1, _SCRIBE_NULL, _SCRIBE_NULL, $supportScattering$)$> +<$declareLightingDirectional($supportScattering$)$> + +<@if supportScattering@> +<$declareDeferredCurvature()$> +<@endif@> + +vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, +vec3 albedo, vec3 fresnel, float metallic, float roughness +<@if supportScattering@> + , float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature +<@endif@> ) { + + <$prepareGlobalLight($supportScattering$)$> + + // Ambient + vec3 ambientDiffuse; + vec3 ambientSpecular; + evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance +<@if supportScattering@> + ,scattering, midNormalCurvature, lowNormalCurvature +<@endif@> ); + color += ambientDiffuse; + color += ambientSpecular; + + + // Directional + vec3 directionalDiffuse; + vec3 directionalSpecular; + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation +<@if supportScattering@> + ,scattering, midNormalCurvature, lowNormalCurvature +<@endif@> ); + color += directionalDiffuse; + color += directionalSpecular; + + return color; +} + +<@endfunc@> + + +<@func declareEvalSkyboxGlobalColor(supportScattering)@> + +<$declareLightingAmbient(_SCRIBE_NULL, 1, _SCRIBE_NULL, $supportScattering$)$> +<$declareLightingDirectional($supportScattering$)$> + +<@if supportScattering@> +<$declareDeferredCurvature()$> +<@endif@> + +vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, + vec3 albedo, vec3 fresnel, float metallic, float roughness +<@if supportScattering@> + , float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature +<@endif@> + ) { + <$prepareGlobalLight($supportScattering$)$> + + // Ambient + vec3 ambientDiffuse; + vec3 ambientSpecular; + evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance +<@if supportScattering@> + ,scattering, midNormalCurvature, lowNormalCurvature +<@endif@> + ); + color += ambientDiffuse; + color += ambientSpecular; + + + // Directional + vec3 directionalDiffuse; + vec3 directionalSpecular; + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation +<@if supportScattering@> + ,scattering, midNormalCurvature, lowNormalCurvature +<@endif@> + ); + color += directionalDiffuse; + color += directionalSpecular; + + return color; +} + +<@endfunc@> + +<@func declareEvalLightmappedColor()@> +vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 albedo, vec3 lightmap) { + Light light = getLight(); + LightAmbient ambient = getLightAmbient(); + + // Catch normals perpendicular to the projection plane, hence the magic number for the threshold + // It should be just 0, but we have inaccuracy so we overshoot + const float PERPENDICULAR_THRESHOLD = -0.005; + vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); // transform to worldspace + float diffuseDot = dot(fragNormal, -getLightDirection(light)); + float facingLight = step(PERPENDICULAR_THRESHOLD, diffuseDot); + + // Reevaluate the shadow attenuation for light facing fragments + float lightAttenuation = (1.0 - facingLight) + facingLight * shadowAttenuation; + + // Diffuse light is the lightmap dimmed by shadow + vec3 diffuseLight = lightAttenuation * lightmap; + + // Ambient light is the lightmap when in shadow + vec3 ambientLight = (1.0 - lightAttenuation) * lightmap * getLightAmbientIntensity(ambient); + + return isLightmapEnabled() * obscurance * albedo * (diffuseLight + ambientLight); +} +<@endfunc@> + + + + +<@func declareEvalGlobalLightingAlphaBlended()@> + +<$declareLightingAmbient(1, 1, 1)$> +<$declareLightingDirectional()$> + +vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float metallic, vec3 emissive, float roughness, float opacity) { + <$prepareGlobalLight()$> + + color += emissive * isEmissiveEnabled(); + + // Ambient + vec3 ambientDiffuse; + vec3 ambientSpecular; + evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance); + color += ambientDiffuse; + color += ambientSpecular / opacity; + + // Directional + vec3 directionalDiffuse; + vec3 directionalSpecular; + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); + color += directionalDiffuse; + color += directionalSpecular / opacity; + + return color; +} + +<@endfunc@> + + +<@endif@> diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 3bf83d08c9..02e4ca9748 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -18,9 +18,11 @@ #include #include +#include +#include + #include #include -#include #include "TextureCache.h" #include "RenderUtilsLogging.h" diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 50499cf31a..6d43e71920 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -36,7 +36,7 @@ vec3 frustumGrid_volumeToGrid(vec3 vpos, ivec3 dims) { vec4 frustumGrid_volumeToClip(vec3 vpos, float rangeNear, float rangeFar) { vec3 ndcPos = vec3(-1.0f + 2.0f * vpos.x, -1.0f + 2.0f * vpos.y, vpos.z); - float depth = rangeNear * (1 - ndcPos.z) + rangeFar * (ndcPos.z); + float depth = rangeNear * (1.0f - ndcPos.z) + rangeFar * (ndcPos.z); vec4 clipPos = vec4(ndcPos.x * depth, ndcPos.y * depth, 1.0f, depth); return clipPos; } @@ -114,14 +114,14 @@ int frustumGrid_eyeDepthToClusterLayer(float eyeZ) { float volumeZ = frustumGrid_eyeToVolumeDepth(eyeZ, frustumGrid.rangeNear, frustumGrid.rangeFar); - float gridZ = frustumGrid_volumeToGridDepth(volumeZ, frustumGrid.dims); + int gridZ = int(frustumGrid_volumeToGridDepth(volumeZ, frustumGrid.dims)); if (gridZ >= frustumGrid.dims.z) { gridZ = frustumGrid.dims.z; } - return int(gridZ); + return gridZ; } ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { @@ -134,8 +134,8 @@ ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { vec3 gridPos = frustumGrid_volumeToGrid(volumePos, frustumGrid.dims); - if (gridPos.z >= frustumGrid.dims.z) { - gridPos.z = frustumGrid.dims.z; + if (gridPos.z >= float(frustumGrid.dims.z)) { + gridPos.z = float(frustumGrid.dims.z); } ivec3 igridPos = ivec3(floor(gridPos)); @@ -154,7 +154,7 @@ ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { int frustumGrid_eyeToClusterDirH(vec3 eyeDir) { if (eyeDir.z >= 0.0f) { - return (eyeDir.x > 0 ? frustumGrid.dims.x : -1); + return (eyeDir.x > 0.0f ? frustumGrid.dims.x : -1); } float eyeDepth = -eyeDir.z; @@ -168,7 +168,7 @@ int frustumGrid_eyeToClusterDirH(vec3 eyeDir) { int frustumGrid_eyeToClusterDirV(vec3 eyeDir) { if (eyeDir.z >= 0.0f) { - return (eyeDir.y > 0 ? frustumGrid.dims.y : -1); + return (eyeDir.y > 0.0f ? frustumGrid.dims.y : -1); } float eyeDepth = -eyeDir.z; diff --git a/libraries/render-utils/src/LightPoint.slh b/libraries/render-utils/src/LightPoint.slh index ac1e415d9d..7e389e11f6 100644 --- a/libraries/render-utils/src/LightPoint.slh +++ b/libraries/render-utils/src/LightPoint.slh @@ -59,12 +59,12 @@ bool evalLightPointEdge(out vec3 color, Light light, vec4 fragLightDirLen, vec3 // Show edges float edge = abs(2.0 * ((lightVolume_getRadius(light.volume) - fragLightDistance) / (0.1)) - 1.0); - if (edge < 1) { + if (edge < 1.0) { float edgeCoord = exp2(-8.0*edge*edge); color = vec3(edgeCoord * edgeCoord * getLightColor(light)); } - return (edge < 1); + return (edge < 1.0); } <@endfunc@> diff --git a/libraries/render-utils/src/LightSpot.slh b/libraries/render-utils/src/LightSpot.slh index a38851b039..8627dae0eb 100644 --- a/libraries/render-utils/src/LightSpot.slh +++ b/libraries/render-utils/src/LightSpot.slh @@ -66,12 +66,12 @@ bool evalLightSpotEdge(out vec3 color, Light light, vec4 fragLightDirLen, float float edgeDistS = dot(fragLightDistance * vec2(cosSpotAngle, sqrt(1.0 - cosSpotAngle * cosSpotAngle)), -lightVolume_getSpotOutsideNormal2(light.volume)); float edgeDist = min(edgeDistR, edgeDistS); float edge = abs(2.0 * (edgeDist / (0.1)) - 1.0); - if (edge < 1) { + if (edge < 1.0) { float edgeCoord = exp2(-8.0*edge*edge); color = vec3(edgeCoord * edgeCoord * getLightColor(light)); } - return (edge < 1); + return (edge < 1.0); } <@endfunc@> diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index 209a1f38d6..521c4894dc 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -157,7 +157,7 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float m float power = specularDistribution(roughness, fragNormal, halfDir); vec3 specular = fresnelColor * power * diffuse; - return vec4(specular, (1.0 - metallic) * diffuse * (1 - fresnelColor.x)); + return vec4(specular, (1.0 - metallic) * diffuse * (1.0 - fresnelColor.x)); } // Frag Shading returns the diffuse amount as W and the specular rgb as xyz @@ -171,7 +171,7 @@ vec4 evalPBRShadingDielectric(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDi float power = specularDistribution(roughness, fragNormal, halfDir); vec3 specular = vec3(fresnelScalar) * power * diffuse; - return vec4(specular, diffuse * (1 - fresnelScalar)); + return vec4(specular, diffuse * (1.0 - fresnelScalar)); } vec4 evalPBRShadingMetallic(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float roughness, vec3 fresnel) { diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index e694935361..6c77fc4a91 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -66,7 +66,7 @@ vec3 fetchNormalMap(vec2 uv) { // unpack normal, swizzle to get into hifi tangent space with Y axis pointing out vec2 t = 2.0 * (texture(normalMap, uv).rg - vec2(0.5, 0.5)); vec2 t2 = t*t; - return vec3(t.x, sqrt(1 - t2.x - t2.y), t.y); + return vec3(t.x, sqrt(1.0 - t2.x - t2.y), t.y); } <@endif@> @@ -163,7 +163,7 @@ vec3 fetchLightmapMap(vec2 uv) { vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); // attenuate the normal map divergence from the mesh normal based on distance // THe attenuation range [20,100] meters from the eye is arbitrary for now - vec3 localNormal = mix(<$fetchedNormal$>, vec3(0.0, 1.0, 0.0), smoothstep(20, 100, (-<$fragPos$>).z)); + vec3 localNormal = mix(<$fetchedNormal$>, vec3(0.0, 1.0, 0.0), smoothstep(20.0, 100.0, (-<$fragPos$>).z)); <$normal$> = vec3(normalizedTangent * localNormal.x + normalizedNormal * localNormal.y + normalizedBitangent * localNormal.z); } <@endfunc@> diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 517fe97dba..e640f54fd4 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -14,7 +14,6 @@ #include #include "DeferredLightingEffect.h" -#include "EntityItem.h" using namespace render; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 63aeacf80c..3b55cac0b8 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -382,8 +382,8 @@ protected: QVector> _collisionRenderItems; QMap _collisionRenderItemsMap; - QVector> _modelMeshRenderItems; - QMap _modelMeshRenderItemsMap; + QVector> _modelMeshRenderItems; + QMap _modelMeshRenderItemsMap; render::ItemIDs _modelMeshRenderItemIDs; diff --git a/libraries/render-utils/src/PickItemsJob.cpp b/libraries/render-utils/src/PickItemsJob.cpp index 48ba605d7b..860262a969 100644 --- a/libraries/render-utils/src/PickItemsJob.cpp +++ b/libraries/render-utils/src/PickItemsJob.cpp @@ -31,26 +31,26 @@ void PickItemsJob::run(const render::RenderContextPointer& renderContext, const } render::ItemBound PickItemsJob::findNearestItem(const render::RenderContextPointer& renderContext, const render::ItemBounds& inputs, float& minIsectDistance) const { - const glm::vec3 rayOrigin = renderContext->args->getViewFrustum().getPosition(); - const glm::vec3 rayDirection = renderContext->args->getViewFrustum().getDirection(); - BoxFace face; - glm::vec3 normal; - float isectDistance; - render::ItemBound nearestItem( render::Item::INVALID_ITEM_ID ); - const float minDistance = 0.2f; - const float maxDistance = 50.f; + const glm::vec3 rayOrigin = renderContext->args->getViewFrustum().getPosition(); + const glm::vec3 rayDirection = renderContext->args->getViewFrustum().getDirection(); + BoxFace face; + glm::vec3 normal; + float isectDistance; + render::ItemBound nearestItem( render::Item::INVALID_ITEM_ID ); + const float minDistance = 0.2f; + const float maxDistance = 50.f; render::ItemKey itemKey; - for (const auto& itemBound : inputs) { - if (!itemBound.bound.contains(rayOrigin) && itemBound.bound.findRayIntersection(rayOrigin, rayDirection, isectDistance, face, normal)) { - auto& item = renderContext->_scene->getItem(itemBound.id); + for (const auto& itemBound : inputs) { + if (!itemBound.bound.contains(rayOrigin) && itemBound.bound.findRayIntersection(rayOrigin, rayDirection, isectDistance, face, normal)) { + auto& item = renderContext->_scene->getItem(itemBound.id); itemKey = item.getKey(); - if (itemKey.isWorldSpace() && isectDistance>minDistance && isectDistance < minIsectDistance && isectDistanceminDistance && isectDistance < minIsectDistance && isectDistance; + using Config = PickItemsConfig; + using Input = render::ItemBounds; + using Output = render::ItemBounds; + using JobModel = render::Job::ModelIO; PickItemsJob(render::ItemKey::Flags validKeys = render::ItemKey::Builder().withTypeMeta().withTypeShape().build()._flags, render::ItemKey::Flags excludeKeys = 0); - void configure(const Config& config); - void run(const render::RenderContextPointer& renderContext, const PickItemsJob::Input& input, PickItemsJob::Output& output); + void configure(const Config& config); + void run(const render::RenderContextPointer& renderContext, const PickItemsJob::Input& input, PickItemsJob::Output& output); private: @@ -47,7 +47,7 @@ private: render::ItemKey::Flags _excludeKeys; bool _isEnabled{ false }; - render::ItemBound findNearestItem(const render::RenderContextPointer& renderContext, const render::ItemBounds& inputs, float& minIsectDistance) const; + render::ItemBound findNearestItem(const render::RenderContextPointer& renderContext, const render::ItemBounds& inputs, float& minIsectDistance) const; }; #endif // hifi_render_utils_PickItemsJob_h diff --git a/libraries/render-utils/src/SubsurfaceScattering.slh b/libraries/render-utils/src/SubsurfaceScattering.slh index 42ffafd9ff..201ec2291a 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.slh +++ b/libraries/render-utils/src/SubsurfaceScattering.slh @@ -105,7 +105,7 @@ vec3 integrate(float cosTheta, float skinRadius) { vec3 totalLight = vec3(0.0); const float _PI = 3.14159265358979523846; - const float step = 2.0 * _PI / <$NumIntegrationSteps$>; + const float step = 2.0 * _PI / float(<$NumIntegrationSteps$>); float a = -(_PI); diff --git a/libraries/render-utils/src/forward_model.slf b/libraries/render-utils/src/forward_model.slf index daeead65ec..7b708a1d24 100644 --- a/libraries/render-utils/src/forward_model.slf +++ b/libraries/render-utils/src/forward_model.slf @@ -1,7 +1,7 @@ <@include gpu/Config.slh@> <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> -// model.frag +// forward_model.frag // fragment shader // // Created by Andrzej Kapolka on 10/14/13. @@ -11,12 +11,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include DeferredBufferWrite.slh@> + !> + +<@include ForwardGlobalLight.slh@> +<$declareEvalSkyboxGlobalColor()$> <@include model/Material.slh@> +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + <@include MaterialTextures.slh@> -<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, _SCRIBE_NULL)$> in vec4 _position; in vec3 _normal; @@ -24,12 +30,13 @@ in vec3 _color; in vec2 _texCoord0; in vec2 _texCoord1; +out vec4 _fragColor; void main(void) { Material mat = getMaterial(); int matKey = getMaterialKey(mat); <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$> - <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + !> float opacity = 1.0; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; @@ -39,21 +46,43 @@ void main(void) { <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; + float metallic = getMaterialMetallic(mat); + vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value + if (metallic <= 0.5) { + metallic = 0.0; + } else { + fresnel = albedo; + metallic = 1.0; + } + float roughness = getMaterialRoughness(mat); <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; vec3 emissive = getMaterialEmissive(mat); <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; - float scattering = getMaterialScattering(mat); - packDeferredFragment( - normalize(_normal.xyz), - opacity, + vec3 fragPosition = _position.xyz; + + TransformCamera cam = getTransformCamera(); + vec3 fragNormal; + <$transformEyeToWorldDir(cam, _normal, fragNormal)$> + + /* vec4 color = vec4(evalSkyboxGlobalColor( + cam._viewInverse, + 1.0, + 1.0, + fragPosition, + fragNormal, albedo, - roughness, - getMaterialMetallic(mat), - emissive, - occlusionTex, - scattering); + fresnel, + metallic, + roughness), + opacity); + color.rgb += emissive * isEmissiveEnabled(); + + */ + + _fragColor = vec4(albedo, opacity); + } diff --git a/libraries/render-utils/src/forward_model_normal_map.slf b/libraries/render-utils/src/forward_model_normal_map.slf index 5cc1a1859f..a199483b9f 100644 --- a/libraries/render-utils/src/forward_model_normal_map.slf +++ b/libraries/render-utils/src/forward_model_normal_map.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// model_normal_map.frag +// forward_model_normal_map.frag // fragment shader // // Created by Andrzej Kapolka on 10/29/13. @@ -12,7 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include DeferredBufferWrite.slh@> +<@include ForwardBufferWrite.slh@> <@include model/Material.slh@> @@ -47,12 +47,12 @@ void main(void) { <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; vec3 viewNormal; - <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$> + <$tangentToViewSpace(normalTex, _normal, _tangent, viewNormal)$> float scattering = getMaterialScattering(mat); <$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>; - packDeferredFragment( + packForwardFragment( viewNormal, opacity, albedo, diff --git a/libraries/render-utils/src/forward_model_normal_specular_map.slf b/libraries/render-utils/src/forward_model_normal_specular_map.slf index 9e079b33a0..ca6bbec3da 100644 --- a/libraries/render-utils/src/forward_model_normal_specular_map.slf +++ b/libraries/render-utils/src/forward_model_normal_specular_map.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// model_normal_specular_map.frag +// forward_model_normal_specular_map.frag // fragment shader // // Created by Andrzej Kapolka on 5/6/14. @@ -12,7 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include DeferredBufferWrite.slh@> +<@include ForwardBufferWrite.slh@> <@include model/Material.slh@> @@ -47,14 +47,14 @@ void main(void) { <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; vec3 viewNormal; - <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$> + <$tangentToViewSpace(normalTex, _normal, _tangent, viewNormal)$> float metallic = getMaterialMetallic(mat); <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; float scattering = getMaterialScattering(mat); - packDeferredFragment( + packForwardFragment( normalize(viewNormal.xyz), opacity, albedo, diff --git a/libraries/render-utils/src/forward_model_specular_map.slf b/libraries/render-utils/src/forward_model_specular_map.slf index 47b5e3389d..d2fdd18794 100644 --- a/libraries/render-utils/src/forward_model_specular_map.slf +++ b/libraries/render-utils/src/forward_model_specular_map.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// model_specular_map.frag +// forward_model_specular_map.frag // fragment shader // // Created by Andrzej Kapolka on 5/6/14. @@ -12,7 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include DeferredBufferWrite.slh@> +<@include ForwardBufferWrite.slh@> <@include model/Material.slh@> @@ -51,7 +51,7 @@ void main(void) { float scattering = getMaterialScattering(mat); - packDeferredFragment( + packForwardFragment( normalize(_normal), opacity, albedo, diff --git a/libraries/render-utils/src/forward_model_translucent.slf b/libraries/render-utils/src/forward_model_translucent.slf new file mode 100644 index 0000000000..52e8ce50e7 --- /dev/null +++ b/libraries/render-utils/src/forward_model_translucent.slf @@ -0,0 +1,81 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// forward_model_translucent.frag +// fragment shader +// +// Created by Sam Gateau on 2/15/2016. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include model/Material.slh@> + +<@include ForwardGlobalLight.slh@> + +<$declareEvalGlobalLightingAlphaBlended()$> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> + +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec4 _position; +in vec3 _normal; +in vec3 _color; +in float _alpha; + +out vec4 _fragColor; + +void main(void) { + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = getMaterialOpacity(mat) * _alpha; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + float metallic = getMaterialMetallic(mat); + vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value + if (metallic <= 0.5) { + metallic = 0.0; + } else { + fresnel = albedo; + metallic = 1.0; + } + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + vec3 fragPosition = _position.xyz; + vec3 fragNormal = normalize(_normal); + + TransformCamera cam = getTransformCamera(); + + _fragColor = vec4(evalGlobalLightingAlphaBlended( + cam._viewInverse, + 1.0, + occlusionTex, + fragPosition, + fragNormal, + albedo, + fresnel, + metallic, + emissive, + roughness, opacity), + opacity); +} diff --git a/libraries/render-utils/src/forward_model_unlit.slf b/libraries/render-utils/src/forward_model_unlit.slf index 750b51fe8c..fb760467c9 100644 --- a/libraries/render-utils/src/forward_model_unlit.slf +++ b/libraries/render-utils/src/forward_model_unlit.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// material_opaque_unlit.frag +// forward_model_unlit.frag // fragment shader // // Created by Sam Gateau on 5/5/2016. @@ -12,7 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include DeferredBufferWrite.slh@> +<@include ForwardBufferWrite.slh@> <@include LightingModel.slh@> <@include model/Material.slh@> @@ -38,7 +38,7 @@ void main(void) { <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; - packDeferredFragmentUnlit( + packForwardFragmentUnlit( normalize(_normal), opacity, albedo * isUnlitEnabled()); diff --git a/libraries/render-utils/src/glowLine.slf b/libraries/render-utils/src/glowLine.slf index c0af97930a..6f0281c5ec 100644 --- a/libraries/render-utils/src/glowLine.slf +++ b/libraries/render-utils/src/glowLine.slf @@ -20,7 +20,7 @@ void main(void) { float alpha = 1.0 - abs(inColor.a); // Convert from a linear alpha curve to a sharp peaked one - alpha = pow(alpha, 10); + alpha = pow(alpha, 10.0); // Drop everything where the curve falls off to nearly nothing if (alpha <= 0.05) { diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index c570957dfb..b88e2e9ee2 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -53,12 +53,12 @@ void main(void) { - ivec3 cluster = clusterGrid_getCluster(gpu_InstanceID); + ivec3 cluster = clusterGrid_getCluster(gpu_InstanceID()); int numLights = cluster.x + cluster.y; float numLightsScale = clamp(numLights * 0.1, 0.0, 1.0); - ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID); + ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID()); float boxScale = 0.99; vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3((1.0 - boxScale) * 0.5 + (1.0 - numLightsScale) * boxScale * 0.5) + numLightsScale * boxScale * pos.xyz); @@ -69,5 +69,5 @@ void main(void) { TransformCamera cam = getTransformCamera(); <$transformWorldToClipPos(cam, worldPos, gl_Position)$> - varColor = vec4(colorWheel(fract(float(gpu_InstanceID) / float(frustumGrid_numClusters()))), (numLights >0 ? 0.9 : 0.1)); + varColor = vec4(colorWheel(fract(float(gpu_InstanceID()) / float(frustumGrid_numClusters()))), (numLights >0 ? 0.9 : 0.1)); } \ No newline at end of file diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv index 5840f11d0a..912c39f93c 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv @@ -53,7 +53,7 @@ void main(void) { ); vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID); + ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID()); vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz); vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0)); @@ -62,5 +62,5 @@ void main(void) { TransformCamera cam = getTransformCamera(); <$transformWorldToClipPos(cam, worldPos, gl_Position)$> - varColor = vec4(colorWheel(fract(float(gpu_InstanceID) / float(frustumGrid_numClusters()))), 0.9); + varColor = vec4(colorWheel(fract(float(gpu_InstanceID()) / float(frustumGrid_numClusters()))), 0.9); } \ No newline at end of file diff --git a/libraries/render-utils/src/lightClusters_drawGrid.slv b/libraries/render-utils/src/lightClusters_drawGrid.slv index 1475666ec6..aac7fe59a5 100644 --- a/libraries/render-utils/src/lightClusters_drawGrid.slv +++ b/libraries/render-utils/src/lightClusters_drawGrid.slv @@ -54,10 +54,10 @@ void main(void) { vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - ivec3 cluster = clusterGrid_getCluster(gpu_InstanceID); + ivec3 cluster = clusterGrid_getCluster(gpu_InstanceID()); int numLights = cluster.x + cluster.y; - ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID); + ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID()); float boxScale = 1.0; @@ -69,5 +69,5 @@ void main(void) { TransformCamera cam = getTransformCamera(); <$transformWorldToClipPos(cam, worldPos, gl_Position)$> - varColor = vec4(colorWheel(fract(float(gpu_InstanceID) / float(frustumGrid_numClusters()))), (numLights > 0 ? 0.9 : 0.0)); + varColor = vec4(colorWheel(fract(float(gpu_InstanceID()) / float(frustumGrid_numClusters()))), (numLights > 0 ? 0.9 : 0.0)); } \ No newline at end of file diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index 228560f394..1e3b6908cd 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -72,7 +72,7 @@ void main(void) { normal, 1.0, diffuse, - max(0, 1.0 - shininess / 128.0), + max(0.0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular, specular); @@ -81,7 +81,7 @@ void main(void) { normal, 1.0, diffuse, - max(0, 1.0 - shininess / 128.0), + max(0.0, 1.0 - shininess / 128.0), length(specular), DEFAULT_EMISSIVE, DEFAULT_OCCLUSION, diff --git a/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf b/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf index e96ac60b45..ecbc60b648 100644 --- a/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf +++ b/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf @@ -123,7 +123,7 @@ void main(void) { // Calculate dF/du and dF/dv vec2 viewportScale = perspectiveScale * getInvWidthHeight(); - vec2 du = vec2( viewportScale.x * (stereoSide.w > 0.0 ? 0.5 : 1.0), 0.0f ); + vec2 du = vec2( viewportScale.x * (float(stereoSide.w) > 0.0 ? 0.5 : 1.0), 0.0f ); vec2 dv = vec2( 0.0f, viewportScale.y ); vec4 dFdu = vec4(getWorldNormalDiff(frameTexcoordPos, du), getEyeDepthDiff(frameTexcoordPos, du)); diff --git a/libraries/render/CMakeLists.txt b/libraries/render/CMakeLists.txt index 561dff4290..8fd05bd320 100644 --- a/libraries/render/CMakeLists.txt +++ b/libraries/render/CMakeLists.txt @@ -2,8 +2,7 @@ set(TARGET_NAME render) AUTOSCRIBE_SHADER_LIB(gpu model) setup_hifi_library() -link_hifi_libraries(shared ktx gpu model) # render needs octree only for getAccuracyAngle(float, int) -include_hifi_library_headers(octree) +link_hifi_libraries(shared ktx gpu model octree) target_nsight() diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 240693b422..1650d09c5d 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -16,7 +16,7 @@ #include "Scene.h" #include "../task/Task.h" -#include "gpu/Batch.h" +#include namespace render { diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 21638fbb70..96faf9719e 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -25,7 +25,7 @@ #include "Args.h" -#include "model/Material.h" +#include #include "ShapePipeline.h" namespace render { diff --git a/libraries/render/src/render/TransitionStage.h b/libraries/render/src/render/TransitionStage.h index 8dfef1b78e..226d531d8b 100644 --- a/libraries/render/src/render/TransitionStage.h +++ b/libraries/render/src/render/TransitionStage.h @@ -18,19 +18,19 @@ namespace render { - // Transition stage to set up Transition-related effects - class TransitionStage : public render::Stage { - public: + // Transition stage to set up Transition-related effects + class TransitionStage : public render::Stage { + public: static const std::string& getName() { return _name; } - using Index = indexed_container::Index; - static const Index INVALID_INDEX{ indexed_container::INVALID_INDEX }; + using Index = indexed_container::Index; + static const Index INVALID_INDEX{ indexed_container::INVALID_INDEX }; using TransitionIdList = indexed_container::Indices; static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - bool checkTransitionId(Index index) const { return _transitions.checkIndex(index); } + bool checkTransitionId(Index index) const { return _transitions.checkIndex(index); } const Transition& getTransition(Index TransitionId) const { return _transitions.get(TransitionId); } @@ -48,10 +48,10 @@ namespace render { static std::string _name; - Transitions _transitions; + Transitions _transitions; TransitionIdList _activeTransitionIds; - }; - using TransitionStagePointer = std::shared_ptr; + }; + using TransitionStagePointer = std::shared_ptr; class TransitionStageSetup { public: diff --git a/libraries/render/src/render/drawItemBounds.slf b/libraries/render/src/render/drawItemBounds.slf index 4fb23df8f6..e01d1607bd 100644 --- a/libraries/render/src/render/drawItemBounds.slf +++ b/libraries/render/src/render/drawItemBounds.slf @@ -19,7 +19,7 @@ out vec4 outFragColor; void main(void) { float var = step(fract(varTexcoord.x * varTexcoord.y * 1.0), 0.5); - if (varColor.a == 0) { + if (varColor.a == 0.0) { outFragColor = vec4(mix(vec3(0.0), varColor.xyz, var), mix(0.0, 1.0, var)); } else { diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index 6dc3188b3f..fef11c12e9 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -33,7 +33,7 @@ bool UsersScriptingInterface::getIgnoreStatus(const QUuid& nodeID) { void UsersScriptingInterface::personalMute(const QUuid& nodeID, bool muteEnabled) { // ask the NodeList to mute the user with the given session ID - // "Personal Mute" only applies one way and is not global + // "Personal Mute" only applies one way and is not global DependencyManager::get()->personalMuteNodeBySessionID(nodeID, muteEnabled); } diff --git a/libraries/script-engine/src/Vec3.cpp b/libraries/script-engine/src/Vec3.cpp index a156f56d96..c21f96cd47 100644 --- a/libraries/script-engine/src/Vec3.cpp +++ b/libraries/script-engine/src/Vec3.cpp @@ -90,6 +90,6 @@ glm::vec3 Vec3::fromPolar(float elevation, float azimuth) { } float Vec3::getAngle(const glm::vec3& v1, const glm::vec3& v2) { - return glm::acos(glm::dot(glm::normalize(v1), glm::normalize(v2))); + return glm::acos(glm::dot(glm::normalize(v1), glm::normalize(v2))); } diff --git a/libraries/script-engine/src/WebSocketClass.cpp b/libraries/script-engine/src/WebSocketClass.cpp index 19148b26e9..76faaab415 100644 --- a/libraries/script-engine/src/WebSocketClass.cpp +++ b/libraries/script-engine/src/WebSocketClass.cpp @@ -25,7 +25,7 @@ WebSocketClass::WebSocketClass(QScriptEngine* engine, QString url) : WebSocketClass::WebSocketClass(QScriptEngine* engine, QWebSocket* qWebSocket) : _webSocket(qWebSocket), - _engine(engine) + _engine(engine) { initialize(); } diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 1fefda06b3..f9b835df5c 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -3,8 +3,6 @@ set(TARGET_NAME shared) # TODO: there isn't really a good reason to have Script linked here - let's get what is requiring it out (RegisteredMetaTypes.cpp) setup_hifi_library(Gui Network Script Widgets) -target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes") - if (WIN32) target_link_libraries(${TARGET_NAME} Wbemuuid.lib) endif() diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index 7a453e63c3..e6fc7ce96b 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -12,6 +12,7 @@ #ifndef hifi_DependencyManager_h #define hifi_DependencyManager_h +#include #include #include #include @@ -64,6 +65,15 @@ public: template static void registerInheritance(); + template + static size_t typeHash() { +#ifdef Q_OS_ANDROID + size_t hashCode = std::hash{}( typeid(T).name() ); +#else + size_t hashCode = typeid(T).hash_code(); +#endif + return hashCode; + } private: static DependencyManager& manager(); @@ -134,14 +144,14 @@ void DependencyManager::destroy() { template void DependencyManager::registerInheritance() { - size_t baseHashCode = typeid(Base).hash_code(); - size_t derivedHashCode = typeid(Derived).hash_code(); + size_t baseHashCode = typeHash(); + size_t derivedHashCode = typeHash(); manager()._inheritanceHash.insert(baseHashCode, derivedHashCode); } template size_t DependencyManager::getHashCode() { - size_t hashCode = typeid(T).hash_code(); + size_t hashCode = typeHash(); auto derivedHashCode = _inheritanceHash.find(hashCode); while (derivedHashCode != _inheritanceHash.end()) { diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 0636411f51..cd7a6530f9 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "PathUtils.h" + #include #include #include @@ -16,7 +18,6 @@ #include #include #include -#include "PathUtils.h" #include #include // std::once #include "shared/GlobalAppProperties.h" @@ -92,18 +93,17 @@ QUrl PathUtils::defaultScriptsLocation(const QString& newDefaultPath) { if (!overriddenDefaultScriptsLocation.isEmpty()) { path = overriddenDefaultScriptsLocation; } else { -#ifdef Q_OS_WIN - path = QCoreApplication::applicationDirPath() + "/scripts"; -#elif defined(Q_OS_OSX) +#if defined(Q_OS_OSX) path = QCoreApplication::applicationDirPath() + "/../Resources/scripts"; +#elif defined(Q_OS_ANDROID) + path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/scripts"; #else path = QCoreApplication::applicationDirPath() + "/scripts"; #endif } // turn the string into a legit QUrl - QFileInfo fileInfo(path); - return QUrl::fromLocalFile(fileInfo.canonicalFilePath()); + return QUrl::fromLocalFile(QFileInfo(path).canonicalFilePath()); } QString PathUtils::stripFilename(const QUrl& url) { diff --git a/libraries/shared/src/Preferences.h b/libraries/shared/src/Preferences.h index 6fa2cb9b1f..a243a6d58d 100644 --- a/libraries/shared/src/Preferences.h +++ b/libraries/shared/src/Preferences.h @@ -257,12 +257,12 @@ public: }; class SpinnerSliderPreference : public FloatPreference { - Q_OBJECT + Q_OBJECT public: - SpinnerSliderPreference(const QString& category, const QString& name, Getter getter, Setter setter) - : FloatPreference(category, name, getter, setter) { } + SpinnerSliderPreference(const QString& category, const QString& name, Getter getter, Setter setter) + : FloatPreference(category, name, getter, setter) { } - Type getType() override { return SpinnerSlider; } + Type getType() override { return SpinnerSlider; } }; class IntSpinnerPreference : public IntPreference { diff --git a/libraries/shared/src/SettingHandle.h b/libraries/shared/src/SettingHandle.h index 341a4cb101..e77ee00b05 100644 --- a/libraries/shared/src/SettingHandle.h +++ b/libraries/shared/src/SettingHandle.h @@ -39,7 +39,7 @@ public: QStringList childKeys() const; QStringList allKeys() const; bool contains(const QString& key) const; - int beginReadArray(const QString & prefix); + int beginReadArray(const QString & prefix); void beginWriteArray(const QString& prefix, int size = -1); void endArray(); void setArrayIndex(int i); diff --git a/libraries/shared/src/shared/PlatformHacks.h b/libraries/shared/src/shared/PlatformHacks.h new file mode 100644 index 0000000000..909f0bac9a --- /dev/null +++ b/libraries/shared/src/shared/PlatformHacks.h @@ -0,0 +1,18 @@ +// +// Created by Bradley Austin Davis on 2017/09/15 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once +#ifndef hifi_shared_PlatformHacks_h +#define hifi_shared_PlatformHacks_h + +#include + +#if defined(Q_OS_ANDROID) +#include "platform/AndroidHacks.h" +#endif + +#endif diff --git a/libraries/shared/src/shared/platform/AndroidHacks.h b/libraries/shared/src/shared/platform/AndroidHacks.h new file mode 100644 index 0000000000..29ab013f98 --- /dev/null +++ b/libraries/shared/src/shared/platform/AndroidHacks.h @@ -0,0 +1,50 @@ +// +// androidhacks.h +// interface/src +// +// Created by Cristian Duarte & Gabriel Calero on 1/4/17. +// Copyright 2017 High Fidelity, Inc. +// +// hacks to get android to compile +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#pragma once +#ifndef hifi_shared_platform_androidhacks_h +#define hifi_shared_platform_androidhacks_h + +#include +#include + +#include + +// Only for gnu stl, so checking if using llvm +// (If there is a better check than this http://stackoverflow.com/questions/31657499/how-to-detect-stdlib-libc-in-the-preprocessor, improve this one) +#if (_LIBCPP_VERSION) + // NOTHING, these functions are well defined on libc++ +#else + +using namespace std; +namespace std +{ + // to_string impl + // error: no member named 'to_string' in namespace 'std' + // http://stackoverflow.com/questions/26095886/error-to-string-is-not-a-member-of-std + template + inline std::string to_string(T value) { + std::ostringstream os; + os << value; + return os.str(); + } + + inline float stof(std::string str) { + return atof(str.c_str()); + } +} + +#endif // _LIBCPP_VERSION + +#endif // hifi_androidhacks_h diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index 68a6fd25b9..f28157ff97 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -2,7 +2,5 @@ set(TARGET_NAME ui) setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns) link_hifi_libraries(shared networking gl audio) -if (NOT ANDROID) - # Required for some low level GL interaction in the OffscreenQMLSurface - target_glew() -endif () +# Required for some low level GL interaction in the OffscreenQMLSurface +target_opengl() diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index 70daff944a..12cb7e2e4b 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -170,7 +170,7 @@ void VrMenu::addMenu(QMenu* menu) { QObject* parent = menu->parent(); QObject* qmlParent = nullptr; QMenu* parentMenu = dynamic_cast(parent); - if (parentMenu) { + if (parentMenu && menu->menuAction()) { MenuUserData* userData = MenuUserData::forObject(parentMenu->menuAction()); if (!userData) { return; diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index d03842d45a..6125aea15c 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -827,7 +827,7 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even switch (event->type()) { case QEvent::Resize: { QResizeEvent* resizeEvent = static_cast(event); - QWidget* widget = dynamic_cast(originalDestination); + QWidget* widget = static_cast(originalDestination); if (widget) { this->resize(resizeEvent->size()); } @@ -932,7 +932,7 @@ void OffscreenQmlSurface::focusDestroyed(QObject *obj) { } void OffscreenQmlSurface::onFocusObjectChanged(QObject* object) { - QQuickItem* item = dynamic_cast(object); + QQuickItem* item = static_cast(object); if (!item) { setFocusText(false); _currentFocusItem = nullptr; @@ -1019,6 +1019,10 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key) { } void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric) { +#if Q_OS_ANDROID + return; +#endif + if (!object) { return; } diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 18844a1995..3d06a4b223 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -88,7 +88,7 @@ ovrSession acquireOculusSession() { } if (!session) { - ovrInitParams initParams { + ovrInitParams initParams { ovrInit_RequestVersion | ovrInit_MixedRendering, OVR_MINOR_VERSION, nullptr, 0, 0 }; diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index 80c8698bb6..804ff7d62e 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -181,7 +181,7 @@ bool OculusLegacyDisplayPlugin::internalActivate() { } void OculusLegacyDisplayPlugin::internalDeactivate() { - Parent::internalDeactivate(); + Parent::internalDeactivate(); ovrHmd_Destroy(_hmd); _hmd = nullptr; ovr_Shutdown(); diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index 20345467df..36bdd1c792 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -17,7 +17,7 @@ const float TARGET_RATE_OculusLegacy = 75.0f; class GLWindow; class OculusLegacyDisplayPlugin : public HmdDisplayPlugin { - using Parent = HmdDisplayPlugin; + using Parent = HmdDisplayPlugin; public: OculusLegacyDisplayPlugin(); bool isSupported() const override; diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index 9847e9f7b9..7c6886ad93 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -19,6 +19,7 @@ #include #include +#include #include @@ -114,13 +115,37 @@ public: } }; + + +const std::string VERTEX_SHADER_DEFINES{ R"GLSL( +#version 410 core +#define GPU_VERTEX_SHADER +#define GPU_TRANSFORM_IS_STEREO +#define GPU_TRANSFORM_STEREO_CAMERA +#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED +#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN +)GLSL" }; + +const std::string PIXEL_SHADER_DEFINES{ R"GLSL( +#version 410 core +#define GPU_PIXEL_SHADER +#define GPU_TRANSFORM_IS_STEREO +#define GPU_TRANSFORM_STEREO_CAMERA +#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED +#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN +)GLSL" }; + void testShaderBuild(const char* vs_src, const char * fs_src) { - auto vs = gpu::Shader::createVertex(std::string(vs_src)); - auto fs = gpu::Shader::createPixel(std::string(fs_src)); - auto pr = gpu::Shader::createProgram(vs, fs); - if (!gpu::Shader::makeProgram(*pr)) { + std::string error; + GLuint vs, fs; + if (!gl::compileShader(GL_VERTEX_SHADER, vs_src, VERTEX_SHADER_DEFINES, vs, error) || + !gl::compileShader(GL_FRAGMENT_SHADER, fs_src, PIXEL_SHADER_DEFINES, fs, error)) { throw std::runtime_error("Failed to compile shader"); } + auto pr = gl::compileProgram({ vs, fs }, error); + if (!pr) { + throw std::runtime_error("Failed to link shader"); + } } void QTestWindow::draw() { diff --git a/tools/oven/src/ui/BakeWidget.cpp b/tools/oven/src/ui/BakeWidget.cpp index 23a4822d82..9fb8f2f880 100644 --- a/tools/oven/src/ui/BakeWidget.cpp +++ b/tools/oven/src/ui/BakeWidget.cpp @@ -17,7 +17,7 @@ #include "BakeWidget.h" BakeWidget::BakeWidget(QWidget* parent, Qt::WindowFlags flags) : - QWidget(parent, flags) + QWidget(parent, flags) { }