mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-18 09:58:55 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into discovery
This commit is contained in:
commit
2b75240771
189 changed files with 6047 additions and 3392 deletions
cmake/externals/openvr
interface
resources
src
libraries
display-plugins
CMakeLists.txt
src
entities-renderer/src
gl/src/gl
GLEscrow.hGLHelpers.cppGLHelpers.hGLWindow.cppOffscreenGLCanvas.cppOffscreenGLCanvas.hQOpenGLDebugLoggerWrapper.cppQOpenGLDebugLoggerWrapper.h
gpu-gl/src/gpu
gl
GLBackend.cppGLBackend.hGLBackendInput.cppGLBackendOutput.cppGLBackendPipeline.cppGLBackendQuery.cppGLBackendState.cppGLBackendTexture.cppGLBackendTransform.cppGLBuffer.cppGLBuffer.hGLFramebuffer.cppGLFramebuffer.hGLPipeline.cppGLPipeline.hGLQuery.hGLShader.cppGLShader.hGLShared.cppGLShared.hGLTexture.cppGLTexture.h
gl41
4
cmake/externals/openvr/CMakeLists.txt
vendored
4
cmake/externals/openvr/CMakeLists.txt
vendored
|
@ -7,8 +7,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://github.com/ValveSoftware/openvr/archive/v0.9.19.zip
|
||||
URL_MD5 843f9dde488584d8af1f3ecf2252b4e0
|
||||
URL https://github.com/ValveSoftware/openvr/archive/v1.0.2.zip
|
||||
URL_MD5 0d1cf5f579cf092e33f34759967b7046
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
|
|
Binary file not shown.
Before ![]() (image error) Size: 110 KiB After ![]() (image error) Size: 106 KiB ![]() ![]() |
BIN
interface/resources/images/steam-sign-in.png
Normal file
BIN
interface/resources/images/steam-sign-in.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 5.7 KiB |
|
@ -10,296 +10,70 @@
|
|||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import "controls"
|
||||
import "styles"
|
||||
|
||||
import "controls-uit"
|
||||
import "styles-uit"
|
||||
import "windows"
|
||||
|
||||
ScrollingWindow {
|
||||
import "LoginDialog"
|
||||
|
||||
ModalWindow {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
objectName: "LoginDialog"
|
||||
height: loginDialog.implicitHeight
|
||||
width: loginDialog.implicitWidth
|
||||
// FIXME make movable
|
||||
anchors.centerIn: parent
|
||||
destroyOnHidden: false
|
||||
hideBackground: true
|
||||
shown: false
|
||||
implicitWidth: 520
|
||||
implicitHeight: 320
|
||||
destroyOnCloseButton: true
|
||||
destroyOnHidden: true
|
||||
visible: true
|
||||
|
||||
property string iconText: ""
|
||||
property int iconSize: 50
|
||||
|
||||
property string title: ""
|
||||
property int titleWidth: 0
|
||||
|
||||
LoginDialog {
|
||||
id: loginDialog
|
||||
implicitWidth: backgroundRectangle.width
|
||||
implicitHeight: backgroundRectangle.height
|
||||
readonly property int inputWidth: 500
|
||||
readonly property int inputHeight: 60
|
||||
readonly property int borderWidth: 30
|
||||
readonly property int closeMargin: 16
|
||||
readonly property real tan30: 0.577 // tan(30°)
|
||||
readonly property int inputSpacing: 16
|
||||
|
||||
Rectangle {
|
||||
id: backgroundRectangle
|
||||
width: loginDialog.inputWidth + loginDialog.borderWidth * 2
|
||||
height: loginDialog.inputHeight * 6 + loginDialog.closeMargin * 2
|
||||
radius: loginDialog.closeMargin * 2
|
||||
color: "#2c86b1"
|
||||
opacity: 0.85
|
||||
}
|
||||
|
||||
Column {
|
||||
id: mainContent
|
||||
width: loginDialog.inputWidth
|
||||
spacing: loginDialog.inputSpacing
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
// Offset content down a little
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.closeMargin
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight
|
||||
radius: height / 2
|
||||
color: "#ebebeb"
|
||||
|
||||
Image {
|
||||
source: "../images/login-username.svg"
|
||||
width: loginDialog.inputHeight * 0.65
|
||||
height: width
|
||||
sourceSize: Qt.size(width, height);
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
leftMargin: loginDialog.inputHeight / 4
|
||||
}
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: username
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: loginDialog.inputHeight
|
||||
rightMargin: loginDialog.inputHeight / 2
|
||||
}
|
||||
|
||||
helperText: "username or email"
|
||||
color: hifi.colors.text
|
||||
|
||||
KeyNavigation.tab: password
|
||||
KeyNavigation.backtab: password
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight
|
||||
radius: height / 2
|
||||
color: "#ebebeb"
|
||||
|
||||
Image {
|
||||
source: "../images/login-password.svg"
|
||||
width: loginDialog.inputHeight * 0.65
|
||||
height: width
|
||||
sourceSize: Qt.size(width, height);
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
leftMargin: loginDialog.inputHeight / 4
|
||||
}
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: password
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: loginDialog.inputHeight
|
||||
rightMargin: loginDialog.inputHeight / 2
|
||||
}
|
||||
|
||||
helperText: "password"
|
||||
echoMode: TextInput.Password
|
||||
color: hifi.colors.text
|
||||
|
||||
KeyNavigation.tab: username
|
||||
KeyNavigation.backtab: username
|
||||
onFocusChanged: {
|
||||
if (password.focus) {
|
||||
password.selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight / 2
|
||||
|
||||
Text {
|
||||
id: messageText
|
||||
|
||||
visible: loginDialog.statusText != "" && loginDialog.statusText != "Logging in..."
|
||||
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight / 2
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
text: loginDialog.statusText
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Row {
|
||||
id: messageSpinner
|
||||
|
||||
visible: loginDialog.statusText == "Logging in..."
|
||||
onVisibleChanged: visible ? messageSpinnerAnimation.restart() : messageSpinnerAnimation.stop()
|
||||
|
||||
spacing: 24
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: spinner1
|
||||
width: 10
|
||||
height: 10
|
||||
color: "#ebebeb"
|
||||
opacity: 0.05
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: spinner2
|
||||
width: 10
|
||||
height: 10
|
||||
color: "#ebebeb"
|
||||
opacity: 0.05
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: spinner3
|
||||
width: 10
|
||||
height: 10
|
||||
color: "#ebebeb"
|
||||
opacity: 0.05
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: messageSpinnerAnimation
|
||||
running: messageSpinner.visible
|
||||
loops: Animation.Infinite
|
||||
NumberAnimation { target: spinner1; property: "opacity"; to: 1.0; duration: 1000 }
|
||||
NumberAnimation { target: spinner2; property: "opacity"; to: 1.0; duration: 1000 }
|
||||
NumberAnimation { target: spinner3; property: "opacity"; to: 1.0; duration: 1000 }
|
||||
NumberAnimation { target: spinner1; property: "opacity"; to: 0.05; duration: 0 }
|
||||
NumberAnimation { target: spinner2; property: "opacity"; to: 0.05; duration: 0 }
|
||||
NumberAnimation { target: spinner3; property: "opacity"; to: 0.05; duration: 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: loginDialog.inputWidth
|
||||
height: loginDialog.inputHeight
|
||||
radius: height / 2
|
||||
color: "#353535"
|
||||
|
||||
TextInput {
|
||||
anchors.fill: parent
|
||||
text: "Login"
|
||||
color: "white"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
loginDialog.login(username.text, password.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors { left: parent.left; right: parent.right; }
|
||||
height: loginDialog.inputHeight
|
||||
|
||||
Image {
|
||||
id: hifiIcon
|
||||
source: "../images/hifi-logo-blackish.svg"
|
||||
width: loginDialog.inputHeight
|
||||
height: width
|
||||
sourceSize: Qt.size(width, height);
|
||||
anchors { verticalCenter: parent.verticalCenter; horizontalCenter: parent.horizontalCenter }
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors { verticalCenter: parent.verticalCenter; right: hifiIcon.left; margins: loginDialog.inputSpacing }
|
||||
text: "Password?"
|
||||
scale: 0.8
|
||||
font.underline: true
|
||||
color: "#e0e0e0"
|
||||
MouseArea {
|
||||
anchors { fill: parent; margins: -loginDialog.inputSpacing / 2 }
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new")
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors { verticalCenter: parent.verticalCenter; left: hifiIcon.right; margins: loginDialog.inputSpacing }
|
||||
text: "Register"
|
||||
scale: 0.8
|
||||
font.underline: true
|
||||
color: "#e0e0e0"
|
||||
|
||||
MouseArea {
|
||||
anchors { fill: parent; margins: -loginDialog.inputSpacing / 2 }
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: loginDialog.openUrl(loginDialog.rootUrl + "/signup")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onShownChanged: {
|
||||
if (!shown) {
|
||||
username.text = ""
|
||||
password.text = ""
|
||||
loginDialog.statusText = ""
|
||||
} else {
|
||||
username.forceActiveFocus()
|
||||
Loader {
|
||||
id: bodyLoader
|
||||
anchors.fill: parent
|
||||
source: loginDialog.isSteamRunning() ? "LoginDialog/SignInBody.qml" : "LoginDialog/LinkAccountBody.qml"
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.modifiers === Qt.ControlModifier)
|
||||
switch (event.key) {
|
||||
case Qt.Key_A:
|
||||
event.accepted = true
|
||||
detailedText.selectAll()
|
||||
break
|
||||
case Qt.Key_C:
|
||||
event.accepted = true
|
||||
detailedText.copy()
|
||||
break
|
||||
case Qt.Key_Period:
|
||||
if (Qt.platform.os === "osx") {
|
||||
event.accepted = true
|
||||
content.reject()
|
||||
}
|
||||
break
|
||||
} else switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
root.shown = false;
|
||||
event.accepted = true;
|
||||
break;
|
||||
event.accepted = true
|
||||
destroy()
|
||||
break
|
||||
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
if (username.activeFocus) {
|
||||
event.accepted = true
|
||||
password.forceActiveFocus()
|
||||
} else if (password.activeFocus) {
|
||||
event.accepted = true
|
||||
if (username.text == "") {
|
||||
username.forceActiveFocus()
|
||||
} else {
|
||||
loginDialog.login(username.text, password.text)
|
||||
}
|
||||
}
|
||||
event.accepted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
125
interface/resources/qml/LoginDialog/CompleteProfileBody.qml
Normal file
125
interface/resources/qml/LoginDialog/CompleteProfileBody.qml
Normal file
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// CompleteProfileBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: completeProfileBody
|
||||
clip: true
|
||||
width: pane.width
|
||||
height: pane.height
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, additionalTextContainer.contentWidth)
|
||||
var targetHeight = 4 * hifi.dimensions.contentSpacing.y + buttons.height + additionalTextContainer.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: 3 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 200
|
||||
|
||||
text: qsTr("Create your profile")
|
||||
color: hifi.buttons.blue
|
||||
|
||||
onClicked: loginDialog.createAccountFromStream()
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Cancel")
|
||||
|
||||
|
||||
onClicked: root.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: additionalTextContainer
|
||||
anchors {
|
||||
top: buttons.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
|
||||
|
||||
wrapMode: Text.WordWrap
|
||||
lineHeight: 2
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: {
|
||||
bodyLoader.source = "LinkAccountBody.qml"
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Complete Your Profile")
|
||||
root.iconText = "<"
|
||||
d.resize();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleCreateCompleted: {
|
||||
console.log("Create Succeeded")
|
||||
|
||||
loginDialog.loginThroughSteam()
|
||||
}
|
||||
onHandleCreateFailed: {
|
||||
console.log("Create Failed: " + error)
|
||||
|
||||
bodyLoader.source = "UsernameCollisionBody.qml"
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded")
|
||||
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
}
|
||||
}
|
||||
}
|
215
interface/resources/qml/LoginDialog/LinkAccountBody.qml
Normal file
215
interface/resources/qml/LoginDialog/LinkAccountBody.qml
Normal file
|
@ -0,0 +1,215 @@
|
|||
//
|
||||
// LinkAccountBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: linkAccountBody
|
||||
clip: true
|
||||
width: root.pane.width
|
||||
height: root.pane.height
|
||||
|
||||
function login() {
|
||||
mainTextContainer.visible = false
|
||||
loginDialog.login(usernameField.text, passwordField.text)
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, form.contentWidth)
|
||||
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
|
||||
4 * hifi.dimensions.contentSpacing.y + form.height +
|
||||
4 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
visible: false
|
||||
|
||||
text: qsTr("Username or password incorrect.")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.redAccent
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
id: form
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: 2 * hifi.dimensions.contentSpacing.y
|
||||
|
||||
Row {
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
||||
TextField {
|
||||
id: usernameField
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
width: 350
|
||||
|
||||
label: "User Name or Email"
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
}
|
||||
Row {
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
||||
TextField {
|
||||
id: passwordField
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
width: 350
|
||||
|
||||
label: "Password"
|
||||
echoMode: TextInput.Password
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: form.bottom
|
||||
right: parent.right
|
||||
margins: 0
|
||||
topMargin: 3 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
id: linkAccountButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 200
|
||||
|
||||
text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Login")
|
||||
color: hifi.buttons.blue
|
||||
|
||||
onClicked: linkAccountBody.login()
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Cancel")
|
||||
|
||||
onClicked: root.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Sign Into High Fidelity")
|
||||
root.iconText = "<"
|
||||
d.resize();
|
||||
|
||||
usernameField.forceActiveFocus()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded, linking steam account")
|
||||
|
||||
if (loginDialog.isSteamRunning()) {
|
||||
loginDialog.linkSteam()
|
||||
} else {
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
mainTextContainer.visible = true
|
||||
}
|
||||
onHandleLinkCompleted: {
|
||||
console.log("Link Succeeded")
|
||||
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLinkFailed: {
|
||||
console.log("Link Failed")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true
|
||||
linkAccountBody.login()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
128
interface/resources/qml/LoginDialog/SignInBody.qml
Normal file
128
interface/resources/qml/LoginDialog/SignInBody.qml
Normal file
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// SignInBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: signInBody
|
||||
clip: true
|
||||
width: pane.width
|
||||
height: pane.height
|
||||
|
||||
property bool required: false
|
||||
|
||||
function login() {
|
||||
console.log("Trying to log in")
|
||||
loginDialog.loginThroughSteam()
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
root.destroy()
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, mainTextContainer.contentWidth)
|
||||
var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: required ? qsTr("This domain's owner requires that you sign in:")
|
||||
: qsTr("Sign in to access your user account:")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
lineHeight: 2
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
width: undefined // invalidate so that the image's size sets the width
|
||||
height: undefined // invalidate so that the image's size sets the height
|
||||
focus: true
|
||||
|
||||
style: OriginalStyles.ButtonStyle {
|
||||
background: Image {
|
||||
id: buttonImage
|
||||
source: "../../images/steam-sign-in.png"
|
||||
}
|
||||
}
|
||||
onClicked: signInBody.login()
|
||||
}
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Cancel");
|
||||
|
||||
onClicked: signInBody.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = required ? qsTr("Sign In Required")
|
||||
: qsTr("Sign In")
|
||||
root.iconText = ""
|
||||
d.resize();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded")
|
||||
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
|
||||
bodyLoader.source = "CompleteProfileBody.qml"
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
}
|
||||
}
|
173
interface/resources/qml/LoginDialog/UsernameCollisionBody.qml
Normal file
173
interface/resources/qml/LoginDialog/UsernameCollisionBody.qml
Normal file
|
@ -0,0 +1,173 @@
|
|||
//
|
||||
// UsernameCollisionBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: usernameCollisionBody
|
||||
clip: true
|
||||
width: root.pane.width
|
||||
height: root.pane.height
|
||||
|
||||
function create() {
|
||||
mainTextContainer.visible = false
|
||||
loginDialog.createAccountFromStream(textField.text)
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, Math.max(mainTextContainer.contentWidth,
|
||||
termsContainer.contentWidth))
|
||||
var targetHeight = mainTextContainer.height +
|
||||
2 * hifi.dimensions.contentSpacing.y + textField.height +
|
||||
5 * hifi.dimensions.contentSpacing.y + termsContainer.height +
|
||||
1 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: qsTr("Your Steam username is not available.")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.redAccent
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
|
||||
TextField {
|
||||
id: textField
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
width: 250
|
||||
|
||||
placeholderText: "Choose your own"
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
id: termsContainer
|
||||
anchors {
|
||||
top: textField.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 3 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: termsContainer.bottom
|
||||
right: parent.right
|
||||
margins: 0
|
||||
topMargin: 1 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 200
|
||||
|
||||
text: qsTr("Create your profile")
|
||||
color: hifi.buttons.blue
|
||||
|
||||
onClicked: usernameCollisionBody.create()
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Cancel")
|
||||
|
||||
onClicked: root.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Complete Your Profile")
|
||||
root.iconText = "<"
|
||||
d.resize();
|
||||
}
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleCreateCompleted: {
|
||||
console.log("Create Succeeded")
|
||||
|
||||
loginDialog.loginThroughSteam()
|
||||
}
|
||||
onHandleCreateFailed: {
|
||||
console.log("Create Failed: " + error)
|
||||
|
||||
mainTextContainer.visible = true
|
||||
mainTextContainer.text = "\"" + textField.text + qsTr("\" is invalid or already taken.")
|
||||
}
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded")
|
||||
|
||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
|
||||
bodyLoader.item.width = root.pane.width
|
||||
bodyLoader.item.height = root.pane.height
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true
|
||||
usernameCollisionBody.create()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
90
interface/resources/qml/LoginDialog/WelcomeBody.qml
Normal file
90
interface/resources/qml/LoginDialog/WelcomeBody.qml
Normal file
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// WelcomeBody.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: welcomeBody
|
||||
clip: true
|
||||
width: pane.width
|
||||
height: pane.height
|
||||
|
||||
property bool welcomeBack: false
|
||||
|
||||
function setTitle() {
|
||||
root.title = (welcomeBack ? qsTr("Welcome back <b>") : qsTr("Welcome <b>")) + Account.username + qsTr("</b>!")
|
||||
root.iconText = ""
|
||||
d.resize();
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, mainTextContainer.contentWidth)
|
||||
var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: qsTr("You are now signed into High Fidelity")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
lineHeight: 2
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: qsTr("Close");
|
||||
|
||||
onClicked: root.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: welcomeBody.setTitle()
|
||||
|
||||
Connections {
|
||||
target: Account
|
||||
onUsernameChanged: welcomeBody.setTitle()
|
||||
}
|
||||
}
|
20
interface/resources/qml/controls-uit/HorizontalRule.qml
Normal file
20
interface/resources/qml/controls-uit/HorizontalRule.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// HorizontalRule.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: hifi.colors.lightGray
|
||||
}
|
21
interface/resources/qml/controls-uit/HorizontalSpacer.qml
Normal file
21
interface/resources/qml/controls-uit/HorizontalSpacer.qml
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// HorizontalSpacer.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property alias size: root.width
|
||||
|
||||
width: hifi.dimensions.controlInterlineHeight
|
||||
height: 1 // Must be non-zero
|
||||
}
|
|
@ -13,6 +13,9 @@ import QtQuick 2.5
|
|||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property alias size: root.height
|
||||
|
||||
width: 1 // Must be non-zero
|
||||
height: hifi.dimensions.controlInterlineHeight
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ import "messageDialog"
|
|||
ModalWindow {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
implicitWidth: 640
|
||||
implicitHeight: 320
|
||||
destroyOnCloseButton: true
|
||||
destroyOnHidden: true
|
||||
visible: true
|
||||
|
@ -70,7 +68,7 @@ ModalWindow {
|
|||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWdith: 1280
|
||||
readonly property int maxWidth: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
|
@ -80,7 +78,7 @@ ModalWindow {
|
|||
+ (informativeTextContainer.text != "" ? informativeTextContainer.contentHeight + 3 * hifi.dimensions.contentSpacing.y : 0)
|
||||
+ buttons.height
|
||||
+ (content.state === "expanded" ? details.implicitHeight + hifi.dimensions.contentSpacing.y : 0)
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth)
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWidth) ? d.maxWidth : targetWidth)
|
||||
root.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)
|
||||
}
|
||||
}
|
||||
|
|
18
interface/resources/qml/styles-uit/ButtonLabel.qml
Normal file
18
interface/resources/qml/styles-uit/ButtonLabel.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// ButtonLabel.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayBold {
|
||||
font.pixelSize: hifi.fontSizes.buttonLabel
|
||||
}
|
20
interface/resources/qml/styles-uit/IconButton.qml
Normal file
20
interface/resources/qml/styles-uit/IconButton.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// IconButton.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.iconButton
|
||||
font.capitalization: Font.AllUppercase
|
||||
font.letterSpacing: 1.5
|
||||
}
|
18
interface/resources/qml/styles-uit/InputLabel.qml
Normal file
18
interface/resources/qml/styles-uit/InputLabel.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// InputLabel.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewaySemiBold {
|
||||
font.pixelSize: hifi.fontSizes.inputLabel
|
||||
}
|
18
interface/resources/qml/styles-uit/ListItem.qml
Normal file
18
interface/resources/qml/styles-uit/ListItem.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// ListItem.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.listItem
|
||||
}
|
18
interface/resources/qml/styles-uit/Logs.qml
Normal file
18
interface/resources/qml/styles-uit/Logs.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Logs.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
AnonymousProRegular {
|
||||
font.pixelSize: hifi.fontSizes.logs
|
||||
}
|
19
interface/resources/qml/styles-uit/MenuItem.qml
Normal file
19
interface/resources/qml/styles-uit/MenuItem.qml
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// MenuItem.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewaySemiBold {
|
||||
lineHeight: 2
|
||||
font.pixelSize: hifi.fontSizes.menuItem
|
||||
}
|
18
interface/resources/qml/styles-uit/OverlayTitle.qml
Normal file
18
interface/resources/qml/styles-uit/OverlayTitle.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// OverlayTitle.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.overlayTitle
|
||||
}
|
19
interface/resources/qml/styles-uit/SectionName.qml
Normal file
19
interface/resources/qml/styles-uit/SectionName.qml
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// SectionName.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.sectionName
|
||||
font.capitalization: Font.AllUppercase
|
||||
}
|
18
interface/resources/qml/styles-uit/ShortcutText.qml
Normal file
18
interface/resources/qml/styles-uit/ShortcutText.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// ShortcutText.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayLight {
|
||||
font.pixelSize: hifi.fontSizes.shortcutText
|
||||
}
|
19
interface/resources/qml/styles-uit/TabName.qml
Normal file
19
interface/resources/qml/styles-uit/TabName.qml
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// TabName.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
RalewayRegular {
|
||||
font.pixelSize: hifi.fontSizes.tabName
|
||||
font.capitalization: Font.AllUppercase
|
||||
}
|
18
interface/resources/qml/styles-uit/TextFieldInput.qml
Normal file
18
interface/resources/qml/styles-uit/TextFieldInput.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// TextFieldInput.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "."
|
||||
|
||||
FiraSansSemiBold {
|
||||
font.pixelSize: hifi.fontSizes.textFieldInput
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/11
|
||||
// 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
|
||||
//
|
||||
|
||||
#version 410 core
|
||||
|
||||
uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
layout(location = 0) in vec3 inLineDistance;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
vec2 d = inLineDistance.xy;
|
||||
d.y = abs(d.y);
|
||||
d.x = abs(d.x);
|
||||
if (d.x > 1.0) {
|
||||
d.x = (d.x - 1.0) / 0.02;
|
||||
} else {
|
||||
d.x = 0.0;
|
||||
}
|
||||
float alpha = 1.0 - length(d);
|
||||
if (alpha <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
alpha = pow(alpha, 10.0);
|
||||
if (alpha < 0.05) {
|
||||
discard;
|
||||
}
|
||||
FragColor = vec4(color.rgb, alpha);
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/11
|
||||
// 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
|
||||
//
|
||||
#version 410 core
|
||||
#extension GL_EXT_geometry_shader4 : enable
|
||||
|
||||
layout(location = 0) out vec3 outLineDistance;
|
||||
|
||||
layout(lines) in;
|
||||
layout(triangle_strip, max_vertices = 24) out;
|
||||
|
||||
vec3[2] getOrthogonals(in vec3 n, float scale) {
|
||||
float yDot = abs(dot(n, vec3(0, 1, 0)));
|
||||
|
||||
vec3 result[2];
|
||||
if (yDot < 0.9) {
|
||||
result[0] = normalize(cross(n, vec3(0, 1, 0)));
|
||||
} else {
|
||||
result[0] = normalize(cross(n, vec3(1, 0, 0)));
|
||||
}
|
||||
// The cross of result[0] and n is orthogonal to both, which are orthogonal to each other
|
||||
result[1] = cross(result[0], n);
|
||||
result[0] *= scale;
|
||||
result[1] *= scale;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
vec2 orthogonal(vec2 v) {
|
||||
vec2 result = v.yx;
|
||||
result.y *= -1.0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 endpoints[2];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
endpoints[i] = gl_PositionIn[i].xy / gl_PositionIn[i].w;
|
||||
}
|
||||
vec2 lineNormal = normalize(endpoints[1] - endpoints[0]);
|
||||
vec2 lineOrthogonal = orthogonal(lineNormal);
|
||||
lineNormal *= 0.02;
|
||||
lineOrthogonal *= 0.02;
|
||||
|
||||
gl_Position = gl_PositionIn[0];
|
||||
gl_Position.xy -= lineOrthogonal;
|
||||
outLineDistance = vec3(-1.02, -1, gl_Position.z);
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = gl_PositionIn[0];
|
||||
gl_Position.xy += lineOrthogonal;
|
||||
outLineDistance = vec3(-1.02, 1, gl_Position.z);
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = gl_PositionIn[1];
|
||||
gl_Position.xy -= lineOrthogonal;
|
||||
outLineDistance = vec3(1.02, -1, gl_Position.z);
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = gl_PositionIn[1];
|
||||
gl_Position.xy += lineOrthogonal;
|
||||
outLineDistance = vec3(1.02, 1, gl_Position.z);
|
||||
EmitVertex();
|
||||
|
||||
EndPrimitive();
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/11
|
||||
// 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
|
||||
//
|
||||
#version 410 core
|
||||
uniform mat4 mvp = mat4(1);
|
||||
|
||||
in vec3 Position;
|
||||
|
||||
void main() {
|
||||
gl_Position = mvp * vec4(Position, 1);
|
||||
}
|
|
@ -6,18 +6,27 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#version 410 core
|
||||
|
||||
uniform sampler2D sampler;
|
||||
uniform float alpha = 1.0;
|
||||
uniform vec4 glowPoints = vec4(-1);
|
||||
uniform vec4 glowColors[2];
|
||||
uniform vec2 resolution = vec2(3960.0, 1188.0);
|
||||
uniform float radius = 0.005;
|
||||
|
||||
struct OverlayData {
|
||||
mat4 mvp;
|
||||
vec4 glowPoints;
|
||||
vec4 glowColors[2];
|
||||
vec4 resolutionRadiusAlpha;
|
||||
};
|
||||
|
||||
layout(std140) uniform overlayBuffer {
|
||||
OverlayData overlay;
|
||||
};
|
||||
|
||||
vec2 resolution = overlay.resolutionRadiusAlpha.xy;
|
||||
float radius = overlay.resolutionRadiusAlpha.z;
|
||||
float alpha = overlay.resolutionRadiusAlpha.w;
|
||||
vec4 glowPoints = overlay.glowPoints;
|
||||
vec4 glowColors[2] = overlay.glowColors;
|
||||
|
||||
in vec3 vPosition;
|
||||
in vec2 vTexCoord;
|
||||
in vec4 vGlowPoints;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
|
@ -31,9 +40,10 @@ float easeInOutCubic(float f) {
|
|||
}
|
||||
|
||||
void main() {
|
||||
FragColor = texture(sampler, vTexCoord);
|
||||
|
||||
vec2 aspect = resolution;
|
||||
aspect /= resolution.x;
|
||||
FragColor = texture(sampler, vTexCoord);
|
||||
|
||||
float glowIntensity = 0.0;
|
||||
float dist1 = distance(vTexCoord * aspect, glowPoints.xy * aspect);
|
||||
|
|
|
@ -6,12 +6,21 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#version 410 core
|
||||
struct OverlayData {
|
||||
mat4 mvp;
|
||||
vec4 glowPoints;
|
||||
vec4 glowColors[2];
|
||||
vec4 resolutionRadiusAlpha;
|
||||
};
|
||||
|
||||
uniform mat4 mvp = mat4(1);
|
||||
layout(std140) uniform overlayBuffer {
|
||||
OverlayData overlay;
|
||||
};
|
||||
|
||||
in vec3 Position;
|
||||
in vec2 TexCoord;
|
||||
mat4 mvp = overlay.mvp;
|
||||
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 3) in vec2 TexCoord;
|
||||
|
||||
out vec3 vPosition;
|
||||
out vec2 vTexCoord;
|
||||
|
|
|
@ -86,15 +86,16 @@
|
|||
#include <PhysicsHelpers.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <plugins/CodecPlugin.h>
|
||||
#include <RecordingScriptingInterface.h>
|
||||
#include <RenderableWebEntityItem.h>
|
||||
#include <RenderShadowTask.h>
|
||||
#include <RenderDeferredTask.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include <RecordingScriptingInterface.h>
|
||||
#include <ScriptEngines.h>
|
||||
#include <ScriptCache.h>
|
||||
#include <SoundCache.h>
|
||||
#include <ScriptEngines.h>
|
||||
#include <steamworks-wrapper/SteamClient.h>
|
||||
#include <Tooltip.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
@ -256,7 +257,10 @@ public:
|
|||
void run() override {
|
||||
while (!_quit) {
|
||||
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
|
||||
|
||||
// Don't do heartbeat detection under nsight
|
||||
if (nsightActive()) {
|
||||
continue;
|
||||
}
|
||||
uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us
|
||||
uint64_t now = usecTimestampNow();
|
||||
auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0;
|
||||
|
@ -304,8 +308,6 @@ public:
|
|||
// Don't actually crash in debug builds, in case this apparent deadlock is simply from
|
||||
// the developer actively debugging code
|
||||
#ifdef NDEBUG
|
||||
|
||||
|
||||
deadlockDetectionCrash();
|
||||
#endif
|
||||
}
|
||||
|
@ -778,16 +780,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
_glWidget->makeCurrent();
|
||||
_glWidget->initializeGL();
|
||||
|
||||
_chromiumShareContext = new OffscreenGLCanvas();
|
||||
_chromiumShareContext->create(_glWidget->context()->contextHandle());
|
||||
_chromiumShareContext->makeCurrent();
|
||||
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
|
||||
|
||||
_offscreenContext = new OffscreenGLCanvas();
|
||||
_offscreenContext->create(_glWidget->context()->contextHandle());
|
||||
_offscreenContext->makeCurrent();
|
||||
initializeGL();
|
||||
_offscreenContext->makeCurrent();
|
||||
// Make sure we don't time out during slow operations at startup
|
||||
updateHeartbeat();
|
||||
|
||||
|
@ -1497,11 +1490,18 @@ void Application::initializeGL() {
|
|||
_isGLInitialized = true;
|
||||
}
|
||||
|
||||
_glWidget->makeCurrent();
|
||||
_chromiumShareContext = new OffscreenGLCanvas();
|
||||
_chromiumShareContext->create(_glWidget->context()->contextHandle());
|
||||
_chromiumShareContext->makeCurrent();
|
||||
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
|
||||
|
||||
_glWidget->makeCurrent();
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
// The gpu context can make child contexts for transfers, so
|
||||
// we need to restore primary rendering context
|
||||
_offscreenContext->makeCurrent();
|
||||
_glWidget->makeCurrent();
|
||||
|
||||
initDisplay();
|
||||
qCDebug(interfaceapp, "Initialized Display.");
|
||||
|
@ -1520,7 +1520,8 @@ void Application::initializeGL() {
|
|||
// Needs to happen AFTER the render engine initialization to access its configuration
|
||||
initializeUi();
|
||||
qCDebug(interfaceapp, "Initialized Offscreen UI.");
|
||||
_offscreenContext->makeCurrent();
|
||||
_glWidget->makeCurrent();
|
||||
|
||||
|
||||
// call Menu getInstance static method to set up the menu
|
||||
// Needs to happen AFTER the QML UI initialization
|
||||
|
@ -1536,8 +1537,13 @@ void Application::initializeGL() {
|
|||
|
||||
_idleLoopStdev.reset();
|
||||
|
||||
_offscreenContext = new OffscreenGLCanvas();
|
||||
_offscreenContext->create(_glWidget->context()->contextHandle());
|
||||
_offscreenContext->makeCurrent();
|
||||
|
||||
// update before the first render
|
||||
update(0);
|
||||
|
||||
}
|
||||
|
||||
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
|
||||
|
@ -1554,7 +1560,7 @@ void Application::initializeUi() {
|
|||
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->create(_offscreenContext->getContext());
|
||||
offscreenUi->create(_glWidget->context()->contextHandle());
|
||||
|
||||
auto rootContext = offscreenUi->getRootContext();
|
||||
|
||||
|
@ -1631,6 +1637,8 @@ void Application::initializeUi() {
|
|||
rootContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
|
||||
|
||||
rootContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
|
||||
|
||||
rootContext->setContextProperty("Steam", new SteamScriptingInterface(engine));
|
||||
|
||||
|
||||
_glWidget->installEventFilter(offscreenUi.data());
|
||||
|
@ -1723,17 +1731,7 @@ void Application::paintGL() {
|
|||
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
||||
resizeGL();
|
||||
|
||||
// Before anything else, let's sync up the gpuContext with the true glcontext used in case anything happened
|
||||
{
|
||||
PerformanceTimer perfTimer("syncCache");
|
||||
renderArgs._context->syncCache();
|
||||
}
|
||||
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
// Final framebuffer that will be handled to the display-plugin
|
||||
auto finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
|
||||
_gpuContext->beginFrame(finalFramebuffer, getHMDSensorPose());
|
||||
_gpuContext->beginFrame(getHMDSensorPose());
|
||||
// Reset the gpu::Context Stages
|
||||
// Back to the default framebuffer;
|
||||
gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) {
|
||||
|
@ -1863,7 +1861,10 @@ void Application::paintGL() {
|
|||
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform());
|
||||
|
||||
// Primary rendering pass
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
const QSize size = framebufferCache->getFrameBufferSize();
|
||||
// Final framebuffer that will be handled to the display-plugin
|
||||
auto finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
|
||||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/mainRender");
|
||||
|
@ -1888,7 +1889,6 @@ void Application::paintGL() {
|
|||
auto baseProjection = renderArgs.getViewFrustum().getProjection();
|
||||
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||
float IPDScale = hmdInterface->getIPDScale();
|
||||
mat4 headPose = displayPlugin->getHeadPose();
|
||||
|
||||
// FIXME we probably don't need to set the projection matrix every frame,
|
||||
// only when the display plugin changes (or in non-HMD modes when the user
|
||||
|
@ -1904,13 +1904,6 @@ void Application::paintGL() {
|
|||
// Apply IPD scaling
|
||||
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
|
||||
eyeOffsets[eye] = eyeOffsetTransform;
|
||||
|
||||
// Tell the plugin what pose we're using to render. In this case we're just using the
|
||||
// unmodified head pose because the only plugin that cares (the Oculus plugin) uses it
|
||||
// for rotational timewarp. If we move to support positonal timewarp, we need to
|
||||
// ensure this contains the full pose composed with the eye offsets.
|
||||
displayPlugin->setEyeRenderPose(_frameCount, eye, headPose * glm::inverse(eyeOffsetTransform));
|
||||
|
||||
eyeProjections[eye] = displayPlugin->getEyeProjection(eye, baseProjection);
|
||||
});
|
||||
renderArgs._context->setStereoProjections(eyeProjections);
|
||||
|
@ -1918,36 +1911,26 @@ void Application::paintGL() {
|
|||
}
|
||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
displaySide(&renderArgs, _myCamera);
|
||||
|
||||
renderArgs._blitFramebuffer.reset();
|
||||
renderArgs._context->enableStereo(false);
|
||||
}
|
||||
|
||||
_gpuContext->endFrame();
|
||||
|
||||
gpu::TexturePointer overlayTexture = _applicationOverlay.acquireOverlay();
|
||||
if (overlayTexture) {
|
||||
displayPlugin->submitOverlayTexture(overlayTexture);
|
||||
}
|
||||
|
||||
// deliver final composited scene to the display plugin
|
||||
auto frame = _gpuContext->endFrame();
|
||||
frame->frameIndex = _frameCount;
|
||||
frame->framebuffer = finalFramebuffer;
|
||||
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer){
|
||||
DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer);
|
||||
};
|
||||
frame->overlay = _applicationOverlay.getOverlayTexture();
|
||||
// deliver final scene rendering commands to the display plugin
|
||||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/pluginOutput");
|
||||
PerformanceTimer perfTimer("pluginOutput");
|
||||
|
||||
auto finalTexture = finalFramebuffer->getRenderBuffer(0);
|
||||
Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture));
|
||||
_lockedFramebufferMap[finalTexture] = finalFramebuffer;
|
||||
|
||||
Q_ASSERT(isCurrentContext(_offscreenContext->getContext()));
|
||||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/pluginSubmitScene");
|
||||
PerformanceTimer perfTimer("pluginSubmitScene");
|
||||
displayPlugin->submitSceneTexture(_frameCount, finalTexture);
|
||||
}
|
||||
Q_ASSERT(isCurrentContext(_offscreenContext->getContext()));
|
||||
displayPlugin->submitFrame(frame);
|
||||
}
|
||||
|
||||
// Reset the framebuffer and stereo state
|
||||
renderArgs._blitFramebuffer.reset();
|
||||
renderArgs._context->enableStereo(false);
|
||||
|
||||
{
|
||||
Stats::getInstance()->setRenderDetails(renderArgs._details);
|
||||
}
|
||||
|
@ -2943,6 +2926,8 @@ void Application::idle(float nsecsElapsed) {
|
|||
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
|
||||
SteamClient::runCallbacks();
|
||||
|
||||
float secondsSinceLastUpdate = nsecsElapsed / NSECS_PER_MSEC / MSECS_PER_SECOND;
|
||||
|
||||
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
|
||||
|
@ -3251,6 +3236,14 @@ void Application::init() {
|
|||
addressLookupString = arguments().value(urlIndex + 1);
|
||||
}
|
||||
|
||||
// when +connect_lobby in command line, join steam lobby
|
||||
const QString STEAM_LOBBY_COMMAND_LINE_KEY = "+connect_lobby";
|
||||
int lobbyIndex = arguments().indexOf(STEAM_LOBBY_COMMAND_LINE_KEY);
|
||||
if (lobbyIndex != -1) {
|
||||
QString lobbyId = arguments().value(lobbyIndex + 1);
|
||||
SteamClient::joinLobby(lobbyId);
|
||||
}
|
||||
|
||||
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
||||
if (addressLookupString.isEmpty() && firstRun.get()) {
|
||||
qDebug() << "First run and no URL passed... attempting to go to Home or Entry...";
|
||||
|
@ -4837,6 +4830,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
|
||||
scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine));
|
||||
}
|
||||
|
||||
bool Application::canAcceptURL(const QString& urlString) const {
|
||||
|
@ -4875,7 +4870,7 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
|
|||
}
|
||||
|
||||
if (defaultUpload) {
|
||||
toggleAssetServerWidget(urlString);
|
||||
showAssetServerWidget(urlString);
|
||||
}
|
||||
return defaultUpload;
|
||||
}
|
||||
|
@ -5063,7 +5058,7 @@ void Application::toggleRunningScriptsWidget() const {
|
|||
//}
|
||||
}
|
||||
|
||||
void Application::toggleAssetServerWidget(QString filePath) {
|
||||
void Application::showAssetServerWidget(QString filePath) {
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) {
|
||||
return;
|
||||
}
|
||||
|
@ -5395,6 +5390,7 @@ void Application::updateDisplayMode() {
|
|||
DisplayPluginList advanced;
|
||||
DisplayPluginList developer;
|
||||
foreach(auto displayPlugin, displayPlugins) {
|
||||
displayPlugin->setContext(_gpuContext);
|
||||
auto grouping = displayPlugin->getGrouping();
|
||||
switch (grouping) {
|
||||
case Plugin::ADVANCED:
|
||||
|
@ -5464,9 +5460,6 @@ void Application::updateDisplayMode() {
|
|||
_displayPlugin->deactivate();
|
||||
}
|
||||
|
||||
// FIXME probably excessive and useless context switching
|
||||
_offscreenContext->makeCurrent();
|
||||
|
||||
bool active = newDisplayPlugin->activate();
|
||||
|
||||
if (!active) {
|
||||
|
@ -5611,20 +5604,6 @@ bool Application::makeRenderingContextCurrent() {
|
|||
return _offscreenContext->makeCurrent();
|
||||
}
|
||||
|
||||
void Application::releaseSceneTexture(const gpu::TexturePointer& texture) {
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
auto& framebufferMap = _lockedFramebufferMap;
|
||||
Q_ASSERT(framebufferMap.contains(texture));
|
||||
auto framebufferPointer = framebufferMap[texture];
|
||||
framebufferMap.remove(texture);
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
framebufferCache->releaseFramebuffer(framebufferPointer);
|
||||
}
|
||||
|
||||
void Application::releaseOverlayTexture(const gpu::TexturePointer& texture) {
|
||||
_applicationOverlay.releaseOverlay(texture);
|
||||
}
|
||||
|
||||
bool Application::isForeground() const {
|
||||
return _isForeground && !_window->isMinimized();
|
||||
}
|
||||
|
|
|
@ -112,8 +112,6 @@ public:
|
|||
virtual MainWindow* getPrimaryWindow() override;
|
||||
virtual QOpenGLContext* getPrimaryContext() override;
|
||||
virtual bool makeRenderingContextCurrent() override;
|
||||
virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override;
|
||||
virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override;
|
||||
virtual bool isForeground() const override;
|
||||
|
||||
virtual DisplayPluginPointer getActiveDisplayPlugin() const override;
|
||||
|
@ -280,7 +278,7 @@ public slots:
|
|||
Q_INVOKABLE void loadScriptURLDialog() const;
|
||||
void toggleLogDialog();
|
||||
void toggleRunningScriptsWidget() const;
|
||||
void toggleAssetServerWidget(QString filePath = "");
|
||||
Q_INVOKABLE void showAssetServerWidget(QString filePath = "");
|
||||
|
||||
void handleLocalServerConnection() const;
|
||||
void readArgumentsFromLocalSocket() const;
|
||||
|
@ -435,7 +433,6 @@ private:
|
|||
InputPluginList _activeInputPlugins;
|
||||
|
||||
bool _activatingDisplayPlugin { false };
|
||||
QMap<gpu::TexturePointer, gpu::FramebufferPointer> _lockedFramebufferMap;
|
||||
|
||||
QUndoStack _undoStack;
|
||||
UndoStackScriptingInterface _undoStackScriptingInterface;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <AddressManager.h>
|
||||
#include <DomainHandler.h>
|
||||
#include <NodeList.h>
|
||||
#include <steamworks-wrapper/SteamClient.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
|
||||
|
@ -36,11 +37,11 @@ const QString SESSION_ID_KEY = "session_id";
|
|||
|
||||
void DiscoverabilityManager::updateLocation() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
if (_mode.get() != Discoverability::None && accountManager->isLoggedIn()) {
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
auto& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
|
||||
|
||||
if (_mode.get() != Discoverability::None && accountManager->isLoggedIn()) {
|
||||
// construct a QJsonObject given the user's current address information
|
||||
QJsonObject rootObject;
|
||||
|
||||
|
@ -48,8 +49,6 @@ void DiscoverabilityManager::updateLocation() {
|
|||
|
||||
QString pathString = addressManager->currentPath();
|
||||
|
||||
const QString LOCATION_KEY_IN_ROOT = "location";
|
||||
|
||||
const QString PATH_KEY_IN_LOCATION = "path";
|
||||
locationObject.insert(PATH_KEY_IN_LOCATION, pathString);
|
||||
|
||||
|
@ -90,6 +89,7 @@ void DiscoverabilityManager::updateLocation() {
|
|||
// we have a changed location, send it now
|
||||
_lastLocationObject = locationObject;
|
||||
|
||||
const QString LOCATION_KEY_IN_ROOT = "location";
|
||||
rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject);
|
||||
|
||||
apiPath = API_USER_LOCATION_PATH;
|
||||
|
@ -109,6 +109,9 @@ void DiscoverabilityManager::updateLocation() {
|
|||
accountManager->sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Optional,
|
||||
QNetworkAccessManager::PutOperation, callbackParameters);
|
||||
}
|
||||
|
||||
// Update Steam
|
||||
SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingAddress());
|
||||
}
|
||||
|
||||
void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) {
|
||||
|
|
|
@ -134,7 +134,7 @@ Menu::Menu() {
|
|||
// Edit > My Asset Server
|
||||
auto assetServerAction = addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_A,
|
||||
qApp, SLOT(toggleAssetServerWidget()));
|
||||
qApp, SLOT(showAssetServerWidget()));
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QObject::connect(nodeList.data(), &NodeList::canWriteAssetsChanged, assetServerAction, &QAction::setEnabled);
|
||||
assetServerAction->setEnabled(nodeList->getThisNodeCanWriteAssets());
|
||||
|
|
|
@ -142,7 +142,7 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) {
|
|||
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);
|
||||
batch.setProjectionTransform(legacyProjection);
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setViewTransform(Transform());
|
||||
batch.resetViewTransform();
|
||||
|
||||
geometryCache->renderQuad(batch, x, y, w, h, backgroundColor, _audioScopeBackground);
|
||||
renderLineStrip(batch, _inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput);
|
||||
|
|
|
@ -122,11 +122,13 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
|||
_driveKeys[i] = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
// Necessary to select the correct slot
|
||||
using SlotType = void(MyAvatar::*)(const glm::vec3&, bool, const glm::quat&, bool);
|
||||
|
||||
// connect to AddressManager signal for location jumps
|
||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||
[=](const glm::vec3& newPosition, bool hasOrientation, const glm::quat& newOrientation, bool shouldFaceLocation){
|
||||
goToLocation(newPosition, hasOrientation, newOrientation, shouldFaceLocation);
|
||||
});
|
||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||
this, static_cast<SlotType>(&MyAvatar::goToLocation));
|
||||
|
||||
_characterController.setEnabled(true);
|
||||
|
||||
|
@ -1859,7 +1861,7 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
|||
glm::quat quatOrientation = cancelOutRollAndPitch(newOrientation);
|
||||
|
||||
if (shouldFaceLocation) {
|
||||
quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
quatOrientation = newOrientation * glm::angleAxis(PI, Vectors::UP);
|
||||
|
||||
// move the user a couple units away
|
||||
const float DISTANCE_TO_USER = 2.0f;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
@ -20,12 +22,13 @@
|
|||
#include <gl/OpenGLVersionChecker.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <steamworks-wrapper/SteamClient.h>
|
||||
|
||||
#include "AddressManager.h"
|
||||
#include "Application.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "UserActivityLogger.h"
|
||||
#include "MainWindow.h"
|
||||
#include <thread>
|
||||
|
||||
#ifdef HAS_BUGSPLAT
|
||||
#include <BuildInfo.h>
|
||||
|
@ -137,6 +140,8 @@ int main(int argc, const char* argv[]) {
|
|||
// or in the main window ctor, before GL startup.
|
||||
Application::initPlugins(arguments);
|
||||
|
||||
SteamClient::init();
|
||||
|
||||
int exitCode;
|
||||
{
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
|
@ -202,6 +207,8 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
Application::shutdownPlugins();
|
||||
|
||||
SteamClient::shutdown();
|
||||
|
||||
qCDebug(interfaceapp, "Normal exit.");
|
||||
#if !defined(DEBUG) && !defined(Q_OS_LINUX)
|
||||
// HACK: exit immediately (don't handle shutdown callbacks) for Release build
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
AccountScriptingInterface* AccountScriptingInterface::getInstance() {
|
||||
static AccountScriptingInterface sharedInstance;
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
QObject::connect(accountManager.data(), &AccountManager::profileChanged,
|
||||
&sharedInstance, &AccountScriptingInterface::usernameChanged);
|
||||
return &sharedInstance;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
class AccountScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
|
||||
|
||||
signals:
|
||||
void usernameChanged();
|
||||
|
||||
public slots:
|
||||
static AccountScriptingInterface* getInstance();
|
||||
QString getUsername();
|
||||
|
|
|
@ -179,6 +179,10 @@ QScriptValue WindowScriptingInterface::save(const QString& title, const QString&
|
|||
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::showAssetServer(const QString& upload) {
|
||||
QMetaObject::invokeMethod(qApp, "showAssetServerWidget", Qt::QueuedConnection, Q_ARG(QString, upload));
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getInnerWidth() {
|
||||
return qApp->getWindow()->geometry().width();
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ public slots:
|
|||
CustomPromptResult customPrompt(const QVariant& config);
|
||||
QScriptValue browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
||||
QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
||||
void showAssetServer(const QString& upload = "");
|
||||
void copyToClipboard(const QString& text);
|
||||
void takeSnapshot(bool notify);
|
||||
void shareSnapshot(const QString& path);
|
||||
|
|
|
@ -67,7 +67,9 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
|||
|
||||
// Execute the batch into our framebuffer
|
||||
doInBatch(renderArgs->_context, [&](gpu::Batch& batch) {
|
||||
PROFILE_RANGE_BATCH(batch, "ApplicationOverlayRender");
|
||||
renderArgs->_batch = &batch;
|
||||
batch.enableStereo(false);
|
||||
|
||||
int width = _overlayFramebuffer->getWidth();
|
||||
int height = _overlayFramebuffer->getHeight();
|
||||
|
@ -101,7 +103,7 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
|
|||
geometryCache->useSimpleDrawPipeline(batch);
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setViewTransform(Transform());
|
||||
batch.resetViewTransform();
|
||||
batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _uiTexture);
|
||||
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1));
|
||||
|
@ -121,7 +123,7 @@ void ApplicationOverlay::renderAudioScope(RenderArgs* renderArgs) {
|
|||
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP);
|
||||
batch.setProjectionTransform(legacyProjection);
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setViewTransform(Transform());
|
||||
batch.resetViewTransform();
|
||||
|
||||
// Render the audio scope
|
||||
DependencyManager::get<AudioScope>()->render(renderArgs, width, height);
|
||||
|
@ -140,7 +142,7 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
|
|||
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP);
|
||||
batch.setProjectionTransform(legacyProjection);
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setViewTransform(Transform());
|
||||
batch.resetViewTransform();
|
||||
|
||||
// Render all of the Script based "HUD" aka 2D overlays.
|
||||
// note: we call them HUD, as opposed to 2D, only because there are some cases of 3D HUD overlays, like the
|
||||
|
@ -166,7 +168,7 @@ void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
|
|||
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP);
|
||||
batch.setProjectionTransform(legacyProjection);
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setViewTransform(Transform());
|
||||
batch.resetViewTransform();
|
||||
|
||||
float screenRatio = ((float)qApp->getDevicePixelRatio());
|
||||
float renderRatio = ((float)qApp->getRenderResolutionScale());
|
||||
|
@ -228,7 +230,7 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderAr
|
|||
geometryCache->useSimpleDrawPipeline(batch);
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setViewTransform(Transform());
|
||||
batch.resetViewTransform();
|
||||
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
// FIXME: THe line width of CONNECTION_STATUS_BORDER_LINE_WIDTH is not supported anymore, we ll need a workaround
|
||||
|
||||
|
@ -246,10 +248,6 @@ static const auto COLOR_FORMAT = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)
|
|||
static const auto DEFAULT_SAMPLER = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR);
|
||||
static const auto DEPTH_FORMAT = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
||||
|
||||
std::mutex _textureGuard;
|
||||
using Lock = std::unique_lock<std::mutex>;
|
||||
std::queue<gpu::TexturePointer> _availableTextures;
|
||||
|
||||
void ApplicationOverlay::buildFramebufferObject() {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
|
||||
|
@ -265,22 +263,6 @@ void ApplicationOverlay::buildFramebufferObject() {
|
|||
_overlayFramebuffer->setDepthStencilBuffer(overlayDepthTexture, DEPTH_FORMAT);
|
||||
}
|
||||
|
||||
if (!_overlayFramebuffer->getRenderBuffer(0)) {
|
||||
gpu::TexturePointer newColorAttachment;
|
||||
{
|
||||
Lock lock(_textureGuard);
|
||||
if (!_availableTextures.empty()) {
|
||||
newColorAttachment = _availableTextures.front();
|
||||
_availableTextures.pop();
|
||||
}
|
||||
}
|
||||
if (newColorAttachment) {
|
||||
newColorAttachment->resize2D(width, height, newColorAttachment->getNumSamples());
|
||||
_overlayFramebuffer->setRenderBuffer(0, newColorAttachment);
|
||||
}
|
||||
}
|
||||
|
||||
// If the overlay framebuffer still has no color attachment, no textures were available for rendering, so build a new one
|
||||
if (!_overlayFramebuffer->getRenderBuffer(0)) {
|
||||
const gpu::Sampler OVERLAY_SAMPLER(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP);
|
||||
auto colorBuffer = gpu::TexturePointer(gpu::Texture::create2D(COLOR_FORMAT, width, height, OVERLAY_SAMPLER));
|
||||
|
@ -288,20 +270,9 @@ void ApplicationOverlay::buildFramebufferObject() {
|
|||
}
|
||||
}
|
||||
|
||||
gpu::TexturePointer ApplicationOverlay::acquireOverlay() {
|
||||
gpu::TexturePointer ApplicationOverlay::getOverlayTexture() {
|
||||
if (!_overlayFramebuffer) {
|
||||
return gpu::TexturePointer();
|
||||
}
|
||||
auto result = _overlayFramebuffer->getRenderBuffer(0);
|
||||
_overlayFramebuffer->setRenderBuffer(0, gpu::TexturePointer());
|
||||
return result;
|
||||
}
|
||||
|
||||
void ApplicationOverlay::releaseOverlay(gpu::TexturePointer texture) {
|
||||
if (texture) {
|
||||
Lock lock(_textureGuard);
|
||||
_availableTextures.push(texture);
|
||||
} else {
|
||||
qWarning() << "Attempted to release null texture";
|
||||
}
|
||||
}
|
||||
return _overlayFramebuffer->getRenderBuffer(0);
|
||||
}
|
|
@ -26,8 +26,7 @@ public:
|
|||
|
||||
void renderOverlay(RenderArgs* renderArgs);
|
||||
|
||||
gpu::TexturePointer acquireOverlay();
|
||||
void releaseOverlay(gpu::TexturePointer pointer);
|
||||
gpu::TexturePointer getOverlayTexture();
|
||||
|
||||
private:
|
||||
void renderStatsAndLogs(RenderArgs* renderArgs);
|
||||
|
|
|
@ -12,8 +12,11 @@
|
|||
#include "LoginDialog.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include <NetworkingConstants.h>
|
||||
#include <steamworks-wrapper/SteamClient.h>
|
||||
|
||||
#include "AccountManager.h"
|
||||
#include "DependencyManager.h"
|
||||
|
@ -21,9 +24,7 @@
|
|||
|
||||
HIFI_QML_DEF(LoginDialog)
|
||||
|
||||
LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent),
|
||||
_rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString())
|
||||
{
|
||||
LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
connect(accountManager.data(), &AccountManager::loginComplete,
|
||||
this, &LoginDialog::handleLoginCompleted);
|
||||
|
@ -53,36 +54,102 @@ void LoginDialog::toggleAction() {
|
|||
}
|
||||
}
|
||||
|
||||
void LoginDialog::handleLoginCompleted(const QUrl&) {
|
||||
hide();
|
||||
bool LoginDialog::isSteamRunning() const {
|
||||
return SteamClient::isRunning();
|
||||
}
|
||||
|
||||
void LoginDialog::handleLoginFailed() {
|
||||
setStatusText("Invalid username or password");
|
||||
}
|
||||
|
||||
void LoginDialog::setStatusText(const QString& statusText) {
|
||||
if (statusText != _statusText) {
|
||||
_statusText = statusText;
|
||||
emit statusTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString LoginDialog::statusText() const {
|
||||
return _statusText;
|
||||
}
|
||||
|
||||
QString LoginDialog::rootUrl() const {
|
||||
return _rootUrl;
|
||||
}
|
||||
|
||||
void LoginDialog::login(const QString& username, const QString& password) {
|
||||
void LoginDialog::login(const QString& username, const QString& password) const {
|
||||
qDebug() << "Attempting to login " << username;
|
||||
setStatusText("Logging in...");
|
||||
DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
|
||||
}
|
||||
|
||||
void LoginDialog::openUrl(const QString& url) {
|
||||
qDebug() << url;
|
||||
QDesktopServices::openUrl(url);
|
||||
void LoginDialog::loginThroughSteam() {
|
||||
qDebug() << "Attempting to login through Steam";
|
||||
SteamClient::requestTicket([this](Ticket ticket) {
|
||||
if (ticket.isNull()) {
|
||||
emit handleLoginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
DependencyManager::get<AccountManager>()->requestAccessTokenWithSteam(ticket);
|
||||
});
|
||||
}
|
||||
|
||||
void LoginDialog::linkSteam() {
|
||||
qDebug() << "Attempting to link Steam account";
|
||||
SteamClient::requestTicket([this](Ticket ticket) {
|
||||
if (ticket.isNull()) {
|
||||
emit handleLoginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "linkCompleted";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "linkFailed";
|
||||
|
||||
const QString LINK_STEAM_PATH = "api/v1/user/steam/link";
|
||||
|
||||
QJsonObject payload;
|
||||
payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->sendRequest(LINK_STEAM_PATH, AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::PostOperation, callbackParams,
|
||||
QJsonDocument(payload).toJson());
|
||||
});
|
||||
}
|
||||
|
||||
void LoginDialog::createAccountFromStream(QString username) {
|
||||
qDebug() << "Attempting to create account from Steam info";
|
||||
SteamClient::requestTicket([this, username](Ticket ticket) {
|
||||
if (ticket.isNull()) {
|
||||
emit handleLoginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "createCompleted";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "createFailed";
|
||||
|
||||
const QString CREATE_ACCOUNT_FROM_STEAM_PATH = "api/v1/user/steam/create";
|
||||
|
||||
QJsonObject payload;
|
||||
payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));
|
||||
if (!username.isEmpty()) {
|
||||
payload.insert("username", QJsonValue::fromVariant(QVariant(username)));
|
||||
}
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->sendRequest(CREATE_ACCOUNT_FROM_STEAM_PATH, AccountManagerAuth::None,
|
||||
QNetworkAccessManager::PostOperation, callbackParams,
|
||||
QJsonDocument(payload).toJson());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void LoginDialog::openUrl(const QString& url) const {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto browser = offscreenUi->load("Browser.qml");
|
||||
browser->setProperty("url", url);
|
||||
}
|
||||
|
||||
void LoginDialog::linkCompleted(QNetworkReply& reply) {
|
||||
emit handleLinkCompleted();
|
||||
}
|
||||
|
||||
void LoginDialog::linkFailed(QNetworkReply& reply) {
|
||||
emit handleLinkFailed(reply.errorString());
|
||||
}
|
||||
|
||||
void LoginDialog::createCompleted(QNetworkReply& reply) {
|
||||
emit handleCreateCompleted();
|
||||
}
|
||||
|
||||
void LoginDialog::createFailed(QNetworkReply& reply) {
|
||||
emit handleCreateFailed(reply.errorString());
|
||||
}
|
||||
|
||||
|
|
|
@ -16,35 +16,44 @@
|
|||
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
class LoginDialog : public OffscreenQmlDialog {
|
||||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
|
||||
Q_PROPERTY(QString statusText READ statusText WRITE setStatusText NOTIFY statusTextChanged)
|
||||
Q_PROPERTY(QString rootUrl READ rootUrl)
|
||||
|
||||
public:
|
||||
static void toggleAction();
|
||||
|
||||
LoginDialog(QQuickItem* parent = nullptr);
|
||||
|
||||
void setStatusText(const QString& statusText);
|
||||
QString statusText() const;
|
||||
|
||||
QString rootUrl() const;
|
||||
|
||||
signals:
|
||||
void statusTextChanged();
|
||||
|
||||
protected:
|
||||
void handleLoginCompleted(const QUrl& authURL);
|
||||
void handleLoginCompleted();
|
||||
void handleLoginFailed();
|
||||
|
||||
Q_INVOKABLE void login(const QString& username, const QString& password);
|
||||
Q_INVOKABLE void openUrl(const QString& url);
|
||||
private:
|
||||
QString _statusText;
|
||||
const QString _rootUrl;
|
||||
void handleLinkCompleted();
|
||||
void handleLinkFailed(QString error);
|
||||
|
||||
void handleCreateCompleted();
|
||||
void handleCreateFailed(QString error);
|
||||
|
||||
public slots:
|
||||
void linkCompleted(QNetworkReply& reply);
|
||||
void linkFailed(QNetworkReply& reply);
|
||||
|
||||
void createCompleted(QNetworkReply& reply);
|
||||
void createFailed(QNetworkReply& reply);
|
||||
|
||||
protected slots:
|
||||
Q_INVOKABLE bool isSteamRunning() const;
|
||||
|
||||
Q_INVOKABLE void login(const QString& username, const QString& password) const;
|
||||
Q_INVOKABLE void loginThroughSteam();
|
||||
Q_INVOKABLE void linkSteam();
|
||||
Q_INVOKABLE void createAccountFromStream(QString username = QString());
|
||||
|
||||
Q_INVOKABLE void openUrl(const QString& url) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_LoginDialog_h
|
||||
|
|
|
@ -121,7 +121,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
|
|||
batch.setResourceTexture(0, textureCache->getWhiteTexture()); // FIXME - do we really need to do this??
|
||||
batch.setProjectionTransform(legacyProjection);
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setViewTransform(Transform());
|
||||
batch.resetViewTransform();
|
||||
|
||||
thisOverlay->render(renderArgs);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
set(TARGET_NAME display-plugins)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu display-plugins)
|
||||
setup_hifi_library(OpenGL)
|
||||
link_hifi_libraries(shared plugins ui-plugins gl gpu-gl ui)
|
||||
link_hifi_libraries(shared plugins ui-plugins gl gpu-gl ui render-utils)
|
||||
|
||||
target_opengl()
|
||||
|
||||
|
|
|
@ -33,18 +33,6 @@ bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() {
|
|||
return Parent::internalActivate();
|
||||
}
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) {
|
||||
_wantVsync = true; // always
|
||||
Parent::submitSceneTexture(frameIndex, sceneTexture);
|
||||
}
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::internalPresent() {
|
||||
if (_wantVsync != isVsyncEnabled()) {
|
||||
enableVsync(_wantVsync);
|
||||
}
|
||||
Parent::internalPresent();
|
||||
}
|
||||
|
||||
static const uint32_t MIN_THROTTLE_CHECK_FRAMES = 60;
|
||||
|
||||
bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
|
||||
|
|
|
@ -24,10 +24,6 @@ public:
|
|||
|
||||
virtual bool internalActivate() override;
|
||||
|
||||
virtual void submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) override;
|
||||
|
||||
virtual void internalPresent() override;
|
||||
|
||||
virtual bool isThrottled() const override;
|
||||
|
||||
protected:
|
||||
|
@ -40,5 +36,4 @@ private:
|
|||
QAction* _vsyncAction { nullptr };
|
||||
uint32_t _framerateTarget { 0 };
|
||||
int _fullscreenTarget{ -1 };
|
||||
bool _wantVsync { true };
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "NullDisplayPlugin.h"
|
||||
#include "stereo/SideBySideStereoDisplayPlugin.h"
|
||||
#include "stereo/InterleavedStereoDisplayPlugin.h"
|
||||
#include "hmd/DebugHmdDisplayPlugin.h"
|
||||
#include "Basic2DWindowOpenGLDisplayPlugin.h"
|
||||
|
||||
const QString& DisplayPlugin::MENU_PATH() {
|
||||
|
@ -23,6 +24,7 @@ const QString& DisplayPlugin::MENU_PATH() {
|
|||
DisplayPluginList getDisplayPlugins() {
|
||||
DisplayPlugin* PLUGIN_POOL[] = {
|
||||
new Basic2DWindowOpenGLDisplayPlugin(),
|
||||
new DebugHmdDisplayPlugin(),
|
||||
#ifdef DEBUG
|
||||
new NullDisplayPlugin(),
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
#include <QtGui/QImage>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <FramebufferCache.h>
|
||||
#include <gpu/Frame.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
const QString NullDisplayPlugin::NAME("NullDisplayPlugin");
|
||||
|
||||
|
@ -22,12 +25,10 @@ bool NullDisplayPlugin::hasFocus() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void NullDisplayPlugin::submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) {
|
||||
_container->releaseSceneTexture(sceneTexture);
|
||||
}
|
||||
|
||||
void NullDisplayPlugin::submitOverlayTexture(const gpu::TexturePointer& overlayTexture) {
|
||||
_container->releaseOverlayTexture(overlayTexture);
|
||||
void NullDisplayPlugin::submitFrame(const gpu::FramePointer& frame) {
|
||||
if (frame) {
|
||||
_gpuContext->consumeFrameUpdates(frame);
|
||||
}
|
||||
}
|
||||
|
||||
QImage NullDisplayPlugin::getScreenshot() const {
|
||||
|
|
|
@ -11,16 +11,14 @@
|
|||
|
||||
class NullDisplayPlugin : public DisplayPlugin {
|
||||
public:
|
||||
~NullDisplayPlugin() final {}
|
||||
const QString& getName() const override { return NAME; }
|
||||
grouping getGrouping() const override { return DEVELOPER; }
|
||||
|
||||
virtual ~NullDisplayPlugin() final {}
|
||||
virtual const QString& getName() const override { return NAME; }
|
||||
virtual grouping getGrouping() const override { return DEVELOPER; }
|
||||
|
||||
virtual glm::uvec2 getRecommendedRenderSize() const override;
|
||||
virtual bool hasFocus() const override;
|
||||
virtual void submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) override;
|
||||
virtual void submitOverlayTexture(const gpu::TexturePointer& overlayTexture) override;
|
||||
virtual QImage getScreenshot() const override;
|
||||
glm::uvec2 getRecommendedRenderSize() const override;
|
||||
bool hasFocus() const override;
|
||||
void submitFrame(const gpu::FramePointer& newFrame) override;
|
||||
QImage getScreenshot() const override;
|
||||
private:
|
||||
static const QString NAME;
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "OpenGLDisplayPlugin.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QThread>
|
||||
|
@ -19,26 +20,56 @@
|
|||
#if defined(Q_OS_MAC)
|
||||
#include <OpenGL/CGLCurrent.h>
|
||||
#endif
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <gpu/Texture.h>
|
||||
#include <gl/GLWidget.h>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <shared/NsightHelpers.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <gl/GLWidget.h>
|
||||
#include <gl/Config.h>
|
||||
#include <gl/GLEscrow.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <CursorManager.h>
|
||||
#include "CompositorHelper.h"
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
#include <gpu/gl/GLShared.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
#include <FramebufferCache.h>
|
||||
#include <shared/NsightHelpers.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <ui/Menu.h>
|
||||
#include <CursorManager.h>
|
||||
|
||||
#include "CompositorHelper.h"
|
||||
|
||||
#if THREADED_PRESENT
|
||||
const char* SRGB_TO_LINEAR_FRAG = R"SCRIBE(
|
||||
|
||||
// FIXME, for display plugins that don't block on something like vsync, just
|
||||
// cap the present rate at 200
|
||||
// const static unsigned int MAX_PRESENT_RATE = 200;
|
||||
uniform sampler2D colorMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
|
||||
out vec4 outFragColor;
|
||||
|
||||
float sRGBFloatToLinear(float value) {
|
||||
const float SRGB_ELBOW = 0.04045;
|
||||
|
||||
return (value <= SRGB_ELBOW) ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4);
|
||||
}
|
||||
|
||||
vec3 colorToLinearRGB(vec3 srgb) {
|
||||
return vec3(sRGBFloatToLinear(srgb.r), sRGBFloatToLinear(srgb.g), sRGBFloatToLinear(srgb.b));
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
outFragColor.a = 1.0;
|
||||
outFragColor.rgb = colorToLinearRGB(texture(colorMap, varTexCoord0).rgb);
|
||||
}
|
||||
|
||||
)SCRIBE";
|
||||
|
||||
extern QThread* RENDER_THREAD;
|
||||
|
||||
class PresentThread : public QThread, public Dependency {
|
||||
using Mutex = std::mutex;
|
||||
|
@ -86,13 +117,22 @@ public:
|
|||
|
||||
|
||||
virtual void run() override {
|
||||
// FIXME determine the best priority balance between this and the main thread...
|
||||
// It may be dependent on the display plugin being used, since VR plugins should
|
||||
// have higher priority on rendering (although we could say that the Oculus plugin
|
||||
// doesn't need that since it has async timewarp).
|
||||
// A higher priority here
|
||||
setPriority(QThread::HighPriority);
|
||||
OpenGLDisplayPlugin* currentPlugin{ nullptr };
|
||||
thread()->setPriority(QThread::HighestPriority);
|
||||
Q_ASSERT(_context);
|
||||
_context->makeCurrent();
|
||||
Q_ASSERT(isCurrentContext(_context->contextHandle()));
|
||||
while (!_shutdown) {
|
||||
if (_pendingMainThreadOperation) {
|
||||
PROFILE_RANGE("MainThreadOp")
|
||||
{
|
||||
Lock lock(_mutex);
|
||||
_context->doneCurrent();
|
||||
// Move the context to the main thread
|
||||
_context->moveToThread(qApp->thread());
|
||||
_pendingMainThreadOperation = false;
|
||||
|
@ -111,33 +151,46 @@ public:
|
|||
// Check for a new display plugin
|
||||
{
|
||||
Lock lock(_mutex);
|
||||
_context->makeCurrent();
|
||||
// Check if we have a new plugin to activate
|
||||
while (!_newPluginQueue.empty()) {
|
||||
auto newPlugin = _newPluginQueue.front();
|
||||
if (newPlugin != currentPlugin) {
|
||||
// Deactivate the old plugin
|
||||
if (currentPlugin != nullptr) {
|
||||
try {
|
||||
currentPlugin->uncustomizeContext();
|
||||
} catch (const oglplus::Error& error) {
|
||||
qWarning() << "OpenGL error in uncustomizeContext: " << error.what();
|
||||
}
|
||||
_context->makeCurrent();
|
||||
currentPlugin->uncustomizeContext();
|
||||
CHECK_GL_ERROR();
|
||||
_context->doneCurrent();
|
||||
}
|
||||
|
||||
if (newPlugin) {
|
||||
try {
|
||||
newPlugin->customizeContext();
|
||||
} catch (const oglplus::Error& error) {
|
||||
qWarning() << "OpenGL error in customizeContext: " << error.what();
|
||||
}
|
||||
bool hasVsync = true;
|
||||
bool wantVsync = newPlugin->wantVsync();
|
||||
_context->makeCurrent();
|
||||
#if defined(Q_OS_WIN)
|
||||
wglSwapIntervalEXT(wantVsync ? 1 : 0);
|
||||
hasVsync = wglGetSwapIntervalEXT() != 0;
|
||||
#elif defined(Q_OS_MAC)
|
||||
GLint interval = wantVsync ? 1 : 0;
|
||||
newPlugin->swapBuffers();
|
||||
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||
newPlugin->swapBuffers();
|
||||
CGLGetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||
hasVsync = interval != 0;
|
||||
#else
|
||||
// TODO: Fill in for linux
|
||||
Q_UNUSED(wantVsync);
|
||||
#endif
|
||||
newPlugin->setVsyncEnabled(hasVsync);
|
||||
newPlugin->customizeContext();
|
||||
CHECK_GL_ERROR();
|
||||
_context->doneCurrent();
|
||||
}
|
||||
currentPlugin = newPlugin;
|
||||
_newPluginQueue.pop();
|
||||
_condition.notify_one();
|
||||
}
|
||||
}
|
||||
_context->doneCurrent();
|
||||
}
|
||||
|
||||
// If there's no active plugin, just sleep
|
||||
|
@ -147,18 +200,14 @@ public:
|
|||
continue;
|
||||
}
|
||||
|
||||
// take the latest texture and present it
|
||||
// Execute the frame and present it to the display device.
|
||||
_context->makeCurrent();
|
||||
if (isCurrentContext(_context->contextHandle())) {
|
||||
try {
|
||||
currentPlugin->present();
|
||||
} catch (const oglplus::Error& error) {
|
||||
qWarning() << "OpenGL error in presentation: " << error.what();
|
||||
}
|
||||
_context->doneCurrent();
|
||||
} else {
|
||||
qWarning() << "Makecurrent failed";
|
||||
{
|
||||
PROFILE_RANGE("PluginPresent")
|
||||
currentPlugin->present();
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
_context->doneCurrent();
|
||||
}
|
||||
|
||||
Lock lock(_mutex);
|
||||
|
@ -204,27 +253,6 @@ private:
|
|||
QGLContext* _context { nullptr };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
OpenGLDisplayPlugin::OpenGLDisplayPlugin() {
|
||||
_sceneTextureEscrow.setRecycler([this](const gpu::TexturePointer& texture){
|
||||
cleanupForSceneTexture(texture);
|
||||
_container->releaseSceneTexture(texture);
|
||||
});
|
||||
_overlayTextureEscrow.setRecycler([this](const gpu::TexturePointer& texture) {
|
||||
_container->releaseOverlayTexture(texture);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::cleanupForSceneTexture(const gpu::TexturePointer& sceneTexture) {
|
||||
withRenderThreadLock([&] {
|
||||
Q_ASSERT(_sceneTextureToFrameIndexMap.contains(sceneTexture));
|
||||
_sceneTextureToFrameIndexMap.remove(sceneTexture);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool OpenGLDisplayPlugin::activate() {
|
||||
if (!_cursorsData.size()) {
|
||||
auto& cursorManager = Cursor::Manager::instance();
|
||||
|
@ -242,9 +270,7 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
if (!_container) {
|
||||
return false;
|
||||
}
|
||||
_vsyncSupported = _container->getPrimaryWidget()->isVsyncSupported();
|
||||
|
||||
#if THREADED_PRESENT
|
||||
// Start the present thread if necessary
|
||||
QSharedPointer<PresentThread> presentThread;
|
||||
if (DependencyManager::isSet<PresentThread>()) {
|
||||
|
@ -259,7 +285,9 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
presentThread->start();
|
||||
}
|
||||
_presentThread = presentThread.data();
|
||||
#endif
|
||||
if (!RENDER_THREAD) {
|
||||
RENDER_THREAD = _presentThread;
|
||||
}
|
||||
|
||||
// Child classes may override this in order to do things like initialize
|
||||
// libraries, etc
|
||||
|
@ -267,17 +295,10 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if THREADED_PRESENT
|
||||
|
||||
// This should not return until the new context has been customized
|
||||
// and the old context (if any) has been uncustomized
|
||||
presentThread->setNewDisplayPlugin(this);
|
||||
#else
|
||||
static auto widget = _container->getPrimaryWidget();
|
||||
widget->makeCurrent();
|
||||
customizeContext();
|
||||
_container->makeRenderingContextCurrent();
|
||||
#endif
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
connect(compositorHelper.data(), &CompositorHelper::alphaChanged, [this] {
|
||||
|
@ -296,20 +317,12 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
}
|
||||
|
||||
void OpenGLDisplayPlugin::deactivate() {
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
disconnect(compositorHelper.data());
|
||||
|
||||
#if THREADED_PRESENT
|
||||
auto presentThread = DependencyManager::get<PresentThread>();
|
||||
// Does not return until the GL transition has completeed
|
||||
presentThread->setNewDisplayPlugin(nullptr);
|
||||
#else
|
||||
static auto widget = _container->getPrimaryWidget();
|
||||
widget->makeCurrent();
|
||||
uncustomizeContext();
|
||||
_container->makeRenderingContextCurrent();
|
||||
#endif
|
||||
internalDeactivate();
|
||||
|
||||
_container->showDisplayPluginsTools(false);
|
||||
|
@ -323,58 +336,99 @@ void OpenGLDisplayPlugin::deactivate() {
|
|||
Parent::deactivate();
|
||||
}
|
||||
|
||||
|
||||
void OpenGLDisplayPlugin::customizeContext() {
|
||||
#if THREADED_PRESENT
|
||||
auto presentThread = DependencyManager::get<PresentThread>();
|
||||
Q_ASSERT(thread() == presentThread->thread());
|
||||
#endif
|
||||
enableVsync();
|
||||
|
||||
getGLBackend()->setCameraCorrection(mat4());
|
||||
|
||||
for (auto& cursorValue : _cursorsData) {
|
||||
auto& cursorData = cursorValue.second;
|
||||
if (!cursorData.texture) {
|
||||
const auto& image = cursorData.image;
|
||||
glGenTextures(1, &cursorData.texture);
|
||||
glBindTexture(GL_TEXTURE_2D, cursorData.texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
auto image = cursorData.image;
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
cursorData.texture.reset(
|
||||
gpu::Texture::create2D(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
|
||||
cursorData.texture->setUsage(usage.build());
|
||||
cursorData.texture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.byteCount(), image.constBits());
|
||||
cursorData.texture->autoGenerateMips(-1);
|
||||
}
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
using namespace oglplus;
|
||||
Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
|
||||
Context::Disable(Capability::Blend);
|
||||
Context::Disable(Capability::DepthTest);
|
||||
Context::Disable(Capability::CullFace);
|
||||
|
||||
_program = loadDefaultShader();
|
||||
|
||||
auto uniforms = _program->ActiveUniforms();
|
||||
while (!uniforms.Empty()) {
|
||||
auto uniform = uniforms.Front();
|
||||
if (uniform.Name() == "mvp") {
|
||||
_mvpUniform = uniform.Index();
|
||||
if (!_presentPipeline) {
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setScissorEnable(true);
|
||||
_simplePipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
if (uniform.Name() == "alpha") {
|
||||
_alphaUniform = uniform.Index();
|
||||
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(SRGB_TO_LINEAR_FRAG));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setScissorEnable(true);
|
||||
_presentPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
_overlayPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
_cursorPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
uniforms.Next();
|
||||
}
|
||||
|
||||
_plane = loadPlane(_program);
|
||||
|
||||
_compositeFramebuffer = std::make_shared<BasicFramebufferWrapper>();
|
||||
_compositeFramebuffer->Init(getRecommendedRenderSize());
|
||||
auto renderSize = getRecommendedRenderSize();
|
||||
_compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y));
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::uncustomizeContext() {
|
||||
_presentPipeline.reset();
|
||||
_cursorPipeline.reset();
|
||||
_overlayPipeline.reset();
|
||||
_compositeFramebuffer.reset();
|
||||
_program.reset();
|
||||
_plane.reset();
|
||||
withPresentThreadLock([&] {
|
||||
_currentFrame.reset();
|
||||
while (!_newFrameQueue.empty()) {
|
||||
_gpuContext->consumeFrameUpdates(_newFrameQueue.front());
|
||||
_newFrameQueue.pop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -420,172 +474,161 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) {
|
||||
void OpenGLDisplayPlugin::submitFrame(const gpu::FramePointer& newFrame) {
|
||||
if (_lockCurrentTexture) {
|
||||
_container->releaseSceneTexture(sceneTexture);
|
||||
return;
|
||||
}
|
||||
|
||||
withRenderThreadLock([&] {
|
||||
_sceneTextureToFrameIndexMap[sceneTexture] = frameIndex;
|
||||
withNonPresentThreadLock([&] {
|
||||
_newFrameQueue.push(newFrame);
|
||||
});
|
||||
|
||||
// Submit it to the presentation thread via escrow
|
||||
_sceneTextureEscrow.submit(sceneTexture);
|
||||
|
||||
#if THREADED_PRESENT
|
||||
#else
|
||||
static auto widget = _container->getPrimaryWidget();
|
||||
widget->makeCurrent();
|
||||
present();
|
||||
_container->makeRenderingContextCurrent();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::submitOverlayTexture(const gpu::TexturePointer& overlayTexture) {
|
||||
// Submit it to the presentation thread via escrow
|
||||
_overlayTextureEscrow.submit(overlayTexture);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::updateTextures() {
|
||||
// FIXME intrduce a GPU wait instead of a CPU/GPU sync point?
|
||||
#if THREADED_PRESENT
|
||||
if (_sceneTextureEscrow.fetchSignaledAndRelease(_currentSceneTexture)) {
|
||||
#else
|
||||
if (_sceneTextureEscrow.fetchAndReleaseWithGpuWait(_currentSceneTexture)) {
|
||||
#endif
|
||||
updateFrameData();
|
||||
_newFrameRate.increment();
|
||||
}
|
||||
|
||||
_overlayTextureEscrow.fetchSignaledAndRelease(_currentOverlayTexture);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::updateFrameData() {
|
||||
withPresentThreadLock([&] {
|
||||
auto previousFrameIndex = _currentPresentFrameIndex;
|
||||
_currentPresentFrameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture];
|
||||
auto skippedCount = (_currentPresentFrameIndex - previousFrameIndex) - 1;
|
||||
gpu::FramePointer oldFrame = _currentFrame;
|
||||
uint32_t skippedCount = 0;
|
||||
if (!_newFrameQueue.empty()) {
|
||||
// We're changing frames, so we can cleanup any GL resources that might have been used by the old frame
|
||||
_gpuContext->recycle();
|
||||
}
|
||||
while (!_newFrameQueue.empty()) {
|
||||
_currentFrame = _newFrameQueue.front();
|
||||
_newFrameQueue.pop();
|
||||
_gpuContext->consumeFrameUpdates(_currentFrame);
|
||||
if (_currentFrame && oldFrame) {
|
||||
skippedCount += (_currentFrame->frameIndex - oldFrame->frameIndex) - 1;
|
||||
}
|
||||
}
|
||||
_droppedFrameRate.increment(skippedCount);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositeOverlay() {
|
||||
using namespace oglplus;
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
|
||||
useProgram(_program);
|
||||
// set the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(_compositeOverlayAlpha);
|
||||
// check the alpha
|
||||
// Overlay draw
|
||||
if (isStereo()) {
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
drawUnitQuad();
|
||||
});
|
||||
} else {
|
||||
// Overlay draw
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
|
||||
drawUnitQuad();
|
||||
}
|
||||
// restore the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(1.0);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositePointer() {
|
||||
using namespace oglplus;
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
|
||||
useProgram(_program);
|
||||
// set the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(_compositeOverlayAlpha);
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(compositorHelper->getReticleTransform(glm::mat4()));
|
||||
if (isStereo()) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
drawUnitQuad();
|
||||
});
|
||||
} else {
|
||||
drawUnitQuad();
|
||||
}
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
|
||||
// restore the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(1.0);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositeScene() {
|
||||
using namespace oglplus;
|
||||
useProgram(_program);
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
|
||||
drawUnitQuad();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositeLayers() {
|
||||
using namespace oglplus;
|
||||
auto targetRenderSize = getRecommendedRenderSize();
|
||||
if (!_compositeFramebuffer || _compositeFramebuffer->size != targetRenderSize) {
|
||||
_compositeFramebuffer = std::make_shared<BasicFramebufferWrapper>();
|
||||
_compositeFramebuffer->Init(targetRenderSize);
|
||||
}
|
||||
_compositeFramebuffer->Bound(Framebuffer::Target::Draw, [&] {
|
||||
Context::Viewport(targetRenderSize.x, targetRenderSize.y);
|
||||
auto sceneTextureId = getSceneTextureId();
|
||||
auto overlayTextureId = getOverlayTextureId();
|
||||
glBindTexture(GL_TEXTURE_2D, sceneTextureId);
|
||||
compositeScene();
|
||||
if (overlayTextureId) {
|
||||
glBindTexture(GL_TEXTURE_2D, overlayTextureId);
|
||||
Context::Enable(Capability::Blend);
|
||||
Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
|
||||
compositeOverlay();
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
if (compositorHelper->getReticleVisible()) {
|
||||
auto& cursorManager = Cursor::Manager::instance();
|
||||
const auto& cursorData = _cursorsData[cursorManager.getCursor()->getIcon()];
|
||||
glBindTexture(GL_TEXTURE_2D, cursorData.texture);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, overlayTextureId);
|
||||
compositePointer();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
Context::Disable(Capability::Blend);
|
||||
render([&](gpu::Batch& batch){
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.setPipeline(_overlayPipeline);
|
||||
batch.setResourceTexture(0, _currentFrame->overlay);
|
||||
if (isStereo()) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
batch.setViewportTransform(eyeViewport(eye));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
} else {
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _currentFrame->framebuffer->getSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
compositeExtra();
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositePointer() {
|
||||
auto& cursorManager = Cursor::Manager::instance();
|
||||
const auto& cursorData = _cursorsData[cursorManager.getCursor()->getIcon()];
|
||||
auto cursorTransform = DependencyManager::get<CompositorHelper>()->getReticleTransform(glm::mat4());
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.setPipeline(_cursorPipeline);
|
||||
batch.setResourceTexture(0, cursorData.texture);
|
||||
batch.resetViewTransform();
|
||||
batch.setModelTransform(cursorTransform);
|
||||
if (isStereo()) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
batch.setViewportTransform(eyeViewport(eye));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
} else {
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _currentFrame->framebuffer->getSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositeScene() {
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.setViewportTransform(ivec4(uvec2(), _compositeFramebuffer->getSize()));
|
||||
batch.setStateScissorRect(ivec4(uvec2(), _compositeFramebuffer->getSize()));
|
||||
batch.resetViewTransform();
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setPipeline(_simplePipeline);
|
||||
batch.setResourceTexture(0, _currentFrame->framebuffer->getRenderBuffer(0));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositeLayers() {
|
||||
auto renderSize = getRecommendedRenderSize();
|
||||
if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) {
|
||||
_compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y));
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE_EX("compositeScene", 0xff0077ff, (uint64_t)presentCount())
|
||||
compositeScene();
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE_EX("compositeOverlay", 0xff0077ff, (uint64_t)presentCount())
|
||||
compositeOverlay();
|
||||
}
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
if (compositorHelper->getReticleVisible()) {
|
||||
PROFILE_RANGE_EX("compositePointer", 0xff0077ff, (uint64_t)presentCount())
|
||||
compositePointer();
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE_EX("compositeExtra", 0xff0077ff, (uint64_t)presentCount())
|
||||
compositeExtra();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::internalPresent() {
|
||||
using namespace oglplus;
|
||||
const uvec2& srcSize = _compositeFramebuffer->size;
|
||||
uvec2 dstSize = getSurfacePixels();
|
||||
_compositeFramebuffer->Bound(FramebufferTarget::Read, [&] {
|
||||
Context::BlitFramebuffer(
|
||||
0, 0, srcSize.x, srcSize.y,
|
||||
0, 0, dstSize.x, dstSize.y,
|
||||
BufferSelectBit::ColorBuffer, BlitFilter::Nearest);
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
batch.setFramebuffer(gpu::FramebufferPointer());
|
||||
batch.setViewportTransform(ivec4(uvec2(0), getSurfacePixels()));
|
||||
batch.setResourceTexture(0, _compositeFramebuffer->getRenderBuffer(0));
|
||||
batch.setPipeline(_presentPipeline);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::present() {
|
||||
PROFILE_RANGE_EX(__FUNCTION__, 0xffffff00, (uint64_t)presentCount())
|
||||
updateFrameData();
|
||||
incrementPresentCount();
|
||||
|
||||
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)presentCount())
|
||||
{
|
||||
PROFILE_RANGE_EX("recycle", 0xff00ff00, (uint64_t)presentCount())
|
||||
_gpuContext->recycle();
|
||||
}
|
||||
|
||||
if (_currentFrame) {
|
||||
{
|
||||
// Execute the frame rendering commands
|
||||
PROFILE_RANGE_EX("execute", 0xff00ff00, (uint64_t)presentCount())
|
||||
_gpuContext->executeFrame(_currentFrame);
|
||||
}
|
||||
|
||||
updateTextures();
|
||||
if (_currentSceneTexture) {
|
||||
// Write all layers to a local framebuffer
|
||||
compositeLayers();
|
||||
{
|
||||
PROFILE_RANGE_EX("composite", 0xff00ffff, (uint64_t)presentCount())
|
||||
compositeLayers();
|
||||
}
|
||||
|
||||
// Take the composite framebuffer and send it to the output device
|
||||
internalPresent();
|
||||
{
|
||||
PROFILE_RANGE_EX("internalPresent", 0xff00ffff, (uint64_t)presentCount())
|
||||
internalPresent();
|
||||
}
|
||||
_presentRate.increment();
|
||||
_activeProgram.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,7 +638,7 @@ float OpenGLDisplayPlugin::newFramePresentRate() const {
|
|||
|
||||
float OpenGLDisplayPlugin::droppedFrameRate() const {
|
||||
float result;
|
||||
withRenderThreadLock([&] {
|
||||
withNonPresentThreadLock([&] {
|
||||
result = _droppedFrameRate.rate();
|
||||
});
|
||||
return result;
|
||||
|
@ -605,102 +648,27 @@ float OpenGLDisplayPlugin::presentRate() const {
|
|||
return _presentRate.rate();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::drawUnitQuad() {
|
||||
useProgram(_program);
|
||||
_plane->Use();
|
||||
_plane->Draw();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::enableVsync(bool enable) {
|
||||
if (!_vsyncSupported) {
|
||||
return;
|
||||
}
|
||||
#if defined(Q_OS_WIN)
|
||||
wglSwapIntervalEXT(enable ? 1 : 0);
|
||||
#elif defined(Q_OS_MAC)
|
||||
GLint interval = enable ? 1 : 0;
|
||||
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||
#else
|
||||
// TODO: Fill in for linux
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OpenGLDisplayPlugin::isVsyncEnabled() {
|
||||
if (!_vsyncSupported) {
|
||||
return true;
|
||||
}
|
||||
#if defined(Q_OS_WIN)
|
||||
return wglGetSwapIntervalEXT() != 0;
|
||||
#elif defined(Q_OS_MAC)
|
||||
GLint interval;
|
||||
CGLGetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||
return interval != 0;
|
||||
#else
|
||||
// TODO: Fill in for linux
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::swapBuffers() {
|
||||
static auto widget = _container->getPrimaryWidget();
|
||||
widget->swapBuffers();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const {
|
||||
#if THREADED_PRESENT
|
||||
static auto presentThread = DependencyManager::get<PresentThread>();
|
||||
presentThread->withMainThreadContext(f);
|
||||
_container->makeRenderingContextCurrent();
|
||||
#else
|
||||
static auto widget = _container->getPrimaryWidget();
|
||||
widget->makeCurrent();
|
||||
f();
|
||||
_container->makeRenderingContextCurrent();
|
||||
#endif
|
||||
}
|
||||
|
||||
QImage OpenGLDisplayPlugin::getScreenshot() const {
|
||||
using namespace oglplus;
|
||||
auto width = _compositeFramebuffer->size.x;
|
||||
if (isHmd()) {
|
||||
width /= 2;
|
||||
}
|
||||
|
||||
QImage screenshot(width, _compositeFramebuffer->size.y, QImage::Format_RGBA8888);
|
||||
auto size = _compositeFramebuffer->getSize();
|
||||
auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend();
|
||||
QImage screenshot(size.x, size.y, QImage::Format_ARGB32);
|
||||
withMainThreadContext([&] {
|
||||
Framebuffer::Bind(Framebuffer::Target::Read, _compositeFramebuffer->fbo);
|
||||
Context::ReadPixels(0, 0, width, _compositeFramebuffer->size.y, enums::PixelDataFormat::RGBA, enums::PixelDataType::UnsignedByte, screenshot.bits());
|
||||
glBackend->downloadFramebuffer(_compositeFramebuffer, ivec4(uvec2(0), size), screenshot);
|
||||
});
|
||||
return screenshot.mirrored(false, true);
|
||||
}
|
||||
|
||||
uint32_t OpenGLDisplayPlugin::getSceneTextureId() const {
|
||||
if (!_currentSceneTexture) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _currentSceneTexture->getHardwareId();
|
||||
}
|
||||
|
||||
uint32_t OpenGLDisplayPlugin::getOverlayTextureId() const {
|
||||
if (!_currentOverlayTexture) {
|
||||
return 0;
|
||||
}
|
||||
return _currentOverlayTexture->getHardwareId();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::eyeViewport(Eye eye) const {
|
||||
using namespace oglplus;
|
||||
uvec2 vpSize = _compositeFramebuffer->size;
|
||||
vpSize.x /= 2;
|
||||
uvec2 vpPos;
|
||||
if (eye == Eye::Right) {
|
||||
vpPos.x = vpSize.x;
|
||||
}
|
||||
Context::Viewport(vpPos.x, vpPos.y, vpSize.x, vpSize.y);
|
||||
}
|
||||
|
||||
glm::uvec2 OpenGLDisplayPlugin::getSurfacePixels() const {
|
||||
uvec2 result;
|
||||
auto window = _container->getPrimaryWidget();
|
||||
|
@ -724,14 +692,7 @@ bool OpenGLDisplayPlugin::hasFocus() const {
|
|||
return window ? window->hasFocus() : false;
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::useProgram(const ProgramPtr& program) {
|
||||
if (_activeProgram != program) {
|
||||
program->Bind();
|
||||
_activeProgram = program;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::assertIsRenderThread() const {
|
||||
void OpenGLDisplayPlugin::assertNotPresentThread() const {
|
||||
Q_ASSERT(QThread::currentThread() != _presentThread);
|
||||
}
|
||||
|
||||
|
@ -740,8 +701,39 @@ void OpenGLDisplayPlugin::assertIsPresentThread() const {
|
|||
}
|
||||
|
||||
bool OpenGLDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
||||
withRenderThreadLock([&] {
|
||||
withNonPresentThreadLock([&] {
|
||||
_compositeOverlayAlpha = _overlayAlpha;
|
||||
});
|
||||
return Parent::beginFrameRender(frameIndex);
|
||||
}
|
||||
|
||||
ivec4 OpenGLDisplayPlugin::eyeViewport(Eye eye) const {
|
||||
uvec2 vpSize = _currentFrame->framebuffer->getSize();
|
||||
vpSize.x /= 2;
|
||||
uvec2 vpPos;
|
||||
if (eye == Eye::Right) {
|
||||
vpPos.x = vpSize.x;
|
||||
}
|
||||
return ivec4(vpPos, vpSize);
|
||||
}
|
||||
|
||||
gpu::gl::GLBackend* OpenGLDisplayPlugin::getGLBackend() {
|
||||
if (!_gpuContext || !_gpuContext->getBackend()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto backend = _gpuContext->getBackend().get();
|
||||
#if defined(Q_OS_MAC)
|
||||
// Should be dynamic_cast, but that doesn't work in plugins on OSX
|
||||
auto glbackend = static_cast<gpu::gl::GLBackend*>(backend);
|
||||
#else
|
||||
auto glbackend = dynamic_cast<gpu::gl::GLBackend*>(backend);
|
||||
#endif
|
||||
|
||||
return glbackend;
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::render(std::function<void(gpu::Batch& batch)> f) {
|
||||
gpu::Batch batch;
|
||||
f(batch);
|
||||
_gpuContext->executeBatch(batch);
|
||||
}
|
||||
|
|
|
@ -11,17 +11,21 @@
|
|||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
#include <gl/OglplusHelpers.h>
|
||||
#include <gl/GLEscrow.h>
|
||||
#include <shared/RateCounter.h>
|
||||
|
||||
#define THREADED_PRESENT 1
|
||||
namespace gpu {
|
||||
namespace gl {
|
||||
class GLBackend;
|
||||
}
|
||||
}
|
||||
|
||||
class OpenGLDisplayPlugin : public DisplayPlugin {
|
||||
Q_OBJECT
|
||||
|
@ -33,19 +37,14 @@ protected:
|
|||
using Condition = std::condition_variable;
|
||||
using TextureEscrow = GLEscrow<gpu::TexturePointer>;
|
||||
public:
|
||||
OpenGLDisplayPlugin();
|
||||
|
||||
// These must be final to ensure proper ordering of operations
|
||||
// between the main thread and the presentation thread
|
||||
bool activate() override final;
|
||||
void deactivate() override final;
|
||||
|
||||
bool eventFilter(QObject* receiver, QEvent* event) override;
|
||||
bool isDisplayVisible() const override { return true; }
|
||||
|
||||
|
||||
void submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) override;
|
||||
void submitOverlayTexture(const gpu::TexturePointer& overlayTexture) override;
|
||||
void submitFrame(const gpu::FramePointer& newFrame) override;
|
||||
|
||||
glm::uvec2 getRecommendedRenderSize() const override {
|
||||
return getSurfacePixels();
|
||||
|
@ -64,17 +63,18 @@ public:
|
|||
float droppedFrameRate() const override;
|
||||
|
||||
bool beginFrameRender(uint32_t frameIndex) override;
|
||||
|
||||
virtual bool wantVsync() const { return true; }
|
||||
void setVsyncEnabled(bool vsyncEnabled) { _vsyncEnabled = vsyncEnabled; }
|
||||
bool isVsyncEnabled() const { return _vsyncEnabled; }
|
||||
|
||||
protected:
|
||||
#if THREADED_PRESENT
|
||||
friend class PresentThread;
|
||||
#endif
|
||||
uint32_t getSceneTextureId() const;
|
||||
uint32_t getOverlayTextureId() const;
|
||||
|
||||
glm::uvec2 getSurfaceSize() const;
|
||||
glm::uvec2 getSurfacePixels() const;
|
||||
|
||||
void compositeLayers();
|
||||
virtual void compositeLayers();
|
||||
virtual void compositeScene();
|
||||
virtual void compositeOverlay();
|
||||
virtual void compositePointer();
|
||||
|
@ -82,10 +82,6 @@ protected:
|
|||
|
||||
virtual bool hasFocus() const override;
|
||||
|
||||
// FIXME make thread safe?
|
||||
virtual bool isVsyncEnabled();
|
||||
virtual void enableVsync(bool enable = true);
|
||||
|
||||
// These functions must only be called on the presentation thread
|
||||
virtual void customizeContext();
|
||||
virtual void uncustomizeContext();
|
||||
|
@ -93,54 +89,46 @@ protected:
|
|||
// Returns true on successful activation
|
||||
virtual bool internalActivate() { return true; }
|
||||
virtual void internalDeactivate() {}
|
||||
virtual void cleanupForSceneTexture(const gpu::TexturePointer& sceneTexture);
|
||||
|
||||
// Plugin specific functionality to send the composed scene to the output window or device
|
||||
virtual void internalPresent();
|
||||
|
||||
void withMainThreadContext(std::function<void()> f) const;
|
||||
|
||||
void useProgram(const ProgramPtr& program);
|
||||
void present();
|
||||
void updateTextures();
|
||||
void drawUnitQuad();
|
||||
void swapBuffers();
|
||||
void eyeViewport(Eye eye) const;
|
||||
|
||||
virtual void updateFrameData();
|
||||
|
||||
QThread* _presentThread{ nullptr };
|
||||
ProgramPtr _program;
|
||||
int32_t _mvpUniform { -1 };
|
||||
int32_t _alphaUniform { -1 };
|
||||
ShapeWrapperPtr _plane;
|
||||
void withMainThreadContext(std::function<void()> f) const;
|
||||
|
||||
void present();
|
||||
virtual void swapBuffers();
|
||||
ivec4 eyeViewport(Eye eye) const;
|
||||
|
||||
void render(std::function<void(gpu::Batch& batch)> f);
|
||||
|
||||
bool _vsyncEnabled { true };
|
||||
QThread* _presentThread{ nullptr };
|
||||
std::queue<gpu::FramePointer> _newFrameQueue;
|
||||
RateCounter<> _droppedFrameRate;
|
||||
RateCounter<> _newFrameRate;
|
||||
RateCounter<> _presentRate;
|
||||
QMap<gpu::TexturePointer, uint32_t> _sceneTextureToFrameIndexMap;
|
||||
uint32_t _currentPresentFrameIndex { 0 };
|
||||
float _compositeOverlayAlpha{ 1.0f };
|
||||
|
||||
gpu::TexturePointer _currentSceneTexture;
|
||||
gpu::TexturePointer _currentOverlayTexture;
|
||||
|
||||
TextureEscrow _sceneTextureEscrow;
|
||||
TextureEscrow _overlayTextureEscrow;
|
||||
|
||||
bool _vsyncSupported { false };
|
||||
gpu::FramePointer _currentFrame;
|
||||
gpu::FramebufferPointer _compositeFramebuffer;
|
||||
gpu::PipelinePointer _overlayPipeline;
|
||||
gpu::PipelinePointer _simplePipeline;
|
||||
gpu::PipelinePointer _presentPipeline;
|
||||
gpu::PipelinePointer _cursorPipeline;
|
||||
float _compositeOverlayAlpha { 1.0f };
|
||||
|
||||
struct CursorData {
|
||||
QImage image;
|
||||
vec2 hotSpot;
|
||||
uvec2 size;
|
||||
uint32_t texture { 0 };
|
||||
gpu::TexturePointer texture;
|
||||
};
|
||||
|
||||
std::map<uint16_t, CursorData> _cursorsData;
|
||||
BasicFramebufferWrapperPtr _compositeFramebuffer;
|
||||
bool _lockCurrentTexture { false };
|
||||
|
||||
void assertIsRenderThread() const;
|
||||
void assertNotPresentThread() const;
|
||||
void assertIsPresentThread() const;
|
||||
|
||||
template<typename F>
|
||||
|
@ -151,17 +139,17 @@ protected:
|
|||
}
|
||||
|
||||
template<typename F>
|
||||
void withRenderThreadLock(F f) const {
|
||||
assertIsRenderThread();
|
||||
void withNonPresentThreadLock(F f) const {
|
||||
assertNotPresentThread();
|
||||
Lock lock(_presentMutex);
|
||||
f();
|
||||
}
|
||||
|
||||
private:
|
||||
gpu::gl::GLBackend* getGLBackend();
|
||||
|
||||
// Any resource shared by the main thread and the presentation thread must
|
||||
// be serialized through this mutex
|
||||
mutable Mutex _presentMutex;
|
||||
ProgramPtr _activeProgram;
|
||||
float _overlayAlpha{ 1.0f };
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/31
|
||||
// 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 "DebugHmdDisplayPlugin.h"
|
||||
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
|
||||
#include <ViewFrustum.h>
|
||||
#include <controllers/Pose.h>
|
||||
#include <gpu/Frame.h>
|
||||
|
||||
const QString DebugHmdDisplayPlugin::NAME("HMD Simulator");
|
||||
|
||||
static const QString DEBUG_FLAG("HIFI_DEBUG_HMD");
|
||||
static bool enableDebugHmd = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
|
||||
|
||||
bool DebugHmdDisplayPlugin::isSupported() const {
|
||||
return enableDebugHmd;
|
||||
}
|
||||
|
||||
void DebugHmdDisplayPlugin::resetSensors() {
|
||||
_currentRenderFrameInfo.renderPose = glm::mat4(); // identity
|
||||
}
|
||||
|
||||
bool DebugHmdDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
||||
_currentRenderFrameInfo = FrameInfo();
|
||||
_currentRenderFrameInfo.sensorSampleTime = secTimestampNow();
|
||||
_currentRenderFrameInfo.predictedDisplayTime = _currentRenderFrameInfo.sensorSampleTime;
|
||||
// FIXME simulate head movement
|
||||
//_currentRenderFrameInfo.renderPose = ;
|
||||
//_currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose;
|
||||
|
||||
withNonPresentThreadLock([&] {
|
||||
_uiModelTransform = DependencyManager::get<CompositorHelper>()->getModelTransform();
|
||||
_frameInfos[frameIndex] = _currentRenderFrameInfo;
|
||||
|
||||
_handPoses[0] = glm::translate(mat4(), vec3(-0.3f, 0.0f, 0.0f));
|
||||
_handLasers[0].color = vec4(1, 0, 0, 1);
|
||||
_handLasers[0].mode = HandLaserMode::Overlay;
|
||||
|
||||
_handPoses[1] = glm::translate(mat4(), vec3(0.3f, 0.0f, 0.0f));
|
||||
_handLasers[1].color = vec4(0, 1, 1, 1);
|
||||
_handLasers[1].mode = HandLaserMode::Overlay;
|
||||
});
|
||||
return Parent::beginFrameRender(frameIndex);
|
||||
}
|
||||
|
||||
// DLL based display plugins MUST initialize GLEW inside the DLL code.
|
||||
void DebugHmdDisplayPlugin::customizeContext() {
|
||||
glewExperimental = true;
|
||||
glewInit();
|
||||
glGetError(); // clear the potential error from glewExperimental
|
||||
Parent::customizeContext();
|
||||
}
|
||||
|
||||
bool DebugHmdDisplayPlugin::internalActivate() {
|
||||
_ipd = 0.0327499993f * 2.0f;
|
||||
_eyeProjections[0][0] = vec4{ 0.759056330, 0.000000000, 0.000000000, 0.000000000 };
|
||||
_eyeProjections[0][1] = vec4{ 0.000000000, 0.682773232, 0.000000000, 0.000000000 };
|
||||
_eyeProjections[0][2] = vec4{ -0.0580431037, -0.00619550655, -1.00000489, -1.00000000 };
|
||||
_eyeProjections[0][3] = vec4{ 0.000000000, 0.000000000, -0.0800003856, 0.000000000 };
|
||||
_eyeProjections[1][0] = vec4{ 0.752847493, 0.000000000, 0.000000000, 0.000000000 };
|
||||
_eyeProjections[1][1] = vec4{ 0.000000000, 0.678060353, 0.000000000, 0.000000000 };
|
||||
_eyeProjections[1][2] = vec4{ 0.0578232110, -0.00669418881, -1.00000489, -1.000000000 };
|
||||
_eyeProjections[1][3] = vec4{ 0.000000000, 0.000000000, -0.0800003856, 0.000000000 };
|
||||
_eyeInverseProjections[0] = glm::inverse(_eyeProjections[0]);
|
||||
_eyeInverseProjections[1] = glm::inverse(_eyeProjections[1]);
|
||||
_eyeOffsets[0][3] = vec4{ -0.0327499993, 0.0, 0.0149999997, 1.0 };
|
||||
_eyeOffsets[0][3] = vec4{ 0.0327499993, 0.0, 0.0149999997, 1.0 };
|
||||
_renderTargetSize = { 3024, 1680 };
|
||||
_cullingProjection = _eyeProjections[0];
|
||||
// This must come after the initialization, so that the values calculated
|
||||
// above are available during the customizeContext call (when not running
|
||||
// in threaded present mode)
|
||||
return Parent::internalActivate();
|
||||
}
|
||||
|
||||
void DebugHmdDisplayPlugin::updatePresentPose() {
|
||||
float yaw = sinf(secTimestampNow()) * 0.25f;
|
||||
float pitch = cosf(secTimestampNow()) * 0.25f;
|
||||
// Simulates head pose latency correction
|
||||
_currentPresentFrameInfo.presentPose =
|
||||
glm::mat4_cast(glm::angleAxis(yaw, Vectors::UP)) *
|
||||
glm::mat4_cast(glm::angleAxis(pitch, Vectors::RIGHT));
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/31
|
||||
// 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
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "HmdDisplayPlugin.h"
|
||||
|
||||
class DebugHmdDisplayPlugin : public HmdDisplayPlugin {
|
||||
using Parent = HmdDisplayPlugin;
|
||||
|
||||
public:
|
||||
const QString& getName() const override { return NAME; }
|
||||
grouping getGrouping() const override { return DEVELOPER; }
|
||||
|
||||
bool isSupported() const override;
|
||||
void resetSensors() override final;
|
||||
bool beginFrameRender(uint32_t frameIndex) override;
|
||||
float getTargetFrameRate() const override { return 90; }
|
||||
|
||||
|
||||
protected:
|
||||
void updatePresentPose() override;
|
||||
void hmdPresent() override {}
|
||||
bool isHmdMounted() const override { return true; }
|
||||
void customizeContext() override;
|
||||
bool internalActivate() override;
|
||||
private:
|
||||
static const QString NAME;
|
||||
};
|
|
@ -1,10 +1,11 @@
|
|||
//
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2016/02/15
|
||||
// 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 "HmdDisplayPlugin.h"
|
||||
|
||||
#include <memory>
|
||||
|
@ -22,9 +23,10 @@
|
|||
#include <CursorManager.h>
|
||||
#include <gl/GLWidget.h>
|
||||
#include <shared/NsightHelpers.h>
|
||||
|
||||
#include <gpu/DrawUnitQuadTexcoord_vert.h>
|
||||
#include <gpu/DrawTexture_frag.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
|
@ -32,94 +34,18 @@
|
|||
#include "../CompositorHelper.h"
|
||||
|
||||
static const QString MONO_PREVIEW = "Mono Preview";
|
||||
static const QString REPROJECTION = "Allow Reprojection";
|
||||
static const QString DISABLE_PREVIEW = "Disable Preview";
|
||||
static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate";
|
||||
static const QString DEVELOPER_MENU_PATH = "Developer>" + DisplayPlugin::MENU_PATH();
|
||||
static const bool DEFAULT_MONO_VIEW = true;
|
||||
static const int NUMBER_OF_HANDS = 2;
|
||||
static const glm::mat4 IDENTITY_MATRIX;
|
||||
|
||||
|
||||
glm::uvec2 HmdDisplayPlugin::getRecommendedUiSize() const {
|
||||
return CompositorHelper::VIRTUAL_SCREEN_SIZE;
|
||||
}
|
||||
|
||||
QRect HmdDisplayPlugin::getRecommendedOverlayRect() const {
|
||||
return CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT;
|
||||
}
|
||||
|
||||
bool HmdDisplayPlugin::internalActivate() {
|
||||
_monoPreview = _container->getBoolSetting("monoPreview", DEFAULT_MONO_VIEW);
|
||||
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), MONO_PREVIEW,
|
||||
[this](bool clicked) {
|
||||
_monoPreview = clicked;
|
||||
_container->setBoolSetting("monoPreview", _monoPreview);
|
||||
}, true, _monoPreview);
|
||||
_container->removeMenu(FRAMERATE);
|
||||
_container->addMenu(DEVELOPER_MENU_PATH);
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, DEVELOPER_MENU_PATH, REPROJECTION,
|
||||
[this](bool clicked) {
|
||||
_enableReprojection = clicked;
|
||||
_container->setBoolSetting("enableReprojection", _enableReprojection);
|
||||
}, true, _enableReprojection);
|
||||
|
||||
for_each_eye([&](Eye eye) {
|
||||
_eyeInverseProjections[eye] = glm::inverse(_eyeProjections[eye]);
|
||||
});
|
||||
|
||||
if (_previewTextureID == 0) {
|
||||
QImage previewTexture(PathUtils::resourcesPath() + "images/preview.png");
|
||||
if (!previewTexture.isNull()) {
|
||||
glGenTextures(1, &_previewTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, _previewTextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, previewTexture.width(), previewTexture.height(), 0,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, previewTexture.mirrored(false, true).bits());
|
||||
using namespace oglplus;
|
||||
Texture::MinFilter(TextureTarget::_2D, TextureMinFilter::Linear);
|
||||
Texture::MagFilter(TextureTarget::_2D, TextureMagFilter::Linear);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
_previewAspect = ((float)previewTexture.width())/((float)previewTexture.height());
|
||||
_firstPreview = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Parent::internalActivate();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::internalDeactivate() {
|
||||
if (_previewTextureID != 0) {
|
||||
glDeleteTextures(1, &_previewTextureID);
|
||||
_previewTextureID = 0;
|
||||
}
|
||||
Parent::internalDeactivate();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::customizeContext() {
|
||||
Parent::customizeContext();
|
||||
// Only enable mirroring if we know vsync is disabled
|
||||
// On Mac, this won't work due to how the contexts are handled, so don't try
|
||||
#if !defined(Q_OS_MAC)
|
||||
enableVsync(false);
|
||||
static const bool DEFAULT_DISABLE_PREVIEW = false;
|
||||
#endif
|
||||
_enablePreview = !isVsyncEnabled();
|
||||
_sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO);
|
||||
using namespace oglplus;
|
||||
if (!_enablePreview) {
|
||||
const std::string version("#version 410 core\n");
|
||||
compileProgram(_previewProgram, version + DrawUnitQuadTexcoord_vert, version + DrawTexture_frag);
|
||||
_previewUniforms.previewTexture = Uniform<int>(*_previewProgram, "colorMap").Location();
|
||||
}
|
||||
|
||||
updateReprojectionProgram();
|
||||
updateOverlayProgram();
|
||||
#ifdef HMD_HAND_LASER_SUPPORT
|
||||
updateLaserProgram();
|
||||
_laserGeometry = loadLaser(_laserProgram);
|
||||
#endif
|
||||
}
|
||||
static const glm::mat4 IDENTITY_MATRIX;
|
||||
static const size_t NUMBER_OF_HANDS = 2;
|
||||
|
||||
//#define LIVE_SHADER_RELOAD 1
|
||||
extern glm::vec3 getPoint(float yaw, float pitch);
|
||||
|
||||
static QString readFile(const QString& filename) {
|
||||
QFile file(filename);
|
||||
|
@ -129,183 +55,220 @@ static QString readFile(const QString& filename) {
|
|||
return result;
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::updateReprojectionProgram() {
|
||||
static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_reproject.vert";
|
||||
static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_reproject.frag";
|
||||
#if LIVE_SHADER_RELOAD
|
||||
static qint64 vsBuiltAge = 0;
|
||||
static qint64 fsBuiltAge = 0;
|
||||
QFileInfo vsInfo(vsFile);
|
||||
QFileInfo fsInfo(fsFile);
|
||||
auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch();
|
||||
auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch();
|
||||
if (!_reprojectionProgram || vsAge > vsBuiltAge || fsAge > fsBuiltAge) {
|
||||
vsBuiltAge = vsAge;
|
||||
fsBuiltAge = fsAge;
|
||||
#else
|
||||
if (!_reprojectionProgram) {
|
||||
#endif
|
||||
QString vsSource = readFile(vsFile);
|
||||
QString fsSource = readFile(fsFile);
|
||||
ProgramPtr program;
|
||||
try {
|
||||
compileProgram(program, vsSource.toLocal8Bit().toStdString(), fsSource.toLocal8Bit().toStdString());
|
||||
if (program) {
|
||||
using namespace oglplus;
|
||||
_reprojectionUniforms.reprojectionMatrix = Uniform<glm::mat3>(*program, "reprojection").Location();
|
||||
_reprojectionUniforms.inverseProjectionMatrix = Uniform<glm::mat4>(*program, "inverseProjections").Location();
|
||||
_reprojectionUniforms.projectionMatrix = Uniform<glm::mat4>(*program, "projections").Location();
|
||||
_reprojectionProgram = program;
|
||||
}
|
||||
} catch (std::runtime_error& error) {
|
||||
qWarning() << "Error building reprojection shader " << error.what();
|
||||
}
|
||||
}
|
||||
|
||||
glm::uvec2 HmdDisplayPlugin::getRecommendedUiSize() const {
|
||||
return CompositorHelper::VIRTUAL_SCREEN_SIZE;
|
||||
}
|
||||
|
||||
#ifdef HMD_HAND_LASER_SUPPORT
|
||||
void HmdDisplayPlugin::updateLaserProgram() {
|
||||
static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_hand_lasers.vert";
|
||||
static const QString gsFile = PathUtils::resourcesPath() + "/shaders/hmd_hand_lasers.geom";
|
||||
static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_hand_lasers.frag";
|
||||
|
||||
#if LIVE_SHADER_RELOAD
|
||||
static qint64 vsBuiltAge = 0;
|
||||
static qint64 gsBuiltAge = 0;
|
||||
static qint64 fsBuiltAge = 0;
|
||||
QFileInfo vsInfo(vsFile);
|
||||
QFileInfo fsInfo(fsFile);
|
||||
QFileInfo gsInfo(fsFile);
|
||||
auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch();
|
||||
auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch();
|
||||
auto gsAge = gsInfo.lastModified().toMSecsSinceEpoch();
|
||||
if (!_laserProgram || vsAge > vsBuiltAge || fsAge > fsBuiltAge || gsAge > gsBuiltAge) {
|
||||
vsBuiltAge = vsAge;
|
||||
gsBuiltAge = gsAge;
|
||||
fsBuiltAge = fsAge;
|
||||
#else
|
||||
if (!_laserProgram) {
|
||||
#endif
|
||||
|
||||
QString vsSource = readFile(vsFile);
|
||||
QString fsSource = readFile(fsFile);
|
||||
QString gsSource = readFile(gsFile);
|
||||
ProgramPtr program;
|
||||
try {
|
||||
compileProgram(program, vsSource.toLocal8Bit().toStdString(), gsSource.toLocal8Bit().toStdString(), fsSource.toLocal8Bit().toStdString());
|
||||
if (program) {
|
||||
using namespace oglplus;
|
||||
_laserUniforms.color = Uniform<glm::vec4>(*program, "color").Location();
|
||||
_laserUniforms.mvp = Uniform<glm::mat4>(*program, "mvp").Location();
|
||||
_laserProgram = program;
|
||||
}
|
||||
} catch (std::runtime_error& error) {
|
||||
qWarning() << "Error building hand laser composite shader " << error.what();
|
||||
}
|
||||
}
|
||||
QRect HmdDisplayPlugin::getRecommendedOverlayRect() const {
|
||||
return CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT;
|
||||
}
|
||||
#endif
|
||||
|
||||
void HmdDisplayPlugin::updateOverlayProgram() {
|
||||
static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui_glow.vert";
|
||||
static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui_glow.frag";
|
||||
|
||||
#if LIVE_SHADER_RELOAD
|
||||
static qint64 vsBuiltAge = 0;
|
||||
static qint64 fsBuiltAge = 0;
|
||||
QFileInfo vsInfo(vsFile);
|
||||
QFileInfo fsInfo(fsFile);
|
||||
auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch();
|
||||
auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch();
|
||||
if (!_overlayProgram || vsAge > vsBuiltAge || fsAge > fsBuiltAge) {
|
||||
vsBuiltAge = vsAge;
|
||||
fsBuiltAge = fsAge;
|
||||
#else
|
||||
if (!_overlayProgram) {
|
||||
#endif
|
||||
QString vsSource = readFile(vsFile);
|
||||
QString fsSource = readFile(fsFile);
|
||||
ProgramPtr program;
|
||||
try {
|
||||
compileProgram(program, vsSource.toLocal8Bit().toStdString(), fsSource.toLocal8Bit().toStdString());
|
||||
if (program) {
|
||||
using namespace oglplus;
|
||||
_overlayUniforms.mvp = Uniform<glm::mat4>(*program, "mvp").Location();
|
||||
_overlayUniforms.alpha = Uniform<float>(*program, "alpha").Location();
|
||||
_overlayUniforms.glowColors = Uniform<glm::vec4>(*program, "glowColors").Location();
|
||||
_overlayUniforms.glowPoints = Uniform<glm::vec4>(*program, "glowPoints").Location();
|
||||
_overlayUniforms.resolution = Uniform<glm::vec2>(*program, "resolution").Location();
|
||||
_overlayUniforms.radius = Uniform<float>(*program, "radius").Location();
|
||||
_overlayProgram = program;
|
||||
useProgram(_overlayProgram);
|
||||
Uniform<glm::vec2>(*_overlayProgram, _overlayUniforms.resolution).Set(CompositorHelper::VIRTUAL_SCREEN_SIZE);
|
||||
}
|
||||
} catch (std::runtime_error& error) {
|
||||
qWarning() << "Error building overlay composite shader " << error.what();
|
||||
}
|
||||
bool HmdDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
||||
if (!_vsyncEnabled && !_disablePreviewItemAdded) {
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), DISABLE_PREVIEW,
|
||||
[this](bool clicked) {
|
||||
_disablePreview = clicked;
|
||||
_container->setBoolSetting("disableHmdPreview", _disablePreview);
|
||||
if (_disablePreview) {
|
||||
_clearPreviewFlag = true;
|
||||
}
|
||||
}, true, _disablePreview);
|
||||
_disablePreviewItemAdded = true;
|
||||
}
|
||||
return Parent::beginFrameRender(frameIndex);
|
||||
}
|
||||
|
||||
|
||||
bool HmdDisplayPlugin::internalActivate() {
|
||||
_disablePreviewItemAdded = false;
|
||||
_monoPreview = _container->getBoolSetting("monoPreview", DEFAULT_MONO_VIEW);
|
||||
_clearPreviewFlag = true;
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), MONO_PREVIEW,
|
||||
[this](bool clicked) {
|
||||
_monoPreview = clicked;
|
||||
_container->setBoolSetting("monoPreview", _monoPreview);
|
||||
}, true, _monoPreview);
|
||||
#if defined(Q_OS_MAC)
|
||||
_disablePreview = true;
|
||||
#else
|
||||
_disablePreview = _container->getBoolSetting("disableHmdPreview", DEFAULT_DISABLE_PREVIEW || _vsyncEnabled);
|
||||
#endif
|
||||
|
||||
_container->removeMenu(FRAMERATE);
|
||||
for_each_eye([&](Eye eye) {
|
||||
_eyeInverseProjections[eye] = glm::inverse(_eyeProjections[eye]);
|
||||
});
|
||||
|
||||
_clearPreviewFlag = true;
|
||||
|
||||
return Parent::internalActivate();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::internalDeactivate() {
|
||||
Parent::internalDeactivate();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::customizeContext() {
|
||||
Parent::customizeContext();
|
||||
_overlayRenderer.build();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::uncustomizeContext() {
|
||||
_overlayProgram.reset();
|
||||
_sphereSection.reset();
|
||||
_compositeFramebuffer.reset();
|
||||
_previewProgram.reset();
|
||||
_reprojectionProgram.reset();
|
||||
#ifdef HMD_HAND_LASER_SUPPORT
|
||||
_laserProgram.reset();
|
||||
_laserGeometry.reset();
|
||||
#endif
|
||||
// This stops the weirdness where if the preview was disabled, on switching back to 2D,
|
||||
// the vsync was stuck in the disabled state. No idea why that happens though.
|
||||
_disablePreview = false;
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0));
|
||||
});
|
||||
internalPresent();
|
||||
_overlayRenderer = OverlayRenderer();
|
||||
Parent::uncustomizeContext();
|
||||
}
|
||||
|
||||
// By default assume we'll present with the same pose as the render
|
||||
ivec4 HmdDisplayPlugin::getViewportForSourceSize(const uvec2& size) const {
|
||||
// screen preview mirroring
|
||||
auto window = _container->getPrimaryWidget();
|
||||
auto devicePixelRatio = window->devicePixelRatio();
|
||||
auto windowSize = toGlm(window->size());
|
||||
windowSize *= devicePixelRatio;
|
||||
float windowAspect = aspect(windowSize);
|
||||
float sceneAspect = aspect(size);
|
||||
float aspectRatio = sceneAspect / windowAspect;
|
||||
uvec2 targetViewportSize = windowSize;
|
||||
if (aspectRatio < 1.0f) {
|
||||
targetViewportSize.x *= aspectRatio;
|
||||
} else {
|
||||
targetViewportSize.y /= aspectRatio;
|
||||
}
|
||||
uvec2 targetViewportPosition;
|
||||
if (targetViewportSize.x < windowSize.x) {
|
||||
targetViewportPosition.x = (windowSize.x - targetViewportSize.x) / 2;
|
||||
} else if (targetViewportSize.y < windowSize.y) {
|
||||
targetViewportPosition.y = (windowSize.y - targetViewportSize.y) / 2;
|
||||
}
|
||||
return ivec4(targetViewportPosition, targetViewportSize);
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::internalPresent() {
|
||||
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)presentCount())
|
||||
|
||||
// Composite together the scene, overlay and mouse cursor
|
||||
hmdPresent();
|
||||
|
||||
if (!_disablePreview) {
|
||||
// screen preview mirroring
|
||||
auto sourceSize = _renderTargetSize;
|
||||
if (_monoPreview) {
|
||||
sourceSize.x >>= 1;
|
||||
}
|
||||
auto viewport = getViewportForSourceSize(sourceSize);
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
batch.setFramebuffer(gpu::FramebufferPointer());
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0));
|
||||
batch.setStateScissorRect(viewport);
|
||||
if (_monoPreview) {
|
||||
viewport.z *= 2;
|
||||
}
|
||||
batch.setViewportTransform(viewport);
|
||||
batch.setResourceTexture(0, _compositeFramebuffer->getRenderBuffer(0));
|
||||
batch.setPipeline(_presentPipeline);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
swapBuffers();
|
||||
} else if (_clearPreviewFlag) {
|
||||
auto image = QImage(PathUtils::resourcesPath() + "images/preview.png");
|
||||
image = image.mirrored();
|
||||
image = image.convertToFormat(QImage::Format_RGBA8888);
|
||||
if (!_previewTexture) {
|
||||
_previewTexture.reset(
|
||||
gpu::Texture::create2D(
|
||||
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA),
|
||||
image.width(), image.height(),
|
||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
_previewTexture->setUsage(gpu::Texture::Usage::Builder().withColor().build());
|
||||
_previewTexture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.byteCount(), image.constBits());
|
||||
_previewTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
||||
if (getGLBackend()->isTextureReady(_previewTexture)) {
|
||||
auto viewport = getViewportForSourceSize(uvec2(_previewTexture->getDimensions()));
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
batch.setFramebuffer(gpu::FramebufferPointer());
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0));
|
||||
batch.setStateScissorRect(viewport);
|
||||
batch.setViewportTransform(viewport);
|
||||
batch.setResourceTexture(0, _previewTexture);
|
||||
batch.setPipeline(_presentPipeline);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
_clearPreviewFlag = false;
|
||||
swapBuffers();
|
||||
}
|
||||
}
|
||||
postPreview();
|
||||
}
|
||||
|
||||
// HMD specific stuff
|
||||
|
||||
glm::mat4 HmdDisplayPlugin::getHeadPose() const {
|
||||
return _currentRenderFrameInfo.renderPose;
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::updatePresentPose() {
|
||||
// By default assume we'll present with the same pose as the render
|
||||
_currentPresentFrameInfo.presentPose = _currentPresentFrameInfo.renderPose;
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::compositeScene() {
|
||||
updatePresentPose();
|
||||
void HmdDisplayPlugin::updateFrameData() {
|
||||
// Check if we have old frame data to discard
|
||||
static const uint32_t INVALID_FRAME = (uint32_t)(~0);
|
||||
uint32_t oldFrameIndex = _currentFrame ? _currentFrame->frameIndex : INVALID_FRAME;
|
||||
|
||||
if (!_enableReprojection || glm::mat3() == _currentPresentFrameInfo.presentReprojection) {
|
||||
// No reprojection required
|
||||
Parent::compositeScene();
|
||||
return;
|
||||
Parent::updateFrameData();
|
||||
uint32_t newFrameIndex = _currentFrame ? _currentFrame->frameIndex : INVALID_FRAME;
|
||||
|
||||
if (oldFrameIndex != newFrameIndex) {
|
||||
withPresentThreadLock([&] {
|
||||
if (oldFrameIndex != INVALID_FRAME) {
|
||||
auto itr = _frameInfos.find(oldFrameIndex);
|
||||
if (itr != _frameInfos.end()) {
|
||||
_frameInfos.erase(itr);
|
||||
}
|
||||
}
|
||||
if (newFrameIndex != INVALID_FRAME) {
|
||||
_currentPresentFrameInfo = _frameInfos[newFrameIndex];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef DEBUG_REPROJECTION_SHADER
|
||||
_reprojectionProgram = getReprojectionProgram();
|
||||
#endif
|
||||
useProgram(_reprojectionProgram);
|
||||
updatePresentPose();
|
||||
|
||||
using namespace oglplus;
|
||||
Texture::MinFilter(TextureTarget::_2D, TextureMinFilter::Linear);
|
||||
Texture::MagFilter(TextureTarget::_2D, TextureMagFilter::Linear);
|
||||
Uniform<glm::mat3>(*_reprojectionProgram, _reprojectionUniforms.reprojectionMatrix).Set(_currentPresentFrameInfo.presentReprojection);
|
||||
//Uniform<glm::mat4>(*_reprojectionProgram, PROJECTION_MATRIX_LOCATION).Set(_eyeProjections);
|
||||
//Uniform<glm::mat4>(*_reprojectionProgram, INVERSE_PROJECTION_MATRIX_LOCATION).Set(_eyeInverseProjections);
|
||||
// FIXME what's the right oglplus mechanism to do this? It's not that ^^^ ... better yet, switch to a uniform buffer
|
||||
glUniformMatrix4fv(_reprojectionUniforms.inverseProjectionMatrix, 2, GL_FALSE, &(_eyeInverseProjections[0][0][0]));
|
||||
glUniformMatrix4fv(_reprojectionUniforms.projectionMatrix, 2, GL_FALSE, &(_eyeProjections[0][0][0]));
|
||||
_plane->UseInProgram(*_reprojectionProgram);
|
||||
_plane->Draw();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::compositeOverlay() {
|
||||
using namespace oglplus;
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
glm::mat4 modelMat = compositorHelper->getModelTransform().getMatrix();
|
||||
if (_currentFrame) {
|
||||
auto batchPose = _currentFrame->pose;
|
||||
auto currentPose = _currentPresentFrameInfo.presentPose;
|
||||
auto correction = glm::inverse(batchPose) * currentPose;
|
||||
getGLBackend()->setCameraCorrection(correction);
|
||||
}
|
||||
|
||||
withPresentThreadLock([&] {
|
||||
_presentHandLasers = _handLasers;
|
||||
_presentHandPoses = _handPoses;
|
||||
_presentUiModelTransform = _uiModelTransform;
|
||||
});
|
||||
std::array<vec2, NUMBER_OF_HANDS> handGlowPoints { { vec2(-1), vec2(-1) } };
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
glm::mat4 modelMat = compositorHelper->getModelTransform().getMatrix();
|
||||
std::array<vec2, NUMBER_OF_HANDS> handGlowPoints{ { vec2(-1), vec2(-1) } };
|
||||
|
||||
// compute the glow point interesections
|
||||
for (int i = 0; i < NUMBER_OF_HANDS; ++i) {
|
||||
for (size_t i = 0; i < NUMBER_OF_HANDS; ++i) {
|
||||
if (_presentHandPoses[i] == IDENTITY_MATRIX) {
|
||||
continue;
|
||||
}
|
||||
|
@ -331,6 +294,9 @@ void HmdDisplayPlugin::compositeOverlay() {
|
|||
continue;
|
||||
}
|
||||
|
||||
_presentHandLaserPoints[i].first = vec3(_presentHandPoses[i][3]);
|
||||
_presentHandLaserPoints[i].second = _presentHandLaserPoints[i].first + (castDirection * distance);
|
||||
|
||||
vec3 intersectionPosition = vec3(_presentHandPoses[i][3]) + (castDirection * distance) - _presentUiModelTransform.getTranslation();
|
||||
intersectionPosition = glm::inverse(_presentUiModelTransform.getRotation()) * intersectionPosition;
|
||||
|
||||
|
@ -353,154 +319,174 @@ void HmdDisplayPlugin::compositeOverlay() {
|
|||
handGlowPoints[i] = yawPitch;
|
||||
}
|
||||
|
||||
updateOverlayProgram();
|
||||
if (!_overlayProgram) {
|
||||
return;
|
||||
}
|
||||
|
||||
useProgram(_overlayProgram);
|
||||
for_each_eye([&](Eye eye) {
|
||||
auto modelView = glm::inverse(_currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye)) * modelMat;
|
||||
_overlayRenderer.mvps[eye] = _eyeProjections[eye] * modelView;
|
||||
});
|
||||
|
||||
// Setup the uniforms
|
||||
{
|
||||
if (_overlayUniforms.alpha >= 0) {
|
||||
Uniform<float>(*_overlayProgram, _overlayUniforms.alpha).Set(_compositeOverlayAlpha);
|
||||
}
|
||||
if (_overlayUniforms.glowPoints >= 0) {
|
||||
vec4 glowPoints(handGlowPoints[0], handGlowPoints[1]);
|
||||
Uniform<glm::vec4>(*_overlayProgram, _overlayUniforms.glowPoints).Set(glowPoints);
|
||||
}
|
||||
if (_overlayUniforms.glowColors >= 0) {
|
||||
std::array<glm::vec4, NUMBER_OF_HANDS> glowColors;
|
||||
glowColors[0] = _presentHandLasers[0].color;
|
||||
glowColors[1] = _presentHandLasers[1].color;
|
||||
glProgramUniform4fv(GetName(*_overlayProgram), _overlayUniforms.glowColors, 2, &glowColors[0].r);
|
||||
auto& uniforms = _overlayRenderer.uniforms;
|
||||
uniforms.alpha = _compositeOverlayAlpha;
|
||||
uniforms.glowPoints = vec4(handGlowPoints[0], handGlowPoints[1]);
|
||||
uniforms.glowColors[0] = _presentHandLasers[0].color;
|
||||
uniforms.glowColors[1] = _presentHandLasers[1].color;
|
||||
}
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::OverlayRenderer::build() {
|
||||
vertices = std::make_shared<gpu::Buffer>();
|
||||
indices = std::make_shared<gpu::Buffer>();
|
||||
|
||||
//UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
|
||||
|
||||
static const float fov = CompositorHelper::VIRTUAL_UI_TARGET_FOV.y;
|
||||
static const float aspectRatio = CompositorHelper::VIRTUAL_UI_ASPECT_RATIO;
|
||||
static const uint16_t stacks = 128;
|
||||
static const uint16_t slices = 64;
|
||||
|
||||
Vertex vertex;
|
||||
|
||||
// Compute vertices positions and texture UV coordinate
|
||||
// Create and write to buffer
|
||||
for (int i = 0; i < stacks; i++) {
|
||||
vertex.uv.y = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f
|
||||
// abs(theta) <= fov / 2.0f
|
||||
float pitch = -fov * (vertex.uv.y - 0.5f);
|
||||
for (int j = 0; j < slices; j++) {
|
||||
vertex.uv.x = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f
|
||||
// abs(phi) <= fov * aspectRatio / 2.0f
|
||||
float yaw = -fov * aspectRatio * (vertex.uv.x - 0.5f);
|
||||
vertex.pos = getPoint(yaw, pitch);
|
||||
vertices->append(sizeof(Vertex), (gpu::Byte*)&vertex);
|
||||
}
|
||||
}
|
||||
|
||||
_sphereSection->Use();
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
auto modelView = glm::inverse(_currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye)) * modelMat;
|
||||
auto mvp = _eyeProjections[eye] * modelView;
|
||||
Uniform<glm::mat4>(*_overlayProgram, _overlayUniforms.mvp).Set(mvp);
|
||||
_sphereSection->Draw();
|
||||
// Compute number of indices needed
|
||||
static const int VERTEX_PER_TRANGLE = 3;
|
||||
static const int TRIANGLE_PER_RECTANGLE = 2;
|
||||
int numberOfRectangles = (slices - 1) * (stacks - 1);
|
||||
indexCount = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE;
|
||||
|
||||
// Compute indices order
|
||||
std::vector<GLushort> indices;
|
||||
for (int i = 0; i < stacks - 1; i++) {
|
||||
for (int j = 0; j < slices - 1; j++) {
|
||||
GLushort bottomLeftIndex = i * slices + j;
|
||||
GLushort bottomRightIndex = bottomLeftIndex + 1;
|
||||
GLushort topLeftIndex = bottomLeftIndex + slices;
|
||||
GLushort topRightIndex = topLeftIndex + 1;
|
||||
// FIXME make a z-order curve for better vertex cache locality
|
||||
indices.push_back(topLeftIndex);
|
||||
indices.push_back(bottomLeftIndex);
|
||||
indices.push_back(topRightIndex);
|
||||
|
||||
indices.push_back(topRightIndex);
|
||||
indices.push_back(bottomLeftIndex);
|
||||
indices.push_back(bottomRightIndex);
|
||||
}
|
||||
}
|
||||
this->indices->append(indices);
|
||||
format = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
format->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
format->setAttribute(gpu::Stream::TEXCOORD, gpu::Stream::TEXCOORD, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
uniformBuffers[0] = std::make_shared<gpu::Buffer>(sizeof(Uniforms), nullptr);
|
||||
uniformBuffers[1] = std::make_shared<gpu::Buffer>(sizeof(Uniforms), nullptr);
|
||||
updatePipeline();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::OverlayRenderer::updatePipeline() {
|
||||
static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui_glow.vert";
|
||||
static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_ui_glow.frag";
|
||||
|
||||
#if LIVE_SHADER_RELOAD
|
||||
static qint64 vsBuiltAge = 0;
|
||||
static qint64 fsBuiltAge = 0;
|
||||
QFileInfo vsInfo(vsFile);
|
||||
QFileInfo fsInfo(fsFile);
|
||||
auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch();
|
||||
auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch();
|
||||
if (!pipeline || vsAge > vsBuiltAge || fsAge > fsBuiltAge) {
|
||||
vsBuiltAge = vsAge;
|
||||
fsBuiltAge = fsAge;
|
||||
#else
|
||||
if (!pipeline) {
|
||||
#endif
|
||||
QString vsSource = readFile(vsFile);
|
||||
QString fsSource = readFile(fsFile);
|
||||
auto vs = gpu::Shader::createVertex(vsSource.toLocal8Bit().toStdString());
|
||||
auto ps = gpu::Shader::createPixel(fsSource.toLocal8Bit().toStdString());
|
||||
auto program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::gl::GLBackend::makeProgram(*program, gpu::Shader::BindingSet());
|
||||
this->uniformsLocation = program->getBuffers().findLocation("overlayBuffer");
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::OverlayRenderer::render(HmdDisplayPlugin& plugin) {
|
||||
updatePipeline();
|
||||
for_each_eye([&](Eye eye){
|
||||
uniforms.mvp = mvps[eye];
|
||||
uniformBuffers[eye]->setSubData(0, uniforms);
|
||||
});
|
||||
plugin.render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(plugin._compositeFramebuffer);
|
||||
batch.setPipeline(pipeline);
|
||||
batch.setInputFormat(format);
|
||||
gpu::BufferView posView(vertices, VERTEX_OFFSET, vertices->getSize(), VERTEX_STRIDE, format->getAttributes().at(gpu::Stream::POSITION)._element);
|
||||
gpu::BufferView uvView(vertices, TEXTURE_OFFSET, vertices->getSize(), VERTEX_STRIDE, format->getAttributes().at(gpu::Stream::TEXCOORD)._element);
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, posView);
|
||||
batch.setInputBuffer(gpu::Stream::TEXCOORD, uvView);
|
||||
batch.setIndexBuffer(gpu::UINT16, indices, 0);
|
||||
batch.setResourceTexture(0, plugin._currentFrame->overlay);
|
||||
// FIXME use stereo information input to set both MVPs in the uniforms
|
||||
for_each_eye([&](Eye eye) {
|
||||
batch.setUniformBuffer(uniformsLocation, uniformBuffers[eye]);
|
||||
batch.setViewportTransform(plugin.eyeViewport(eye));
|
||||
batch.drawIndexed(gpu::TRIANGLES, indexCount);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::compositePointer() {
|
||||
using namespace oglplus;
|
||||
|
||||
auto& cursorManager = Cursor::Manager::instance();
|
||||
const auto& cursorData = _cursorsData[cursorManager.getCursor()->getIcon()];
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
|
||||
useProgram(_program);
|
||||
// set the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(_compositeOverlayAlpha);
|
||||
|
||||
// Mouse pointer
|
||||
_plane->Use();
|
||||
// Reconstruct the headpose from the eye poses
|
||||
auto headPosition = vec3(_currentPresentFrameInfo.presentPose[3]);
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
auto eyePose = _currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye);
|
||||
auto reticleTransform = compositorHelper->getReticleTransform(eyePose, headPosition);
|
||||
auto mvp = _eyeProjections[eye] * reticleTransform;
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
|
||||
_plane->Draw();
|
||||
});
|
||||
// restore the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(1.0);
|
||||
}
|
||||
|
||||
|
||||
void HmdDisplayPlugin::internalPresent() {
|
||||
|
||||
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)presentCount())
|
||||
|
||||
// Composite together the scene, overlay and mouse cursor
|
||||
hmdPresent();
|
||||
|
||||
// screen preview mirroring
|
||||
auto window = _container->getPrimaryWidget();
|
||||
auto devicePixelRatio = window->devicePixelRatio();
|
||||
auto windowSize = toGlm(window->size());
|
||||
windowSize *= devicePixelRatio;
|
||||
float windowAspect = aspect(windowSize);
|
||||
float sceneAspect = _enablePreview ? aspect(_renderTargetSize) : _previewAspect;
|
||||
if (_enablePreview && _monoPreview) {
|
||||
sceneAspect /= 2.0f;
|
||||
}
|
||||
float aspectRatio = sceneAspect / windowAspect;
|
||||
|
||||
uvec2 targetViewportSize = windowSize;
|
||||
if (aspectRatio < 1.0f) {
|
||||
targetViewportSize.x *= aspectRatio;
|
||||
} else {
|
||||
targetViewportSize.y /= aspectRatio;
|
||||
}
|
||||
|
||||
uvec2 targetViewportPosition;
|
||||
if (targetViewportSize.x < windowSize.x) {
|
||||
targetViewportPosition.x = (windowSize.x - targetViewportSize.x) / 2;
|
||||
} else if (targetViewportSize.y < windowSize.y) {
|
||||
targetViewportPosition.y = (windowSize.y - targetViewportSize.y) / 2;
|
||||
}
|
||||
|
||||
if (_enablePreview) {
|
||||
using namespace oglplus;
|
||||
Context::Clear().ColorBuffer();
|
||||
auto sourceSize = _compositeFramebuffer->size;
|
||||
if (_monoPreview) {
|
||||
sourceSize.x /= 2;
|
||||
}
|
||||
_compositeFramebuffer->Bound(Framebuffer::Target::Read, [&] {
|
||||
Context::BlitFramebuffer(
|
||||
0, 0, sourceSize.x, sourceSize.y,
|
||||
targetViewportPosition.x, targetViewportPosition.y,
|
||||
targetViewportPosition.x + targetViewportSize.x, targetViewportPosition.y + targetViewportSize.y,
|
||||
BufferSelectBit::ColorBuffer, BlitFilter::Nearest);
|
||||
render([&](gpu::Batch& batch) {
|
||||
// FIXME use standard gpu stereo rendering for this.
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.setPipeline(_cursorPipeline);
|
||||
batch.setResourceTexture(0, cursorData.texture);
|
||||
batch.resetViewTransform();
|
||||
for_each_eye([&](Eye eye) {
|
||||
batch.setViewportTransform(eyeViewport(eye));
|
||||
batch.setProjectionTransform(_eyeProjections[eye]);
|
||||
auto eyePose = _currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye);
|
||||
auto reticleTransform = compositorHelper->getReticleTransform(eyePose, headPosition);
|
||||
batch.setModelTransform(reticleTransform);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
swapBuffers();
|
||||
} else if (_firstPreview || windowSize != _prevWindowSize || devicePixelRatio != _prevDevicePixelRatio) {
|
||||
useProgram(_previewProgram);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glViewport(targetViewportPosition.x, targetViewportPosition.y, targetViewportSize.x, targetViewportSize.y);
|
||||
glUniform1i(_previewUniforms.previewTexture, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, _previewTextureID);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
swapBuffers();
|
||||
_firstPreview = false;
|
||||
_prevWindowSize = windowSize;
|
||||
_prevDevicePixelRatio = devicePixelRatio;
|
||||
});
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::compositeOverlay() {
|
||||
if (!_currentFrame || !_currentFrame->overlay) {
|
||||
return;
|
||||
}
|
||||
|
||||
postPreview();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) {
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::updateFrameData() {
|
||||
// Check if we have old frame data to discard
|
||||
withPresentThreadLock([&] {
|
||||
auto itr = _frameInfos.find(_currentPresentFrameIndex);
|
||||
if (itr != _frameInfos.end()) {
|
||||
_frameInfos.erase(itr);
|
||||
}
|
||||
});
|
||||
|
||||
Parent::updateFrameData();
|
||||
|
||||
withPresentThreadLock([&] {
|
||||
_currentPresentFrameInfo = _frameInfos[_currentPresentFrameIndex];
|
||||
});
|
||||
}
|
||||
|
||||
glm::mat4 HmdDisplayPlugin::getHeadPose() const {
|
||||
return _currentRenderFrameInfo.renderPose;
|
||||
_overlayRenderer.render(*this);
|
||||
}
|
||||
|
||||
bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const vec4& color, const vec3& direction) {
|
||||
|
@ -508,7 +494,7 @@ bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const ve
|
|||
info.mode = mode;
|
||||
info.color = color;
|
||||
info.direction = direction;
|
||||
withRenderThreadLock([&] {
|
||||
withNonPresentThreadLock([&] {
|
||||
if (hands & Hand::LeftHand) {
|
||||
_handLasers[0] = info;
|
||||
}
|
||||
|
@ -522,7 +508,6 @@ bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const ve
|
|||
}
|
||||
|
||||
void HmdDisplayPlugin::compositeExtra() {
|
||||
#ifdef HMD_HAND_LASER_SUPPORT
|
||||
// If neither hand laser is activated, exit
|
||||
if (!_presentHandLasers[0].valid() && !_presentHandLasers[1].valid()) {
|
||||
return;
|
||||
|
@ -532,64 +517,20 @@ void HmdDisplayPlugin::compositeExtra() {
|
|||
return;
|
||||
}
|
||||
|
||||
updateLaserProgram();
|
||||
|
||||
// Render hand lasers
|
||||
using namespace oglplus;
|
||||
useProgram(_laserProgram);
|
||||
_laserGeometry->Use();
|
||||
std::array<mat4, NUMBER_OF_HANDS> handLaserModelMatrices;
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_HANDS; ++i) {
|
||||
if (_presentHandPoses[i] == IDENTITY_MATRIX) {
|
||||
continue;
|
||||
}
|
||||
const auto& handLaser = _presentHandLasers[i];
|
||||
if (!handLaser.valid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& laserDirection = handLaser.direction;
|
||||
auto model = _presentHandPoses[i];
|
||||
auto castDirection = glm::quat_cast(model) * laserDirection;
|
||||
if (glm::abs(glm::length2(castDirection) - 1.0f) > EPSILON) {
|
||||
castDirection = glm::normalize(castDirection);
|
||||
}
|
||||
|
||||
// FIXME fetch the actual UI radius from... somewhere?
|
||||
float uiRadius = 1.0f;
|
||||
|
||||
// Find the intersection of the laser with he UI and use it to scale the model matrix
|
||||
float distance;
|
||||
if (!glm::intersectRaySphere(vec3(_presentHandPoses[i][3]), castDirection, _presentUiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure we rotate to match the desired laser direction
|
||||
if (laserDirection != Vectors::UNIT_NEG_Z) {
|
||||
auto rotation = glm::rotation(Vectors::UNIT_NEG_Z, laserDirection);
|
||||
model = model * glm::mat4_cast(rotation);
|
||||
}
|
||||
|
||||
model = glm::scale(model, vec3(distance));
|
||||
handLaserModelMatrices[i] = model;
|
||||
}
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
auto eyePose = _currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye);
|
||||
auto view = glm::inverse(eyePose);
|
||||
const auto& projection = _eyeProjections[eye];
|
||||
for (int i = 0; i < NUMBER_OF_HANDS; ++i) {
|
||||
if (handLaserModelMatrices[i] == IDENTITY_MATRIX) {
|
||||
continue;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.setFramebuffer(_compositeFramebuffer);
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _renderTargetSize));
|
||||
batch.setViewTransform(_currentPresentFrameInfo.presentPose, false);
|
||||
bilateral::for_each_side([&](bilateral::Side side){
|
||||
auto index = bilateral::index(side);
|
||||
if (_presentHandPoses[index] == IDENTITY_MATRIX) {
|
||||
return;
|
||||
}
|
||||
Uniform<glm::mat4>(*_laserProgram, "mvp").Set(projection * view * handLaserModelMatrices[i]);
|
||||
Uniform<glm::vec4>(*_laserProgram, "color").Set(_presentHandLasers[i].color);
|
||||
_laserGeometry->Draw();
|
||||
}
|
||||
const auto& points = _presentHandLaserPoints[index];
|
||||
const auto& lasers = _presentHandLasers[index];
|
||||
geometryCache->renderGlowLine(batch, points.first, points.second, lasers.color);
|
||||
});
|
||||
});
|
||||
glDisable(GL_BLEND);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -9,14 +9,16 @@
|
|||
|
||||
#include <ThreadSafeValueCache.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <Transform.h>
|
||||
|
||||
#include "../OpenGLDisplayPlugin.h"
|
||||
#include <gpu/Format.h>
|
||||
#include <gpu/Stream.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#define HMD_HAND_LASER_SUPPORT
|
||||
#endif
|
||||
#include "../CompositorHelper.h"
|
||||
#include "../OpenGLDisplayPlugin.h"
|
||||
|
||||
class HmdDisplayPlugin : public OpenGLDisplayPlugin {
|
||||
using Parent = OpenGLDisplayPlugin;
|
||||
|
@ -28,7 +30,6 @@ public:
|
|||
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override final { return _cullingProjection; }
|
||||
glm::uvec2 getRecommendedUiSize() const override final;
|
||||
glm::uvec2 getRecommendedRenderSize() const override final { return _renderTargetSize; }
|
||||
void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final;
|
||||
bool isDisplayVisible() const override { return isHmdMounted(); }
|
||||
|
||||
QRect getRecommendedOverlayRect() const override final;
|
||||
|
@ -37,15 +38,19 @@ public:
|
|||
|
||||
bool setHandLaser(uint32_t hands, HandLaserMode mode, const vec4& color, const vec3& direction) override;
|
||||
|
||||
bool wantVsync() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void hmdPresent() = 0;
|
||||
virtual bool isHmdMounted() const = 0;
|
||||
virtual void postPreview() {};
|
||||
virtual void updatePresentPose();
|
||||
|
||||
bool beginFrameRender(uint32_t frameIndex) override;
|
||||
bool internalActivate() override;
|
||||
void internalDeactivate() override;
|
||||
void compositeScene() override;
|
||||
void compositeOverlay() override;
|
||||
void compositePointer() override;
|
||||
void internalPresent() override;
|
||||
|
@ -67,82 +72,74 @@ protected:
|
|||
|
||||
Transform _uiModelTransform;
|
||||
std::array<HandLaserInfo, 2> _handLasers;
|
||||
std::array<glm::mat4, 2> _handPoses;
|
||||
std::array<mat4, 2> _handPoses;
|
||||
|
||||
Transform _presentUiModelTransform;
|
||||
std::array<HandLaserInfo, 2> _presentHandLasers;
|
||||
std::array<mat4, 2> _presentHandPoses;
|
||||
std::array<std::pair<vec3, vec3>, 2> _presentHandLaserPoints;
|
||||
|
||||
std::array<glm::mat4, 2> _eyeOffsets;
|
||||
std::array<glm::mat4, 2> _eyeProjections;
|
||||
std::array<glm::mat4, 2> _eyeInverseProjections;
|
||||
std::array<mat4, 2> _eyeOffsets;
|
||||
std::array<mat4, 2> _eyeProjections;
|
||||
std::array<mat4, 2> _eyeInverseProjections;
|
||||
|
||||
glm::mat4 _cullingProjection;
|
||||
glm::uvec2 _renderTargetSize;
|
||||
mat4 _cullingProjection;
|
||||
uvec2 _renderTargetSize;
|
||||
float _ipd { 0.064f };
|
||||
|
||||
struct FrameInfo {
|
||||
glm::mat4 rawRenderPose;
|
||||
glm::mat4 renderPose;
|
||||
glm::mat4 rawPresentPose;
|
||||
glm::mat4 presentPose;
|
||||
mat4 renderPose;
|
||||
mat4 presentPose;
|
||||
double sensorSampleTime { 0 };
|
||||
double predictedDisplayTime { 0 };
|
||||
glm::mat3 presentReprojection;
|
||||
mat3 presentReprojection;
|
||||
};
|
||||
|
||||
QMap<uint32_t, FrameInfo> _frameInfos;
|
||||
FrameInfo _currentPresentFrameInfo;
|
||||
FrameInfo _currentRenderFrameInfo;
|
||||
|
||||
bool _disablePreview{ true };
|
||||
private:
|
||||
void updateOverlayProgram();
|
||||
#ifdef HMD_HAND_LASER_SUPPORT
|
||||
void updateLaserProgram();
|
||||
#endif
|
||||
void updateReprojectionProgram();
|
||||
ivec4 getViewportForSourceSize(const uvec2& size) const;
|
||||
|
||||
bool _enablePreview { false };
|
||||
bool _disablePreviewItemAdded { false };
|
||||
bool _monoPreview { true };
|
||||
bool _enableReprojection { true };
|
||||
bool _firstPreview { true };
|
||||
bool _clearPreviewFlag { false };
|
||||
gpu::TexturePointer _previewTexture;
|
||||
|
||||
ProgramPtr _overlayProgram;
|
||||
struct OverlayUniforms {
|
||||
int32_t mvp { -1 };
|
||||
int32_t alpha { -1 };
|
||||
int32_t glowColors { -1 };
|
||||
int32_t glowPoints { -1 };
|
||||
int32_t resolution { -1 };
|
||||
int32_t radius { -1 };
|
||||
} _overlayUniforms;
|
||||
struct OverlayRenderer {
|
||||
gpu::Stream::FormatPointer format;
|
||||
gpu::BufferPointer vertices;
|
||||
gpu::BufferPointer indices;
|
||||
uint32_t indexCount { 0 };
|
||||
gpu::PipelinePointer pipeline;
|
||||
int32_t uniformsLocation { -1 };
|
||||
|
||||
ProgramPtr _previewProgram;
|
||||
struct PreviewUniforms {
|
||||
int32_t previewTexture { -1 };
|
||||
} _previewUniforms;
|
||||
// FIXME this is stupid, use the built in transformation pipeline
|
||||
std::array<gpu::BufferPointer, 2> uniformBuffers;
|
||||
std::array<mat4, 2> mvps;
|
||||
|
||||
float _previewAspect { 0 };
|
||||
GLuint _previewTextureID { 0 };
|
||||
glm::uvec2 _prevWindowSize { 0, 0 };
|
||||
qreal _prevDevicePixelRatio { 0 };
|
||||
struct Uniforms {
|
||||
mat4 mvp;
|
||||
vec4 glowPoints { -1 };
|
||||
vec4 glowColors[2];
|
||||
vec2 resolution { CompositorHelper::VIRTUAL_SCREEN_SIZE };
|
||||
float radius { 0.005f };
|
||||
float alpha { 1.0f };
|
||||
} uniforms;
|
||||
|
||||
struct Vertex {
|
||||
vec3 pos;
|
||||
vec2 uv;
|
||||
} vertex;
|
||||
|
||||
ProgramPtr _reprojectionProgram;
|
||||
struct ReprojectionUniforms {
|
||||
int32_t reprojectionMatrix { -1 };
|
||||
int32_t inverseProjectionMatrix { -1 };
|
||||
int32_t projectionMatrix { -1 };
|
||||
} _reprojectionUniforms;
|
||||
static const size_t VERTEX_OFFSET { offsetof(Vertex, pos) };
|
||||
static const size_t TEXTURE_OFFSET { offsetof(Vertex, uv) };
|
||||
static const int VERTEX_STRIDE { sizeof(Vertex) };
|
||||
|
||||
ShapeWrapperPtr _sphereSection;
|
||||
|
||||
#ifdef HMD_HAND_LASER_SUPPORT
|
||||
ProgramPtr _laserProgram;
|
||||
struct LaserUniforms {
|
||||
int32_t mvp { -1 };
|
||||
int32_t color { -1 };
|
||||
} _laserUniforms;
|
||||
ShapeWrapperPtr _laserGeometry;
|
||||
#endif
|
||||
void build();
|
||||
void updatePipeline();
|
||||
void render(HmdDisplayPlugin& plugin);
|
||||
} _overlayRenderer;
|
||||
};
|
||||
|
||||
|
|
|
@ -8,52 +8,56 @@
|
|||
|
||||
#include "InterleavedStereoDisplayPlugin.h"
|
||||
|
||||
static const char * INTERLEAVED_TEXTURED_VS = R"VS(#version 410 core
|
||||
#pragma line __LINE__
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
in vec3 Position;
|
||||
in vec2 TexCoord;
|
||||
static const char* INTERLEAVED_SRGB_TO_LINEAR_FRAG = R"SCRIBE(
|
||||
|
||||
out vec2 vTexCoord;
|
||||
struct TextureData {
|
||||
ivec2 textureSize;
|
||||
};
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(Position, 1);
|
||||
vTexCoord = TexCoord;
|
||||
}
|
||||
layout(std140) uniform textureDataBuffer {
|
||||
TextureData textureData;
|
||||
};
|
||||
|
||||
)VS";
|
||||
uniform sampler2D colorMap;
|
||||
|
||||
static const char * INTERLEAVED_TEXTURED_FS = R"FS(#version 410 core
|
||||
#pragma line __LINE__
|
||||
in vec2 varTexCoord0;
|
||||
|
||||
uniform sampler2D sampler;
|
||||
uniform ivec2 textureSize;
|
||||
out vec4 outFragColor;
|
||||
|
||||
in vec2 vTexCoord;
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
ivec2 texCoord = ivec2(floor(vTexCoord * textureSize));
|
||||
void main(void) {
|
||||
ivec2 texCoord = ivec2(floor(varTexCoord0 * textureData.textureSize));
|
||||
texCoord.x /= 2;
|
||||
int row = int(floor(gl_FragCoord.y));
|
||||
if (row % 2 > 0) {
|
||||
texCoord.x += (textureSize.x / 2);
|
||||
texCoord.x += (textureData.textureSize.x / 2);
|
||||
}
|
||||
FragColor = texelFetch(sampler, texCoord, 0); //texture(sampler, texCoord);
|
||||
outFragColor = vec4(pow(texelFetch(colorMap, texCoord, 0).rgb, vec3(2.2)), 1.0);
|
||||
}
|
||||
|
||||
)FS";
|
||||
)SCRIBE";
|
||||
|
||||
const QString InterleavedStereoDisplayPlugin::NAME("3D TV - Interleaved");
|
||||
|
||||
void InterleavedStereoDisplayPlugin::customizeContext() {
|
||||
StereoDisplayPlugin::customizeContext();
|
||||
// Set up the stencil buffers? Or use a custom shader?
|
||||
compileProgram(_interleavedProgram, INTERLEAVED_TEXTURED_VS, INTERLEAVED_TEXTURED_FS);
|
||||
if (!_interleavedPresentPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(INTERLEAVED_SRGB_TO_LINEAR_FRAG));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
_interleavedPresentPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
}
|
||||
|
||||
void InterleavedStereoDisplayPlugin::uncustomizeContext() {
|
||||
_interleavedProgram.reset();
|
||||
_interleavedPresentPipeline.reset();
|
||||
StereoDisplayPlugin::uncustomizeContext();
|
||||
}
|
||||
|
||||
|
@ -65,15 +69,14 @@ glm::uvec2 InterleavedStereoDisplayPlugin::getRecommendedRenderSize() const {
|
|||
}
|
||||
|
||||
void InterleavedStereoDisplayPlugin::internalPresent() {
|
||||
using namespace oglplus;
|
||||
auto sceneSize = getRecommendedRenderSize();
|
||||
_interleavedProgram->Bind();
|
||||
Uniform<ivec2>(*_interleavedProgram, "textureSize").SetValue(sceneSize);
|
||||
auto surfaceSize = getSurfacePixels();
|
||||
Context::Viewport(0, 0, surfaceSize.x, surfaceSize.y);
|
||||
glBindTexture(GL_TEXTURE_2D, GetName(_compositeFramebuffer->color));
|
||||
_plane->Use();
|
||||
_plane->Draw();
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
batch.setFramebuffer(gpu::FramebufferPointer());
|
||||
batch.setViewportTransform(ivec4(uvec2(0), getSurfacePixels()));
|
||||
batch.setResourceTexture(0, _currentFrame->framebuffer->getRenderBuffer(0));
|
||||
batch.setPipeline(_interleavedPresentPipeline);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ protected:
|
|||
void internalPresent() override;
|
||||
|
||||
private:
|
||||
ProgramPtr _interleavedProgram;
|
||||
static const QString NAME;
|
||||
gpu::PipelinePointer _interleavedPresentPipeline;
|
||||
gpu::BufferPointer _textureDataBuffer;
|
||||
};
|
||||
|
|
|
@ -7,11 +7,6 @@
|
|||
//
|
||||
|
||||
#include "SideBySideStereoDisplayPlugin.h"
|
||||
#include <GLMHelpers.h>
|
||||
#include <CursorManager.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <gl/GLWidget.h>
|
||||
#include "../CompositorHelper.h"
|
||||
|
||||
const QString SideBySideStereoDisplayPlugin::NAME("3D TV - Side by Side Stereo");
|
||||
|
||||
|
|
|
@ -101,4 +101,3 @@ void StereoDisplayPlugin::internalDeactivate() {
|
|||
float StereoDisplayPlugin::getRecommendedAspectRatio() const {
|
||||
return aspect(Parent::getRecommendedRenderSize());
|
||||
}
|
||||
|
||||
|
|
75
libraries/display-plugins/src/hmd_ui_glow.slf
Normal file
75
libraries/display-plugins/src/hmd_ui_glow.slf
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/11
|
||||
// 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
|
||||
//
|
||||
|
||||
uniform sampler2D sampler;
|
||||
|
||||
struct OverlayData {
|
||||
mat4 mvp;
|
||||
vec4 glowPoints;
|
||||
vec4 glowColors[2];
|
||||
vec4 resolutionRadiusAlpha;
|
||||
};
|
||||
|
||||
layout(std140) uniform overlayBuffer {
|
||||
OverlayData overlay;
|
||||
};
|
||||
|
||||
vec2 resolution = overlay.resolutionRadiusAlpha.xy;
|
||||
float radius = overlay.resolutionRadiusAlpha.z;
|
||||
float alpha = overlay.resolutionRadiusAlpha.w;
|
||||
vec4 glowPoints = overlay.glowPoints;
|
||||
vec4 glowColors[2] = overlay.glowColors;
|
||||
|
||||
in vec3 vPosition;
|
||||
in vec2 vTexCoord;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
float easeInOutCubic(float f) {
|
||||
const float d = 1.0;
|
||||
const float b = 0.0;
|
||||
const float c = 1.0;
|
||||
float t = f;
|
||||
if ((t /= d / 2.0) < 1.0) return c / 2.0 * t * t * t + b;
|
||||
return c / 2.0 * ((t -= 2.0) * t * t + 2.0) + b;
|
||||
}
|
||||
|
||||
void main() {
|
||||
FragColor = texture(sampler, vTexCoord);
|
||||
|
||||
vec2 aspect = resolution;
|
||||
aspect /= resolution.x;
|
||||
|
||||
float glowIntensity = 0.0;
|
||||
float dist1 = distance(vTexCoord * aspect, glowPoints.xy * aspect);
|
||||
float dist2 = distance(vTexCoord * aspect, glowPoints.zw * aspect);
|
||||
float dist = min(dist1, dist2);
|
||||
vec3 glowColor = glowColors[0].rgb;
|
||||
if (dist2 < dist1) {
|
||||
glowColor = glowColors[1].rgb;
|
||||
}
|
||||
|
||||
if (dist <= radius) {
|
||||
glowIntensity = 1.0 - (dist / radius);
|
||||
glowColor.rgb = pow(glowColor, vec3(1.0 - glowIntensity));
|
||||
glowIntensity = easeInOutCubic(glowIntensity);
|
||||
glowIntensity = pow(glowIntensity, 0.5);
|
||||
}
|
||||
|
||||
if (alpha <= 0.0) {
|
||||
if (glowIntensity <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
FragColor = vec4(glowColor, glowIntensity);
|
||||
return;
|
||||
}
|
||||
|
||||
FragColor.rgb = mix(FragColor.rgb, glowColor.rgb, glowIntensity);
|
||||
FragColor.a *= alpha;
|
||||
}
|
32
libraries/display-plugins/src/hmd_ui_glow.slv
Normal file
32
libraries/display-plugins/src/hmd_ui_glow.slv
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/11
|
||||
// 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
|
||||
//
|
||||
|
||||
struct OverlayData {
|
||||
mat4 mvp;
|
||||
vec4 glowPoints;
|
||||
vec4 glowColors[2];
|
||||
vec4 resolutionRadiusAlpha;
|
||||
};
|
||||
|
||||
layout(std140) uniform overlayBuffer {
|
||||
OverlayData overlay;
|
||||
};
|
||||
|
||||
mat4 mvp = overlay.mvp;
|
||||
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 3) in vec2 TexCoord;
|
||||
|
||||
out vec3 vPosition;
|
||||
out vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = mvp * vec4(Position, 1);
|
||||
vTexCoord = TexCoord;
|
||||
vPosition = Position;
|
||||
}
|
|
@ -57,7 +57,10 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Text, RenderableTextEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, RenderableWebEntityItem::factory)
|
||||
// Offscreen web surfaces are incompatible with nSight
|
||||
if (!nsightActive()) {
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, RenderableWebEntityItem::factory)
|
||||
}
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Line, RenderableLineEntityItem::factory)
|
||||
|
@ -159,7 +162,9 @@ void EntityTreeRenderer::init() {
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::shutdown() {
|
||||
_entitiesScriptEngine->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential
|
||||
}
|
||||
_shuttingDown = true;
|
||||
|
||||
clear(); // always clear() on shutdown
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
// The GLEscrow class provides a simple mechanism for producer GL contexts to provide
|
||||
// content to a consumer where the consumer is assumed to be connected to a display and
|
||||
// therefore must never be blocked.
|
||||
|
|
|
@ -2,18 +2,16 @@
|
|||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtGui/QSurfaceFormat>
|
||||
#include <QtOpenGL/QGL>
|
||||
#include <QOpenGLContext>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QRegularExpression>
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
#ifdef DEBUG
|
||||
static bool enableDebug = true;
|
||||
#else
|
||||
static const QString DEBUG_FLAG("HIFI_ENABLE_OPENGL_45");
|
||||
static bool enableDebug = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
#endif
|
||||
|
||||
#include <QtGui/QSurfaceFormat>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QOpenGLDebugLogger>
|
||||
|
||||
#include <QtOpenGL/QGL>
|
||||
|
||||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
||||
static QSurfaceFormat format;
|
||||
|
@ -23,7 +21,8 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
|||
format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS);
|
||||
format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS);
|
||||
setGLFormatVersion(format);
|
||||
if (enableDebug) {
|
||||
if (GLDebug::enabled()) {
|
||||
qDebug() << "Enabling debug context";
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
}
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
|
||||
|
@ -72,3 +71,36 @@ QJsonObject getGLContextData() {
|
|||
{ "renderer", glRenderer },
|
||||
};
|
||||
}
|
||||
|
||||
QThread* RENDER_THREAD = nullptr;
|
||||
|
||||
bool isRenderThread() {
|
||||
return QThread::currentThread() == RENDER_THREAD;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool enableDebugLogger = true;
|
||||
#else
|
||||
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENGL");
|
||||
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
#endif
|
||||
|
||||
bool GLDebug::enabled() {
|
||||
return enableDebugLogger;
|
||||
}
|
||||
|
||||
void GLDebug::log(const QOpenGLDebugMessage & debugMessage) {
|
||||
qDebug() << debugMessage;
|
||||
}
|
||||
|
||||
void GLDebug::setupLogger(QObject* window) {
|
||||
if (enabled()) {
|
||||
QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(window);
|
||||
logger->initialize(); // initializes in the current context, i.e. ctx
|
||||
logger->enableMessages();
|
||||
QObject::connect(logger, &QOpenGLDebugLogger::messageLogged, window, [&](const QOpenGLDebugMessage & debugMessage) {
|
||||
GLDebug::log(debugMessage);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -18,6 +18,8 @@
|
|||
// but GL implementations usually just come with buffer sizes in multiples of 8)
|
||||
#define DEFAULT_GL_STENCIL_BUFFER_BITS 8
|
||||
|
||||
class QObject;
|
||||
class QOpenGLDebugMessage;
|
||||
class QSurfaceFormat;
|
||||
class QGLFormat;
|
||||
|
||||
|
@ -29,4 +31,15 @@ const QGLFormat& getDefaultGLFormat();
|
|||
QJsonObject getGLContextData();
|
||||
int glVersionToInteger(QString glVersion);
|
||||
|
||||
bool isRenderThread();
|
||||
|
||||
|
||||
class GLDebug {
|
||||
public:
|
||||
static bool enabled();
|
||||
static void log(const QOpenGLDebugMessage& debugMessage);
|
||||
static void setupLogger(QObject* window = nullptr);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
#include "GLWindow.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QOpenGLDebugLogger>
|
||||
|
||||
#include "GLHelpers.h"
|
||||
|
||||
|
|
|
@ -13,30 +13,16 @@
|
|||
#include "OffscreenGLCanvas.h"
|
||||
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtGui/QOffscreenSurface>
|
||||
#include <QtGui/QOpenGLDebugLogger>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
|
||||
#include "GLHelpers.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool enableDebugLogger = true;
|
||||
#else
|
||||
static const QString DEBUG_FLAG("HIFI_ENABLE_OPENGL_45");
|
||||
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
#endif
|
||||
|
||||
|
||||
OffscreenGLCanvas::OffscreenGLCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface){
|
||||
}
|
||||
|
||||
OffscreenGLCanvas::~OffscreenGLCanvas() {
|
||||
if (_logger) {
|
||||
makeCurrent();
|
||||
delete _logger;
|
||||
_logger = nullptr;
|
||||
}
|
||||
|
||||
_context->doneCurrent();
|
||||
delete _context;
|
||||
_context = nullptr;
|
||||
|
@ -68,25 +54,14 @@ bool OffscreenGLCanvas::makeCurrent() {
|
|||
bool result = _context->makeCurrent(_offscreenSurface);
|
||||
Q_ASSERT(result);
|
||||
|
||||
std::call_once(_reportOnce, []{
|
||||
std::call_once(_reportOnce, [this]{
|
||||
qDebug() << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
|
||||
qDebug() << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
qDebug() << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR));
|
||||
qDebug() << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER));
|
||||
GLDebug::setupLogger(this);
|
||||
});
|
||||
|
||||
|
||||
if (result && !_logger) {
|
||||
_logger = new QOpenGLDebugLogger(this);
|
||||
if (_logger->initialize()) {
|
||||
connect(_logger, &QOpenGLDebugLogger::messageLogged, [](const QOpenGLDebugMessage& message) {
|
||||
qDebug() << message;
|
||||
});
|
||||
_logger->disableMessages(QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::NotificationSeverity);
|
||||
_logger->startLogging(QOpenGLDebugLogger::LoggingMode::SynchronousLogging);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -101,4 +76,4 @@ QObject* OffscreenGLCanvas::getContextObject() {
|
|||
void OffscreenGLCanvas::moveToThreadWithContext(QThread* thread) {
|
||||
moveToThread(thread);
|
||||
_context->moveToThread(thread);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ protected:
|
|||
std::once_flag _reportOnce;
|
||||
QOpenGLContext* _context{ nullptr };
|
||||
QOffscreenSurface* _offscreenSurface{ nullptr };
|
||||
QOpenGLDebugLogger* _logger{ nullptr };
|
||||
};
|
||||
|
||||
#endif // hifi_OffscreenGLCanvas_h
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// QOpenGLDebugLoggerWrapper.cpp
|
||||
//
|
||||
//
|
||||
// Created by Clement on 12/4/15.
|
||||
// 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 "QOpenGLDebugLoggerWrapper.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QOpenGLDebugLogger>
|
||||
|
||||
void OpenGLDebug::log(const QOpenGLDebugMessage & debugMessage) {
|
||||
qDebug() << debugMessage;
|
||||
}
|
||||
|
||||
void setupDebugLogger(QObject* window) {
|
||||
QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(window);
|
||||
logger->initialize(); // initializes in the current context, i.e. ctx
|
||||
logger->enableMessages();
|
||||
QObject::connect(logger, &QOpenGLDebugLogger::messageLogged, window, [&](const QOpenGLDebugMessage & debugMessage) {
|
||||
OpenGLDebug::log(debugMessage);
|
||||
|
||||
});
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// QOpenGLDebugLoggerWrapper.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 12/4/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_QOpenGLDebugLoggerWrapper_h
|
||||
#define hifi_QOpenGLDebugLoggerWrapper_h
|
||||
|
||||
class QObject;
|
||||
class QOpenGLDebugMessage;
|
||||
|
||||
void setupDebugLogger(QObject* window);
|
||||
|
||||
class OpenGLDebug {
|
||||
public:
|
||||
static void log(const QOpenGLDebugMessage & debugMessage);
|
||||
};
|
||||
|
||||
#endif // hifi_QOpenGLDebugLoggerWrapper_h
|
|
@ -32,30 +32,44 @@
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
static const QString DEBUG_FLAG("HIFI_ENABLE_OPENGL_45");
|
||||
static bool enableOpenGL45 = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
static const QString DEBUG_FLAG("HIFI_DISABLE_OPENGL_45");
|
||||
static bool disableOpenGL45 = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
|
||||
Backend* GLBackend::createBackend() {
|
||||
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();
|
||||
GLBackend* result;
|
||||
if (enableOpenGL45 && version >= 0x0405) {
|
||||
std::shared_ptr<GLBackend> result;
|
||||
if (!disableOpenGL45 && version >= 0x0405) {
|
||||
qDebug() << "Using OpenGL 4.5 backend";
|
||||
result = new gpu::gl45::GL45Backend();
|
||||
result = std::make_shared<gpu::gl45::GL45Backend>();
|
||||
} else {
|
||||
qDebug() << "Using OpenGL 4.1 backend";
|
||||
result = new gpu::gl41::GL41Backend();
|
||||
result = std::make_shared<gpu::gl41::GL41Backend>();
|
||||
}
|
||||
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(shader, slotBindings);
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings);
|
||||
}
|
||||
|
||||
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||
|
@ -120,24 +134,9 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::gl::GLBackend::do_popProfileRange),
|
||||
};
|
||||
|
||||
extern std::function<uint32(const Texture& texture)> TEXTURE_ID_RESOLVER;
|
||||
|
||||
void GLBackend::init() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
|
||||
TEXTURE_ID_RESOLVER = [](const Texture& texture)->uint32 {
|
||||
auto object = Backend::getGPUObject<GLTexture>(texture);
|
||||
if (!object) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (object->getSyncState() != GLSyncState::Idle) {
|
||||
return object->_downsampleSource._texture;
|
||||
}
|
||||
return object->_texture;
|
||||
};
|
||||
|
||||
QString vendor{ (const char*)glGetString(GL_VENDOR) };
|
||||
QString renderer{ (const char*)glGetString(GL_RENDERER) };
|
||||
qCDebug(gpugllogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
|
||||
|
@ -178,6 +177,7 @@ void GLBackend::init() {
|
|||
}
|
||||
|
||||
GLBackend::GLBackend() {
|
||||
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment);
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ GLBackend::~GLBackend() {
|
|||
killTransform();
|
||||
}
|
||||
|
||||
void GLBackend::renderPassTransfer(Batch& batch) {
|
||||
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();
|
||||
|
@ -245,7 +245,7 @@ void GLBackend::renderPassTransfer(Batch& batch) {
|
|||
_inRenderTransferPass = false;
|
||||
}
|
||||
|
||||
void GLBackend::renderPassDraw(Batch& batch) {
|
||||
void GLBackend::renderPassDraw(const Batch& batch) {
|
||||
_currentDraw = -1;
|
||||
_transform._camerasItr = _transform._cameraOffsets.begin();
|
||||
const size_t numCommands = batch.getCommands().size();
|
||||
|
@ -290,11 +290,8 @@ void GLBackend::renderPassDraw(Batch& batch) {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBackend::render(Batch& batch) {
|
||||
// Finalize the batch by moving all the instanced rendering into the command buffer
|
||||
batch.preExecute();
|
||||
|
||||
_stereo._skybox = batch.isSkyboxEnabled();
|
||||
void GLBackend::render(const Batch& batch) {
|
||||
_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;
|
||||
|
@ -318,6 +315,7 @@ void GLBackend::render(Batch& batch) {
|
|||
|
||||
|
||||
void GLBackend::syncCache() {
|
||||
recycle();
|
||||
syncTransformStateCache();
|
||||
syncPipelineStateCache();
|
||||
syncInputStateCache();
|
||||
|
@ -334,21 +332,21 @@ void GLBackend::setupStereoSide(int side) {
|
|||
_transform.bindCurrentCamera(side);
|
||||
}
|
||||
|
||||
void GLBackend::do_resetStages(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_resetStages(const Batch& batch, size_t paramOffset) {
|
||||
resetStages();
|
||||
}
|
||||
|
||||
void GLBackend::do_runLambda(Batch& batch, size_t paramOffset) {
|
||||
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(Batch& batch, size_t paramOffset) {
|
||||
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(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_stopNamedCall(const Batch& batch, size_t paramOffset) {
|
||||
batch._currentNamedCall.clear();
|
||||
}
|
||||
|
||||
|
@ -365,14 +363,16 @@ void GLBackend::resetStages() {
|
|||
}
|
||||
|
||||
|
||||
void GLBackend::do_pushProfileRange(Batch& batch, size_t paramOffset) {
|
||||
#if defined(NSIGHT_FOUND)
|
||||
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(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_popProfileRange(const Batch& batch, size_t paramOffset) {
|
||||
profileRanges.pop_back();
|
||||
#if defined(NSIGHT_FOUND)
|
||||
nvtxRangePop();
|
||||
#endif
|
||||
|
@ -385,7 +385,7 @@ void GLBackend::do_popProfileRange(Batch& batch, size_t paramOffset) {
|
|||
// 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_glActiveBindTexture(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_glActiveBindTexture(const Batch& batch, size_t paramOffset) {
|
||||
glActiveTexture(batch._params[paramOffset + 2]._uint);
|
||||
glBindTexture(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._uint),
|
||||
|
@ -394,7 +394,7 @@ void GLBackend::do_glActiveBindTexture(Batch& batch, size_t paramOffset) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform1i(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -408,7 +408,7 @@ void GLBackend::do_glUniform1i(Batch& batch, size_t paramOffset) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform1f(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -422,7 +422,7 @@ void GLBackend::do_glUniform1f(Batch& batch, size_t paramOffset) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform2f(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -436,7 +436,7 @@ void GLBackend::do_glUniform2f(Batch& batch, size_t paramOffset) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform3f(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -451,7 +451,7 @@ void GLBackend::do_glUniform3f(Batch& batch, size_t paramOffset) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform4f(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -467,7 +467,7 @@ void GLBackend::do_glUniform4f(Batch& batch, size_t paramOffset) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform3fv(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -477,12 +477,12 @@ void GLBackend::do_glUniform3fv(Batch& batch, size_t paramOffset) {
|
|||
glUniform3fv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint));
|
||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform4fv(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -492,13 +492,13 @@ void GLBackend::do_glUniform4fv(Batch& batch, size_t paramOffset) {
|
|||
|
||||
GLint location = GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int);
|
||||
GLsizei count = batch._params[paramOffset + 1]._uint;
|
||||
const GLfloat* value = (const GLfloat*)batch.editData(batch._params[paramOffset + 0]._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(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -508,12 +508,12 @@ void GLBackend::do_glUniform4iv(Batch& batch, size_t paramOffset) {
|
|||
glUniform4iv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLint*)batch.editData(batch._params[paramOffset + 0]._uint));
|
||||
(const GLint*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniformMatrix3fv(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -525,11 +525,11 @@ void GLBackend::do_glUniformMatrix3fv(Batch& batch, size_t paramOffset) {
|
|||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
||||
batch._params[paramOffset + 2]._uint,
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint));
|
||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) {
|
||||
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
|
||||
|
@ -541,11 +541,11 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) {
|
|||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
||||
batch._params[paramOffset + 2]._uint,
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint));
|
||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glColor4f(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_glColor4f(const Batch& batch, size_t paramOffset) {
|
||||
|
||||
glm::vec4 newColor(
|
||||
batch._params[paramOffset + 3]._float,
|
||||
|
@ -559,3 +559,132 @@ void GLBackend::do_glColor4f(Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::releaseBuffer(GLuint id, Size size) const {
|
||||
Lock lock(_trashMutex);
|
||||
_buffersTrash.push_back({ id, size });
|
||||
}
|
||||
|
||||
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);
|
||||
_shadersTrash.push_back(id);
|
||||
}
|
||||
|
||||
void GLBackend::releaseQuery(GLuint id) const {
|
||||
Lock lock(_trashMutex);
|
||||
_queriesTrash.push_back(id);
|
||||
}
|
||||
|
||||
void GLBackend::recycle() const {
|
||||
{
|
||||
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);
|
||||
decrementBufferGPUCount();
|
||||
updateBufferGPUMemoryUsage(pair.second, 0);
|
||||
}
|
||||
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);
|
||||
decrementTextureGPUCount();
|
||||
updateTextureGPUMemoryUsage(pair.second, 0);
|
||||
}
|
||||
if (!ids.empty()) {
|
||||
glDeleteTextures((GLsizei)ids.size(), ids.data());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <bitset>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
@ -30,20 +31,22 @@
|
|||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
class GLBackend : public Backend {
|
||||
class GLBackend : public Backend, public std::enable_shared_from_this<GLBackend> {
|
||||
// Context Backend static interface required
|
||||
friend class gpu::Context;
|
||||
static void init();
|
||||
static Backend* createBackend();
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings);
|
||||
static BackendPointer createBackend();
|
||||
|
||||
protected:
|
||||
explicit GLBackend(bool syncCache);
|
||||
GLBackend();
|
||||
public:
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet());
|
||||
|
||||
~GLBackend();
|
||||
|
||||
void render(Batch& batch) final;
|
||||
void setCameraCorrection(const Mat4& correction);
|
||||
void render(const Batch& batch) final;
|
||||
|
||||
// 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
|
||||
|
@ -72,74 +75,74 @@ public:
|
|||
size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; }
|
||||
|
||||
// Draw Stage
|
||||
virtual void do_draw(Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_drawIndexed(Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_drawInstanced(Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_drawIndexedInstanced(Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_multiDrawIndirect(Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) = 0;
|
||||
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(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setInputBuffer(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setIndexBuffer(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setIndirectBuffer(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_generateTextureMips(Batch& batch, size_t paramOffset) final;
|
||||
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(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setViewTransform(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setProjectionTransform(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setViewportTransform(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setDepthRangeTransform(Batch& batch, size_t paramOffset) final;
|
||||
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(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setUniformBuffer(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Resource Stage
|
||||
virtual void do_setResourceTexture(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Pipeline Stage
|
||||
virtual void do_setPipeline(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setPipeline(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Output stage
|
||||
virtual void do_setFramebuffer(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_clearFramebuffer(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_blit(Batch& batch, size_t paramOffset) = 0;
|
||||
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(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_endQuery(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_getQuery(Batch& batch, size_t paramOffset) final;
|
||||
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(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_resetStages(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_runLambda(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_runLambda(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_startNamedCall(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_stopNamedCall(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;
|
||||
|
||||
virtual void do_pushProfileRange(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_popProfileRange(Batch& batch, size_t paramOffset) final;
|
||||
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_glActiveBindTexture(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glActiveBindTexture(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_glUniform1i(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform1f(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform2f(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform3f(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform4f(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform3fv(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform4fv(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform4iv(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniformMatrix3fv(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) final;
|
||||
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(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;
|
||||
|
@ -156,21 +159,28 @@ public:
|
|||
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(Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setStateScissorRect(Batch& batch, size_t paramOffset) 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 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;
|
||||
|
||||
protected:
|
||||
|
||||
virtual GLuint getFramebufferID(const FramebufferPointer& framebuffer) = 0;
|
||||
void recycle() const override;
|
||||
virtual GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) = 0;
|
||||
|
||||
virtual GLuint getBufferID(const Buffer& buffer) = 0;
|
||||
virtual GLBuffer* syncGPUObject(const Buffer& buffer) = 0;
|
||||
|
||||
virtual GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) = 0;
|
||||
virtual GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) = 0;
|
||||
|
||||
virtual GLuint getQueryID(const QueryPointer& query) = 0;
|
||||
virtual GLQuery* syncGPUObject(const Query& query) = 0;
|
||||
|
||||
static const size_t INVALID_OFFSET = (size_t)-1;
|
||||
|
@ -178,8 +188,17 @@ protected:
|
|||
int32_t _uboAlignment { 0 };
|
||||
int _currentDraw { -1 };
|
||||
|
||||
void renderPassTransfer(Batch& batch);
|
||||
void renderPassDraw(Batch& batch);
|
||||
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<GLuint> _framebuffersTrash;
|
||||
mutable std::list<GLuint> _shadersTrash;
|
||||
mutable std::list<GLuint> _programsTrash;
|
||||
mutable std::list<GLuint> _queriesTrash;
|
||||
|
||||
void renderPassTransfer(const Batch& batch);
|
||||
void renderPassDraw(const Batch& batch);
|
||||
void setupStereoSide(int side);
|
||||
|
||||
virtual void initInput() final;
|
||||
|
@ -229,6 +248,14 @@ protected:
|
|||
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 {
|
||||
using CameraBufferElement = TransformCamera;
|
||||
using TransformCameras = std::vector<CameraBufferElement>;
|
||||
|
@ -243,7 +270,11 @@ protected:
|
|||
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 };
|
||||
|
@ -297,14 +328,21 @@ protected:
|
|||
PipelinePointer _pipeline;
|
||||
|
||||
GLuint _program { 0 };
|
||||
GLint _cameraCorrectionLocation { -1 };
|
||||
GLShader* _programShader { nullptr };
|
||||
bool _invalidProgram { false };
|
||||
|
||||
State::Data _stateCache { State::DEFAULT };
|
||||
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
|
||||
|
@ -323,7 +361,7 @@ protected:
|
|||
|
||||
void resetStages();
|
||||
|
||||
typedef void (GLBackend::*CommandCall)(Batch&, size_t);
|
||||
typedef void (GLBackend::*CommandCall)(const Batch&, size_t);
|
||||
static CommandCall _commandCalls[Batch::NUM_COMMANDS];
|
||||
friend class GLState;
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
void GLBackend::do_setInputFormat(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_setInputFormat(const Batch& batch, size_t paramOffset) {
|
||||
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
|
||||
|
||||
if (format != _input._format) {
|
||||
|
@ -23,7 +23,7 @@ void GLBackend::do_setInputFormat(Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setInputBuffer(Batch& batch, size_t paramOffset) {
|
||||
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);
|
||||
|
@ -116,7 +116,7 @@ void GLBackend::resetInputStage() {
|
|||
|
||||
}
|
||||
|
||||
void GLBackend::do_setIndexBuffer(Batch& batch, size_t paramOffset) {
|
||||
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;
|
||||
|
||||
|
@ -133,7 +133,7 @@ void GLBackend::do_setIndexBuffer(Batch& batch, size_t paramOffset) {
|
|||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_setIndirectBuffer(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_setIndirectBuffer(const Batch& batch, size_t paramOffset) {
|
||||
_input._indirectBufferOffset = batch._params[paramOffset + 1]._uint;
|
||||
_input._indirectBufferStride = batch._params[paramOffset + 2]._uint;
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ void GLBackend::resetOutputStage() {
|
|||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
|
||||
void GLBackend::do_setFramebuffer(Batch& batch, size_t paramOffset) {
|
||||
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);
|
||||
|
@ -47,7 +47,7 @@ void GLBackend::do_setFramebuffer(Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_clearFramebuffer(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||
if (_stereo._enable && !_pipeline._stateCache.scissorEnable) {
|
||||
qWarning("Clear without scissor in stereo mode");
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
||||
PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
if (_pipeline._pipeline == pipeline) {
|
||||
|
@ -34,13 +34,14 @@ void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) {
|
|||
_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(*pipeline);
|
||||
auto pipelineObject = GLPipeline::sync(*this, *pipeline);
|
||||
if (!pipelineObject) {
|
||||
return;
|
||||
}
|
||||
|
@ -53,6 +54,7 @@ void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) {
|
|||
_pipeline._program = glprogram;
|
||||
_pipeline._programShader = pipelineObject->_program;
|
||||
_pipeline._invalidProgram = true;
|
||||
_pipeline._cameraCorrectionLocation = pipelineObject->_cameraCorrection;
|
||||
}
|
||||
|
||||
// Now for the state
|
||||
|
@ -68,6 +70,10 @@ void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) {
|
|||
// 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;
|
||||
}
|
||||
|
@ -135,7 +141,7 @@ void GLBackend::resetUniformStage() {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setUniformBuffer(Batch& batch, size_t paramOffset) {
|
||||
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;
|
||||
|
@ -184,7 +190,7 @@ void GLBackend::resetResourceStage() {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 1]._uint;
|
||||
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ static bool timeElapsed = true;
|
|||
static bool timeElapsed = false;
|
||||
#endif
|
||||
|
||||
void GLBackend::do_beginQuery(Batch& batch, size_t paramOffset) {
|
||||
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) {
|
||||
|
@ -34,7 +34,7 @@ void GLBackend::do_beginQuery(Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_endQuery(Batch& batch, size_t paramOffset) {
|
||||
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) {
|
||||
|
@ -47,7 +47,7 @@ void GLBackend::do_endQuery(Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_getQuery(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) {
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
|
|
|
@ -290,7 +290,7 @@ void GLBackend::do_setStateColorWriteMask(uint32 mask) {
|
|||
}
|
||||
|
||||
|
||||
void GLBackend::do_setStateBlendFactor(Batch& batch, size_t paramOffset) {
|
||||
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,
|
||||
|
@ -300,9 +300,9 @@ void GLBackend::do_setStateBlendFactor(Batch& batch, size_t paramOffset) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateScissorRect(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_setStateScissorRect(const Batch& batch, size_t paramOffset) {
|
||||
Vec4i rect;
|
||||
memcpy(&rect, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i));
|
||||
memcpy(&rect, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i));
|
||||
|
||||
if (_stereo._enable) {
|
||||
rect.z /= 2;
|
||||
|
|
|
@ -14,7 +14,14 @@
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) {
|
||||
bool GLBackend::isTextureReady(const TexturePointer& texture) {
|
||||
// DO not transfer the texture, this call is expected for rendering texture
|
||||
GLTexture* object = syncGPUObject(texture, true);
|
||||
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;
|
||||
|
|
|
@ -14,21 +14,22 @@ using namespace gpu;
|
|||
using namespace gpu::gl;
|
||||
|
||||
// Transform Stage
|
||||
void GLBackend::do_setModelTransform(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_setModelTransform(const Batch& batch, size_t paramOffset) {
|
||||
}
|
||||
|
||||
void GLBackend::do_setViewTransform(Batch& batch, size_t paramOffset) {
|
||||
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(Batch& batch, size_t paramOffset) {
|
||||
memcpy(&_transform._projection, batch.editData(batch._params[paramOffset]._uint), sizeof(Mat4));
|
||||
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(Batch& batch, size_t paramOffset) {
|
||||
memcpy(&_transform._viewport, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i));
|
||||
void GLBackend::do_setViewportTransform(const Batch& batch, size_t paramOffset) {
|
||||
memcpy(&_transform._viewport, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i));
|
||||
|
||||
if (!_inRenderTransferPass && !isStereo()) {
|
||||
ivec4& vp = _transform._viewport;
|
||||
|
@ -39,7 +40,7 @@ void GLBackend::do_setViewportTransform(Batch& batch, size_t paramOffset) {
|
|||
_transform._invalidViewport = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setDepthRangeTransform(Batch& batch, size_t paramOffset) {
|
||||
void GLBackend::do_setDepthRangeTransform(const Batch& batch, size_t paramOffset) {
|
||||
|
||||
Vec2 depthRange(batch._params[paramOffset + 1]._float, batch._params[paramOffset + 0]._float);
|
||||
|
||||
|
@ -82,6 +83,16 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -7,20 +7,24 @@
|
|||
//
|
||||
|
||||
#include "GLBuffer.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
GLBuffer::~GLBuffer() {
|
||||
glDeleteBuffers(1, &_id);
|
||||
Backend::decrementBufferGPUCount();
|
||||
Backend::updateBufferGPUMemoryUsage(_size, 0);
|
||||
if (_id) {
|
||||
auto backend = _backend.lock();
|
||||
if (backend) {
|
||||
backend->releaseBuffer(_id, _size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLBuffer::GLBuffer(const Buffer& buffer, GLuint id) :
|
||||
GLObject(buffer, id),
|
||||
_size((GLuint)buffer._sysmem.getSize()),
|
||||
_stamp(buffer._sysmem.getStamp())
|
||||
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::incrementBufferGPUCount();
|
||||
Backend::updateBufferGPUMemoryUsage(0, _size);
|
||||
|
|
|
@ -9,21 +9,30 @@
|
|||
#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(const Buffer& buffer) {
|
||||
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.getSysmem().getStamp()) {
|
||||
object = new GLBufferType(buffer, object);
|
||||
if (!object || object->_stamp != buffer._renderSysmem.getStamp()) {
|
||||
object = new GLBufferType(backend.shared_from_this(), buffer, object);
|
||||
}
|
||||
|
||||
if (0 != (buffer._flags & Buffer::DIRTY)) {
|
||||
if (0 != (buffer._renderPages._flags & PageManager::DIRTY)) {
|
||||
object->transfer();
|
||||
}
|
||||
|
||||
|
@ -31,8 +40,8 @@ public:
|
|||
}
|
||||
|
||||
template <typename GLBufferType>
|
||||
static GLuint getId(const Buffer& buffer) {
|
||||
GLBuffer* bo = sync<GLBufferType>(buffer);
|
||||
static GLuint getId(GLBackend& backend, const Buffer& buffer) {
|
||||
GLBuffer* bo = sync<GLBufferType>(backend, buffer);
|
||||
if (bo) {
|
||||
return bo->_buffer;
|
||||
} else {
|
||||
|
@ -49,7 +58,7 @@ public:
|
|||
virtual void transfer() = 0;
|
||||
|
||||
protected:
|
||||
GLBuffer(const Buffer& buffer, GLuint id);
|
||||
GLBuffer(const std::weak_ptr<GLBackend>& backend, const Buffer& buffer, GLuint id);
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -7,10 +7,19 @@
|
|||
//
|
||||
|
||||
#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;
|
||||
|
|
|
@ -9,13 +9,14 @@
|
|||
#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(const Framebuffer& framebuffer) {
|
||||
static GLFramebufferType* sync(GLBackend& backend, const Framebuffer& framebuffer) {
|
||||
GLFramebufferType* object = Backend::getGPUObject<GLFramebufferType>(framebuffer);
|
||||
|
||||
bool needsUpate { false };
|
||||
|
@ -36,7 +37,7 @@ public:
|
|||
// need to have a gpu object?
|
||||
if (!object) {
|
||||
// All is green, assign the gpuobject to the Framebuffer
|
||||
object = new GLFramebufferType(framebuffer);
|
||||
object = new GLFramebufferType(backend.shared_from_this(), framebuffer);
|
||||
Backend::setGPUObject(framebuffer, object);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
@ -46,8 +47,8 @@ public:
|
|||
}
|
||||
|
||||
template <typename GLFramebufferType>
|
||||
static GLuint getId(const Framebuffer& framebuffer) {
|
||||
GLFramebufferType* fbo = sync<GLFramebufferType>(framebuffer);
|
||||
static GLuint getId(GLBackend& backend, const Framebuffer& framebuffer) {
|
||||
GLFramebufferType* fbo = sync<GLFramebufferType>(backend, framebuffer);
|
||||
if (fbo) {
|
||||
return fbo->_id;
|
||||
} else {
|
||||
|
@ -65,8 +66,8 @@ protected:
|
|||
virtual void update() = 0;
|
||||
bool checkStatus(GLenum target) const;
|
||||
|
||||
GLFramebuffer(const Framebuffer& framebuffer, GLuint id) : GLObject(framebuffer, id) {}
|
||||
~GLFramebuffer() { if (_id) { glDeleteFramebuffers(1, &_id); } };
|
||||
GLFramebuffer(const std::weak_ptr<GLBackend>& backend, const Framebuffer& framebuffer, GLuint id) : GLObject(backend, framebuffer, id) {}
|
||||
~GLFramebuffer();
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
GLPipeline* GLPipeline::sync(const Pipeline& pipeline) {
|
||||
GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) {
|
||||
GLPipeline* object = Backend::getGPUObject<GLPipeline>(pipeline);
|
||||
|
||||
// If GPU object already created then good
|
||||
|
@ -30,7 +30,7 @@ GLPipeline* GLPipeline::sync(const Pipeline& pipeline) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
GLShader* programObject = GLShader::sync(*shader);
|
||||
GLShader* programObject = GLShader::sync(backend, *shader);
|
||||
if (programObject == nullptr) {
|
||||
shader->setCompilationHasFailed(true);
|
||||
return nullptr;
|
||||
|
@ -48,6 +48,10 @@ GLPipeline* GLPipeline::sync(const Pipeline& pipeline) {
|
|||
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.
|
||||
object->_cameraCorrection = shader->getBuffers().findLocation("cameraCorrectionBuffer");
|
||||
object->_program = programObject;
|
||||
object->_state = stateObject;
|
||||
|
||||
|
|
|
@ -14,10 +14,13 @@ namespace gpu { namespace gl {
|
|||
|
||||
class GLPipeline : public GPUObject {
|
||||
public:
|
||||
static GLPipeline* sync(const Pipeline& pipeline);
|
||||
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 };
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define hifi_gpu_gl_GLQuery_h
|
||||
|
||||
#include "GLShared.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
|
@ -16,13 +17,13 @@ class GLQuery : public GLObject<Query> {
|
|||
using Parent = gpu::gl::GLObject<Query>;
|
||||
public:
|
||||
template <typename GLQueryType>
|
||||
static GLQueryType* sync(const Query& query) {
|
||||
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(query);
|
||||
object = new GLQueryType(backend.shared_from_this(), query);
|
||||
(void)CHECK_GL_ERROR();
|
||||
Backend::setGPUObject(query, object);
|
||||
}
|
||||
|
@ -31,12 +32,12 @@ public:
|
|||
}
|
||||
|
||||
template <typename GLQueryType>
|
||||
static GLuint getId(const QueryPointer& query) {
|
||||
static GLuint getId(GLBackend& backend, const QueryPointer& query) {
|
||||
if (!query) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLQuery* object = sync<GLQueryType>(*query);
|
||||
GLQuery* object = sync<GLQueryType>(backend, *query);
|
||||
if (!object) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -49,7 +50,7 @@ public:
|
|||
GLuint64 _result { (GLuint64)-1 };
|
||||
|
||||
protected:
|
||||
GLQuery(const Query& query, GLuint endId, GLuint beginId) : Parent(query, endId), _beginqo(beginId){}
|
||||
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 };
|
||||
|
|
|
@ -11,16 +11,19 @@
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
GLShader::GLShader() {
|
||||
GLShader::GLShader(const std::weak_ptr<GLBackend>& backend) : _backend(backend) {
|
||||
}
|
||||
|
||||
GLShader::~GLShader() {
|
||||
for (auto& so : _shaderObjects) {
|
||||
if (so.glshader != 0) {
|
||||
glDeleteShader(so.glshader);
|
||||
}
|
||||
if (so.glprogram != 0) {
|
||||
glDeleteProgram(so.glprogram);
|
||||
auto backend = _backend.lock();
|
||||
if (backend) {
|
||||
if (so.glshader != 0) {
|
||||
backend->releaseShader(so.glshader);
|
||||
}
|
||||
if (so.glprogram != 0) {
|
||||
backend->releaseProgram(so.glprogram);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +57,7 @@ static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
|
|||
""
|
||||
} };
|
||||
|
||||
GLShader* compileBackendShader(const Shader& shader) {
|
||||
GLShader* compileBackendShader(GLBackend& backend, const Shader& shader) {
|
||||
// Any GLSLprogram ? normally yes...
|
||||
const std::string& shaderSource = shader.getSource().getCode();
|
||||
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
|
||||
|
@ -72,13 +75,13 @@ GLShader* compileBackendShader(const Shader& shader) {
|
|||
}
|
||||
|
||||
// So far so good, the shader is created successfully
|
||||
GLShader* object = new GLShader();
|
||||
GLShader* object = new GLShader(backend.shared_from_this());
|
||||
object->_shaderObjects = shaderObjects;
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
GLShader* compileBackendProgram(const Shader& program) {
|
||||
GLShader* compileBackendProgram(GLBackend& backend, const Shader& program) {
|
||||
if (!program.isProgram()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -91,7 +94,7 @@ GLShader* compileBackendProgram(const Shader& program) {
|
|||
// 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(*subShader);
|
||||
auto object = GLShader::sync(backend, *subShader);
|
||||
if (object) {
|
||||
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
|
||||
} else {
|
||||
|
@ -111,13 +114,13 @@ GLShader* compileBackendProgram(const Shader& program) {
|
|||
}
|
||||
|
||||
// So far so good, the program versions have all been created successfully
|
||||
GLShader* object = new GLShader();
|
||||
GLShader* object = new GLShader(backend.shared_from_this());
|
||||
object->_shaderObjects = programObjects;
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
GLShader* GLShader::sync(const Shader& shader) {
|
||||
GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
|
||||
GLShader* object = Backend::getGPUObject<GLShader>(shader);
|
||||
|
||||
// If GPU object already created then good
|
||||
|
@ -126,26 +129,27 @@ GLShader* GLShader::sync(const Shader& shader) {
|
|||
}
|
||||
// need to have a gpu object?
|
||||
if (shader.isProgram()) {
|
||||
GLShader* tempObject = compileBackendProgram(shader);
|
||||
GLShader* tempObject = compileBackendProgram(backend, shader);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
} else if (shader.isDomain()) {
|
||||
GLShader* tempObject = compileBackendShader(shader);
|
||||
GLShader* tempObject = compileBackendShader(backend, shader);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
}
|
||||
|
||||
glFinish();
|
||||
return object;
|
||||
}
|
||||
|
||||
bool GLShader::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
|
||||
bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings) {
|
||||
|
||||
// First make sure the Shader has been compiled
|
||||
GLShader* object = sync(shader);
|
||||
GLShader* object = sync(backend, shader);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
|
@ -181,7 +185,6 @@ bool GLShader::makeProgram(Shader& shader, const Shader::BindingSet& slotBinding
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ namespace gpu { namespace gl {
|
|||
|
||||
class GLShader : public GPUObject {
|
||||
public:
|
||||
static GLShader* sync(const Shader& shader);
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings);
|
||||
static GLShader* sync(GLBackend& backend, const Shader& shader);
|
||||
static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings);
|
||||
|
||||
enum Version {
|
||||
Mono = 0,
|
||||
|
@ -28,7 +28,7 @@ public:
|
|||
using UniformMapping = std::map<GLint, GLint>;
|
||||
using UniformMappingVersions = std::vector<UniformMapping>;
|
||||
|
||||
GLShader();
|
||||
GLShader(const std::weak_ptr<GLBackend>& backend);
|
||||
~GLShader();
|
||||
|
||||
ShaderObjects _shaderObjects;
|
||||
|
@ -44,6 +44,7 @@ public:
|
|||
return srcLoc;
|
||||
}
|
||||
|
||||
const std::weak_ptr<GLBackend> _backend;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -557,46 +557,67 @@ int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindin
|
|||
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++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLint binding = -1;
|
||||
uniformBlocks.push_back(UniformBlockInfo(glprogram, i));
|
||||
}
|
||||
|
||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length);
|
||||
glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, name);
|
||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding);
|
||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
|
||||
|
||||
GLuint blockIndex = glGetUniformBlockIndex(glprogram, name);
|
||||
|
||||
// CHeck if there is a requested binding for this block
|
||||
auto requestedBinding = slotBindings.find(std::string(name));
|
||||
for (auto& info : uniformBlocks) {
|
||||
auto requestedBinding = slotBindings.find(info.name);
|
||||
if (requestedBinding != slotBindings.end()) {
|
||||
// If yes force it
|
||||
if (binding != (*requestedBinding)._location) {
|
||||
binding = (*requestedBinding)._location;
|
||||
glUniformBlockBinding(glprogram, blockIndex, binding);
|
||||
}
|
||||
} else if (binding == 0) {
|
||||
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()) {
|
||||
binding = slotIt - uniformBufferSlotMap.begin();
|
||||
glUniformBlockBinding(glprogram, blockIndex, binding);
|
||||
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?!
|
||||
binding = -1;
|
||||
info.binding = -1;
|
||||
}
|
||||
}
|
||||
// If binding is valid record it
|
||||
if (binding >= 0) {
|
||||
uniformBufferSlotMap[binding] = blockIndex;
|
||||
}
|
||||
|
||||
Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER);
|
||||
buffers.insert(Shader::Slot(name, binding, element, Resource::BUFFER, size));
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -121,15 +121,19 @@ static const GLenum ELEMENT_TYPE_TO_GL[gpu::NUM_TYPES] = {
|
|||
bool checkGLError(const char* name = nullptr);
|
||||
bool checkGLErrorDebug(const char* name = nullptr);
|
||||
|
||||
class GLBackend;
|
||||
|
||||
template <typename GPUType>
|
||||
struct GLObject : public GPUObject {
|
||||
public:
|
||||
GLObject(const GPUType& gpuObject, GLuint id) : _gpuObject(gpuObject), _id(id) {}
|
||||
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;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <NumericalConstants.h>
|
||||
|
||||
#include "GLTextureTransfer.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
@ -117,7 +118,9 @@ float GLTexture::getMemoryPressure() {
|
|||
return (float)consumedGpuMemory / (float)availableTextureMemory;
|
||||
}
|
||||
|
||||
GLTexture::DownsampleSource::DownsampleSource(GLTexture* oldTexture) :
|
||||
GLTexture::DownsampleSource::DownsampleSource(const std::weak_ptr<gl::GLBackend>& backend, GLTexture* oldTexture) :
|
||||
_backend(backend),
|
||||
_size(oldTexture ? oldTexture->_size : 0),
|
||||
_texture(oldTexture ? oldTexture->takeOwnership() : 0),
|
||||
_minMip(oldTexture ? oldTexture->_minMip : 0),
|
||||
_maxMip(oldTexture ? oldTexture->_maxMip : 0)
|
||||
|
@ -126,20 +129,22 @@ GLTexture::DownsampleSource::DownsampleSource(GLTexture* oldTexture) :
|
|||
|
||||
GLTexture::DownsampleSource::~DownsampleSource() {
|
||||
if (_texture) {
|
||||
glDeleteTextures(1, &_texture);
|
||||
Backend::decrementTextureGPUCount();
|
||||
auto backend = _backend.lock();
|
||||
if (backend) {
|
||||
backend->releaseTexture(_texture, _size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLTexture::GLTexture(const gpu::Texture& texture, GLuint id, GLTexture* originalTexture, bool transferrable) :
|
||||
GLObject(texture, id),
|
||||
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture, bool transferrable) :
|
||||
GLObject(backend, texture, id),
|
||||
_storageStamp(texture.getStamp()),
|
||||
_target(getGLTextureType(texture)),
|
||||
_maxMip(texture.maxMip()),
|
||||
_minMip(texture.minMip()),
|
||||
_virtualSize(texture.evalTotalSize()),
|
||||
_transferrable(transferrable),
|
||||
_downsampleSource(originalTexture)
|
||||
_downsampleSource(backend, originalTexture)
|
||||
{
|
||||
if (_transferrable) {
|
||||
uint16 mipCount = usedMipLevels();
|
||||
|
@ -156,8 +161,8 @@ GLTexture::GLTexture(const gpu::Texture& texture, GLuint id, GLTexture* original
|
|||
|
||||
|
||||
// Create the texture and allocate storage
|
||||
GLTexture::GLTexture(const Texture& texture, GLuint id, bool transferrable) :
|
||||
GLTexture(texture, id, nullptr, transferrable)
|
||||
GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) :
|
||||
GLTexture(backend, texture, id, nullptr, transferrable)
|
||||
{
|
||||
// FIXME, do during allocation
|
||||
//Backend::updateTextureGPUMemoryUsage(0, _size);
|
||||
|
@ -165,8 +170,8 @@ GLTexture::GLTexture(const Texture& texture, GLuint id, bool transferrable) :
|
|||
}
|
||||
|
||||
// Create the texture and copy from the original higher resolution version
|
||||
GLTexture::GLTexture(const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
|
||||
GLTexture(texture, id, originalTexture, originalTexture->_transferrable)
|
||||
GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
|
||||
GLTexture(backend, texture, id, originalTexture, originalTexture->_transferrable)
|
||||
{
|
||||
Q_ASSERT(_minMip >= originalTexture->_minMip);
|
||||
// Set the GPU object last because that implicitly destroys the originalTexture object
|
||||
|
@ -188,11 +193,11 @@ GLTexture::~GLTexture() {
|
|||
}
|
||||
|
||||
if (_id) {
|
||||
glDeleteTextures(1, &_id);
|
||||
const_cast<GLuint&>(_id) = 0;
|
||||
Backend::decrementTextureGPUCount();
|
||||
auto backend = _backend.lock();
|
||||
if (backend) {
|
||||
backend->releaseTexture(_id, _size);
|
||||
}
|
||||
}
|
||||
Backend::updateTextureGPUMemoryUsage(_size, 0);
|
||||
Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "GLShared.h"
|
||||
#include "GLTextureTransfer.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
|
@ -24,7 +25,7 @@ public:
|
|||
static std::shared_ptr<GLTextureTransferHelper> _textureTransferHelper;
|
||||
|
||||
template <typename GLTextureType>
|
||||
static GLTextureType* sync(const TexturePointer& texturePointer, bool needTransfer) {
|
||||
static GLTextureType* sync(GLBackend& backend, const TexturePointer& texturePointer, bool needTransfer) {
|
||||
const Texture& texture = *texturePointer;
|
||||
if (!texture.isDefined()) {
|
||||
// NO texture definition yet so let's avoid thinking
|
||||
|
@ -38,7 +39,7 @@ public:
|
|||
// for easier use of immutable storage)
|
||||
if (!object || object->isInvalid()) {
|
||||
// This automatically any previous texture
|
||||
object = new GLTextureType(texture, needTransfer);
|
||||
object = new GLTextureType(backend.shared_from_this(), texture, needTransfer);
|
||||
if (!object->_transferrable) {
|
||||
object->createTexture();
|
||||
object->_contentStamp = texture.getDataStamp();
|
||||
|
@ -62,7 +63,7 @@ public:
|
|||
if (object->isOverMaxMemory() && texturePointer->incremementMinMip()) {
|
||||
// WARNING, this code path will essentially `delete this`,
|
||||
// so no dereferencing of this instance should be done past this point
|
||||
object = new GLTextureType(texture, object);
|
||||
object = new GLTextureType(backend.shared_from_this(), texture, object);
|
||||
_textureTransferHelper->transferTexture(texturePointer);
|
||||
}
|
||||
} else if (object->isOutdated()) {
|
||||
|
@ -75,13 +76,13 @@ public:
|
|||
}
|
||||
|
||||
template <typename GLTextureType>
|
||||
static GLuint getId(const TexturePointer& texture, bool shouldSync) {
|
||||
static GLuint getId(GLBackend& backend, const TexturePointer& texture, bool shouldSync) {
|
||||
if (!texture) {
|
||||
return 0;
|
||||
}
|
||||
GLTextureType* object { nullptr };
|
||||
if (shouldSync) {
|
||||
object = sync<GLTextureType>(texture, shouldSync);
|
||||
object = sync<GLTextureType>(backend, texture, shouldSync);
|
||||
} else {
|
||||
object = Backend::getGPUObject<GLTextureType>(*texture);
|
||||
}
|
||||
|
@ -92,11 +93,13 @@ public:
|
|||
GLuint result = object->_id;
|
||||
|
||||
// Don't return textures that are in transfer state
|
||||
if ((object->getSyncState() != GLSyncState::Idle) ||
|
||||
// Don't return transferrable textures that have never completed transfer
|
||||
(!object->_transferrable || 0 != object->_transferCount)) {
|
||||
// Will be either 0 or the original texture being downsampled.
|
||||
result = object->_downsampleSource._texture;
|
||||
if (shouldSync) {
|
||||
if ((object->getSyncState() != GLSyncState::Idle) ||
|
||||
// Don't return transferrable textures that have never completed transfer
|
||||
(!object->_transferrable || 0 != object->_transferCount)) {
|
||||
// Will be either 0 or the original texture being downsampled.
|
||||
result = object->_downsampleSource._texture;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -123,10 +126,12 @@ public:
|
|||
|
||||
struct DownsampleSource {
|
||||
using Pointer = std::shared_ptr<DownsampleSource>;
|
||||
DownsampleSource() : _texture(0), _minMip(0), _maxMip(0) {}
|
||||
DownsampleSource(GLTexture* originalTexture);
|
||||
DownsampleSource(const std::weak_ptr<gl::GLBackend>& backend) : _backend(backend), _size(0), _texture(0), _minMip(0), _maxMip(0) {}
|
||||
DownsampleSource(const std::weak_ptr<gl::GLBackend>& backend, GLTexture* originalTexture);
|
||||
~DownsampleSource();
|
||||
void reset() const { const_cast<GLuint&>(_texture) = 0; }
|
||||
const std::weak_ptr<gl::GLBackend>& _backend;
|
||||
const GLuint _size { 0 };
|
||||
const GLuint _texture { 0 };
|
||||
const uint16 _minMip { 0 };
|
||||
const uint16 _maxMip { 0 };
|
||||
|
@ -168,8 +173,8 @@ protected:
|
|||
const GLuint _size { 0 }; // true size as reported by the gl api
|
||||
std::atomic<GLSyncState> _syncState { GLSyncState::Idle };
|
||||
|
||||
GLTexture(const Texture& texture, GLuint id, bool transferrable);
|
||||
GLTexture(const Texture& texture, GLuint id, GLTexture* originalTexture);
|
||||
GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable);
|
||||
GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, GLTexture* originalTexture);
|
||||
|
||||
void setSyncState(GLSyncState syncState) { _syncState = syncState; }
|
||||
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
|
||||
|
@ -188,7 +193,7 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
GLTexture(const gpu::Texture& gpuTexture, GLuint id, GLTexture* originalTexture, bool transferrable);
|
||||
GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& gpuTexture, GLuint id, GLTexture* originalTexture, bool transferrable);
|
||||
|
||||
friend class GLTextureTransferHelper;
|
||||
friend class GLBackend;
|
||||
|
|
|
@ -18,7 +18,7 @@ Q_LOGGING_CATEGORY(gpugl41logging, "hifi.gpu.gl41")
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl41;
|
||||
|
||||
void GL41Backend::do_draw(Batch& batch, size_t paramOffset) {
|
||||
void GL41Backend::do_draw(const Batch& batch, size_t paramOffset) {
|
||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
||||
GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType];
|
||||
uint32 numVertices = batch._params[paramOffset + 1]._uint;
|
||||
|
@ -43,7 +43,7 @@ void GL41Backend::do_draw(Batch& batch, size_t paramOffset) {
|
|||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GL41Backend::do_drawIndexed(Batch& batch, size_t paramOffset) {
|
||||
void GL41Backend::do_drawIndexed(const Batch& batch, size_t paramOffset) {
|
||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
||||
GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType];
|
||||
uint32 numIndices = batch._params[paramOffset + 1]._uint;
|
||||
|
@ -72,7 +72,7 @@ void GL41Backend::do_drawIndexed(Batch& batch, size_t paramOffset) {
|
|||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GL41Backend::do_drawInstanced(Batch& batch, size_t paramOffset) {
|
||||
void GL41Backend::do_drawInstanced(const Batch& batch, size_t paramOffset) {
|
||||
GLint numInstances = batch._params[paramOffset + 4]._uint;
|
||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 3]._uint;
|
||||
GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType];
|
||||
|
@ -108,7 +108,7 @@ void glbackend_glDrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsize
|
|||
#endif
|
||||
}
|
||||
|
||||
void GL41Backend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) {
|
||||
void GL41Backend::do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) {
|
||||
GLint numInstances = batch._params[paramOffset + 4]._uint;
|
||||
GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 3]._uint];
|
||||
uint32 numIndices = batch._params[paramOffset + 2]._uint;
|
||||
|
@ -143,7 +143,7 @@ void GL41Backend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
|
||||
|
||||
void GL41Backend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) {
|
||||
void GL41Backend::do_multiDrawIndirect(const Batch& batch, size_t paramOffset) {
|
||||
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
|
||||
uint commandCount = batch._params[paramOffset + 0]._uint;
|
||||
GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint];
|
||||
|
@ -159,7 +159,7 @@ void GL41Backend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) {
|
|||
|
||||
}
|
||||
|
||||
void GL41Backend::do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) {
|
||||
void GL41Backend::do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffset) {
|
||||
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
|
||||
uint commandCount = batch._params[paramOffset + 0]._uint;
|
||||
GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint];
|
||||
|
|
|
@ -40,8 +40,8 @@ public:
|
|||
using Parent = gpu::gl::GLTexture;
|
||||
GLuint allocate();
|
||||
public:
|
||||
GL41Texture(const Texture& buffer, bool transferrable);
|
||||
GL41Texture(const Texture& buffer, GL41Texture* original);
|
||||
GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& buffer, bool transferrable);
|
||||
GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& buffer, GL41Texture* original);
|
||||
|
||||
protected:
|
||||
void transferMip(uint16_t mipLevel, uint8_t face = 0) const;
|
||||
|
@ -68,12 +68,12 @@ protected:
|
|||
gl::GLQuery* syncGPUObject(const Query& query) override;
|
||||
|
||||
// Draw Stage
|
||||
void do_draw(Batch& batch, size_t paramOffset) override;
|
||||
void do_drawIndexed(Batch& batch, size_t paramOffset) override;
|
||||
void do_drawInstanced(Batch& batch, size_t paramOffset) override;
|
||||
void do_drawIndexedInstanced(Batch& batch, size_t paramOffset) override;
|
||||
void do_multiDrawIndirect(Batch& batch, size_t paramOffset) override;
|
||||
void do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) override;
|
||||
void do_draw(const Batch& batch, size_t paramOffset) override;
|
||||
void do_drawIndexed(const Batch& batch, size_t paramOffset) override;
|
||||
void do_drawInstanced(const Batch& batch, size_t paramOffset) override;
|
||||
void do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) override;
|
||||
void do_multiDrawIndirect(const Batch& batch, size_t paramOffset) override;
|
||||
void do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffset) override;
|
||||
|
||||
// Input Stage
|
||||
void updateInput() override;
|
||||
|
@ -85,7 +85,7 @@ protected:
|
|||
void resetTransformStage();
|
||||
|
||||
// Output stage
|
||||
void do_blit(Batch& batch, size_t paramOffset) override;
|
||||
void do_blit(const Batch& batch, size_t paramOffset) override;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -8,55 +8,60 @@
|
|||
#include "GL41Backend.h"
|
||||
#include "../gl/GLBuffer.h"
|
||||
|
||||
namespace gpu {
|
||||
namespace gl41 {
|
||||
class GL41Buffer : public gl::GLBuffer {
|
||||
using Parent = gpu::gl::GLBuffer;
|
||||
static GLuint allocate() {
|
||||
GLuint result;
|
||||
glGenBuffers(1, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
GL41Buffer(const std::weak_ptr<gl::GLBackend>& backend, const Buffer& buffer, GL41Buffer* original) : Parent(backend, buffer, allocate()) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, _size, nullptr, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
if (original && original->_size) {
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer);
|
||||
glBindBuffer(GL_COPY_READ_BUFFER, original->_buffer);
|
||||
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, original->_size);
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
|
||||
glBindBuffer(GL_COPY_READ_BUFFER, 0);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
Backend::setGPUObject(buffer, this);
|
||||
}
|
||||
|
||||
void transfer() override {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
|
||||
(void)CHECK_GL_ERROR();
|
||||
Size offset;
|
||||
Size size;
|
||||
Size currentPage { 0 };
|
||||
auto data = _gpuObject._renderSysmem.readData();
|
||||
while (_gpuObject._renderPages.getNextTransferBlock(offset, size, currentPage)) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, offset, size, data + offset);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
(void)CHECK_GL_ERROR();
|
||||
_gpuObject._renderPages._flags &= ~PageManager::DIRTY;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl41;
|
||||
|
||||
class GL41Buffer : public gl::GLBuffer {
|
||||
using Parent = gpu::gl::GLBuffer;
|
||||
static GLuint allocate() {
|
||||
GLuint result;
|
||||
glGenBuffers(1, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
GL41Buffer(const Buffer& buffer, GL41Buffer* original) : Parent(buffer, allocate()) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, _size, nullptr, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
if (original && original->_size) {
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer);
|
||||
glBindBuffer(GL_COPY_READ_BUFFER, original->_buffer);
|
||||
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, original->_size);
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
|
||||
glBindBuffer(GL_COPY_READ_BUFFER, 0);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
Backend::setGPUObject(buffer, this);
|
||||
}
|
||||
|
||||
void transfer() override {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
|
||||
(void)CHECK_GL_ERROR();
|
||||
Size offset;
|
||||
Size size;
|
||||
Size currentPage { 0 };
|
||||
auto data = _gpuObject.getSysmem().readData();
|
||||
while (_gpuObject.getNextTransferBlock(offset, size, currentPage)) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, offset, size, data + offset);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
(void)CHECK_GL_ERROR();
|
||||
_gpuObject._flags &= ~Buffer::DIRTY;
|
||||
}
|
||||
};
|
||||
|
||||
GLuint GL41Backend::getBufferID(const Buffer& buffer) {
|
||||
return GL41Buffer::getId<GL41Buffer>(buffer);
|
||||
return GL41Buffer::getId<GL41Buffer>(*this, buffer);
|
||||
}
|
||||
|
||||
gl::GLBuffer* GL41Backend::syncGPUObject(const Buffer& buffer) {
|
||||
return GL41Buffer::sync<GL41Buffer>(buffer);
|
||||
return GL41Buffer::sync<GL41Buffer>(*this, buffer);
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
for (auto& b : _gpuObject.getRenderBuffers()) {
|
||||
surface = b._texture;
|
||||
if (surface) {
|
||||
gltexture = gl::GLTexture::sync<GL41Backend::GL41Texture>(surface, false); // Grab the gltexture and don't transfer
|
||||
gltexture = gl::GLTexture::sync<GL41Backend::GL41Texture>(*_backend.lock().get(), surface, false); // Grab the gltexture and don't transfer
|
||||
} else {
|
||||
gltexture = nullptr;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public:
|
|||
if (_gpuObject.getDepthStamp() != _depthStamp) {
|
||||
auto surface = _gpuObject.getDepthStencilBuffer();
|
||||
if (_gpuObject.hasDepthStencil() && surface) {
|
||||
gltexture = gl::GLTexture::sync<GL41Backend::GL41Texture>(surface, false); // Grab the gltexture and don't transfer
|
||||
gltexture = gl::GLTexture::sync<GL41Backend::GL41Texture>(*_backend.lock().get(), surface, false); // Grab the gltexture and don't transfer
|
||||
}
|
||||
|
||||
if (gltexture) {
|
||||
|
@ -115,19 +115,19 @@ public:
|
|||
|
||||
|
||||
public:
|
||||
GL41Framebuffer(const gpu::Framebuffer& framebuffer)
|
||||
: Parent(framebuffer, allocate()) { }
|
||||
GL41Framebuffer(const std::weak_ptr<gl::GLBackend>& backend, const gpu::Framebuffer& framebuffer)
|
||||
: Parent(backend, framebuffer, allocate()) { }
|
||||
};
|
||||
|
||||
gl::GLFramebuffer* GL41Backend::syncGPUObject(const Framebuffer& framebuffer) {
|
||||
return GL41Framebuffer::sync<GL41Framebuffer>(framebuffer);
|
||||
return GL41Framebuffer::sync<GL41Framebuffer>(*this, framebuffer);
|
||||
}
|
||||
|
||||
GLuint GL41Backend::getFramebufferID(const FramebufferPointer& framebuffer) {
|
||||
return framebuffer ? GL41Framebuffer::getId<GL41Framebuffer>(*framebuffer) : 0;
|
||||
return framebuffer ? GL41Framebuffer::getId<GL41Framebuffer>(*this, *framebuffer) : 0;
|
||||
}
|
||||
|
||||
void GL41Backend::do_blit(Batch& batch, size_t paramOffset) {
|
||||
void GL41Backend::do_blit(const Batch& batch, size_t paramOffset) {
|
||||
auto srcframebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
|
||||
Vec4i srcvp;
|
||||
for (auto i = 0; i < 4; ++i) {
|
||||
|
|
|
@ -24,14 +24,14 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
GL41Query(const Query& query)
|
||||
: Parent(query, allocateQuery(), allocateQuery()) { }
|
||||
GL41Query(const std::weak_ptr<gl::GLBackend>& backend, const Query& query)
|
||||
: Parent(backend, query, allocateQuery(), allocateQuery()) { }
|
||||
};
|
||||
|
||||
gl::GLQuery* GL41Backend::syncGPUObject(const Query& query) {
|
||||
return GL41Query::sync<GL41Query>(query);
|
||||
return GL41Query::sync<GL41Query>(*this, query);
|
||||
}
|
||||
|
||||
GLuint GL41Backend::getQueryID(const QueryPointer& query) {
|
||||
return GL41Query::getId<GL41Query>(query);
|
||||
return GL41Query::getId<GL41Query>(*this, query);
|
||||
}
|
||||
|
|
|
@ -30,16 +30,16 @@ GLuint GL41Texture::allocate() {
|
|||
}
|
||||
|
||||
GLuint GL41Backend::getTextureID(const TexturePointer& texture, bool transfer) {
|
||||
return GL41Texture::getId<GL41Texture>(texture, transfer);
|
||||
return GL41Texture::getId<GL41Texture>(*this, texture, transfer);
|
||||
}
|
||||
|
||||
gl::GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
|
||||
return GL41Texture::sync<GL41Texture>(texture, transfer);
|
||||
return GL41Texture::sync<GL41Texture>(*this, texture, transfer);
|
||||
}
|
||||
|
||||
GL41Texture::GL41Texture(const Texture& texture, bool transferrable) : gl::GLTexture(texture, allocate(), transferrable) {}
|
||||
GL41Texture::GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, bool transferrable) : gl::GLTexture(backend, texture, allocate(), transferrable) {}
|
||||
|
||||
GL41Texture::GL41Texture(const Texture& texture, GL41Texture* original) : gl::GLTexture(texture, allocate(), original) {}
|
||||
GL41Texture::GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GL41Texture* original) : gl::GLTexture(backend, texture, allocate(), original) {}
|
||||
|
||||
void GL41Backend::GL41Texture::withPreservedTexture(std::function<void()> f) const {
|
||||
GLint boundTex = -1;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue