From 9cd963af95f2dc9110c916c5b927d3cb564f92fa Mon Sep 17 00:00:00 2001
From: Olivier Prat <olivier@zvork.fr>
Date: Thu, 27 Sep 2018 10:26:51 +0200
Subject: [PATCH] Added generateTextureMipsWithPipeline function in batch

---
 .../gpu-gl-common/src/gpu/gl/GLBackend.cpp    |  5 ++
 .../gpu-gl-common/src/gpu/gl/GLBackend.h      |  5 ++
 .../src/gpu/gl/GLBackendTexture.cpp           | 47 +++++++++++++++++++
 libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp | 23 +++++++++
 libraries/gpu-gl/src/gpu/gl41/GL41Backend.h   |  3 ++
 libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp | 24 ++++++++++
 libraries/gpu-gl/src/gpu/gl45/GL45Backend.h   |  1 +
 libraries/gpu/src/gpu/Batch.cpp               |  9 ++++
 libraries/gpu/src/gpu/Batch.h                 |  3 ++
 libraries/gpu/src/gpu/ShaderConstants.h       |  6 ++-
 10 files changed, 125 insertions(+), 1 deletion(-)

diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp
index 4fea4f2dc5..2842c682e7 100644
--- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp
@@ -64,6 +64,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
     (&::gpu::gl::GLBackend::do_clearFramebuffer),
     (&::gpu::gl::GLBackend::do_blit),
     (&::gpu::gl::GLBackend::do_generateTextureMips),
+    (&::gpu::gl::GLBackend::do_generateTextureMipsWithPipeline),
 
     (&::gpu::gl::GLBackend::do_advance),
 
@@ -163,6 +164,10 @@ GLBackend::GLBackend() {
 GLBackend::~GLBackend() {}
 
 void GLBackend::shutdown() {
+    if (_mipGenerationFramebufferId) {
+        glDeleteFramebuffers(1, &_mipGenerationFramebufferId);
+        _mipGenerationFramebufferId = 0;
+    }
     killInput();
     killTransform();
     killTextureManagementStage();
diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h
index 0b76ef17de..267c2a97ad 100644
--- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h
@@ -288,6 +288,7 @@ public:
     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;
+    virtual void do_generateTextureMipsWithPipeline(const Batch& batch, size_t paramOffset) final;
 
     // Transform Stage
     virtual void do_setModelTransform(const Batch& batch, size_t paramOffset) final;
@@ -407,6 +408,8 @@ public:
 protected:
     virtual GLint getRealUniformLocation(GLint location) const;
 
+    virtual void draw(GLenum mode, uint32 numVertices, uint32 startVertex) = 0;
+
     void recycle() const override;
 
     // FIXME instead of a single flag, create a features struct similar to
@@ -696,6 +699,8 @@ protected:
     virtual void initTextureManagementStage();
     virtual void killTextureManagementStage();
 
+    GLuint _mipGenerationFramebufferId{ 0 };
+
     typedef void (GLBackend::*CommandCall)(const Batch&, size_t);
     static CommandCall _commandCalls[Batch::NUM_COMMANDS];
     friend class GLState;
diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp
index f4fb3fcf2c..f4f2da3ee5 100644
--- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp
+++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp
@@ -79,3 +79,50 @@ void GLBackend::do_generateTextureMips(const Batch& batch, size_t paramOffset) {
 
     object->generateMips();
 }
+
+void GLBackend::do_generateTextureMipsWithPipeline(const Batch& batch, size_t paramOffset) {
+    TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
+    if (!resourceTexture) {
+        return;
+    }
+
+    // Do not transfer the texture, this call is expected for rendering texture
+    GLTexture* object = syncGPUObject(resourceTexture);
+    if (!object) {
+        return;
+    }
+
+    auto numMips = batch._params[paramOffset + 1]._int;
+    if (numMips < 0) {
+        numMips = resourceTexture->getNumMips();
+    } else {
+        numMips = std::min(numMips, (int)resourceTexture->getNumMips());
+    }
+
+    if (_mipGenerationFramebufferId == 0) {
+        glGenFramebuffers(1, &_mipGenerationFramebufferId);
+        Q_ASSERT(_mipGenerationFramebufferId > 0);
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER, _mipGenerationFramebufferId);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+
+    for (int level = 1; level < numMips; level++) {
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, object->_id, level);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, level - 1);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1);
+
+        const auto mipDimensions = resourceTexture->evalMipDimensions(level);
+        glViewport(0, 0, mipDimensions.x, mipDimensions.y);
+        draw(GL_TRIANGLE_STRIP, 4, 0);
+    }
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numMips - 1);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+    resetOutputStage();
+    // Restore viewport
+    ivec4& vp = _transform._viewport;
+    glViewport(vp.x, vp.y, vp.z, vp.w);
+}
diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp
index 88cf89ad99..43ae4691b9 100644
--- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp
+++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp
@@ -20,6 +20,29 @@ using namespace gpu::gl41;
 
 const std::string GL41Backend::GL41_VERSION { "GL41" };
 
+void GL41Backend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) {
+    if (isStereo()) {
+#ifdef GPU_STEREO_DRAWCALL_INSTANCED
+        glDrawArraysInstanced(mode, startVertex, numVertices, 2);
+#else
+        setupStereoSide(0);
+        glDrawArrays(mode, startVertex, numVertices);
+        setupStereoSide(1);
+        glDrawArrays(mode, startVertex, numVertices);
+#endif
+        _stats._DSNumTriangles += 2 * numVertices / 3;
+        _stats._DSNumDrawcalls += 2;
+
+    } else {
+        glDrawArrays(mode, startVertex, numVertices);
+        _stats._DSNumTriangles += numVertices / 3;
+        _stats._DSNumDrawcalls++;
+    }
+    _stats._DSNumAPIDrawcalls++;
+
+    (void)CHECK_GL_ERROR();
+}
+
 void GL41Backend::do_draw(const Batch& batch, size_t paramOffset) {
     Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
     GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType];
diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h
index e5f7415107..5d691d032a 100644
--- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h
+++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h
@@ -130,6 +130,9 @@ public:
     };
 
 protected:
+
+    void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override;
+
     GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;
     GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override;
 
diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp
index bbe011d237..e86eae2c2d 100644
--- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp
+++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp
@@ -42,6 +42,30 @@ void GL45Backend::recycle() const {
     Parent::recycle();
 }
 
+void GL45Backend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) {
+    if (isStereo()) {
+#ifdef GPU_STEREO_DRAWCALL_INSTANCED
+        glDrawArraysInstanced(mode, startVertex, numVertices, 2);
+#else
+        setupStereoSide(0);
+        glDrawArrays(mode, startVertex, numVertices);
+        setupStereoSide(1);
+        glDrawArrays(mode, startVertex, numVertices);
+#endif
+
+        _stats._DSNumTriangles += 2 * numVertices / 3;
+        _stats._DSNumDrawcalls += 2;
+
+    } else {
+        glDrawArrays(mode, startVertex, numVertices);
+        _stats._DSNumTriangles += numVertices / 3;
+        _stats._DSNumDrawcalls++;
+    }
+    _stats._DSNumAPIDrawcalls++;
+
+    (void)CHECK_GL_ERROR();
+}
+
 void GL45Backend::do_draw(const Batch& batch, size_t paramOffset) {
     Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
     GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType];
diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h
index 30656b47c7..77095375af 100644
--- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h
+++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h
@@ -229,6 +229,7 @@ public:
 
 protected:
 
+    void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override;
     void recycle() const override;
 
     GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;
diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp
index 745f1d1845..4cf678f26e 100644
--- a/libraries/gpu/src/gpu/Batch.cpp
+++ b/libraries/gpu/src/gpu/Batch.cpp
@@ -417,6 +417,15 @@ void Batch::generateTextureMips(const TexturePointer& texture) {
     _params.emplace_back(_textures.cache(texture));
 }
 
+void Batch::generateTextureMipsWithPipeline(const TexturePointer& texture, int numMips) {
+    setResourceTexture(gpu::slot::texture::MipCreationInput, texture);
+
+    ADD_COMMAND(generateTextureMipsWithPipeline);
+
+    _params.emplace_back(_textures.cache(texture));
+    _params.emplace_back(numMips);
+}
+
 void Batch::beginQuery(const QueryPointer& query) {
     ADD_COMMAND(beginQuery);
 
diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h
index 8e607a189e..5a4089d2b6 100644
--- a/libraries/gpu/src/gpu/Batch.h
+++ b/libraries/gpu/src/gpu/Batch.h
@@ -216,6 +216,8 @@ public:
 
     // Generate the mips for a texture
     void generateTextureMips(const TexturePointer& texture);
+    // Generate the mips for a texture using the current pipeline
+    void generateTextureMipsWithPipeline(const TexturePointer& destTexture, int numMips = -1);
 
     // Query Section
     void beginQuery(const QueryPointer& query);
@@ -316,6 +318,7 @@ public:
         COMMAND_clearFramebuffer,
         COMMAND_blit,
         COMMAND_generateTextureMips,
+        COMMAND_generateTextureMipsWithPipeline,
 
         COMMAND_advance,
 
diff --git a/libraries/gpu/src/gpu/ShaderConstants.h b/libraries/gpu/src/gpu/ShaderConstants.h
index 13dfd1be9c..426c64e913 100644
--- a/libraries/gpu/src/gpu/ShaderConstants.h
+++ b/libraries/gpu/src/gpu/ShaderConstants.h
@@ -21,6 +21,9 @@
 
 #define GPU_TEXTURE_TRANSFORM_OBJECT 31
 
+// Mip creation
+#define GPU_TEXTURE_MIP_CREATION_INPUT 0
+
 #define GPU_STORAGE_TRANSFORM_OBJECT 7
 
 #define GPU_ATTR_POSITION 0
@@ -67,7 +70,8 @@ enum Buffer {
 namespace texture {
 enum Texture {
     ObjectTransforms = GPU_TEXTURE_TRANSFORM_OBJECT,
-}; 
+    MipCreationInput = GPU_TEXTURE_MIP_CREATION_INPUT,
+};
 } // namespace texture
 
 namespace storage {