Merge branch 'master' of https://github.com/highfidelity/hifi into blue
1
.gitattributes
vendored
|
@ -10,6 +10,7 @@
|
|||
*.json text
|
||||
*.js text
|
||||
*.qml text
|
||||
*.qrc text
|
||||
*.slf text
|
||||
*.slh text
|
||||
*.slv text
|
||||
|
|
5
.gitignore
vendored
|
@ -12,6 +12,11 @@ ext/
|
|||
Makefile
|
||||
*.user
|
||||
|
||||
# Android Studio
|
||||
*.iml
|
||||
local.properties
|
||||
android/libraries
|
||||
|
||||
# Xcode
|
||||
*.xcodeproj
|
||||
*.xcworkspace
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
8
android/app/CMakeLists.txt
Normal file
|
@ -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")
|
57
android/app/build.gradle
Normal file
|
@ -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')
|
25
android/app/proguard-rules.pro
vendored
Normal file
|
@ -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
|
37
android/app/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.saintandreas.testapp">
|
||||
|
||||
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="26" />
|
||||
<uses-feature android:glEsVersion="0x00030001" android:required="true" />
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true"/>
|
||||
<uses-feature android:name="android.software.vr.mode" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:theme="@style/VrActivityTheme"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:screenOrientation="landscape"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:enableVrMode="@string/gvr_vr_mode_component"
|
||||
android:resizeableActivity="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="com.google.intent.category.DAYDREAM"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="com.google.intent.category.CARDBOARD" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
50
android/app/src/main/cpp/GoogleVRHelpers.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <vr/gvr/capi/include/gvr.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
78
android/app/src/main/cpp/native-lib.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include <jni.h>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#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<intptr_t>(renderer);
|
||||
}
|
||||
|
||||
static NativeRenderer *fromJni(jlong renderer) {
|
||||
return reinterpret_cast<NativeRenderer*>(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<gvr_context *>(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"
|
636
android/app/src/main/cpp/renderer.cpp
Normal file
|
@ -0,0 +1,636 @@
|
|||
#include "renderer.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include "GoogleVRHelpers.h"
|
||||
|
||||
#include <gl/GLShaders.h>
|
||||
#include <shared/Bilateral.h>
|
||||
|
||||
#include <gpu/DrawTransformUnitQuad_vert.h>
|
||||
#include <gpu/DrawTexcoordRectTransformUnitQuad_vert.h>
|
||||
#include <gpu/DrawViewportQuadTransformTexcoord_vert.h>
|
||||
#include <gpu/DrawTexture_frag.h>
|
||||
#include <gpu/DrawTextureOpaque_frag.h>
|
||||
#include <gpu/DrawColoredTexture_frag.h>
|
||||
|
||||
#include <render-utils/simple_vert.h>
|
||||
#include <render-utils/simple_frag.h>
|
||||
#include <render-utils/simple_textured_frag.h>
|
||||
#include <render-utils/simple_textured_unlit_frag.h>
|
||||
|
||||
#include <render-utils/deferred_light_vert.h>
|
||||
#include <render-utils/deferred_light_point_vert.h>
|
||||
#include <render-utils/deferred_light_spot_vert.h>
|
||||
|
||||
#include <render-utils/directional_ambient_light_frag.h>
|
||||
#include <render-utils/directional_skybox_light_frag.h>
|
||||
|
||||
#include <render-utils/standardTransformPNTC_vert.h>
|
||||
#include <render-utils/standardDrawTexture_frag.h>
|
||||
|
||||
#include <render-utils/model_vert.h>
|
||||
#include <render-utils/model_shadow_vert.h>
|
||||
#include <render-utils/model_normal_map_vert.h>
|
||||
#include <render-utils/model_lightmap_vert.h>
|
||||
#include <render-utils/model_lightmap_normal_map_vert.h>
|
||||
#include <render-utils/skin_model_vert.h>
|
||||
#include <render-utils/skin_model_shadow_vert.h>
|
||||
#include <render-utils/skin_model_normal_map_vert.h>
|
||||
|
||||
#include <render-utils/model_frag.h>
|
||||
#include <render-utils/model_shadow_frag.h>
|
||||
#include <render-utils/model_normal_map_frag.h>
|
||||
#include <render-utils/model_normal_specular_map_frag.h>
|
||||
#include <render-utils/model_specular_map_frag.h>
|
||||
#include <render-utils/model_lightmap_frag.h>
|
||||
#include <render-utils/model_lightmap_normal_map_frag.h>
|
||||
#include <render-utils/model_lightmap_normal_specular_map_frag.h>
|
||||
#include <render-utils/model_lightmap_specular_map_frag.h>
|
||||
#include <render-utils/model_translucent_frag.h>
|
||||
#include <render-utils/overlay3D_vert.h>
|
||||
#include <render-utils/overlay3D_frag.h>
|
||||
|
||||
#include <render-utils/sdf_text3D_vert.h>
|
||||
#include <render-utils/sdf_text3D_frag.h>
|
||||
|
||||
#if 0
|
||||
#include <model/skybox_vert.h>
|
||||
#include <model/skybox_frag.h>
|
||||
#include <entities-renderer/textured_particle_frag.h>
|
||||
#include <entities-renderer/textured_particle_vert.h>
|
||||
#include <entities-renderer/paintStroke_vert.h>
|
||||
#include <entities-renderer/paintStroke_frag.h>
|
||||
#include <entities-renderer/polyvox_vert.h>
|
||||
#include <entities-renderer/polyvox_frag.h>
|
||||
#endif
|
||||
|
||||
|
||||
template <typename F>
|
||||
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<float, 108> 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<float, 108> 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<float, 108> 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<float, 9> TRIANGLE_VERTS {{
|
||||
-0.5f, -0.5f, 0.0f,
|
||||
0.5f, -0.5f, 0.0f,
|
||||
0.0f, 0.5f, 0.0f
|
||||
}};
|
||||
}
|
||||
|
||||
std::array<gvr::BufferViewport, 2> buildViewports(const std::unique_ptr<gvr::GvrApi> &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<gvr::BufferSpec> 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::milliseconds>(
|
||||
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();
|
||||
}
|
60
android/app/src/main/cpp/renderer.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <array>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#define GVR
|
||||
|
||||
#if defined(GVR)
|
||||
#include <vr/gvr/capi/include/gvr.h>
|
||||
#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<std::chrono::system_clock> start;
|
||||
#if defined(GVR)
|
||||
void InitializeVR();
|
||||
void PrepareFramebuffer();
|
||||
|
||||
std::unique_ptr<gvr::GvrApi> _gvrapi;
|
||||
gvr::ViewerType _gvr_viewer_type;
|
||||
std::unique_ptr<gvr::BufferViewportList> _viewportlist;
|
||||
std::unique_ptr<gvr::SwapChain> _swapchain;
|
||||
std::array<gvr::BufferViewport, 2> _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<glm::mat4, 2> _modelview_cube;
|
||||
std::array<glm::mat4, 2> _modelview_floor;
|
||||
std::array<glm::mat4, 2> _modelview_projection_cube;
|
||||
std::array<glm::mat4, 2> _modelview_projection_floor;
|
||||
std::array<glm::vec3, 2> _light_pos_eye_space;
|
||||
const glm::vec4 _light_pos_world_space{ 0, 2, 0, 1};
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 14 KiB |
4
android/app/src/main/res/values/colors.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="white_opaque">#ffffff</color>
|
||||
</resources>
|
3
android/app/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">TestApp</string>
|
||||
</resources>
|
15
android/app/src/main/res/values/styles.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="android:style/Theme.NoTitleBar.Fullscreen">
|
||||
<!-- Customize your theme here. -->
|
||||
<!--item name="android:windowFullscreen">true</item-->
|
||||
<!--item name="android:windowNoTitle">true</item-->
|
||||
<!--item name="android:windowActionBar">false</item-->
|
||||
|
||||
<!--item name="android:windowContentOverlay">@null</item-->
|
||||
<!--item name="android:background">@color/white_opaque</item-->
|
||||
</style>
|
||||
|
||||
|
||||
</resources>
|
91
android/build.gradle
Normal file
|
@ -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)
|
17
android/gradle.properties
Normal file
|
@ -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
|
1
android/settings.gradle
Normal file
|
@ -0,0 +1 @@
|
|||
include ':app'
|
|
@ -1,82 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- IMPORTANT: Do not manually manipulate this automatically generated file, changes will be gone after the next build! -->
|
||||
|
||||
<manifest package="${ANDROID_APK_PACKAGE}" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="${ANDROID_APK_VERSION_NAME}" android:versionCode="${ANDROID_APK_VERSION_CODE}" android:installLocation="auto">
|
||||
<application
|
||||
android:hardwareAccelerated="true"
|
||||
android:name="org.qtproject.qt5.android.bindings.QtApplication"
|
||||
android:label="@string/AppDisplayName"
|
||||
android:icon="@drawable/icon"
|
||||
android:debuggable="${ANDROID_APK_DEBUGGABLE}">
|
||||
|
||||
<!-- VR MODE -->
|
||||
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
|
||||
|
||||
<activity
|
||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"
|
||||
android:name="${ANDROID_ACTIVITY_NAME}"
|
||||
android:label="@string/AppDisplayName"
|
||||
android:screenOrientation="landscape"
|
||||
android:launchMode="singleTop"
|
||||
${ANDROID_APK_THEME}>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
|
||||
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||
<!-- Deploy Qt libs as part of package -->
|
||||
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
|
||||
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
|
||||
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
|
||||
<!-- Run with local libs -->
|
||||
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
|
||||
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
||||
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
|
||||
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
|
||||
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
|
||||
<!-- Messages maps -->
|
||||
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
||||
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
||||
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||
<!-- Messages maps -->
|
||||
|
||||
<!-- Splash screen -->
|
||||
<!-- <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/> -->
|
||||
|
||||
${ANDROID_EXTRA_ACTIVITY_XML}
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.oculusvr.vrlib.PlatformActivity"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="landscape"
|
||||
android:configChanges="screenSize|orientation|keyboardHidden|keyboard">
|
||||
</activity>
|
||||
|
||||
${ANDROID_EXTRA_APPLICATION_XML}
|
||||
</application>
|
||||
<uses-sdk android:minSdkVersion="${ANDROID_API_LEVEL}" android:targetSdkVersion="${ANDROID_API_LEVEL}"/>
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default permissions. -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
|
||||
<!-- camera permission required for GEAR VR passthrough camera -->
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default features. -->
|
||||
|
||||
<!-- Tell the system this app requires OpenGL ES 3.0. -->
|
||||
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
|
||||
</manifest>
|
|
@ -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()
|
|
@ -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@"
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
|
||||
<!-- IMPORTANT: Do not manually manipulate this automatically generated file, changes will be gone after the next build! -->
|
||||
|
||||
<resources>
|
||||
<string name="AppDisplayName">${ANDROID_APP_DISPLAY_NAME}</string>
|
||||
|
||||
<string name="ministro_not_found_msg">Can\'t find Ministro service.\nThe application can\'t start.</string>
|
||||
<string name="ministro_needed_msg">This application requires Ministro service. Would you like to install it?</string>
|
||||
<string name="fatal_error_msg">Your application encountered a fatal error and cannot continue.</string>
|
||||
</resources>
|
2
cmake/externals/glm/CMakeLists.txt
vendored
|
@ -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=<INSTALL_DIR>
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ${EXTERNAL_ARGS}
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
|
|
4
cmake/externals/tbb/CMakeLists.txt
vendored
|
@ -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 ()
|
||||
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -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. \
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
||||
|
|
32
cmake/macros/TargetOpenSSL.cmake
Normal file
|
@ -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()
|
24
cmake/macros/TargetTBB.cmake
Normal file
|
@ -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()
|
|
@ -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})
|
||||
|
||||
|
|
|
@ -116,6 +116,13 @@ Item {
|
|||
wrapMode: Text.WordWrap
|
||||
readOnly: false // we need to leave this property read-only to allow control to accept QKeyEvent
|
||||
selectByMouse: false
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.key == Qt.Key_Return) {
|
||||
mirrorText.text = "";
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea { // ... and we need this mouse area to prevent mirrorText from getting mouse events to ensure it will never get focus
|
||||
|
|
|
@ -21,9 +21,9 @@ Item {
|
|||
property alias text: label.text
|
||||
property var source
|
||||
|
||||
implicitHeight: source.visible ? 2 * label.implicitHeight : 0
|
||||
implicitHeight: source !== null ? source.visible ? 2 * label.implicitHeight : 0 : 0
|
||||
implicitWidth: 2 * hifi.dimensions.menuPadding.x + check.width + label.width + tail.width
|
||||
visible: source.visible
|
||||
visible: source !== null ? source.visible : false
|
||||
width: parent.width
|
||||
|
||||
Item {
|
||||
|
@ -42,7 +42,9 @@ Item {
|
|||
id: checkbox
|
||||
// FIXME: Should use radio buttons if source.exclusiveGroup.
|
||||
width: 20
|
||||
visible: source.visible && source.type === 1 && source.checkable && !source.exclusiveGroup
|
||||
visible: source !== null ?
|
||||
source.visible && source.type === 1 && source.checkable && !source.exclusiveGroup :
|
||||
false
|
||||
checked: setChecked()
|
||||
function setChecked() {
|
||||
if (!source || source.type !== 1 || !source.checkable) {
|
||||
|
@ -58,7 +60,9 @@ Item {
|
|||
id: radiobutton
|
||||
// FIXME: Should use radio buttons if source.exclusiveGroup.
|
||||
width: 20
|
||||
visible: source.visible && source.type === 1 && source.checkable && source.exclusiveGroup
|
||||
visible: source !== null ?
|
||||
source.visible && source.type === 1 && source.checkable && source.exclusiveGroup :
|
||||
false
|
||||
checked: setChecked()
|
||||
function setChecked() {
|
||||
if (!source || source.type !== 1 || !source.checkable) {
|
||||
|
@ -80,9 +84,13 @@ Item {
|
|||
anchors.left: check.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow50
|
||||
enabled: source.visible && (source.type !== 0 ? source.enabled : false)
|
||||
visible: source.visible
|
||||
color: source !== null ?
|
||||
source.enabled ? hifi.colors.baseGrayShadow :
|
||||
hifi.colors.baseGrayShadow50 :
|
||||
"transparent"
|
||||
|
||||
enabled: source !== null ? source.visible && (source.type !== 0 ? source.enabled : false) : false
|
||||
visible: source !== null ? source.visible : false
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
|
@ -93,7 +101,7 @@ Item {
|
|||
leftMargin: hifi.dimensions.menuPadding.x + check.width
|
||||
rightMargin: hifi.dimensions.menuPadding.x + tail.width
|
||||
}
|
||||
visible: source.type === MenuItemType.Separator
|
||||
visible: source !== null ? source.type === MenuItemType.Separator : false
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
|
@ -117,23 +125,23 @@ Item {
|
|||
|
||||
RalewayLight {
|
||||
id: shortcut
|
||||
text: source.shortcut ? source.shortcut : ""
|
||||
text: source !== null ? source.shortcut ? source.shortcut : "" : ""
|
||||
size: hifi.fontSizes.shortcutText
|
||||
color: hifi.colors.baseGrayShadow
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
visible: source.visible && text != ""
|
||||
visible: source !== null ? source.visible && text != "" : false
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
text: hifi.glyphs.disclosureExpand
|
||||
color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow25
|
||||
color: source !== null ? source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow25 : "transparent"
|
||||
size: 70
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
horizontalAlignment: Text.AlignRight
|
||||
visible: source.visible && (source.type === 2)
|
||||
visible: source !== null ? source.visible && (source.type === 2) : false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,6 @@ Item {
|
|||
|
||||
for (var i = 0; i < items.length; ++i) {
|
||||
var item = items[i];
|
||||
if (!item.visible) continue;
|
||||
switch (item.type) {
|
||||
case MenuItemType.Menu:
|
||||
result.append({"name": item.title, "item": item})
|
||||
|
@ -216,5 +215,4 @@ Item {
|
|||
function nextItem() { d.topMenu.nextItem(); }
|
||||
function selectCurrentItem() { d.topMenu.selectCurrentItem(); }
|
||||
function previousPage() { d.topMenu.previousPage(); }
|
||||
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "../../styles-uit"
|
||||
import "."
|
||||
|
@ -36,7 +34,6 @@ FocusScope {
|
|||
//color: isSubMenu ? hifi.colors.faintGray : hifi.colors.faintGray80
|
||||
}
|
||||
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
x: 0
|
||||
|
@ -68,8 +65,8 @@ FocusScope {
|
|||
delegate: TabletMenuItem {
|
||||
text: name
|
||||
source: item
|
||||
onImplicitHeightChanged: listView.recalcSize()
|
||||
onImplicitWidthChanged: listView.recalcSize()
|
||||
onImplicitHeightChanged: listView !== null ? listView.recalcSize() : 0
|
||||
onImplicitWidthChanged: listView !== null ? listView.recalcSize() : 0
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
@ -124,8 +121,6 @@ FocusScope {
|
|||
function nextItem() { listView.currentIndex = (listView.currentIndex + listView.count + 1) % listView.count; }
|
||||
function selectCurrentItem() { if (listView.currentIndex != -1) root.selected(currentItem.source); }
|
||||
function previousPage() { root.parent.pop(); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2369,6 +2369,7 @@ void Application::initializeUi() {
|
|||
|
||||
// Pre-create a couple of Web3D overlays to speed up tablet UI
|
||||
auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
|
||||
offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1);
|
||||
offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ static const float OPAQUE_ALPHA_THRESHOLD = 0.99f;
|
|||
|
||||
const QString Web3DOverlay::TYPE = "web3d";
|
||||
const QString Web3DOverlay::QML = "Web3DOverlay.qml";
|
||||
|
||||
Web3DOverlay::Web3DOverlay() : _dpi(DPI) {
|
||||
_touchDevice.setCapabilities(QTouchDevice::Position);
|
||||
_touchDevice.setType(QTouchDevice::TouchScreen);
|
||||
|
@ -97,6 +98,10 @@ Web3DOverlay::~Web3DOverlay() {
|
|||
}
|
||||
}
|
||||
|
||||
void Web3DOverlay::rebuildWebSurface() {
|
||||
destroyWebSurface();
|
||||
buildWebSurface();
|
||||
}
|
||||
|
||||
void Web3DOverlay::destroyWebSurface() {
|
||||
if (!_webSurface) {
|
||||
|
@ -136,17 +141,23 @@ void Web3DOverlay::buildWebSurface() {
|
|||
return;
|
||||
}
|
||||
gl::withSavedContext([&] {
|
||||
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(pickURL());
|
||||
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
|
||||
// and the current rendering load)
|
||||
if (_currentMaxFPS != _desiredMaxFPS) {
|
||||
setMaxFPS(_desiredMaxFPS);
|
||||
}
|
||||
loadSourceURL();
|
||||
_webSurface->resume();
|
||||
|
||||
if (isWebContent()) {
|
||||
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(QML);
|
||||
_webSurface->getRootItem()->setProperty("url", _url);
|
||||
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
|
||||
} else {
|
||||
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url);
|
||||
setupQmlSurface();
|
||||
}
|
||||
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
|
||||
_webSurface->resize(QSize(_resolution.x, _resolution.y));
|
||||
_webSurface->getRootItem()->setProperty("url", _url);
|
||||
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
|
||||
_webSurface->resume();
|
||||
});
|
||||
|
||||
auto selfOverlayID = getOverlayID();
|
||||
|
@ -187,88 +198,61 @@ void Web3DOverlay::update(float deltatime) {
|
|||
Parent::update(deltatime);
|
||||
}
|
||||
|
||||
QString Web3DOverlay::pickURL() {
|
||||
bool Web3DOverlay::isWebContent() const {
|
||||
QUrl sourceUrl(_url);
|
||||
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
|
||||
_url.toLower().endsWith(".htm") || _url.toLower().endsWith(".html")) {
|
||||
if (_webSurface) {
|
||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
||||
}
|
||||
return "Web3DOverlay.qml";
|
||||
} else {
|
||||
return QUrl::fromLocalFile(PathUtils::resourcesPath()).toString() + "/" + _url;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Web3DOverlay::loadSourceURL() {
|
||||
if (!_webSurface) {
|
||||
return;
|
||||
}
|
||||
void Web3DOverlay::setupQmlSurface() {
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Vec3", new Vec3());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Quat", new Quat());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
|
||||
|
||||
QUrl sourceUrl(_url);
|
||||
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
|
||||
_url.toLower().endsWith(".htm") || _url.toLower().endsWith(".html")) {
|
||||
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
auto flags = tabletScriptingInterface->getFlags();
|
||||
|
||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
||||
_webSurface->load("Web3DOverlay.qml");
|
||||
_webSurface->resume();
|
||||
_webSurface->getRootItem()->setProperty("url", _url);
|
||||
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
|
||||
|
||||
} else {
|
||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath()));
|
||||
_webSurface->load(_url, [&](QQmlContext* context, QObject* obj) {});
|
||||
_webSurface->resume();
|
||||
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Audio", DependencyManager::get<AudioScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Vec3", new Vec3());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Quat", new Quat());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("DCModel", DependencyManager::get<DomainConnectionModel>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
||||
|
||||
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
auto flags = tabletScriptingInterface->getFlags();
|
||||
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
|
||||
|
||||
_webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Audio", DependencyManager::get<AudioScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("DCModel", DependencyManager::get<DomainConnectionModel>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
||||
|
||||
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
|
||||
|
||||
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data());
|
||||
|
||||
// mark the TabletProxy object as cpp ownership.
|
||||
QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
|
||||
_webSurface->getSurfaceContext()->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
|
||||
|
||||
// Override min fps for tablet UI, for silky smooth scrolling
|
||||
setMaxFPS(90);
|
||||
}
|
||||
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data());
|
||||
// mark the TabletProxy object as cpp ownership.
|
||||
QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
|
||||
_webSurface->getSurfaceContext()->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
|
||||
// Override min fps for tablet UI, for silky smooth scrolling
|
||||
setMaxFPS(90);
|
||||
}
|
||||
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
|
||||
}
|
||||
|
||||
void Web3DOverlay::setMaxFPS(uint8_t maxFPS) {
|
||||
|
@ -605,11 +589,25 @@ QVariant Web3DOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
void Web3DOverlay::setURL(const QString& url) {
|
||||
_url = url;
|
||||
if (_webSurface) {
|
||||
AbstractViewStateInterface::instance()->postLambdaEvent([this, url] {
|
||||
loadSourceURL();
|
||||
});
|
||||
if (url != _url) {
|
||||
bool wasWebContent = isWebContent();
|
||||
_url = url;
|
||||
if (_webSurface) {
|
||||
if (wasWebContent && isWebContent()) {
|
||||
// If we're just targeting a new web URL, then switch to that without messing around
|
||||
// with the underlying QML
|
||||
AbstractViewStateInterface::instance()->postLambdaEvent([this, url] {
|
||||
_webSurface->getRootItem()->setProperty("url", _url);
|
||||
_webSurface->getRootItem()->setProperty("scriptURL", _scriptURL);
|
||||
});
|
||||
} else {
|
||||
// If we're switching to or from web content, or between different QML content
|
||||
// we need to destroy and rebuild the entire QML surface
|
||||
AbstractViewStateInterface::instance()->postLambdaEvent([this, url] {
|
||||
rebuildWebSurface();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,6 @@ public:
|
|||
Web3DOverlay(const Web3DOverlay* Web3DOverlay);
|
||||
virtual ~Web3DOverlay();
|
||||
|
||||
QString pickURL();
|
||||
void loadSourceURL();
|
||||
void setMaxFPS(uint8_t maxFPS);
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
|
@ -82,6 +80,10 @@ protected:
|
|||
Transform evalRenderTransform() override;
|
||||
|
||||
private:
|
||||
void setupQmlSurface();
|
||||
void rebuildWebSurface();
|
||||
bool isWebContent() const;
|
||||
|
||||
InputMode _inputMode { Touch };
|
||||
QSharedPointer<OffscreenQmlSurface> _webSurface;
|
||||
gpu::TexturePointer _texture;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include <QtCore/qsystemdetection.h>
|
||||
#include <QtCore/QtGlobal>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QObject>
|
||||
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
|
||||
#include "AudioGate.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#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<N>::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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -659,22 +659,22 @@ QVector<QUuid> EntityScriptingInterface::findEntitiesInFrustum(QVariantMap frust
|
|||
}
|
||||
|
||||
QVector<QUuid> 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<QUuid> result;
|
||||
if (_entityTree) {
|
||||
QVector<EntityItemPointer> entities;
|
||||
_entityTree->withReadLock([&] {
|
||||
_entityTree->findEntities(center, radius, entities);
|
||||
});
|
||||
QVector<QUuid> result;
|
||||
if (_entityTree) {
|
||||
QVector<EntityItemPointer> 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,
|
||||
|
|
|
@ -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<QUuid> 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<QUuid> 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<QUuid> 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
|
||||
|
|
|
@ -590,7 +590,7 @@ bool EntityTree::findNearPointOperation(const OctreeElementPointer& element, voi
|
|||
bool findRayIntersectionOp(const OctreeElementPointer& element, void* extraData) {
|
||||
RayArgs* args = static_cast<RayArgs*>(extraData);
|
||||
bool keepSearching = true;
|
||||
EntityTreeElementPointer entityTreeElementPointer = std::dynamic_pointer_cast<EntityTreeElement>(element);
|
||||
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast<EntityTreeElement>(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)) {
|
||||
|
|
|
@ -89,15 +89,15 @@ 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 {};
|
||||
// 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 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 };
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "FBXReader.h"
|
||||
#include "ModelFormatLogging.h"
|
||||
#include <shared/PlatformHacks.h>
|
||||
|
||||
QHash<QString, float> 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<glm::vec3>& vertices, const QVector<glm::vec3>& 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<int>(meshPart.quadIndices); // Copy over quad indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway].
|
||||
meshPartNew.quadIndices = QVector<int>(meshPart.quadIndices); // Copy over quad indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway].
|
||||
meshPartNew.quadTrianglesIndices = QVector<int>(meshPart.quadTrianglesIndices); // Copy over quad triangulated indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway].
|
||||
meshPartNew.triangleIndices = QVector<int>(meshPart.triangleIndices); // Copy over triangle indices.
|
||||
meshPartNew.triangleIndices = QVector<int>(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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ()
|
||||
|
|
35
libraries/gl/src/gl/Config.cpp
Normal file
|
@ -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 <mutex>
|
||||
|
||||
#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
|
||||
});
|
||||
}
|
||||
|
|
@ -12,25 +12,67 @@
|
|||
#ifndef hifi_gpu_GPUConfig_h
|
||||
#define hifi_gpu_GPUConfig_h
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES 1
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#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 <EGL/egl.h>
|
||||
#include <GLES3/gl31.h>
|
||||
|
||||
#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 <GL/glew.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#if defined(Q_OS_DARWIN)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glext.h>
|
||||
#include <OpenGL/OpenGL.h>
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
#elif defined(Q_OS_WIN64)
|
||||
#include <GL/wglew.h>
|
||||
|
||||
// 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -25,7 +25,12 @@ class QSurfaceFormat;
|
|||
class QGLFormat;
|
||||
|
||||
template<class F>
|
||||
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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
//
|
||||
#include "GL41Backend.h"
|
||||
#include "../gl/GLShader.h"
|
||||
//#include <gl/GLShaders.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//#include <gl/GLShaders.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
11
libraries/gpu-gles/CMakeLists.txt
Normal file
|
@ -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 ()
|
722
libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
Normal file
|
@ -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 <mutex>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "../gles/GLESBackend.h"
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
#include "nvToolsExt.h"
|
||||
#endif
|
||||
|
||||
#include <GPUIdent.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
|
||||
#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<GLBackend> result;
|
||||
|
||||
qDebug() << "Using OpenGL ES backend";
|
||||
result = std::make_shared<gpu::gles::GLESBackend>();
|
||||
|
||||
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<GLBackend*>(qApp->property(GL_BACKEND_PROPERTY_NAME).value<void*>());
|
||||
}
|
||||
return *INSTANCE;
|
||||
}
|
||||
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings);
|
||||
}
|
||||
|
||||
std::array<QString, 45> 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<void()> 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<void()> lambda) const {
|
||||
Lock lock(_trashMutex);
|
||||
_lambdaQueue.push_back(lambda);
|
||||
}
|
||||
|
||||
void GLBackend::recycle() const {
|
||||
{
|
||||
std::list<std::function<void()>> lamdbasTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_lambdaQueue, lamdbasTrash);
|
||||
}
|
||||
for (auto lambda : lamdbasTrash) {
|
||||
lambda();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<GLuint> ids;
|
||||
std::list<std::pair<GLuint, Size>> 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<GLuint> ids;
|
||||
std::list<GLuint> 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<GLuint> ids;
|
||||
std::list<std::pair<GLuint, Size>> 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<std::pair<GLuint, Texture::ExternalRecycler>> externalTexturesTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_externalTexturesTrash, externalTexturesTrash);
|
||||
}
|
||||
if (!externalTexturesTrash.empty()) {
|
||||
std::vector<GLsync> 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<GLuint> programsTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_programsTrash, programsTrash);
|
||||
}
|
||||
for (auto id : programsTrash) {
|
||||
glDeleteProgram(id);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::list<GLuint> shadersTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_shadersTrash, shadersTrash);
|
||||
}
|
||||
for (auto id : shadersTrash) {
|
||||
glDeleteShader(id);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<GLuint> ids;
|
||||
std::list<GLuint> 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();
|
||||
}
|
427
libraries/gpu-gles/src/gpu/gl/GLBackend.h
Normal file
|
@ -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 <assert.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <bitset>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <list>
|
||||
#include <array>
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include <gpu/Forward.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#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<GLBackend> {
|
||||
// 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<void()> 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<std::string> profileRanges;
|
||||
mutable Mutex _trashMutex;
|
||||
mutable std::list<std::pair<GLuint, Size>> _buffersTrash;
|
||||
mutable std::list<std::pair<GLuint, Size>> _texturesTrash;
|
||||
mutable std::list<std::pair<GLuint, Texture::ExternalRecycler>> _externalTexturesTrash;
|
||||
mutable std::list<GLuint> _framebuffersTrash;
|
||||
mutable std::list<GLuint> _shadersTrash;
|
||||
mutable std::list<GLuint> _programsTrash;
|
||||
mutable std::list<GLuint> _queriesTrash;
|
||||
mutable std::list<std::function<void()>> _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<MAX_NUM_ATTRIBUTES> ActivationCache;
|
||||
ActivationCache _attributeActivation { 0 };
|
||||
|
||||
typedef std::bitset<MAX_NUM_INPUT_BUFFERS> BuffersState;
|
||||
|
||||
BuffersState _invalidBuffers{ 0 };
|
||||
BuffersState _attribBindingBuffers{ 0 };
|
||||
|
||||
Buffers _buffers;
|
||||
Offsets _bufferOffsets;
|
||||
Offsets _bufferStrides;
|
||||
std::vector<GLuint> _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<CameraBufferElement>;
|
||||
|
||||
TransformCamera _camera;
|
||||
TransformCameras _cameras;
|
||||
|
||||
mutable std::map<std::string, GLvoid*> _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<size_t, size_t>;
|
||||
using List = std::list<Pair>;
|
||||
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<BufferPointer, MAX_NUM_UNIFORM_BUFFERS> _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<TexturePointer, MAX_NUM_RESOURCE_TEXTURES> _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<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) };
|
||||
|
||||
State::Data _stateCache{ State::DEFAULT };
|
||||
State::Signature _stateSignatureCache { 0 };
|
||||
|
||||
GLState* _state { nullptr };
|
||||
bool _invalidState { false };
|
||||
|
||||
PipelineStageState() {
|
||||
_cameraCorrectionBuffer.edit<CameraCorrection>() = 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
|
338
libraries/gpu-gles/src/gpu/gl/GLBackendInput.cpp
Normal file
|
@ -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<GLvoid*>(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
|
||||
}
|
||||
|
169
libraries/gpu-gles/src/gpu/gl/GLBackendOutput.cpp
Normal file
|
@ -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 <QtGui/QImage>
|
||||
|
||||
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<GLenum> 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();
|
||||
}
|
250
libraries/gpu-gles/src/gpu/gl/GLBackendPipeline.cpp
Normal file
|
@ -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<GLBuffer>(*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<GLTexture>(*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;
|
||||
}
|
||||
|
93
libraries/gpu-gles/src/gpu/gl/GLBackendQuery.cpp
Normal file
|
@ -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() {
|
||||
}
|
334
libraries/gpu-gles/src/gpu/gl/GLBackendState.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
|
40
libraries/gpu-gles/src/gpu/gl/GLBackendTexture.cpp
Normal file
|
@ -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();
|
||||
}
|
212
libraries/gpu-gles/src/gpu/gl/GLBackendTransform.cpp
Normal file
|
@ -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() {
|
||||
|
||||
}
|
35
libraries/gpu-gles/src/gpu/gl/GLBuffer.cpp
Normal file
|
@ -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<GLBackend>& 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);
|
||||
}
|
||||
|
66
libraries/gpu-gles/src/gpu/gl/GLBuffer.h
Normal file
|
@ -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<Buffer> {
|
||||
public:
|
||||
template <typename GLBufferType>
|
||||
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<GLBufferType>(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 <typename GLBufferType>
|
||||
static GLuint getId(GLBackend& backend, const Buffer& buffer) {
|
||||
GLBuffer* bo = sync<GLBufferType>(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<GLBackend>& backend, const Buffer& buffer, GLuint id);
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
48
libraries/gpu-gles/src/gpu/gl/GLFramebuffer.cpp
Normal file
|
@ -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;
|
||||
}
|
77
libraries/gpu-gles/src/gpu/gl/GLFramebuffer.h
Normal file
|
@ -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<Framebuffer> {
|
||||
public:
|
||||
template <typename GLFramebufferType>
|
||||
static GLFramebufferType* sync(GLBackend& backend, const Framebuffer& framebuffer) {
|
||||
GLFramebufferType* object = Backend::getGPUObject<GLFramebufferType>(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 <typename GLFramebufferType>
|
||||
static GLuint getId(GLBackend& backend, const Framebuffer& framebuffer) {
|
||||
GLFramebufferType* fbo = sync<GLFramebufferType>(backend, framebuffer);
|
||||
if (fbo) {
|
||||
return fbo->_id;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const GLuint& _fbo { _id };
|
||||
std::vector<GLenum> _colorBuffers;
|
||||
Stamp _depthStamp { 0 };
|
||||
std::vector<Stamp> _colorStamps;
|
||||
|
||||
protected:
|
||||
GLenum _status { GL_FRAMEBUFFER_COMPLETE };
|
||||
virtual void update() = 0;
|
||||
bool checkStatus(GLenum target) const;
|
||||
|
||||
GLFramebuffer(const std::weak_ptr<GLBackend>& backend, const Framebuffer& framebuffer, GLuint id) : GLObject(backend, framebuffer, id) {}
|
||||
~GLFramebuffer();
|
||||
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
|
||||
#endif
|
33
libraries/gpu-gles/src/gpu/gl/GLInputFormat.cpp
Normal file
|
@ -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<GLInputFormat>(inputFormat);
|
||||
|
||||
if (!object) {
|
||||
object = new GLInputFormat();
|
||||
object->key = inputFormat.getKey();
|
||||
Backend::setGPUObject(inputFormat, object);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
29
libraries/gpu-gles/src/gpu/gl/GLInputFormat.h
Normal file
|
@ -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
|
62
libraries/gpu-gles/src/gpu/gl/GLPipeline.cpp
Normal file
|
@ -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<GLPipeline>(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;
|
||||
}
|
29
libraries/gpu-gles/src/gpu/gl/GLPipeline.h
Normal file
|
@ -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
|
67
libraries/gpu-gles/src/gpu/gl/GLQuery.h
Normal file
|
@ -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<Query> {
|
||||
using Parent = gpu::gl::GLObject<Query>;
|
||||
public:
|
||||
template <typename GLQueryType>
|
||||
static GLQueryType* sync(GLBackend& backend, const Query& query) {
|
||||
GLQueryType* object = Backend::getGPUObject<GLQueryType>(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 <typename GLQueryType>
|
||||
static GLuint getId(GLBackend& backend, const QueryPointer& query) {
|
||||
if (!query) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLQuery* object = sync<GLQueryType>(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<GLBackend>& 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
|
224
libraries/gpu-gles/src/gpu/gl/GLShader.cpp
Normal file
|
@ -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 <gl/GLShaders.h>
|
||||
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
GLShader::GLShader(const std::weak_ptr<GLBackend>& 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<GLenum, NUM_SHADER_DOMAINS> 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<std::string, NUM_SHADER_DOMAINS> 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<std::string, GLShader::NumVersions> 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<GLShader>(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;
|
||||
}
|
||||
|
59
libraries/gpu-gles/src/gpu/gl/GLShader.h
Normal file
|
@ -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<GLint, GLint>;
|
||||
using UniformMappingVersions = std::vector<UniformMapping>;
|
||||
|
||||
GLShader(const std::weak_ptr<GLBackend>& 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<GLBackend> _backend;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
|
||||
#endif
|