Merge pull request #11348 from jherico/android_new
Working on new android toolchain & sample
1
.gitattributes
vendored
|
@ -10,6 +10,7 @@
|
||||||
*.json text
|
*.json text
|
||||||
*.js text
|
*.js text
|
||||||
*.qml text
|
*.qml text
|
||||||
|
*.qrc text
|
||||||
*.slf text
|
*.slf text
|
||||||
*.slh text
|
*.slh text
|
||||||
*.slv text
|
*.slv text
|
||||||
|
|
5
.gitignore
vendored
|
@ -12,6 +12,11 @@ ext/
|
||||||
Makefile
|
Makefile
|
||||||
*.user
|
*.user
|
||||||
|
|
||||||
|
# Android Studio
|
||||||
|
*.iml
|
||||||
|
local.properties
|
||||||
|
android/libraries
|
||||||
|
|
||||||
# Xcode
|
# Xcode
|
||||||
*.xcodeproj
|
*.xcodeproj
|
||||||
*.xcworkspace
|
*.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.
|
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.
|
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.9.1
|
||||||
* [Qt](http://www.qt.io/download-open-source/#) ~> 5.6.2
|
* [Android Studio](https://developer.android.com/studio/index.html)
|
||||||
* [ant](http://ant.apache.org/bindownload.cgi) ~> 1.9.4
|
* [Google VR SDK](https://github.com/googlevr/gvr-android-sdk/releases)
|
||||||
* [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html) ~> r10d
|
* [Gradle](https://gradle.org/releases/)
|
||||||
* [Android SDK](http://developer.android.com/sdk/installing/index.html) ~> 24.4.1.1
|
|
||||||
* Install the latest Platform-tools
|
### Qt
|
||||||
* Install the latest Build-tools
|
|
||||||
* Install the SDK Platform for API Level 19
|
Download the Qt online installer. Run the installer and select the android_armv7 binaries. Installing to the default path is recommended
|
||||||
* Install Sources for Android SDK for API Level 19
|
|
||||||
* Install the ARM EABI v7a System Image if you want to run an emulator.
|
### 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.
|
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)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
else()
|
else()
|
||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include("cmake/init.cmake")
|
|
||||||
|
|
||||||
project(hifi)
|
project(hifi)
|
||||||
|
|
||||||
|
include("cmake/init.cmake")
|
||||||
|
|
||||||
include("cmake/compiler.cmake")
|
include("cmake/compiler.cmake")
|
||||||
|
|
||||||
if (NOT DEFINED SERVER_ONLY)
|
if (NOT DEFINED SERVER_ONLY)
|
||||||
|
@ -54,11 +57,13 @@ endif()
|
||||||
file(GLOB_RECURSE CMAKE_SRC cmake/*.cmake cmake/CMakeLists.txt)
|
file(GLOB_RECURSE CMAKE_SRC cmake/*.cmake cmake/CMakeLists.txt)
|
||||||
add_custom_target(cmake SOURCES ${CMAKE_SRC})
|
add_custom_target(cmake SOURCES ${CMAKE_SRC})
|
||||||
GroupSources("cmake")
|
GroupSources("cmake")
|
||||||
|
unset(CMAKE_SRC)
|
||||||
|
|
||||||
file(GLOB_RECURSE JS_SRC scripts/*.js unpublishedScripts/*.js)
|
file(GLOB_RECURSE JS_SRC scripts/*.js unpublishedScripts/*.js)
|
||||||
add_custom_target(js SOURCES ${JS_SRC})
|
add_custom_target(js SOURCES ${JS_SRC})
|
||||||
GroupSources("scripts")
|
GroupSources("scripts")
|
||||||
GroupSources("unpublishedScripts")
|
GroupSources("unpublishedScripts")
|
||||||
|
unset(JS_SRC)
|
||||||
|
|
||||||
# Locate the required Qt build on the filesystem
|
# Locate the required Qt build on the filesystem
|
||||||
setup_qt()
|
setup_qt()
|
||||||
|
@ -77,6 +82,12 @@ option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
|
||||||
|
|
||||||
set_packaging_parameters()
|
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
|
# add subdirectories for all targets
|
||||||
if (BUILD_SERVER)
|
if (BUILD_SERVER)
|
||||||
add_subdirectory(assignment-client)
|
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 https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.zip
|
||||||
URL_MD5 579ac77a3110befa3244d68c0ceb7281
|
URL_MD5 579ac77a3110befa3244d68c0ceb7281
|
||||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
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_DOWNLOAD 1
|
||||||
LOG_CONFIGURE 1
|
LOG_CONFIGURE 1
|
||||||
LOG_BUILD 1
|
LOG_BUILD 1
|
||||||
|
|
4
cmake/externals/tbb/CMakeLists.txt
vendored
|
@ -8,9 +8,6 @@ if (WIN32)
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb2017_20170604oss_mac_slim.tar.gz)
|
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb2017_20170604oss_mac_slim.tar.gz)
|
||||||
set(DOWNLOAD_MD5 62bde626b396f8e1a85c6a8ded1d8105)
|
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 ()
|
else ()
|
||||||
set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb2017_20170604oss_lin_slim.tar.gz)
|
set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb2017_20170604oss_lin_slim.tar.gz)
|
||||||
set(DOWNLOAD_MD5 2a5c721f40fa3503ffc12c18dd00011c)
|
set(DOWNLOAD_MD5 2a5c721f40fa3503ffc12c18dd00011c)
|
||||||
|
@ -107,3 +104,4 @@ endif ()
|
||||||
if (DEFINED ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE)
|
if (DEFINED ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE)
|
||||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE "List of tbb include directories")
|
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE "List of tbb include directories")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,23 @@ file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake")
|
||||||
foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS})
|
foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS})
|
||||||
include(${CUSTOM_MACRO})
|
include(${CUSTOM_MACRO})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
unset(HIFI_CUSTOM_MACROS)
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
file(GLOB ANDROID_CUSTOM_MACROS "cmake/android/*.cmake")
|
set(BUILD_SHARED_LIBS ON)
|
||||||
foreach(CUSTOM_MACRO ${ANDROID_CUSTOM_MACROS})
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
|
||||||
include(${CUSTOM_MACRO})
|
|
||||||
endforeach()
|
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 ()
|
endif ()
|
||||||
|
|
|
@ -62,7 +62,9 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
||||||
# since it's unrunnable by the cross-compiling build machine
|
# 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
|
# 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)
|
if (NOT NATIVE_SCRIBE)
|
||||||
message(FATAL_ERROR "The High Fidelity scribe tool is required for shader pre-processing. \
|
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
|
# create a header file our targets can use to find out the application version
|
||||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/includes")
|
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/includes")
|
||||||
configure_file("${HF_CMAKE_DIR}/templates/BuildInfo.h.in" "${CMAKE_BINARY_DIR}/includes/BuildInfo.h")
|
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)
|
endmacro(SET_PACKAGING_PARAMETERS)
|
||||||
|
|
|
@ -12,7 +12,7 @@ macro(SETUP_HIFI_LIBRARY)
|
||||||
project(${TARGET_NAME})
|
project(${TARGET_NAME})
|
||||||
|
|
||||||
# grab the implementation and header files
|
# 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})
|
list(APPEND ${TARGET_NAME}_SRCS ${LIB_SRCS})
|
||||||
|
|
||||||
# add compiler flags to AVX source files
|
# add compiler flags to AVX source files
|
||||||
|
@ -65,7 +65,7 @@ macro(SETUP_HIFI_LIBRARY)
|
||||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
||||||
|
|
||||||
# find these Qt modules and link them to our own target
|
# 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})
|
foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES})
|
||||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
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")
|
set(QT_DEFAULT_ARCH "gcc_64")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32 OR (ANDROID AND ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")))
|
||||||
set(QT_DEFAULT_ROOT "c:/Qt")
|
set(QT_DEFAULT_ROOT "c:/Qt")
|
||||||
else()
|
else()
|
||||||
set(QT_DEFAULT_ROOT "$ENV{HOME}/Qt")
|
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
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
#
|
#
|
||||||
macro(TARGET_GLEW)
|
macro(TARGET_GLEW)
|
||||||
add_dependency_external_projects(glew)
|
if (NOT ANDROID)
|
||||||
find_package(GLEW REQUIRED)
|
add_definitions(-DGLEW_STATIC)
|
||||||
add_definitions(-DGLEW_STATIC)
|
add_dependency_external_projects(glew)
|
||||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS})
|
find_package(GLEW REQUIRED)
|
||||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY})
|
target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY})
|
||||||
|
endif()
|
||||||
endmacro()
|
endmacro()
|
|
@ -6,15 +6,13 @@
|
||||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
#
|
#
|
||||||
macro(TARGET_OPENGL)
|
macro(TARGET_OPENGL)
|
||||||
add_definitions(-DGLEW_STATIC)
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# link in required OS X frameworks and include the right GL headers
|
# link in required OS X frameworks and include the right GL headers
|
||||||
find_library(OpenGL OpenGL)
|
find_library(OpenGL OpenGL)
|
||||||
target_link_libraries(${TARGET_NAME} ${OpenGL})
|
target_link_libraries(${TARGET_NAME} ${OpenGL})
|
||||||
elseif(ANDROID)
|
elseif(ANDROID)
|
||||||
target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL")
|
target_link_libraries(${TARGET_NAME} GLESv3 EGL)
|
||||||
else()
|
else()
|
||||||
target_nsight()
|
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
if (${OPENGL_INCLUDE_DIR})
|
if (${OPENGL_INCLUDE_DIR})
|
||||||
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
||||||
|
@ -22,4 +20,6 @@ macro(TARGET_OPENGL)
|
||||||
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
||||||
target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR})
|
target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
target_nsight()
|
||||||
|
target_glew()
|
||||||
endmacro()
|
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})
|
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
# These are external plugins, but we need to do the 'add dependency' here so that their
|
# These are external plugins, but we need to do the 'add dependency' here so that their
|
||||||
# binary directories get added to the fixup path
|
# 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_bullet()
|
||||||
target_opengl()
|
target_opengl()
|
||||||
|
|
||||||
if (NOT ANDROID)
|
|
||||||
target_glew()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# perform standard include and linking for found externals
|
# perform standard include and linking for found externals
|
||||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||||
|
|
||||||
|
|
|
@ -1503,6 +1503,11 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
|
||||||
int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes);
|
int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes);
|
||||||
_inputRingBuffer.resizeForFrameSize(numFrameSamples);
|
_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();
|
_inputDevice = _audioInput->start();
|
||||||
|
|
||||||
if (_inputDevice) {
|
if (_inputDevice) {
|
||||||
|
@ -1541,6 +1546,31 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
|
||||||
return supportedFormat;
|
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() {
|
void AudioClient::outputNotify() {
|
||||||
int recentUnfulfilled = _audioOutputIODevice.getRecentUnfulfilledReads();
|
int recentUnfulfilled = _audioOutputIODevice.getRecentUnfulfilledReads();
|
||||||
if (recentUnfulfilled > 0) {
|
if (recentUnfulfilled > 0) {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include <QtCore/qsystemdetection.h>
|
#include <QtCore/QtGlobal>
|
||||||
#include <QtCore/QByteArray>
|
#include <QtCore/QByteArray>
|
||||||
#include <QtCore/QElapsedTimer>
|
#include <QtCore/QElapsedTimer>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
@ -173,6 +173,9 @@ public slots:
|
||||||
|
|
||||||
void sendDownstreamAudioStatsPacket() { _stats.publish(); }
|
void sendDownstreamAudioStatsPacket() { _stats.publish(); }
|
||||||
void handleMicAudioInput();
|
void handleMicAudioInput();
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
void audioInputStateChanged(QAudio::State state);
|
||||||
|
#endif
|
||||||
void handleDummyAudioInput();
|
void handleDummyAudioInput();
|
||||||
void handleRecordedAudioInput(const QByteArray& audio);
|
void handleRecordedAudioInput(const QByteArray& audio);
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -403,6 +406,10 @@ private:
|
||||||
RateCounter<> _silentInbound;
|
RateCounter<> _silentInbound;
|
||||||
RateCounter<> _audioInbound;
|
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* _checkDevicesTimer { nullptr };
|
||||||
QTimer* _checkPeakValuesTimer { nullptr };
|
QTimer* _checkPeakValuesTimer { nullptr };
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,11 +6,12 @@
|
||||||
// Copyright 2017 High Fidelity, Inc.
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "AudioGate.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <cstdlib>
|
||||||
#include "AudioDynamics.h"
|
#include "AudioDynamics.h"
|
||||||
#include "AudioGate.h"
|
|
||||||
|
|
||||||
// log2 domain headroom bits above 0dB (int32_t)
|
// log2 domain headroom bits above 0dB (int32_t)
|
||||||
static const int LOG2_HEADROOM_Q30 = 1;
|
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);
|
_dc.process(x);
|
||||||
|
|
||||||
// peak detect
|
// peak detect
|
||||||
int32_t peak = abs(x);
|
int32_t peak = std::abs(x);
|
||||||
|
|
||||||
// convert to log2 domain
|
// convert to log2 domain
|
||||||
peak = fixlog2(peak);
|
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.
|
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() {
|
const QUrl& AvatarData::defaultFullAvatarModelUrl() {
|
||||||
if (_defaultFullAvatarModelUrl.isEmpty()) {
|
if (_defaultFullAvatarModelUrl.isEmpty()) {
|
||||||
_defaultFullAvatarModelUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst");
|
_defaultFullAvatarModelUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "/meshes/defaultAvatar_full.fst");
|
||||||
}
|
}
|
||||||
return _defaultFullAvatarModelUrl;
|
return _defaultFullAvatarModelUrl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,3 @@ link_hifi_libraries(shared)
|
||||||
include_hifi_library_headers(networking)
|
include_hifi_library_headers(networking)
|
||||||
|
|
||||||
GroupSources("src/controllers")
|
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
|
#ifdef DEBUG
|
||||||
new NullDisplayPlugin(),
|
new NullDisplayPlugin(),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(Q_OS_ANDROID)
|
||||||
// Stereo modes
|
// Stereo modes
|
||||||
// SBS left/right
|
// SBS left/right
|
||||||
new SideBySideStereoDisplayPlugin(),
|
new SideBySideStereoDisplayPlugin(),
|
||||||
// Interleaved left/right
|
// Interleaved left/right
|
||||||
new InterleavedStereoDisplayPlugin(),
|
new InterleavedStereoDisplayPlugin(),
|
||||||
|
#endif
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,14 +40,6 @@ bool DebugHmdDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
||||||
return Parent::beginFrameRender(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() {
|
bool DebugHmdDisplayPlugin::internalActivate() {
|
||||||
_ipd = 0.0327499993f * 2.0f;
|
_ipd = 0.0327499993f * 2.0f;
|
||||||
_eyeProjections[0][0] = vec4{ 0.759056330, 0.000000000, 0.000000000, 0.000000000 };
|
_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[0] = glm::inverse(_eyeProjections[0]);
|
||||||
_eyeInverseProjections[1] = glm::inverse(_eyeProjections[1]);
|
_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[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 };
|
_renderTargetSize = { 3024, 1680 };
|
||||||
_cullingProjection = _eyeProjections[0];
|
_cullingProjection = _eyeProjections[0];
|
||||||
// This must come after the initialization, so that the values calculated
|
// This must come after the initialization, so that the values calculated
|
||||||
|
|
|
@ -26,7 +26,6 @@ protected:
|
||||||
void updatePresentPose() override;
|
void updatePresentPose() override;
|
||||||
void hmdPresent() override {}
|
void hmdPresent() override {}
|
||||||
bool isHmdMounted() const override { return true; }
|
bool isHmdMounted() const override { return true; }
|
||||||
void customizeContext() override;
|
|
||||||
bool internalActivate() override;
|
bool internalActivate() override;
|
||||||
private:
|
private:
|
||||||
static const QString NAME;
|
static const QString NAME;
|
||||||
|
|
|
@ -38,7 +38,7 @@ void main(void) {
|
||||||
int frontCondition = 1 -int(gl_FrontFacing) * 2;
|
int frontCondition = 1 -int(gl_FrontFacing) * 2;
|
||||||
vec3 color = varColor.rgb;
|
vec3 color = varColor.rgb;
|
||||||
packDeferredFragmentTranslucent(
|
packDeferredFragmentTranslucent(
|
||||||
interpolatedNormal * frontCondition,
|
float(frontCondition) * interpolatedNormal,
|
||||||
texel.a * varColor.a,
|
texel.a * varColor.a,
|
||||||
polyline.color * texel.rgb,
|
polyline.color * texel.rgb,
|
||||||
vec3(0.01, 0.01, 0.01),
|
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 {
|
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;
|
QVector<QUuid> result;
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
QVector<EntityItemPointer> entities;
|
QVector<EntityItemPointer> entities;
|
||||||
_entityTree->withReadLock([&] {
|
_entityTree->withReadLock([&] {
|
||||||
_entityTree->findEntities(center, radius, entities);
|
_entityTree->findEntities(center, radius, entities);
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach(EntityItemPointer entity, entities) {
|
foreach(EntityItemPointer entity, entities) {
|
||||||
if (entity->getType() == type) {
|
if (entity->getType() == type) {
|
||||||
result << entity->getEntityItemID();
|
result << entity->getEntityItemID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking,
|
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
|
/// 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;
|
Q_INVOKABLE QVector<QUuid> findEntitiesInFrustum(QVariantMap frustum) const;
|
||||||
|
|
||||||
/// finds entities of the indicated type within a sphere given by the center point and radius
|
/// finds entities of the indicated type within a sphere given by the center point and radius
|
||||||
/// @param {QString} string representation of entity type
|
/// @param {QString} string representation of entity type
|
||||||
/// @param {vec3} center point
|
/// @param {vec3} center point
|
||||||
/// @param {float} radius to search
|
/// @param {float} radius to search
|
||||||
/// this function will not find any entities in script engine contexts which don't have access to entities
|
/// 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;
|
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
|
/// 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
|
/// 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) {
|
bool findRayIntersectionOp(const OctreeElementPointer& element, void* extraData) {
|
||||||
RayArgs* args = static_cast<RayArgs*>(extraData);
|
RayArgs* args = static_cast<RayArgs*>(extraData);
|
||||||
bool keepSearching = true;
|
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,
|
if (entityTreeElementPointer->findRayIntersection(args->origin, args->direction, keepSearching,
|
||||||
args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude,
|
args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude,
|
||||||
args->entityIdsToDiscard, args->visibleOnly, args->collidableOnly, args->intersectedObject, args->precisionPicking)) {
|
args->entityIdsToDiscard, args->visibleOnly, args->collidableOnly, args->intersectedObject, args->precisionPicking)) {
|
||||||
|
|
|
@ -89,15 +89,15 @@ class PolyLineEntityItem : public EntityItem {
|
||||||
BoxFace& face, glm::vec3& surfaceNormal,
|
BoxFace& face, glm::vec3& surfaceNormal,
|
||||||
void** intersectedObject, bool precisionPicking) const override { return false; }
|
void** intersectedObject, bool precisionPicking) const override { return false; }
|
||||||
|
|
||||||
// disable these external interfaces as PolyLineEntities caculate their own dimensions based on the points they contain
|
// 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 setRegistrationPoint(const glm::vec3& value) override {};
|
||||||
|
|
||||||
virtual void debugDump() const override;
|
virtual void debugDump() const override;
|
||||||
static const float DEFAULT_LINE_WIDTH;
|
static const float DEFAULT_LINE_WIDTH;
|
||||||
static const int MAX_POINTS_PER_LINE;
|
static const int MAX_POINTS_PER_LINE;
|
||||||
private:
|
private:
|
||||||
void calculateScaleAndRegistrationPoint();
|
void calculateScaleAndRegistrationPoint();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
rgbColor _color;
|
rgbColor _color;
|
||||||
float _lineWidth { DEFAULT_LINE_WIDTH };
|
float _lineWidth { DEFAULT_LINE_WIDTH };
|
||||||
|
|
|
@ -223,7 +223,7 @@ void ShapeEntityItem::debugDump() const {
|
||||||
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
|
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
|
||||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
|
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
|
||||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||||
qCDebug(entities) << "SHAPE EntityItem Ptr:" << this;
|
qCDebug(entities) << "SHAPE EntityItem Ptr:" << this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
|
void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "FBXReader.h"
|
#include "FBXReader.h"
|
||||||
#include "ModelFormatLogging.h"
|
#include "ModelFormatLogging.h"
|
||||||
|
#include <shared/PlatformHacks.h>
|
||||||
|
|
||||||
QHash<QString, float> COMMENT_SCALE_HINTS = {{"This file uses centimeters as units", 1.0f / 100.0f},
|
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}};
|
{"This file uses millimeters as units", 1.0f / 1000.0f}};
|
||||||
|
@ -51,6 +52,10 @@ const QByteArray OBJTokenizer::getLineAsDatum() {
|
||||||
return _device->readLine().trimmed();
|
return _device->readLine().trimmed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float OBJTokenizer::getFloat() {
|
||||||
|
return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data());
|
||||||
|
}
|
||||||
|
|
||||||
int OBJTokenizer::nextToken() {
|
int OBJTokenizer::nextToken() {
|
||||||
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
|
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
|
||||||
int token = _pushedBackToken;
|
int token = _pushedBackToken;
|
||||||
|
@ -125,7 +130,7 @@ glm::vec3 OBJTokenizer::getVec3() {
|
||||||
}
|
}
|
||||||
bool OBJTokenizer::getVertex(glm::vec3& vertex, glm::vec3& vertexColor) {
|
bool OBJTokenizer::getVertex(glm::vec3& vertex, glm::vec3& vertexColor) {
|
||||||
// Used for vertices which may also have a vertex color (RGB [0,1]) to follow.
|
// 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 x = getFloat(); // N.B.: getFloat() has side-effect
|
||||||
auto y = getFloat(); // And order of arguments is different on Windows/Linux.
|
auto y = getFloat(); // And order of arguments is different on Windows/Linux.
|
||||||
auto z = getFloat();
|
auto z = getFloat();
|
||||||
|
@ -168,7 +173,7 @@ void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// OBJFace
|
// 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.
|
// 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 OBJFace::add(const QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& vertexColors) {
|
||||||
bool ok;
|
bool ok;
|
||||||
|
@ -544,9 +549,9 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
|
||||||
|
|
||||||
fbxMeshParts.append(FBXMeshPart());
|
fbxMeshParts.append(FBXMeshPart());
|
||||||
FBXMeshPart& meshPartNew = fbxMeshParts.last();
|
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.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.
|
// 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.
|
// All the faces in the same group will have the same name and material.
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
glm::vec3 getVec3();
|
glm::vec3 getVec3();
|
||||||
bool getVertex(glm::vec3& vertex, glm::vec3& vertexColor);
|
bool getVertex(glm::vec3& vertex, glm::vec3& vertexColor);
|
||||||
glm::vec2 getVec2();
|
glm::vec2 getVec2();
|
||||||
float getFloat() { return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data()); }
|
float getFloat();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QIODevice* _device;
|
QIODevice* _device;
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
set(TARGET_NAME gl)
|
set(TARGET_NAME gl)
|
||||||
setup_hifi_library(OpenGL Qml Quick)
|
setup_hifi_library(OpenGL Qml Quick)
|
||||||
link_hifi_libraries(shared networking)
|
link_hifi_libraries(shared)
|
||||||
|
|
||||||
target_opengl()
|
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
|
#ifndef hifi_gpu_GPUConfig_h
|
||||||
#define 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>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(Q_OS_DARWIN)
|
||||||
|
|
||||||
#include <OpenGL/gl.h>
|
#include <OpenGL/gl.h>
|
||||||
#include <OpenGL/glext.h>
|
#include <OpenGL/glext.h>
|
||||||
#include <OpenGL/OpenGL.h>
|
#include <OpenGL/OpenGL.h>
|
||||||
|
#elif defined(Q_OS_WIN64)
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WIN32)
|
|
||||||
|
|
||||||
#include <GL/wglew.h>
|
#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
|
||||||
|
|
||||||
|
#endif // !defined(Q_OS_ANDROID)
|
||||||
|
|
||||||
|
// Platform specific code to load the GL functions
|
||||||
|
namespace gl {
|
||||||
|
void initModuleGl();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // hifi_gpu_GPUConfig_h
|
#endif // hifi_gpu_GPUConfig_h
|
||||||
|
|
|
@ -28,6 +28,13 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
||||||
static QSurfaceFormat format;
|
static QSurfaceFormat format;
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
std::call_once(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.
|
// Qt Quick may need a depth and stencil buffer. Always make sure these are available.
|
||||||
format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS);
|
format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS);
|
||||||
format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS);
|
format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS);
|
||||||
|
|
|
@ -25,7 +25,12 @@ class QSurfaceFormat;
|
||||||
class QGLFormat;
|
class QGLFormat;
|
||||||
|
|
||||||
template<class F>
|
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);
|
size_t evalGLFormatSwapchainPixelSize(const QSurfaceFormat& format);
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ bool OffscreenGLCanvas::create(QOpenGLContext* sharedContext) {
|
||||||
|
|
||||||
bool OffscreenGLCanvas::makeCurrent() {
|
bool OffscreenGLCanvas::makeCurrent() {
|
||||||
bool result = _context->makeCurrent(_offscreenSurface);
|
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 Version: " << QString((const char*) glGetString(GL_VERSION));
|
||||||
qCDebug(glLogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_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));
|
qCDebug(glLogging) << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR));
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
|
|
||||||
#include "GLHelpers.h"
|
#include "GLHelpers.h"
|
||||||
|
|
||||||
// Minimum gl version required is 4.1
|
|
||||||
#define MINIMUM_GL_VERSION 0x0401
|
|
||||||
|
|
||||||
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
|
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
|
||||||
QApplication(argc, argv)
|
QApplication(argc, argv)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,10 +5,5 @@ if (UNIX)
|
||||||
target_link_libraries(${TARGET_NAME} pthread)
|
target_link_libraries(${TARGET_NAME} pthread)
|
||||||
endif(UNIX)
|
endif(UNIX)
|
||||||
GroupSources("src")
|
GroupSources("src")
|
||||||
|
|
||||||
target_opengl()
|
target_opengl()
|
||||||
target_nsight()
|
|
||||||
|
|
||||||
if (NOT ANDROID)
|
|
||||||
target_glew()
|
|
||||||
endif ()
|
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
//
|
//
|
||||||
#include "GL41Backend.h"
|
#include "GL41Backend.h"
|
||||||
#include "../gl/GLShader.h"
|
#include "../gl/GLShader.h"
|
||||||
//#include <gl/GLShaders.h>
|
|
||||||
|
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
|
using namespace gpu::gl;
|
||||||
using namespace gpu::gl41;
|
using namespace gpu::gl41;
|
||||||
|
|
||||||
// GLSL version
|
// GLSL version
|
||||||
|
@ -84,7 +84,7 @@ int GL41Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::Binding
|
||||||
return ssboCount;
|
return ssboCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL41Backend::makeProgramBindings(gl::ShaderObject& shaderObject) {
|
void GL41Backend::makeProgramBindings(ShaderObject& shaderObject) {
|
||||||
if (!shaderObject.glprogram) {
|
if (!shaderObject.glprogram) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
//#include <gl/GLShaders.h>
|
//#include <gl/GLShaders.h>
|
||||||
|
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
|
using namespace gpu::gl;
|
||||||
using namespace gpu::gl45;
|
using namespace gpu::gl45;
|
||||||
|
|
||||||
// GLSL version
|
// GLSL version
|
||||||
|
@ -132,7 +133,7 @@ int GL45Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::Binding
|
||||||
return ssboCount;*/
|
return ssboCount;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL45Backend::makeProgramBindings(gl::ShaderObject& shaderObject) {
|
void GL45Backend::makeProgramBindings(ShaderObject& shaderObject) {
|
||||||
if (!shaderObject.glprogram) {
|
if (!shaderObject.glprogram) {
|
||||||
return;
|
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
|
879
libraries/gpu-gles/src/gpu/gl/GLShared.cpp
Normal file
|
@ -0,0 +1,879 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/05/14
|
||||||
|
// Copyright 2013-2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#include "GLShared.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
|
#include <GPUIdent.h>
|
||||||
|
#include <NumericalConstants.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(gpugllogging, "hifi.gpu.gl")
|
||||||
|
Q_LOGGING_CATEGORY(trace_render_gpu_gl, "trace.render.gpu.gl")
|
||||||
|
|
||||||
|
namespace gpu { namespace gl {
|
||||||
|
|
||||||
|
bool checkGLError(const char* name) {
|
||||||
|
GLenum error = glGetError();
|
||||||
|
if (!error) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
switch (error) {
|
||||||
|
case GL_INVALID_ENUM:
|
||||||
|
qCDebug(gpugllogging) << "GLBackend::" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag.";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_VALUE:
|
||||||
|
qCDebug(gpugllogging) << "GLBackend" << name << ": A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_OPERATION:
|
||||||
|
qCDebug(gpugllogging) << "GLBackend" << name << ": The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag..";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||||
|
qCDebug(gpugllogging) << "GLBackend" << name << ": The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag.";
|
||||||
|
break;
|
||||||
|
case GL_OUT_OF_MEMORY:
|
||||||
|
qCDebug(gpugllogging) << "GLBackend" << name << ": There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded.";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "GLBackend" << name << ": Unknown error: " << error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkGLErrorDebug(const char* name) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
return checkGLError(name);
|
||||||
|
#else
|
||||||
|
Q_UNUSED(name);
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::Size getFreeDedicatedMemory() {
|
||||||
|
Size result { 0 };
|
||||||
|
static bool nvidiaMemorySupported { false };
|
||||||
|
static bool atiMemorySupported { false };
|
||||||
|
if (nvidiaMemorySupported) {
|
||||||
|
|
||||||
|
GLint nvGpuMemory { 0 };
|
||||||
|
qDebug() << "TODO: GLShared.cpp getFreeDedicatedMemory GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX";
|
||||||
|
//glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &nvGpuMemory);
|
||||||
|
if (GL_NO_ERROR == glGetError()) {
|
||||||
|
result = KB_TO_BYTES(nvGpuMemory);
|
||||||
|
} else {
|
||||||
|
nvidiaMemorySupported = false;
|
||||||
|
}
|
||||||
|
} else if (atiMemorySupported) {
|
||||||
|
GLint atiGpuMemory[4];
|
||||||
|
qDebug() << "TODO: GLShared.cpp getFreeDedicatedMemory GL_TEXTURE_FREE_MEMORY_ATI";
|
||||||
|
// not really total memory, but close enough if called early enough in the application lifecycle
|
||||||
|
//glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, atiGpuMemory);
|
||||||
|
if (GL_NO_ERROR == glGetError()) {
|
||||||
|
result = KB_TO_BYTES(atiGpuMemory[0]);
|
||||||
|
} else {
|
||||||
|
atiMemorySupported = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::Size getDedicatedMemory() {
|
||||||
|
static Size dedicatedMemory { 0 };
|
||||||
|
static std::once_flag once;
|
||||||
|
std::call_once(once, [&] {
|
||||||
|
if (!dedicatedMemory) {
|
||||||
|
GLint atiGpuMemory[4];
|
||||||
|
// not really total memory, but close enough if called early enough in the application lifecycle
|
||||||
|
//glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, atiGpuMemory);
|
||||||
|
qDebug() << "TODO: GLShared.cpp.cpp:initInput GL_TEXTURE_FREE_MEMORY_ATI";
|
||||||
|
if (GL_NO_ERROR == glGetError()) {
|
||||||
|
dedicatedMemory = KB_TO_BYTES(atiGpuMemory[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dedicatedMemory) {
|
||||||
|
GLint nvGpuMemory { 0 };
|
||||||
|
qDebug() << "TODO: GLShared.cpp.cpp:initInput GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX";
|
||||||
|
//glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &nvGpuMemory);
|
||||||
|
if (GL_NO_ERROR == glGetError()) {
|
||||||
|
dedicatedMemory = KB_TO_BYTES(nvGpuMemory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dedicatedMemory) {
|
||||||
|
auto gpuIdent = GPUIdent::getInstance();
|
||||||
|
if (gpuIdent && gpuIdent->isValid()) {
|
||||||
|
dedicatedMemory = MB_TO_BYTES(gpuIdent->getMemory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return dedicatedMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ComparisonFunction comparisonFuncFromGL(GLenum func) {
|
||||||
|
if (func == GL_NEVER) {
|
||||||
|
return NEVER;
|
||||||
|
} else if (func == GL_LESS) {
|
||||||
|
return LESS;
|
||||||
|
} else if (func == GL_EQUAL) {
|
||||||
|
return EQUAL;
|
||||||
|
} else if (func == GL_LEQUAL) {
|
||||||
|
return LESS_EQUAL;
|
||||||
|
} else if (func == GL_GREATER) {
|
||||||
|
return GREATER;
|
||||||
|
} else if (func == GL_NOTEQUAL) {
|
||||||
|
return NOT_EQUAL;
|
||||||
|
} else if (func == GL_GEQUAL) {
|
||||||
|
return GREATER_EQUAL;
|
||||||
|
} else if (func == GL_ALWAYS) {
|
||||||
|
return ALWAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ALWAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
State::StencilOp stencilOpFromGL(GLenum stencilOp) {
|
||||||
|
if (stencilOp == GL_KEEP) {
|
||||||
|
return State::STENCIL_OP_KEEP;
|
||||||
|
} else if (stencilOp == GL_ZERO) {
|
||||||
|
return State::STENCIL_OP_ZERO;
|
||||||
|
} else if (stencilOp == GL_REPLACE) {
|
||||||
|
return State::STENCIL_OP_REPLACE;
|
||||||
|
} else if (stencilOp == GL_INCR_WRAP) {
|
||||||
|
return State::STENCIL_OP_INCR_SAT;
|
||||||
|
} else if (stencilOp == GL_DECR_WRAP) {
|
||||||
|
return State::STENCIL_OP_DECR_SAT;
|
||||||
|
} else if (stencilOp == GL_INVERT) {
|
||||||
|
return State::STENCIL_OP_INVERT;
|
||||||
|
} else if (stencilOp == GL_INCR) {
|
||||||
|
return State::STENCIL_OP_INCR;
|
||||||
|
} else if (stencilOp == GL_DECR) {
|
||||||
|
return State::STENCIL_OP_DECR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return State::STENCIL_OP_KEEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
State::BlendOp blendOpFromGL(GLenum blendOp) {
|
||||||
|
if (blendOp == GL_FUNC_ADD) {
|
||||||
|
return State::BLEND_OP_ADD;
|
||||||
|
} else if (blendOp == GL_FUNC_SUBTRACT) {
|
||||||
|
return State::BLEND_OP_SUBTRACT;
|
||||||
|
} else if (blendOp == GL_FUNC_REVERSE_SUBTRACT) {
|
||||||
|
return State::BLEND_OP_REV_SUBTRACT;
|
||||||
|
} else if (blendOp == GL_MIN) {
|
||||||
|
return State::BLEND_OP_MIN;
|
||||||
|
} else if (blendOp == GL_MAX) {
|
||||||
|
return State::BLEND_OP_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return State::BLEND_OP_ADD;
|
||||||
|
}
|
||||||
|
|
||||||
|
State::BlendArg blendArgFromGL(GLenum blendArg) {
|
||||||
|
if (blendArg == GL_ZERO) {
|
||||||
|
return State::ZERO;
|
||||||
|
} else if (blendArg == GL_ONE) {
|
||||||
|
return State::ONE;
|
||||||
|
} else if (blendArg == GL_SRC_COLOR) {
|
||||||
|
return State::SRC_COLOR;
|
||||||
|
} else if (blendArg == GL_ONE_MINUS_SRC_COLOR) {
|
||||||
|
return State::INV_SRC_COLOR;
|
||||||
|
} else if (blendArg == GL_DST_COLOR) {
|
||||||
|
return State::DEST_COLOR;
|
||||||
|
} else if (blendArg == GL_ONE_MINUS_DST_COLOR) {
|
||||||
|
return State::INV_DEST_COLOR;
|
||||||
|
} else if (blendArg == GL_SRC_ALPHA) {
|
||||||
|
return State::SRC_ALPHA;
|
||||||
|
} else if (blendArg == GL_ONE_MINUS_SRC_ALPHA) {
|
||||||
|
return State::INV_SRC_ALPHA;
|
||||||
|
} else if (blendArg == GL_DST_ALPHA) {
|
||||||
|
return State::DEST_ALPHA;
|
||||||
|
} else if (blendArg == GL_ONE_MINUS_DST_ALPHA) {
|
||||||
|
return State::INV_DEST_ALPHA;
|
||||||
|
} else if (blendArg == GL_CONSTANT_COLOR) {
|
||||||
|
return State::FACTOR_COLOR;
|
||||||
|
} else if (blendArg == GL_ONE_MINUS_CONSTANT_COLOR) {
|
||||||
|
return State::INV_FACTOR_COLOR;
|
||||||
|
} else if (blendArg == GL_CONSTANT_ALPHA) {
|
||||||
|
return State::FACTOR_ALPHA;
|
||||||
|
} else if (blendArg == GL_ONE_MINUS_CONSTANT_ALPHA) {
|
||||||
|
return State::INV_FACTOR_ALPHA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return State::ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCurrentGLState(State::Data& state) {
|
||||||
|
{
|
||||||
|
GLint modes[2];
|
||||||
|
//glGetIntegerv(GL_POLYGON_MODE, modes);
|
||||||
|
qDebug() << "TODO: GLShared.cpp:getCurrentGLState GL_POLYGON_MODE";
|
||||||
|
qDebug() << "TODO: GLShared.cpp:getCurrentGLState GL_FILL";
|
||||||
|
qDebug() << "TODO: GLShared.cpp:getCurrentGLState GL_LINE";
|
||||||
|
|
||||||
|
if (modes[0] == 0 /*GL_FILL*/) {
|
||||||
|
state.fillMode = State::FILL_FACE;
|
||||||
|
} else {
|
||||||
|
if (modes[0] == 0 /*GL_LINE*/) {
|
||||||
|
state.fillMode = State::FILL_LINE;
|
||||||
|
} else {
|
||||||
|
state.fillMode = State::FILL_POINT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if (glIsEnabled(GL_CULL_FACE)) {
|
||||||
|
GLint mode;
|
||||||
|
glGetIntegerv(GL_CULL_FACE_MODE, &mode);
|
||||||
|
state.cullMode = (mode == GL_FRONT ? State::CULL_FRONT : State::CULL_BACK);
|
||||||
|
} else {
|
||||||
|
state.cullMode = State::CULL_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
GLint winding;
|
||||||
|
glGetIntegerv(GL_FRONT_FACE, &winding);
|
||||||
|
state.frontFaceClockwise = (winding == GL_CW);
|
||||||
|
//state.depthClampEnable = glIsEnabled(GL_DEPTH_CLAMP);
|
||||||
|
qDebug() << "TODO: GLShared.cpp.cpp:getCurrentGLState GL_DEPTH_CLAMP";
|
||||||
|
state.scissorEnable = glIsEnabled(GL_SCISSOR_TEST);
|
||||||
|
//state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE);
|
||||||
|
qDebug() << "TODO: GLShared.cpp.cpp:getCurrentGLState GL_MULTISAMPLE";
|
||||||
|
|
||||||
|
//state.antialisedLineEnable = glIsEnabled(GL_LINE_SMOOTH);
|
||||||
|
qDebug() << "TODO: GLShared.cpp.cpp:getCurrentGLState GL_LINE_SMOOTH";
|
||||||
|
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if (glIsEnabled(GL_POLYGON_OFFSET_FILL)) {
|
||||||
|
glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &state.depthBiasSlopeScale);
|
||||||
|
glGetFloatv(GL_POLYGON_OFFSET_UNITS, &state.depthBias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
GLboolean isEnabled = glIsEnabled(GL_DEPTH_TEST);
|
||||||
|
GLboolean writeMask;
|
||||||
|
glGetBooleanv(GL_DEPTH_WRITEMASK, &writeMask);
|
||||||
|
GLint func;
|
||||||
|
glGetIntegerv(GL_DEPTH_FUNC, &func);
|
||||||
|
|
||||||
|
state.depthTest = State::DepthTest(isEnabled, writeMask, comparisonFuncFromGL(func));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
GLboolean isEnabled = glIsEnabled(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
GLint frontWriteMask;
|
||||||
|
GLint frontReadMask;
|
||||||
|
GLint frontRef;
|
||||||
|
GLint frontFail;
|
||||||
|
GLint frontDepthFail;
|
||||||
|
GLint frontPass;
|
||||||
|
GLint frontFunc;
|
||||||
|
glGetIntegerv(GL_STENCIL_WRITEMASK, &frontWriteMask);
|
||||||
|
glGetIntegerv(GL_STENCIL_VALUE_MASK, &frontReadMask);
|
||||||
|
glGetIntegerv(GL_STENCIL_REF, &frontRef);
|
||||||
|
glGetIntegerv(GL_STENCIL_FAIL, &frontFail);
|
||||||
|
glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &frontDepthFail);
|
||||||
|
glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &frontPass);
|
||||||
|
glGetIntegerv(GL_STENCIL_FUNC, &frontFunc);
|
||||||
|
|
||||||
|
GLint backWriteMask;
|
||||||
|
GLint backReadMask;
|
||||||
|
GLint backRef;
|
||||||
|
GLint backFail;
|
||||||
|
GLint backDepthFail;
|
||||||
|
GLint backPass;
|
||||||
|
GLint backFunc;
|
||||||
|
glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &backWriteMask);
|
||||||
|
glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &backReadMask);
|
||||||
|
glGetIntegerv(GL_STENCIL_BACK_REF, &backRef);
|
||||||
|
glGetIntegerv(GL_STENCIL_BACK_FAIL, &backFail);
|
||||||
|
glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &backDepthFail);
|
||||||
|
glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &backPass);
|
||||||
|
glGetIntegerv(GL_STENCIL_BACK_FUNC, &backFunc);
|
||||||
|
|
||||||
|
state.stencilActivation = State::StencilActivation(isEnabled, frontWriteMask, backWriteMask);
|
||||||
|
state.stencilTestFront = State::StencilTest(frontRef, frontReadMask, comparisonFuncFromGL(frontFunc), stencilOpFromGL(frontFail), stencilOpFromGL(frontDepthFail), stencilOpFromGL(frontPass));
|
||||||
|
state.stencilTestBack = State::StencilTest(backRef, backReadMask, comparisonFuncFromGL(backFunc), stencilOpFromGL(backFail), stencilOpFromGL(backDepthFail), stencilOpFromGL(backPass));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
GLint mask = 0xFFFFFFFF;
|
||||||
|
if (glIsEnabled(GL_SAMPLE_MASK)) {
|
||||||
|
glGetIntegerv(GL_SAMPLE_MASK, &mask);
|
||||||
|
state.sampleMask = mask;
|
||||||
|
}
|
||||||
|
state.sampleMask = mask;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
state.alphaToCoverageEnable = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
GLboolean isEnabled = glIsEnabled(GL_BLEND);
|
||||||
|
GLint srcRGB;
|
||||||
|
GLint srcA;
|
||||||
|
GLint dstRGB;
|
||||||
|
GLint dstA;
|
||||||
|
glGetIntegerv(GL_BLEND_SRC_RGB, &srcRGB);
|
||||||
|
glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcA);
|
||||||
|
glGetIntegerv(GL_BLEND_DST_RGB, &dstRGB);
|
||||||
|
glGetIntegerv(GL_BLEND_DST_ALPHA, &dstA);
|
||||||
|
|
||||||
|
GLint opRGB;
|
||||||
|
GLint opA;
|
||||||
|
glGetIntegerv(GL_BLEND_EQUATION_RGB, &opRGB);
|
||||||
|
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &opA);
|
||||||
|
|
||||||
|
state.blendFunction = State::BlendFunction(isEnabled,
|
||||||
|
blendArgFromGL(srcRGB), blendOpFromGL(opRGB), blendArgFromGL(dstRGB),
|
||||||
|
blendArgFromGL(srcA), blendOpFromGL(opA), blendArgFromGL(dstA));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
GLboolean mask[4];
|
||||||
|
glGetBooleanv(GL_COLOR_WRITEMASK, mask);
|
||||||
|
state.colorWriteMask = (mask[0] ? State::WRITE_RED : 0)
|
||||||
|
| (mask[1] ? State::WRITE_GREEN : 0)
|
||||||
|
| (mask[2] ? State::WRITE_BLUE : 0)
|
||||||
|
| (mask[3] ? State::WRITE_ALPHA : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ElementResource {
|
||||||
|
public:
|
||||||
|
gpu::Element _element;
|
||||||
|
uint16 _resource;
|
||||||
|
|
||||||
|
ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ElementResource getFormatFromGLUniform(GLenum gltype) {
|
||||||
|
switch (gltype) {
|
||||||
|
case GL_FLOAT: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
/*
|
||||||
|
case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
*/
|
||||||
|
case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||||
|
|
||||||
|
case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||||
|
|
||||||
|
|
||||||
|
case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||||
|
|
||||||
|
/* {GL_FLOAT_MAT2x3 mat2x3},
|
||||||
|
{GL_FLOAT_MAT2x4 mat2x4},
|
||||||
|
{GL_FLOAT_MAT3x2 mat3x2},
|
||||||
|
{GL_FLOAT_MAT3x4 mat3x4},
|
||||||
|
{GL_FLOAT_MAT4x2 mat4x2},
|
||||||
|
{GL_FLOAT_MAT4x3 mat4x3},
|
||||||
|
{GL_DOUBLE_MAT2 dmat2},
|
||||||
|
{GL_DOUBLE_MAT3 dmat3},
|
||||||
|
{GL_DOUBLE_MAT4 dmat4},
|
||||||
|
{GL_DOUBLE_MAT2x3 dmat2x3},
|
||||||
|
{GL_DOUBLE_MAT2x4 dmat2x4},
|
||||||
|
{GL_DOUBLE_MAT3x2 dmat3x2},
|
||||||
|
{GL_DOUBLE_MAT3x4 dmat3x4},
|
||||||
|
{GL_DOUBLE_MAT4x2 dmat4x2},
|
||||||
|
{GL_DOUBLE_MAT4x3 dmat4x3},
|
||||||
|
*/
|
||||||
|
|
||||||
|
//qDebug() << "TODO: GLShared.cpp.cpp:ElementResource GL_SAMPLER_1D";
|
||||||
|
//case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D);
|
||||||
|
case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D);
|
||||||
|
|
||||||
|
case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D);
|
||||||
|
case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE);
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||||
|
case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||||
|
case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||||
|
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D);
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE);
|
||||||
|
|
||||||
|
case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// {GL_SAMPLER_1D_SHADOW sampler1DShadow},
|
||||||
|
// {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow},
|
||||||
|
|
||||||
|
// {GL_SAMPLER_BUFFER samplerBuffer},
|
||||||
|
// {GL_SAMPLER_2D_RECT sampler2DRect},
|
||||||
|
// {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow},
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D);
|
||||||
|
case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D);
|
||||||
|
case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||||
|
case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D);
|
||||||
|
case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||||
|
|
||||||
|
case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||||
|
case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||||
|
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||||
|
|
||||||
|
// {GL_INT_SAMPLER_BUFFER isamplerBuffer},
|
||||||
|
// {GL_INT_SAMPLER_2D_RECT isampler2DRect},
|
||||||
|
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D);
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D);
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D);
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||||
|
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||||
|
#endif
|
||||||
|
// {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer},
|
||||||
|
// {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect},
|
||||||
|
/*
|
||||||
|
{GL_IMAGE_1D image1D},
|
||||||
|
{GL_IMAGE_2D image2D},
|
||||||
|
{GL_IMAGE_3D image3D},
|
||||||
|
{GL_IMAGE_2D_RECT image2DRect},
|
||||||
|
{GL_IMAGE_CUBE imageCube},
|
||||||
|
{GL_IMAGE_BUFFER imageBuffer},
|
||||||
|
{GL_IMAGE_1D_ARRAY image1DArray},
|
||||||
|
{GL_IMAGE_2D_ARRAY image2DArray},
|
||||||
|
{GL_IMAGE_2D_MULTISAMPLE image2DMS},
|
||||||
|
{GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray},
|
||||||
|
{GL_INT_IMAGE_1D iimage1D},
|
||||||
|
{GL_INT_IMAGE_2D iimage2D},
|
||||||
|
{GL_INT_IMAGE_3D iimage3D},
|
||||||
|
{GL_INT_IMAGE_2D_RECT iimage2DRect},
|
||||||
|
{GL_INT_IMAGE_CUBE iimageCube},
|
||||||
|
{GL_INT_IMAGE_BUFFER iimageBuffer},
|
||||||
|
{GL_INT_IMAGE_1D_ARRAY iimage1DArray},
|
||||||
|
{GL_INT_IMAGE_2D_ARRAY iimage2DArray},
|
||||||
|
{GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS},
|
||||||
|
{GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray},
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_1D uimage1D},
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_2D uimage2D},
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_3D uimage3D},
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect},
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot
|
||||||
|
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer},
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray},
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray},
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS},
|
||||||
|
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray},
|
||||||
|
{GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint}
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
return ElementResource(Element(), Resource::BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
|
||||||
|
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) {
|
||||||
|
GLint uniformsCount = 0;
|
||||||
|
|
||||||
|
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < uniformsCount; i++) {
|
||||||
|
const GLint NAME_LENGTH = 256;
|
||||||
|
GLchar name[NAME_LENGTH];
|
||||||
|
GLint length = 0;
|
||||||
|
GLint size = 0;
|
||||||
|
GLenum type = 0;
|
||||||
|
glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||||
|
GLint location = glGetUniformLocation(glprogram, name);
|
||||||
|
const GLint INVALID_UNIFORM_LOCATION = -1;
|
||||||
|
|
||||||
|
// Try to make sense of the gltype
|
||||||
|
auto elementResource = getFormatFromGLUniform(type);
|
||||||
|
|
||||||
|
// The uniform as a standard var type
|
||||||
|
if (location != INVALID_UNIFORM_LOCATION) {
|
||||||
|
// Let's make sure the name doesn't contains an array element
|
||||||
|
std::string sname(name);
|
||||||
|
auto foundBracket = sname.find_first_of('[');
|
||||||
|
if (foundBracket != std::string::npos) {
|
||||||
|
// std::string arrayname = sname.substr(0, foundBracket);
|
||||||
|
|
||||||
|
if (sname[foundBracket + 1] == '0') {
|
||||||
|
sname = sname.substr(0, foundBracket);
|
||||||
|
} else {
|
||||||
|
// skip this uniform since it's not the first element of an array
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementResource._resource == Resource::BUFFER) {
|
||||||
|
uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource));
|
||||||
|
} else {
|
||||||
|
// For texture/Sampler, the location is the actual binding value
|
||||||
|
GLint binding = -1;
|
||||||
|
glGetUniformiv(glprogram, location, &binding);
|
||||||
|
|
||||||
|
auto requestedBinding = slotBindings.find(std::string(sname));
|
||||||
|
if (requestedBinding != slotBindings.end()) {
|
||||||
|
if (binding != (*requestedBinding)._location) {
|
||||||
|
binding = (*requestedBinding)._location;
|
||||||
|
glProgramUniform1i(glprogram, location, binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
||||||
|
samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniformsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLint UNUSED_SLOT = -1;
|
||||||
|
bool isUnusedSlot(GLint binding) {
|
||||||
|
return (binding == UNUSED_SLOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
|
||||||
|
GLint buffersCount = 0;
|
||||||
|
|
||||||
|
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount);
|
||||||
|
|
||||||
|
// fast exit
|
||||||
|
if (buffersCount == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint maxNumUniformBufferSlots = 0;
|
||||||
|
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots);
|
||||||
|
std::vector<GLint> uniformBufferSlotMap(maxNumUniformBufferSlots, -1);
|
||||||
|
|
||||||
|
struct UniformBlockInfo {
|
||||||
|
using Vector = std::vector<UniformBlockInfo>;
|
||||||
|
const GLuint index{ 0 };
|
||||||
|
const std::string name;
|
||||||
|
GLint binding{ -1 };
|
||||||
|
GLint size{ 0 };
|
||||||
|
|
||||||
|
static std::string getName(GLuint glprogram, GLuint i) {
|
||||||
|
static const GLint NAME_LENGTH = 256;
|
||||||
|
GLint length = 0;
|
||||||
|
GLchar nameBuffer[NAME_LENGTH];
|
||||||
|
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length);
|
||||||
|
glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, nameBuffer);
|
||||||
|
return std::string(nameBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
UniformBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) {
|
||||||
|
glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_BINDING, &binding);
|
||||||
|
glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
UniformBlockInfo::Vector uniformBlocks;
|
||||||
|
uniformBlocks.reserve(buffersCount);
|
||||||
|
for (int i = 0; i < buffersCount; i++) {
|
||||||
|
uniformBlocks.push_back(UniformBlockInfo(glprogram, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& info : uniformBlocks) {
|
||||||
|
auto requestedBinding = slotBindings.find(info.name);
|
||||||
|
if (requestedBinding != slotBindings.end()) {
|
||||||
|
info.binding = (*requestedBinding)._location;
|
||||||
|
glUniformBlockBinding(glprogram, info.index, info.binding);
|
||||||
|
uniformBufferSlotMap[info.binding] = info.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& info : uniformBlocks) {
|
||||||
|
if (slotBindings.count(info.name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the binding is 0, or the binding maps to an already used binding
|
||||||
|
if (info.binding == 0 || uniformBufferSlotMap[info.binding] != UNUSED_SLOT) {
|
||||||
|
// If no binding was assigned then just do it finding a free slot
|
||||||
|
auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), isUnusedSlot);
|
||||||
|
if (slotIt != uniformBufferSlotMap.end()) {
|
||||||
|
info.binding = slotIt - uniformBufferSlotMap.begin();
|
||||||
|
glUniformBlockBinding(glprogram, info.index, info.binding);
|
||||||
|
} else {
|
||||||
|
// This should neve happen, an active ubo cannot find an available slot among the max available?!
|
||||||
|
info.binding = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uniformBufferSlotMap[info.binding] = info.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& info : uniformBlocks) {
|
||||||
|
static const Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER);
|
||||||
|
buffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size));
|
||||||
|
}
|
||||||
|
return buffersCount;
|
||||||
|
}
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
//This has been copied over from gl45backendshader.cpp
|
||||||
|
int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
||||||
|
GLint buffersCount = 0;
|
||||||
|
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &buffersCount);
|
||||||
|
|
||||||
|
// fast exit
|
||||||
|
if (buffersCount == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint maxNumResourceBufferSlots = 0;
|
||||||
|
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxNumResourceBufferSlots);
|
||||||
|
std::vector<GLint> resourceBufferSlotMap(maxNumResourceBufferSlots, -1);
|
||||||
|
|
||||||
|
struct ResourceBlockInfo {
|
||||||
|
using Vector = std::vector<ResourceBlockInfo>;
|
||||||
|
const GLuint index{ 0 };
|
||||||
|
const std::string name;
|
||||||
|
GLint binding{ -1 };
|
||||||
|
GLint size{ 0 };
|
||||||
|
|
||||||
|
static std::string getName(GLuint glprogram, GLuint i) {
|
||||||
|
static const GLint NAME_LENGTH = 256;
|
||||||
|
GLint length = 0;
|
||||||
|
GLchar nameBuffer[NAME_LENGTH];
|
||||||
|
glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, i, NAME_LENGTH, &length, nameBuffer);
|
||||||
|
return std::string(nameBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) {
|
||||||
|
GLenum props[2] = { GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE};
|
||||||
|
glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, i, 2, props, 2, nullptr, &binding);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ResourceBlockInfo::Vector resourceBlocks;
|
||||||
|
resourceBlocks.reserve(buffersCount);
|
||||||
|
for (int i = 0; i < buffersCount; i++) {
|
||||||
|
resourceBlocks.push_back(ResourceBlockInfo(glprogram, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& info : resourceBlocks) {
|
||||||
|
auto requestedBinding = slotBindings.find(info.name);
|
||||||
|
if (requestedBinding != slotBindings.end()) {
|
||||||
|
info.binding = (*requestedBinding)._location;
|
||||||
|
glUniformBlockBinding(glprogram, info.index, info.binding);
|
||||||
|
resourceBufferSlotMap[info.binding] = info.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& info : resourceBlocks) {
|
||||||
|
if (slotBindings.count(info.name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the binding is -1, or the binding maps to an already used binding
|
||||||
|
if (info.binding == -1 || !isUnusedSlot(resourceBufferSlotMap[info.binding])) {
|
||||||
|
// If no binding was assigned then just do it finding a free slot
|
||||||
|
auto slotIt = std::find_if(resourceBufferSlotMap.begin(), resourceBufferSlotMap.end(), isUnusedSlot);
|
||||||
|
if (slotIt != resourceBufferSlotMap.end()) {
|
||||||
|
info.binding = slotIt - resourceBufferSlotMap.begin();
|
||||||
|
glUniformBlockBinding(glprogram, info.index, info.binding);
|
||||||
|
} else {
|
||||||
|
// This should never happen, an active ssbo cannot find an available slot among the max available?!
|
||||||
|
info.binding = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceBufferSlotMap[info.binding] = info.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& info : resourceBlocks) {
|
||||||
|
static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER);
|
||||||
|
resourceBuffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size));
|
||||||
|
}
|
||||||
|
return buffersCount;
|
||||||
|
}
|
||||||
|
//CLIMAX_MERGE_END
|
||||||
|
|
||||||
|
int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) {
|
||||||
|
GLint inputsCount = 0;
|
||||||
|
|
||||||
|
glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < inputsCount; i++) {
|
||||||
|
const GLint NAME_LENGTH = 256;
|
||||||
|
GLchar name[NAME_LENGTH];
|
||||||
|
GLint length = 0;
|
||||||
|
GLint size = 0;
|
||||||
|
GLenum type = 0;
|
||||||
|
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||||
|
|
||||||
|
GLint binding = glGetAttribLocation(glprogram, name);
|
||||||
|
|
||||||
|
auto elementResource = getFormatFromGLUniform(type);
|
||||||
|
inputs.insert(Shader::Slot(name, binding, elementResource._element, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) {
|
||||||
|
/* GLint outputsCount = 0;
|
||||||
|
|
||||||
|
glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < inputsCount; i++) {
|
||||||
|
const GLint NAME_LENGTH = 256;
|
||||||
|
GLchar name[NAME_LENGTH];
|
||||||
|
GLint length = 0;
|
||||||
|
GLint size = 0;
|
||||||
|
GLenum type = 0;
|
||||||
|
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||||
|
|
||||||
|
auto element = getFormatFromGLUniform(type);
|
||||||
|
outputs.insert(Shader::Slot(name, i, element));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return 0; //inputsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeProgramBindings(ShaderObject& shaderObject) {
|
||||||
|
if (!shaderObject.glprogram) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GLuint glprogram = shaderObject.glprogram;
|
||||||
|
GLint loc = -1;
|
||||||
|
|
||||||
|
//Check for gpu specific attribute slotBindings
|
||||||
|
loc = glGetAttribLocation(glprogram, "inPosition");
|
||||||
|
if (loc >= 0 && loc != gpu::Stream::POSITION) {
|
||||||
|
glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition");
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = glGetAttribLocation(glprogram, "inNormal");
|
||||||
|
if (loc >= 0 && loc != gpu::Stream::NORMAL) {
|
||||||
|
glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal");
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = glGetAttribLocation(glprogram, "inColor");
|
||||||
|
if (loc >= 0 && loc != gpu::Stream::COLOR) {
|
||||||
|
glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = glGetAttribLocation(glprogram, "inTexCoord0");
|
||||||
|
if (loc >= 0 && loc != gpu::Stream::TEXCOORD) {
|
||||||
|
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0");
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = glGetAttribLocation(glprogram, "inTangent");
|
||||||
|
if (loc >= 0 && loc != gpu::Stream::TANGENT) {
|
||||||
|
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent");
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = glGetAttribLocation(glprogram, "inTexCoord1");
|
||||||
|
if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) {
|
||||||
|
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1");
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = glGetAttribLocation(glprogram, "inSkinClusterIndex");
|
||||||
|
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) {
|
||||||
|
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex");
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = glGetAttribLocation(glprogram, "inSkinClusterWeight");
|
||||||
|
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) {
|
||||||
|
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight");
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = glGetAttribLocation(glprogram, "_drawCallInfo");
|
||||||
|
if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) {
|
||||||
|
glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link again to take into account the assigned attrib location
|
||||||
|
glLinkProgram(glprogram);
|
||||||
|
|
||||||
|
GLint linked = 0;
|
||||||
|
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||||
|
if (!linked) {
|
||||||
|
qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
||||||
|
}
|
||||||
|
|
||||||
|
// now assign the ubo binding, then DON't relink!
|
||||||
|
|
||||||
|
//Check for gpu specific uniform slotBindings
|
||||||
|
loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer");
|
||||||
|
if (loc >= 0) {
|
||||||
|
// FIXME GLES
|
||||||
|
// glShaderStorageBlockBinding(glprogram, loc, TRANSFORM_OBJECT_SLOT);
|
||||||
|
shaderObject.transformObjectSlot = TRANSFORM_OBJECT_SLOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
|
||||||
|
if (loc >= 0) {
|
||||||
|
glUniformBlockBinding(glprogram, loc, TRANSFORM_CAMERA_SLOT);
|
||||||
|
shaderObject.transformCameraSlot = TRANSFORM_CAMERA_SLOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
}
|
||||||
|
|
||||||
|
void serverWait() {
|
||||||
|
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
assert(fence);
|
||||||
|
glWaitSync(fence, 0, GL_TIMEOUT_IGNORED);
|
||||||
|
glDeleteSync(fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clientWait() {
|
||||||
|
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
assert(fence);
|
||||||
|
auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
|
||||||
|
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) {
|
||||||
|
// Minimum sleep
|
||||||
|
QThread::usleep(1);
|
||||||
|
result = glClientWaitSync(fence, 0, 0);
|
||||||
|
}
|
||||||
|
glDeleteSync(fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
} }
|
||||||
|
|
||||||
|
|
||||||
|
using namespace gpu;
|
||||||
|
|
||||||
|
|
167
libraries/gpu-gles/src/gpu/gl/GLShared.h
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/05/15
|
||||||
|
// Copyright 2013-2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#ifndef hifi_gpu_GLShared_h
|
||||||
|
#define hifi_gpu_GLShared_h
|
||||||
|
|
||||||
|
#include <gl/Config.h>
|
||||||
|
#include <gpu/Forward.h>
|
||||||
|
#include <gpu/Format.h>
|
||||||
|
#include <gpu/Context.h>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl)
|
||||||
|
|
||||||
|
namespace gpu { namespace gl {
|
||||||
|
|
||||||
|
static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot
|
||||||
|
|
||||||
|
// Create a fence and inject a GPU wait on the fence
|
||||||
|
void serverWait();
|
||||||
|
|
||||||
|
// Create a fence and synchronously wait on the fence
|
||||||
|
void clientWait();
|
||||||
|
|
||||||
|
gpu::Size getDedicatedMemory();
|
||||||
|
gpu::Size getFreeDedicatedMemory();
|
||||||
|
ComparisonFunction comparisonFuncFromGL(GLenum func);
|
||||||
|
State::StencilOp stencilOpFromGL(GLenum stencilOp);
|
||||||
|
State::BlendOp blendOpFromGL(GLenum blendOp);
|
||||||
|
State::BlendArg blendArgFromGL(GLenum blendArg);
|
||||||
|
void getCurrentGLState(State::Data& state);
|
||||||
|
|
||||||
|
struct ShaderObject {
|
||||||
|
GLuint glshader { 0 };
|
||||||
|
GLuint glprogram { 0 };
|
||||||
|
GLint transformCameraSlot { -1 };
|
||||||
|
GLint transformObjectSlot { -1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
|
||||||
|
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers);
|
||||||
|
int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
|
||||||
|
int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs);
|
||||||
|
int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs);
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
//makeResourceBufferSlots has been added to glbacked as a virtual function and is being used in gl42 and gl45 overrides.
|
||||||
|
//Since these files dont exist in the andoid version create a stub here.
|
||||||
|
int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& resourceBuffers);
|
||||||
|
//CLIMAX_MERGE_END
|
||||||
|
void makeProgramBindings(ShaderObject& shaderObject);
|
||||||
|
|
||||||
|
enum GLSyncState {
|
||||||
|
// The object is currently undergoing no processing, although it's content
|
||||||
|
// may be out of date, or it's storage may be invalid relative to the
|
||||||
|
// owning GPU object
|
||||||
|
Idle,
|
||||||
|
// The object has been queued for transfer to the GPU
|
||||||
|
Pending,
|
||||||
|
// The object has been transferred to the GPU, but is awaiting
|
||||||
|
// any post transfer operations that may need to occur on the
|
||||||
|
// primary rendering thread
|
||||||
|
Transferred,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GLenum BLEND_OPS_TO_GL[State::NUM_BLEND_OPS] = {
|
||||||
|
GL_FUNC_ADD,
|
||||||
|
GL_FUNC_SUBTRACT,
|
||||||
|
GL_FUNC_REVERSE_SUBTRACT,
|
||||||
|
GL_MIN,
|
||||||
|
GL_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GLenum BLEND_ARGS_TO_GL[State::NUM_BLEND_ARGS] = {
|
||||||
|
GL_ZERO,
|
||||||
|
GL_ONE,
|
||||||
|
GL_SRC_COLOR,
|
||||||
|
GL_ONE_MINUS_SRC_COLOR,
|
||||||
|
GL_SRC_ALPHA,
|
||||||
|
GL_ONE_MINUS_SRC_ALPHA,
|
||||||
|
GL_DST_ALPHA,
|
||||||
|
GL_ONE_MINUS_DST_ALPHA,
|
||||||
|
GL_DST_COLOR,
|
||||||
|
GL_ONE_MINUS_DST_COLOR,
|
||||||
|
GL_SRC_ALPHA_SATURATE,
|
||||||
|
GL_CONSTANT_COLOR,
|
||||||
|
GL_ONE_MINUS_CONSTANT_COLOR,
|
||||||
|
GL_CONSTANT_ALPHA,
|
||||||
|
GL_ONE_MINUS_CONSTANT_ALPHA,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GLenum COMPARISON_TO_GL[gpu::NUM_COMPARISON_FUNCS] = {
|
||||||
|
GL_NEVER,
|
||||||
|
GL_LESS,
|
||||||
|
GL_EQUAL,
|
||||||
|
GL_LEQUAL,
|
||||||
|
GL_GREATER,
|
||||||
|
GL_NOTEQUAL,
|
||||||
|
GL_GEQUAL,
|
||||||
|
GL_ALWAYS
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GLenum PRIMITIVE_TO_GL[gpu::NUM_PRIMITIVES] = {
|
||||||
|
GL_POINTS,
|
||||||
|
GL_LINES,
|
||||||
|
GL_LINE_STRIP,
|
||||||
|
GL_TRIANGLES,
|
||||||
|
GL_TRIANGLE_STRIP,
|
||||||
|
GL_TRIANGLE_FAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GLenum ELEMENT_TYPE_TO_GL[gpu::NUM_TYPES] = {
|
||||||
|
GL_FLOAT,
|
||||||
|
GL_INT,
|
||||||
|
GL_UNSIGNED_INT,
|
||||||
|
GL_HALF_FLOAT,
|
||||||
|
GL_SHORT,
|
||||||
|
GL_UNSIGNED_SHORT,
|
||||||
|
GL_BYTE,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
// Normalized values
|
||||||
|
GL_INT,
|
||||||
|
GL_UNSIGNED_INT,
|
||||||
|
GL_SHORT,
|
||||||
|
GL_UNSIGNED_SHORT,
|
||||||
|
GL_BYTE,
|
||||||
|
GL_UNSIGNED_BYTE
|
||||||
|
};
|
||||||
|
|
||||||
|
bool checkGLError(const char* name = nullptr);
|
||||||
|
bool checkGLErrorDebug(const char* name = nullptr);
|
||||||
|
|
||||||
|
class GLBackend;
|
||||||
|
|
||||||
|
template <typename GPUType>
|
||||||
|
struct GLObject : public GPUObject {
|
||||||
|
public:
|
||||||
|
GLObject(const std::weak_ptr<GLBackend>& backend, const GPUType& gpuObject, GLuint id) : _gpuObject(gpuObject), _id(id), _backend(backend) {}
|
||||||
|
|
||||||
|
virtual ~GLObject() { }
|
||||||
|
|
||||||
|
const GPUType& _gpuObject;
|
||||||
|
const GLuint _id;
|
||||||
|
protected:
|
||||||
|
const std::weak_ptr<GLBackend> _backend;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GlBuffer;
|
||||||
|
class GLFramebuffer;
|
||||||
|
class GLPipeline;
|
||||||
|
class GLQuery;
|
||||||
|
class GLState;
|
||||||
|
class GLShader;
|
||||||
|
class GLTexture;
|
||||||
|
|
||||||
|
} } // namespace gpu::gl
|
||||||
|
|
||||||
|
#define CHECK_GL_ERROR() gpu::gl::checkGLErrorDebug(__FUNCTION__)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
248
libraries/gpu-gles/src/gpu/gl/GLState.cpp
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/05/15
|
||||||
|
// Copyright 2013-2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1
|
||||||
|
#pragma GCC diagnostic ignored "-Wsuggest-override"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "GLState.h"
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "GLBackend.h"
|
||||||
|
|
||||||
|
using namespace gpu;
|
||||||
|
using namespace gpu::gl;
|
||||||
|
|
||||||
|
typedef GLState::Command Command;
|
||||||
|
typedef GLState::CommandPointer CommandPointer;
|
||||||
|
typedef GLState::Command1<uint32> Command1U;
|
||||||
|
typedef GLState::Command1<int32> Command1I;
|
||||||
|
typedef GLState::Command1<bool> Command1B;
|
||||||
|
typedef GLState::Command1<Vec2> CommandDepthBias;
|
||||||
|
typedef GLState::Command1<State::DepthTest> CommandDepthTest;
|
||||||
|
typedef GLState::Command3<State::StencilActivation, State::StencilTest, State::StencilTest> CommandStencil;
|
||||||
|
typedef GLState::Command1<State::BlendFunction> CommandBlend;
|
||||||
|
|
||||||
|
const GLState::Commands makeResetStateCommands();
|
||||||
|
|
||||||
|
// NOTE: This must stay in sync with the ordering of the State::Field enum
|
||||||
|
const GLState::Commands makeResetStateCommands() {
|
||||||
|
// Since State::DEFAULT is a static defined in another .cpp the initialisation order is random
|
||||||
|
// and we have a 50/50 chance that State::DEFAULT is not yet initialized.
|
||||||
|
// Since State::DEFAULT = State::Data() it is much easier to not use the actual State::DEFAULT
|
||||||
|
// but another State::Data object with a default initialization.
|
||||||
|
const State::Data DEFAULT = State::Data();
|
||||||
|
|
||||||
|
auto depthBiasCommand = std::make_shared<CommandDepthBias>(&GLBackend::do_setStateDepthBias,
|
||||||
|
Vec2(DEFAULT.depthBias, DEFAULT.depthBiasSlopeScale));
|
||||||
|
auto stencilCommand = std::make_shared<CommandStencil>(&GLBackend::do_setStateStencil, DEFAULT.stencilActivation,
|
||||||
|
DEFAULT.stencilTestFront, DEFAULT.stencilTestBack);
|
||||||
|
|
||||||
|
// The state commands to reset to default,
|
||||||
|
// WARNING depending on the order of the State::Field enum
|
||||||
|
return {
|
||||||
|
std::make_shared<Command1I>(&GLBackend::do_setStateFillMode, DEFAULT.fillMode),
|
||||||
|
std::make_shared<Command1I>(&GLBackend::do_setStateCullMode, DEFAULT.cullMode),
|
||||||
|
std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, DEFAULT.frontFaceClockwise),
|
||||||
|
std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, DEFAULT.depthClampEnable),
|
||||||
|
std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, DEFAULT.scissorEnable),
|
||||||
|
std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, DEFAULT.multisampleEnable),
|
||||||
|
std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, DEFAULT.antialisedLineEnable),
|
||||||
|
|
||||||
|
// Depth bias has 2 fields in State but really one call in GLBackend
|
||||||
|
CommandPointer(depthBiasCommand),
|
||||||
|
CommandPointer(depthBiasCommand),
|
||||||
|
|
||||||
|
std::make_shared<CommandDepthTest>(&GLBackend::do_setStateDepthTest, DEFAULT.depthTest),
|
||||||
|
|
||||||
|
// Depth bias has 3 fields in State but really one call in GLBackend
|
||||||
|
CommandPointer(stencilCommand),
|
||||||
|
CommandPointer(stencilCommand),
|
||||||
|
CommandPointer(stencilCommand),
|
||||||
|
|
||||||
|
std::make_shared<Command1U>(&GLBackend::do_setStateSampleMask, DEFAULT.sampleMask),
|
||||||
|
|
||||||
|
std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.alphaToCoverageEnable),
|
||||||
|
|
||||||
|
std::make_shared<CommandBlend>(&GLBackend::do_setStateBlend, DEFAULT.blendFunction),
|
||||||
|
|
||||||
|
std::make_shared<Command1U>(&GLBackend::do_setStateColorWriteMask, DEFAULT.colorWriteMask)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLState::Commands GLState::_resetStateCommands = makeResetStateCommands();
|
||||||
|
|
||||||
|
|
||||||
|
void generateFillMode(GLState::Commands& commands, State::FillMode fillMode) {
|
||||||
|
commands.push_back(std::make_shared<Command1I>(&GLBackend::do_setStateFillMode, int32(fillMode)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateCullMode(GLState::Commands& commands, State::CullMode cullMode) {
|
||||||
|
commands.push_back(std::make_shared<Command1I>(&GLBackend::do_setStateCullMode, int32(cullMode)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateFrontFaceClockwise(GLState::Commands& commands, bool isClockwise) {
|
||||||
|
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, isClockwise));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateDepthClampEnable(GLState::Commands& commands, bool enable) {
|
||||||
|
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateScissorEnable(GLState::Commands& commands, bool enable) {
|
||||||
|
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateMultisampleEnable(GLState::Commands& commands, bool enable) {
|
||||||
|
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateAntialiasedLineEnable(GLState::Commands& commands, bool enable) {
|
||||||
|
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateDepthBias(GLState::Commands& commands, const State& state) {
|
||||||
|
commands.push_back(std::make_shared<CommandDepthBias>(&GLBackend::do_setStateDepthBias, Vec2(state.getDepthBias(), state.getDepthBiasSlopeScale())));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateDepthTest(GLState::Commands& commands, const State::DepthTest& test) {
|
||||||
|
commands.push_back(std::make_shared<CommandDepthTest>(&GLBackend::do_setStateDepthTest, int32(test.getRaw())));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateStencil(GLState::Commands& commands, const State& state) {
|
||||||
|
commands.push_back(std::make_shared<CommandStencil>(&GLBackend::do_setStateStencil, state.getStencilActivation(), state.getStencilTestFront(), state.getStencilTestBack()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateAlphaToCoverageEnable(GLState::Commands& commands, bool enable) {
|
||||||
|
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateSampleMask(GLState::Commands& commands, uint32 mask) {
|
||||||
|
commands.push_back(std::make_shared<Command1U>(&GLBackend::do_setStateSampleMask, mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateBlend(GLState::Commands& commands, const State& state) {
|
||||||
|
commands.push_back(std::make_shared<CommandBlend>(&GLBackend::do_setStateBlend, state.getBlendFunction()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateColorWriteMask(GLState::Commands& commands, uint32 mask) {
|
||||||
|
commands.push_back(std::make_shared<Command1U>(&GLBackend::do_setStateColorWriteMask, mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
GLState* GLState::sync(const State& state) {
|
||||||
|
GLState* object = Backend::getGPUObject<GLState>(state);
|
||||||
|
|
||||||
|
// If GPU object already created then good
|
||||||
|
if (object) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Else allocate and create the GLState
|
||||||
|
if (!object) {
|
||||||
|
object = new GLState();
|
||||||
|
Backend::setGPUObject(state, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
// here, we need to regenerate something so let's do it all
|
||||||
|
object->_commands.clear();
|
||||||
|
object->_stamp = state.getStamp();
|
||||||
|
object->_signature = state.getSignature();
|
||||||
|
|
||||||
|
bool depthBias = false;
|
||||||
|
bool stencilState = false;
|
||||||
|
|
||||||
|
// go thorugh the list of state fields in the State and record the corresponding gl command
|
||||||
|
for (int i = 0; i < State::NUM_FIELDS; i++) {
|
||||||
|
if (state.getSignature()[i]) {
|
||||||
|
switch (i) {
|
||||||
|
case State::FILL_MODE: {
|
||||||
|
generateFillMode(object->_commands, state.getFillMode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::CULL_MODE: {
|
||||||
|
generateCullMode(object->_commands, state.getCullMode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::DEPTH_BIAS:
|
||||||
|
case State::DEPTH_BIAS_SLOPE_SCALE: {
|
||||||
|
depthBias = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::FRONT_FACE_CLOCKWISE: {
|
||||||
|
generateFrontFaceClockwise(object->_commands, state.isFrontFaceClockwise());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::DEPTH_CLAMP_ENABLE: {
|
||||||
|
generateDepthClampEnable(object->_commands, state.isDepthClampEnable());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::SCISSOR_ENABLE: {
|
||||||
|
generateScissorEnable(object->_commands, state.isScissorEnable());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::MULTISAMPLE_ENABLE: {
|
||||||
|
generateMultisampleEnable(object->_commands, state.isMultisampleEnable());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::ANTIALISED_LINE_ENABLE: {
|
||||||
|
generateAntialiasedLineEnable(object->_commands, state.isAntialiasedLineEnable());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::DEPTH_TEST: {
|
||||||
|
generateDepthTest(object->_commands, state.getDepthTest());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case State::STENCIL_ACTIVATION:
|
||||||
|
case State::STENCIL_TEST_FRONT:
|
||||||
|
case State::STENCIL_TEST_BACK: {
|
||||||
|
stencilState = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case State::SAMPLE_MASK: {
|
||||||
|
generateSampleMask(object->_commands, state.getSampleMask());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::ALPHA_TO_COVERAGE_ENABLE: {
|
||||||
|
generateAlphaToCoverageEnable(object->_commands, state.isAlphaToCoverageEnabled());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case State::BLEND_FUNCTION: {
|
||||||
|
generateBlend(object->_commands, state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case State::COLOR_WRITE_MASK: {
|
||||||
|
generateColorWriteMask(object->_commands, state.getColorWriteMask());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depthBias) {
|
||||||
|
generateDepthBias(object->_commands, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stencilState) {
|
||||||
|
generateStencil(object->_commands, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
73
libraries/gpu-gles/src/gpu/gl/GLState.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/05/15
|
||||||
|
// Copyright 2013-2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#ifndef hifi_gpu_gl_GLState_h
|
||||||
|
#define hifi_gpu_gl_GLState_h
|
||||||
|
|
||||||
|
#include "GLShared.h"
|
||||||
|
|
||||||
|
#include <gpu/State.h>
|
||||||
|
|
||||||
|
namespace gpu { namespace gl {
|
||||||
|
|
||||||
|
class GLBackend;
|
||||||
|
class GLState : public GPUObject {
|
||||||
|
public:
|
||||||
|
static GLState* sync(const State& state);
|
||||||
|
|
||||||
|
class Command {
|
||||||
|
public:
|
||||||
|
virtual void run(GLBackend* backend) = 0;
|
||||||
|
Command() {}
|
||||||
|
virtual ~Command() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> class Command1 : public Command {
|
||||||
|
public:
|
||||||
|
typedef void (GLBackend::*GLFunction)(T);
|
||||||
|
void run(GLBackend* backend) { (backend->*(_func))(_param); }
|
||||||
|
Command1(GLFunction func, T param) : _func(func), _param(param) {};
|
||||||
|
GLFunction _func;
|
||||||
|
T _param;
|
||||||
|
};
|
||||||
|
template <class T, class U> class Command2 : public Command {
|
||||||
|
public:
|
||||||
|
typedef void (GLBackend::*GLFunction)(T, U);
|
||||||
|
void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1); }
|
||||||
|
Command2(GLFunction func, T param0, U param1) : _func(func), _param0(param0), _param1(param1) {};
|
||||||
|
GLFunction _func;
|
||||||
|
T _param0;
|
||||||
|
U _param1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, class U, class V> class Command3 : public Command {
|
||||||
|
public:
|
||||||
|
typedef void (GLBackend::*GLFunction)(T, U, V);
|
||||||
|
void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1, _param2); }
|
||||||
|
Command3(GLFunction func, T param0, U param1, V param2) : _func(func), _param0(param0), _param1(param1), _param2(param2) {};
|
||||||
|
GLFunction _func;
|
||||||
|
T _param0;
|
||||||
|
U _param1;
|
||||||
|
V _param2;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr< Command > CommandPointer;
|
||||||
|
typedef std::vector< CommandPointer > Commands;
|
||||||
|
|
||||||
|
Commands _commands;
|
||||||
|
Stamp _stamp;
|
||||||
|
State::Signature _signature;
|
||||||
|
|
||||||
|
// The state commands to reset to default,
|
||||||
|
static const Commands _resetStateCommands;
|
||||||
|
|
||||||
|
friend class GLBackend;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
||||||
|
|
||||||
|
#endif
|
648
libraries/gpu-gles/src/gpu/gl/GLTexelFormat.cpp
Normal file
|
@ -0,0 +1,648 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/05/15
|
||||||
|
// Copyright 2013-2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "GLTexelFormat.h"
|
||||||
|
|
||||||
|
using namespace gpu;
|
||||||
|
using namespace gpu::gl;
|
||||||
|
|
||||||
|
|
||||||
|
GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
||||||
|
// qDebug() << "GLTexelFormat::evalGLTexelFormatInternal " << dstFormat.getDimension() << ", " << dstFormat.getSemantic() << ", " << dstFormat.getType();
|
||||||
|
GLenum result = GL_RGBA8;
|
||||||
|
switch (dstFormat.getDimension()) {
|
||||||
|
case gpu::SCALAR: {
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
case gpu::SRGB:
|
||||||
|
case gpu::SRGBA:
|
||||||
|
switch (dstFormat.getType()) {
|
||||||
|
case gpu::UINT32:
|
||||||
|
result = GL_R32UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT32:
|
||||||
|
result = GL_R32I;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT32:
|
||||||
|
result = GL_R8;
|
||||||
|
break;
|
||||||
|
case gpu::NINT32:
|
||||||
|
result = GL_R8_SNORM;
|
||||||
|
break;
|
||||||
|
case gpu::FLOAT:
|
||||||
|
result = GL_R32F;
|
||||||
|
break;
|
||||||
|
case gpu::UINT16:
|
||||||
|
result = GL_R16UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT16:
|
||||||
|
result = GL_R16I;
|
||||||
|
break;
|
||||||
|
case gpu::HALF:
|
||||||
|
result = GL_R16F;
|
||||||
|
break;
|
||||||
|
case gpu::UINT8:
|
||||||
|
result = GL_R8UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT8:
|
||||||
|
result = GL_R8I;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT8:
|
||||||
|
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
|
||||||
|
//result = GL_SLUMINANCE8;
|
||||||
|
qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormatInternal GL_SLUMINANCE8";
|
||||||
|
} else {
|
||||||
|
result = GL_R8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case gpu::NINT8:
|
||||||
|
result = GL_R8_SNORM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormatInternal " << dstFormat.getType();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case gpu::R11G11B10:
|
||||||
|
// the type should be float
|
||||||
|
result = GL_R11F_G11F_B10F;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::DEPTH:
|
||||||
|
result = GL_DEPTH_COMPONENT16;
|
||||||
|
switch (dstFormat.getType()) {
|
||||||
|
case gpu::FLOAT:
|
||||||
|
result = GL_DEPTH_COMPONENT32F;
|
||||||
|
break;
|
||||||
|
case gpu::UINT16:
|
||||||
|
case gpu::INT16:
|
||||||
|
case gpu::NUINT16:
|
||||||
|
case gpu::NINT16:
|
||||||
|
case gpu::HALF:
|
||||||
|
result = GL_DEPTH_COMPONENT16;
|
||||||
|
break;
|
||||||
|
case gpu::UINT8:
|
||||||
|
case gpu::INT8:
|
||||||
|
case gpu::NUINT8:
|
||||||
|
case gpu::NINT8:
|
||||||
|
result = GL_DEPTH_COMPONENT24;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::DEPTH_STENCIL:
|
||||||
|
result = GL_DEPTH24_STENCIL8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC2: {
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
result = GL_RG8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC3: {
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
result = GL_RGB8;
|
||||||
|
break;
|
||||||
|
case gpu::SRGB:
|
||||||
|
case gpu::SRGBA:
|
||||||
|
//result = GL_SRGB8; // standard 2.2 gamma correction color
|
||||||
|
result = GL_RGB8; // standard 2.2 gamma correction color
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC4: {
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
result = GL_RGB8;
|
||||||
|
break;
|
||||||
|
case gpu::RGBA:
|
||||||
|
switch (dstFormat.getType()) {
|
||||||
|
case gpu::UINT32:
|
||||||
|
result = GL_RGBA32UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT32:
|
||||||
|
result = GL_RGBA32I;
|
||||||
|
break;
|
||||||
|
case gpu::FLOAT:
|
||||||
|
result = GL_RGBA32F;
|
||||||
|
break;
|
||||||
|
case gpu::UINT16:
|
||||||
|
result = GL_RGBA16UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT16:
|
||||||
|
result = GL_RGBA16I;
|
||||||
|
break;
|
||||||
|
case gpu::HALF:
|
||||||
|
result = GL_RGBA16F;
|
||||||
|
break;
|
||||||
|
case gpu::UINT8:
|
||||||
|
result = GL_RGBA8UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT8:
|
||||||
|
result = GL_RGBA8I;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT8:
|
||||||
|
result = GL_RGBA8;
|
||||||
|
break;
|
||||||
|
case gpu::NINT8:
|
||||||
|
result = GL_RGBA8_SNORM;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT32:
|
||||||
|
case gpu::NINT32:
|
||||||
|
case gpu::NUM_TYPES: // quiet compiler
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case gpu::SRGB:
|
||||||
|
//result = GL_SRGB8;
|
||||||
|
result = GL_RGB8;
|
||||||
|
qDebug() << "SRGBA Here 2";
|
||||||
|
break;
|
||||||
|
case gpu::SRGBA:
|
||||||
|
result = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
//qDebug() << "GLTexelFormat::evalGLTexelFormatInternal result " << result;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) {
|
||||||
|
// qDebug() << "GLTexelFormat::evalGLTexelFormat dst.getDimension=" << dstFormat.getDimension() << " dst.getType=" << dstFormat.getType() << " dst.getSemantic=" << dstFormat.getSemantic();
|
||||||
|
// qDebug() << "GLTexelFormat::evalGLTexelFormat src.getDimension=" << srcFormat.getDimension() << " src.getType=" << srcFormat.getType() << " src.getSemantic=" << srcFormat.getSemantic();
|
||||||
|
|
||||||
|
if (dstFormat != srcFormat) {
|
||||||
|
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||||
|
|
||||||
|
switch (dstFormat.getDimension()) {
|
||||||
|
case gpu::SCALAR: {
|
||||||
|
texel.format = GL_RED;
|
||||||
|
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_R8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
// case gpu::COMPRESSED_R:
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RED_RGTC1";
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_RED_RGTC1;
|
||||||
|
// break;
|
||||||
|
//CLIMAX_MERGE_END
|
||||||
|
|
||||||
|
case gpu::DEPTH:
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT32_OES;
|
||||||
|
break;
|
||||||
|
case gpu::DEPTH_STENCIL:
|
||||||
|
texel.type = GL_UNSIGNED_INT_24_8;
|
||||||
|
texel.format = GL_DEPTH_STENCIL;
|
||||||
|
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC2: {
|
||||||
|
texel.format = GL_RG;
|
||||||
|
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RG8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC3: {
|
||||||
|
texel.format = GL_RGB;
|
||||||
|
|
||||||
|
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RGB8;
|
||||||
|
break;
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
//not needed?
|
||||||
|
// case gpu::COMPRESSED_RGB:
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RGB";
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_RGB;
|
||||||
|
// break;
|
||||||
|
// case gpu::COMPRESSED_SRGB:
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_SRGB";
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_SRGB;
|
||||||
|
// break;
|
||||||
|
//CLIMAX_MERGE_END
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC4: {
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (srcFormat.getSemantic()) {
|
||||||
|
case gpu::BGRA:
|
||||||
|
case gpu::SBGRA:
|
||||||
|
qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_BGRA";
|
||||||
|
//texel.format = GL_BGRA;
|
||||||
|
break;
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
case gpu::SRGB:
|
||||||
|
case gpu::SRGBA:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
texel.internalFormat = GL_RGB8;
|
||||||
|
break;
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RGBA8;
|
||||||
|
break;
|
||||||
|
case gpu::SRGB:
|
||||||
|
//texel.internalFormat = GL_SRGB8;
|
||||||
|
texel.internalFormat = GL_RGB8;
|
||||||
|
qDebug() << "SRGBA Here 3";
|
||||||
|
break;
|
||||||
|
case gpu::SRGBA:
|
||||||
|
texel.internalFormat = GL_SRGB8_ALPHA8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
// case gpu::COMPRESSED_RGBA:
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_RGBA;
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RGBA";
|
||||||
|
// break;
|
||||||
|
// case gpu::COMPRESSED_SRGBA:
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_SRGB_ALPHA";
|
||||||
|
// break;
|
||||||
|
//CLIMAX_MERGE_END
|
||||||
|
// FIXME: WE will want to support this later
|
||||||
|
/*
|
||||||
|
case gpu::COMPRESSED_BC3_RGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_BC3_SRGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::COMPRESSED_BC7_RGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_BC7_SRGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
return texel;
|
||||||
|
} else {
|
||||||
|
GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||||
|
|
||||||
|
switch (dstFormat.getDimension()) {
|
||||||
|
case gpu::SCALAR: {
|
||||||
|
texel.format = GL_RED;
|
||||||
|
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
// case gpu::COMPRESSED_R: {
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RED_RGTC1";
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_RED_RGTC1;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
case gpu::SRGB:
|
||||||
|
case gpu::SRGBA:
|
||||||
|
texel.internalFormat = GL_RED;
|
||||||
|
switch (dstFormat.getType()) {
|
||||||
|
case gpu::UINT32: {
|
||||||
|
texel.internalFormat = GL_R32UI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::INT32: {
|
||||||
|
texel.internalFormat = GL_R32I;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUINT32: {
|
||||||
|
texel.internalFormat = GL_R8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NINT32: {
|
||||||
|
texel.internalFormat = GL_R8_SNORM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::FLOAT: {
|
||||||
|
texel.internalFormat = GL_R32F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::UINT16: {
|
||||||
|
texel.internalFormat = GL_R16UI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::INT16: {
|
||||||
|
texel.internalFormat = GL_R16I;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUINT16: {
|
||||||
|
//texel.internalFormat = GL_R16;
|
||||||
|
qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_R16";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NINT16: {
|
||||||
|
//texel.internalFormat = GL_R16_SNORM;
|
||||||
|
qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_R16_SNORM";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::HALF: {
|
||||||
|
texel.internalFormat = GL_R16F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::UINT8: {
|
||||||
|
texel.internalFormat = GL_R8UI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::INT8: {
|
||||||
|
texel.internalFormat = GL_R8I;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUINT8: {
|
||||||
|
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
|
||||||
|
// texel.internalFormat = GL_SLUMINANCE8;
|
||||||
|
qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_SLUMINANCE8";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
texel.internalFormat = GL_R8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NINT8: {
|
||||||
|
texel.internalFormat = GL_R8_SNORM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUM_TYPES: { // quiet compiler
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::R11G11B10:
|
||||||
|
texel.format = GL_RGB;
|
||||||
|
// the type should be float
|
||||||
|
texel.internalFormat = GL_R11F_G11F_B10F;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::DEPTH:
|
||||||
|
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT32_OES;
|
||||||
|
switch (dstFormat.getType()) {
|
||||||
|
case gpu::UINT32:
|
||||||
|
case gpu::INT32:
|
||||||
|
case gpu::NUINT32:
|
||||||
|
case gpu::NINT32: {
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT32_OES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::FLOAT: {
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT32F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::UINT16:
|
||||||
|
case gpu::INT16:
|
||||||
|
case gpu::NUINT16:
|
||||||
|
case gpu::NINT16:
|
||||||
|
case gpu::HALF: {
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::UINT8:
|
||||||
|
case gpu::INT8:
|
||||||
|
case gpu::NUINT8:
|
||||||
|
case gpu::NINT8: {
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUM_TYPES: { // quiet compiler
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case gpu::DEPTH_STENCIL:
|
||||||
|
texel.type = GL_UNSIGNED_INT_24_8;
|
||||||
|
texel.format = GL_DEPTH_STENCIL;
|
||||||
|
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC2: {
|
||||||
|
texel.format = GL_RG;
|
||||||
|
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RG8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC3: {
|
||||||
|
texel.format = GL_RGB;
|
||||||
|
|
||||||
|
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RGB8;
|
||||||
|
break;
|
||||||
|
case gpu::SRGB:
|
||||||
|
case gpu::SRGBA:
|
||||||
|
//texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color
|
||||||
|
texel.internalFormat = GL_RGB8; // standard 2.2 gamma correction color
|
||||||
|
break;
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
// case gpu::COMPRESSED_RGB:
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_RGB;
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RGB";
|
||||||
|
// break;
|
||||||
|
// case gpu::COMPRESSED_SRGB:
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_SRGB;
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_SRGB";
|
||||||
|
// break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC4: {
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
texel.internalFormat = GL_RGB8;
|
||||||
|
break;
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RGBA8;
|
||||||
|
switch (dstFormat.getType()) {
|
||||||
|
case gpu::UINT32:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA32UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT32:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA32I;
|
||||||
|
break;
|
||||||
|
case gpu::FLOAT:
|
||||||
|
texel.internalFormat = GL_RGBA32F;
|
||||||
|
break;
|
||||||
|
case gpu::UINT16:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA16UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT16:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA16I;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT16:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
//texel.internalFormat = GL_RGBA16;
|
||||||
|
qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_RGBA16";
|
||||||
|
break;
|
||||||
|
case gpu::NINT16:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_RGBA16_SNORM";
|
||||||
|
//texel.internalFormat = GL_RGBA16_SNORM;
|
||||||
|
break;
|
||||||
|
case gpu::HALF:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_RGBA16F;
|
||||||
|
break;
|
||||||
|
case gpu::UINT8:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA8UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT8:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA8I;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT8:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_RGBA8;
|
||||||
|
break;
|
||||||
|
case gpu::NINT8:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_RGBA8_SNORM;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT32:
|
||||||
|
case gpu::NINT32:
|
||||||
|
case gpu::NUM_TYPES: // quiet compiler
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case gpu::SRGB:
|
||||||
|
//texel.internalFormat = GL_SRGB8;
|
||||||
|
texel.internalFormat = GL_RGB8; // standard 2.2 gamma correction color
|
||||||
|
break;
|
||||||
|
case gpu::SRGBA:
|
||||||
|
texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
|
||||||
|
break;
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
// case gpu::COMPRESSED_RGBA:
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_RGBA;
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_RGBA";
|
||||||
|
// break;
|
||||||
|
// case gpu::COMPRESSED_SRGBA:
|
||||||
|
// qDebug() << "TODO: GLTexelFormat.cpp:evalGLTexelFormat GL_COMPRESSED_SRGB_ALPHA";
|
||||||
|
// //texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
|
||||||
|
// break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
//qDebug() << "GLTexelFormat::evalGLTexelFormat Texel.type " << texel.type << " - texel.format=" << texel.format << " texel.internalFormat=" << texel.internalFormat;
|
||||||
|
return texel;
|
||||||
|
}
|
||||||
|
}
|
32
libraries/gpu-gles/src/gpu/gl/GLTexelFormat.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/05/15
|
||||||
|
// Copyright 2013-2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#ifndef hifi_gpu_gl_GLTexelFormat_h
|
||||||
|
#define hifi_gpu_gl_GLTexelFormat_h
|
||||||
|
|
||||||
|
#include "GLShared.h"
|
||||||
|
|
||||||
|
namespace gpu { namespace gl {
|
||||||
|
|
||||||
|
class GLTexelFormat {
|
||||||
|
public:
|
||||||
|
GLenum internalFormat;
|
||||||
|
GLenum format;
|
||||||
|
GLenum type;
|
||||||
|
|
||||||
|
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat) {
|
||||||
|
return evalGLTexelFormat(dstFormat, dstFormat);
|
||||||
|
}
|
||||||
|
static GLenum evalGLTexelFormatInternal(const Element& dstFormat);
|
||||||
|
|
||||||
|
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat);
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
323
libraries/gpu-gles/src/gpu/gl/GLTexture.cpp
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/05/15
|
||||||
|
// Copyright 2013-2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "GLTexture.h"
|
||||||
|
|
||||||
|
#include <NumericalConstants.h>
|
||||||
|
|
||||||
|
#include "GLTextureTransfer.h"
|
||||||
|
#include "GLBackend.h"
|
||||||
|
|
||||||
|
using namespace gpu;
|
||||||
|
using namespace gpu::gl;
|
||||||
|
|
||||||
|
std::shared_ptr<GLTextureTransferHelper> GLTexture::_textureTransferHelper;
|
||||||
|
|
||||||
|
// FIXME placeholder for texture memory over-use
|
||||||
|
#define DEFAULT_MAX_MEMORY_MB 256
|
||||||
|
#define MIN_FREE_GPU_MEMORY_PERCENTAGE 0.25f
|
||||||
|
#define OVER_MEMORY_PRESSURE 2.0f
|
||||||
|
|
||||||
|
const GLenum GLTexture::CUBE_FACE_LAYOUT[6] = {
|
||||||
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||||
|
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||||
|
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
|
||||||
|
};
|
||||||
|
|
||||||
|
const GLenum GLTexture::WRAP_MODES[Sampler::NUM_WRAP_MODES] = {
|
||||||
|
GL_REPEAT, // WRAP_REPEAT,
|
||||||
|
GL_MIRRORED_REPEAT, // WRAP_MIRROR,
|
||||||
|
GL_CLAMP_TO_EDGE, // WRAP_CLAMP,
|
||||||
|
GL_CLAMP_TO_BORDER_EXT, // WRAP_BORDER,
|
||||||
|
|
||||||
|
//GL_MIRROR_CLAMP_TO_EDGE_EXT // WRAP_MIRROR_ONCE,
|
||||||
|
// qDebug() << "TODO: GLTexture.cpp:WRAP_MODES GL_MIRROR_CLAMP_TO_EDGE_EXT";
|
||||||
|
};
|
||||||
|
|
||||||
|
const GLFilterMode GLTexture::FILTER_MODES[Sampler::NUM_FILTERS] = {
|
||||||
|
{ GL_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_POINT,
|
||||||
|
{ GL_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR,
|
||||||
|
{ GL_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT,
|
||||||
|
{ GL_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR,
|
||||||
|
|
||||||
|
{ GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT,
|
||||||
|
{ GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_MAG_POINT_MIP_LINEAR,
|
||||||
|
{ GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
|
||||||
|
{ GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_POINT_MAG_MIP_LINEAR,
|
||||||
|
{ GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_MIP_POINT,
|
||||||
|
{ GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
|
||||||
|
{ GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR_MIP_POINT,
|
||||||
|
{ GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_MIP_LINEAR,
|
||||||
|
{ GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR } //FILTER_ANISOTROPIC,
|
||||||
|
};
|
||||||
|
|
||||||
|
GLenum GLTexture::getGLTextureType(const Texture& texture) {
|
||||||
|
switch (texture.getType()) {
|
||||||
|
case Texture::TEX_2D:
|
||||||
|
return GL_TEXTURE_2D;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Texture::TEX_CUBE:
|
||||||
|
return GL_TEXTURE_CUBE_MAP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
qFatal("Unsupported texture type");
|
||||||
|
}
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
return GL_TEXTURE_2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::vector<GLenum>& GLTexture::getFaceTargets(GLenum target) {
|
||||||
|
static std::vector<GLenum> cubeFaceTargets {
|
||||||
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||||
|
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||||
|
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
|
||||||
|
};
|
||||||
|
static std::vector<GLenum> faceTargets {
|
||||||
|
GL_TEXTURE_2D
|
||||||
|
};
|
||||||
|
switch (target) {
|
||||||
|
case GL_TEXTURE_2D:
|
||||||
|
return faceTargets;
|
||||||
|
case GL_TEXTURE_CUBE_MAP:
|
||||||
|
return cubeFaceTargets;
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
return faceTargets;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default texture memory = GPU total memory - 2GB
|
||||||
|
#define GPU_MEMORY_RESERVE_BYTES MB_TO_BYTES(2048)
|
||||||
|
// Minimum texture memory = 1GB
|
||||||
|
#define TEXTURE_MEMORY_MIN_BYTES MB_TO_BYTES(1024)
|
||||||
|
|
||||||
|
|
||||||
|
float GLTexture::getMemoryPressure() {
|
||||||
|
// Check for an explicit memory limit
|
||||||
|
auto availableTextureMemory = Texture::getAllowedGPUMemoryUsage();
|
||||||
|
|
||||||
|
|
||||||
|
// If no memory limit has been set, use a percentage of the total dedicated memory
|
||||||
|
if (!availableTextureMemory) {
|
||||||
|
#if 0
|
||||||
|
auto totalMemory = getDedicatedMemory();
|
||||||
|
if ((GPU_MEMORY_RESERVE_BYTES + TEXTURE_MEMORY_MIN_BYTES) > totalMemory) {
|
||||||
|
availableTextureMemory = TEXTURE_MEMORY_MIN_BYTES;
|
||||||
|
} else {
|
||||||
|
availableTextureMemory = totalMemory - GPU_MEMORY_RESERVE_BYTES;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Hardcode texture limit for sparse textures at 1 GB for now
|
||||||
|
availableTextureMemory = TEXTURE_MEMORY_MIN_BYTES;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the consumed texture memory divided by the available texture memory.
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
//auto consumedGpuMemory = Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage();
|
||||||
|
//float memoryPressure = (float)consumedGpuMemory / (float)availableTextureMemory;
|
||||||
|
//static Context::Size lastConsumedGpuMemory = 0;
|
||||||
|
//if (memoryPressure > 1.0f && lastConsumedGpuMemory != consumedGpuMemory) {
|
||||||
|
// lastConsumedGpuMemory = consumedGpuMemory;
|
||||||
|
// qCDebug(gpugllogging) << "Exceeded max allowed texture memory: " << consumedGpuMemory << " / " << availableTextureMemory;
|
||||||
|
//}
|
||||||
|
//return memoryPressure;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create the texture and allocate storage
|
||||||
|
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) :
|
||||||
|
GLObject(backend, texture, id),
|
||||||
|
_external(false),
|
||||||
|
_source(texture.source()),
|
||||||
|
_storageStamp(texture.getStamp()),
|
||||||
|
_target(getGLTextureType(texture)),
|
||||||
|
_internalFormat(gl::GLTexelFormat::evalGLTexelFormatInternal(texture.getTexelFormat())),
|
||||||
|
_maxMip(texture.getMaxMip()),
|
||||||
|
_minMip(texture.getMinMip()),
|
||||||
|
_virtualSize(texture.evalTotalSize()),
|
||||||
|
_transferrable(transferrable)
|
||||||
|
{
|
||||||
|
//qDebug() << "GLTexture::GLTexture building GLTexture with _internalFormat" << _internalFormat;
|
||||||
|
auto strongBackend = _backend.lock();
|
||||||
|
strongBackend->recycle();
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
//Backend::incrementTextureGPUCount();
|
||||||
|
//Backend::updateTextureGPUVirtualMemoryUsage(0, _virtualSize);
|
||||||
|
//CLIMAX_MERGE_END
|
||||||
|
Backend::setGPUObject(texture, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint id) :
|
||||||
|
GLObject(backend, texture, id),
|
||||||
|
_external(true),
|
||||||
|
_source(texture.source()),
|
||||||
|
_storageStamp(0),
|
||||||
|
_target(getGLTextureType(texture)),
|
||||||
|
_internalFormat(GL_RGBA8),
|
||||||
|
// FIXME force mips to 0?
|
||||||
|
_maxMip(texture.getMaxMip()),
|
||||||
|
_minMip(texture.getMinMip()),
|
||||||
|
_virtualSize(0),
|
||||||
|
_transferrable(false)
|
||||||
|
{
|
||||||
|
Backend::setGPUObject(texture, this);
|
||||||
|
|
||||||
|
// FIXME Is this necessary?
|
||||||
|
//withPreservedTexture([this] {
|
||||||
|
// syncSampler();
|
||||||
|
// if (_gpuObject.isAutogenerateMips()) {
|
||||||
|
// generateMips();
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexture::~GLTexture() {
|
||||||
|
auto backend = _backend.lock();
|
||||||
|
if (backend) {
|
||||||
|
if (_external) {
|
||||||
|
auto recycler = _gpuObject.getExternalRecycler();
|
||||||
|
if (recycler) {
|
||||||
|
backend->releaseExternalTexture(_id, recycler);
|
||||||
|
} else {
|
||||||
|
qWarning() << "No recycler available for texture " << _id << " possible leak";
|
||||||
|
}
|
||||||
|
} else if (_id) {
|
||||||
|
// WARNING! Sparse textures do not use this code path. See GL45BackendTexture for
|
||||||
|
// the GL45Texture destructor for doing any required work tracking GPU stats
|
||||||
|
backend->releaseTexture(_id, _size);
|
||||||
|
}
|
||||||
|
|
||||||
|
////CLIMAX_MERGE_START
|
||||||
|
//if (!_external && !_transferrable) {
|
||||||
|
// Backend::updateTextureGPUFramebufferMemoryUsage(_size, 0);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
//Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0);
|
||||||
|
//CLIMAX_MERGE_END
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::createTexture() {
|
||||||
|
withPreservedTexture([&] {
|
||||||
|
allocateStorage();
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
syncSampler();
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::withPreservedTexture(std::function<void()> f) const {
|
||||||
|
GLint boundTex = -1;
|
||||||
|
switch (_target) {
|
||||||
|
case GL_TEXTURE_2D:
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_TEXTURE_CUBE_MAP:
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
qFatal("Unsupported texture type");
|
||||||
|
}
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
|
||||||
|
glBindTexture(_target, _texture);
|
||||||
|
f();
|
||||||
|
glBindTexture(_target, boundTex);
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::setSize(GLuint size) const {
|
||||||
|
////CLIMAX_MERGE_START
|
||||||
|
//if (!_external && !_transferrable) {
|
||||||
|
// Backend::updateTextureGPUFramebufferMemoryUsage(_size, 0);
|
||||||
|
//}
|
||||||
|
//Backend::updateTextureGPUMemoryUsage(_size, size);
|
||||||
|
const_cast<GLuint&>(_size) = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLTexture::isInvalid() const {
|
||||||
|
return _storageStamp < _gpuObject.getStamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLTexture::isOutdated() const {
|
||||||
|
return GLSyncState::Idle == _syncState && _contentStamp < _gpuObject.getDataStamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLTexture::isReady() const {
|
||||||
|
// If we have an invalid texture, we're never ready
|
||||||
|
if (isInvalid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto syncState = _syncState.load();
|
||||||
|
if (isOutdated() || Idle != syncState) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Do any post-transfer operations that might be required on the main context / rendering thread
|
||||||
|
void GLTexture::postTransfer() {
|
||||||
|
//CLIMAX_MERGE_START
|
||||||
|
|
||||||
|
// setSyncState(GLSyncState::Idle);
|
||||||
|
// ++_transferCount;
|
||||||
|
|
||||||
|
// // At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory
|
||||||
|
// switch (_gpuObject.getType()) {
|
||||||
|
// case Texture::TEX_2D:
|
||||||
|
// for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) {
|
||||||
|
// if (_gpuObject.isStoredMipFaceAvailable(i)) {
|
||||||
|
// _gpuObject.notifyMipFaceGPULoaded(i);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case Texture::TEX_CUBE:
|
||||||
|
// // transfer pixels from each faces
|
||||||
|
// for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) {
|
||||||
|
// for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) {
|
||||||
|
// if (_gpuObject.isStoredMipFaceAvailable(i, f)) {
|
||||||
|
// _gpuObject.notifyMipFaceGPULoaded(i, f);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// default:
|
||||||
|
// qCWarning(gpugllogging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported";
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//CLIMAX_MERGE_END
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::initTextureTransferHelper() {
|
||||||
|
_textureTransferHelper = std::make_shared<GLTextureTransferHelper>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::startTransfer() {
|
||||||
|
createTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::finishTransfer() {
|
||||||
|
if (_gpuObject.isAutogenerateMips()) {
|
||||||
|
generateMips();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|