From b1eb0b0a46fabdea7ca3122a64253c7265b95095 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Wed, 30 Jan 2019 13:10:52 -0800
Subject: [PATCH] GPU tweaks

---
 .../gpu-gl-common/src/gpu/gl/GLBackend.cpp    |  3 +
 .../gpu-gl-common/src/gpu/gl/GLBackend.h      |  2 +-
 libraries/gpu-gles/src/gpu/gles/GLESBackend.h |  1 +
 .../src/gpu/gles/GLESBackendOutput.cpp        | 66 ++++++++++++++++++-
 libraries/gpu/src/gpu/Context.h               |  3 +-
 5 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp
index 82f4f97e3b..1cf331cd1a 100644
--- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp
@@ -426,6 +426,9 @@ void GLBackend::render(const Batch& batch) {
     GL_PROFILE_RANGE(render_gpu_gl, batch.getName().c_str());
 
     _transform._skybox = _stereo._skybox = batch.isSkyboxEnabled();
+    // FIXME move this to between the transfer and draw passes, so that
+    // framebuffer setup can see the proper stereo state and enable things 
+    // like foveation
     // Allow the batch to override the rendering stereo settings
     // for things like full framebuffer copy operations (deferred lighting passes)
     bool savedStereo = _stereo._enable;
diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h
index b5a279a54c..671d4e11d7 100644
--- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h
@@ -95,7 +95,7 @@ public:
     // Shutdown rendering and persist any required resources
     void shutdown() override;
 
-    void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false);
+    void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) override;
     void render(const Batch& batch) final override;
 
     // This call synchronize the Full Backend cache with the current GLState
diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h
index aaa1be5892..636518c85a 100644
--- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h
+++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h
@@ -48,6 +48,7 @@ public:
     class GLESTexture : public GLTexture {
         using Parent = GLTexture;
         friend class GLESBackend;
+        friend class GLESFramebuffer;
         GLuint allocate(const Texture& texture);
     protected:
         GLESTexture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer);
diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp
index 9c3a83ce13..90ce8c853a 100644
--- a/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp
+++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendOutput.cpp
@@ -17,6 +17,34 @@
 
 namespace gpu { namespace gles { 
 
+
+// returns the FOV from the projection matrix
+static inline vec4 extractFov( const glm::mat4& m) {
+    static const std::array<vec4, 4> CLIPS{ {
+                                                { 1, 0, 0, 1 },
+                                                { -1, 0, 0, 1 },
+                                                { 0, 1, 0, 1 },
+                                                { 0, -1, 0, 1 }
+                                            } };
+
+    glm::mat4 mt = glm::transpose(m);
+    vec4 v, result;
+    // Left
+    v = mt * CLIPS[0];
+    result.x = -atanf(v.z / v.x);
+    // Right
+    v = mt * CLIPS[1];
+    result.y = atanf(v.z / v.x);
+    // Down
+    v = mt * CLIPS[2];
+    result.z = -atanf(v.z / v.y);
+    // Up
+    v = mt * CLIPS[3];
+    result.w = atanf(v.z / v.y);
+    return result;
+}
+
+
 class GLESFramebuffer : public gl::GLFramebuffer {
     using Parent = gl::GLFramebuffer;
     static GLuint allocate() {
@@ -29,6 +57,24 @@ public:
         GLint currentFBO = -1;
         glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &currentFBO);
         glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
+
+        vec2 focalPoint{ -1.0f };
+
+#if 0
+        {
+            auto backend = _backend.lock();
+            if (backend && backend->isStereo()) {
+                glm::mat4 projections[2];
+                backend->getStereoProjections(projections);
+                vec4 fov = extractFov(projections[0]);
+                float fovwidth = fov.x + fov.y;
+                float fovheight = fov.z + fov.w;
+                focalPoint.x = fov.y / fovwidth;
+                focalPoint.y = (fov.z / fovheight) - 0.5f;
+            }
+        }
+#endif
+
         gl::GLTexture* gltexture = nullptr;
         TexturePointer surface;
         if (_gpuObject.getColorStamps() != _colorStamps) {
@@ -58,7 +104,7 @@ public:
                     surface = b._texture;
                     if (surface) {
                         Q_ASSERT(TextureUsageType::RENDERBUFFER == surface->getUsageType());
-                        gltexture = backend->syncGPUObject(surface); 
+                        gltexture = backend->syncGPUObject(surface);
                     } else {
                         gltexture = nullptr;
                     }
@@ -66,6 +112,24 @@ public:
                     if (gltexture) {
                         if (gltexture->_target == GL_TEXTURE_2D) {
                             glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0);
+#if 0
+                            if (glTextureFoveationParametersQCOM && focalPoint.x != -1.0f) {
+                                static GLint FOVEATION_QUERY = 0;
+                                static std::once_flag once;
+                                std::call_once(once, [&]{
+                                    glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_FOVEATED_FEATURE_QUERY_QCOM, &FOVEATION_QUERY);
+                                });
+                                static const float foveaArea = 4.0f;
+                                static const float gain = 16.0f;
+                                GLESBackend::GLESTexture* glestexture = static_cast<GLESBackend::GLESTexture*>(gltexture);
+                                glestexture->withPreservedTexture([=]{
+                                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FOVEATED_FEATURE_BITS_QCOM, GL_FOVEATION_ENABLE_BIT_QCOM | GL_FOVEATION_SCALED_BIN_METHOD_BIT_QCOM);
+                                    glTextureFoveationParametersQCOM(_id, 0, 0, -focalPoint.x, focalPoint.y, gain * 2.0f, gain, foveaArea);
+                                    glTextureFoveationParametersQCOM(_id, 0, 1, focalPoint.x, focalPoint.y, gain * 2.0f, gain, foveaArea);
+                                });
+
+                            }
+#endif
                         } else {
                             glFramebufferTextureLayer(GL_FRAMEBUFFER, colorAttachments[unit], gltexture->_texture, 0,
                                                       b._subresource);
diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h
index b080b0ceac..7109b3dfeb 100644
--- a/libraries/gpu/src/gpu/Context.h
+++ b/libraries/gpu/src/gpu/Context.h
@@ -66,6 +66,7 @@ public:
     virtual void syncProgram(const gpu::ShaderPointer& program) = 0;
     virtual void recycle() const = 0;
     virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0;
+    virtual void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) {}
 
     virtual bool supportedTextureFormat(const gpu::Element& format) = 0;
 
@@ -117,7 +118,6 @@ public:
     static ContextMetricSize textureResourcePopulatedGPUMemSize;
     static ContextMetricSize textureResourceIdealGPUMemSize;
 
-protected:
     virtual bool isStereo() const {
         return _stereo.isStereo();
     }
@@ -127,6 +127,7 @@ protected:
             eyeProjections[i] = _stereo._eyeProjections[i];
         }
     }
+protected:
 
     void getStereoViews(mat4* eyeViews) const {
         for (int i = 0; i < 2; ++i) {