HifiExperimentsruntime gl api switchingebcc81c6 months agoHistory
1031 lines · 36.0 KB · C++
RawDownload
////  GLBackend.cpp//  libraries/gpu/src/gpu////  Created by Sam Gateau on 10/27/2014.//  Copyright 2014 High Fidelity, Inc.//  Copyright 2024 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html//#include "GLBackend.h"  #include <mutex>#include <queue>#include <list>#include <functional>#include <glm/gtc/type_ptr.hpp>#include "gl/Config.h" #if defined(NSIGHT_FOUND)#include "nvToolsExt.h"#endif // Define the GPU_BATCH_DETAILED_TRACING to get detailed tracing of the commands during the batch executions// #define GPU_BATCH_DETAILED_TRACING #include <GPUIdent.h> #include "GLTexture.h"#include "GLShader.h" using namespace gpu;using namespace gpu::gl; GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = {    (&::gpu::gl::GLBackend::do_draw),     (&::gpu::gl::GLBackend::do_drawIndexed),    (&::gpu::gl::GLBackend::do_drawInstanced),    (&::gpu::gl::GLBackend::do_drawIndexedInstanced),    (&::gpu::gl::GLBackend::do_multiDrawIndirect),    (&::gpu::gl::GLBackend::do_multiDrawIndexedIndirect),     (&::gpu::gl::GLBackend::do_setInputFormat),    (&::gpu::gl::GLBackend::do_setInputBuffer),    (&::gpu::gl::GLBackend::do_setIndexBuffer),    (&::gpu::gl::GLBackend::do_setIndirectBuffer),     (&::gpu::gl::GLBackend::do_setModelTransform),    (&::gpu::gl::GLBackend::do_setViewTransform),    (&::gpu::gl::GLBackend::do_setProjectionTransform),    (&::gpu::gl::GLBackend::do_setProjectionJitterEnabled),    (&::gpu::gl::GLBackend::do_setProjectionJitterSequence),    (&::gpu::gl::GLBackend::do_setProjectionJitterScale),    (&::gpu::gl::GLBackend::do_setViewportTransform),    (&::gpu::gl::GLBackend::do_setDepthRangeTransform),     (&::gpu::gl::GLBackend::do_saveViewProjectionTransform),    (&::gpu::gl::GLBackend::do_setSavedViewProjectionTransform),    (&::gpu::gl::GLBackend::do_copySavedViewProjectionTransformToBuffer),     (&::gpu::gl::GLBackend::do_setPipeline),    (&::gpu::gl::GLBackend::do_setStateBlendFactor),    (&::gpu::gl::GLBackend::do_setStateScissorRect),     (&::gpu::gl::GLBackend::do_setUniformBuffer),    (&::gpu::gl::GLBackend::do_setResourceBuffer),    (&::gpu::gl::GLBackend::do_setResourceTexture),    (&::gpu::gl::GLBackend::do_setResourceTextureTable),    (&::gpu::gl::GLBackend::do_setResourceFramebufferSwapChainTexture),     (&::gpu::gl::GLBackend::do_setFramebuffer),    (&::gpu::gl::GLBackend::do_setFramebufferSwapChain),    (&::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),     (&::gpu::gl::GLBackend::do_beginQuery),    (&::gpu::gl::GLBackend::do_endQuery),    (&::gpu::gl::GLBackend::do_getQuery),     (&::gpu::gl::GLBackend::do_resetStages),     (&::gpu::gl::GLBackend::do_disableContextViewCorrection),    (&::gpu::gl::GLBackend::do_restoreContextViewCorrection),    (&::gpu::gl::GLBackend::do_setContextMirrorViewCorrection),    (&::gpu::gl::GLBackend::do_disableContextStereo),    (&::gpu::gl::GLBackend::do_restoreContextStereo),     (&::gpu::gl::GLBackend::do_runLambda),     (&::gpu::gl::GLBackend::do_startNamedCall),    (&::gpu::gl::GLBackend::do_stopNamedCall),     (&::gpu::gl::GLBackend::do_glUniform1i),    (&::gpu::gl::GLBackend::do_glUniform1f),    (&::gpu::gl::GLBackend::do_glUniform2f),    (&::gpu::gl::GLBackend::do_glUniform3f),    (&::gpu::gl::GLBackend::do_glUniform4f),    (&::gpu::gl::GLBackend::do_glUniform3fv),    (&::gpu::gl::GLBackend::do_glUniform4fv),    (&::gpu::gl::GLBackend::do_glUniform4iv),    (&::gpu::gl::GLBackend::do_glUniformMatrix3fv),    (&::gpu::gl::GLBackend::do_glUniformMatrix4fv),     (&::gpu::gl::GLBackend::do_pushProfileRange),    (&::gpu::gl::GLBackend::do_popProfileRange),}; #define GL_GET_INTEGER(NAME) glGetIntegerv(GL_##NAME, &const_cast<GLint&>(NAME));  #define BYTES_PER_KIB 1024L#define BYTES_PER_MIB (1024L * BYTES_PER_KIB) GLint GLBackend::MAX_TEXTURE_IMAGE_UNITS{ 0 };GLint GLBackend::MAX_UNIFORM_BUFFER_BINDINGS{ 0 };GLint GLBackend::MAX_COMBINED_UNIFORM_BLOCKS{ 0 };GLint GLBackend::MAX_COMBINED_TEXTURE_IMAGE_UNITS{ 0 };GLint GLBackend::MAX_UNIFORM_BLOCK_SIZE{ 0 };GLint GLBackend::UNIFORM_BUFFER_OFFSET_ALIGNMENT{ 1 };GLint GLBackend::GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX{ 0 };GLint GLBackend::GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX{ 0 };GLint GLBackend::GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX{ 0 };GLint GLBackend::TEXTURE_FREE_MEMORY_ATI{ 0 }; size_t GLBackend::_totalMemory{ 0 };size_t GLBackend::_dedicatedMemory{ 0 };GLBackend::VideoCardType GLBackend::_videoCard{ GLBackend::Unknown };  #define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 void GLBackend::init() {    static std::once_flag once;    std::call_once(once, [] {         ::gl::ContextInfo contextInfo;        contextInfo.init();        QString vendor { contextInfo.vendor.c_str() };        QString renderer { contextInfo.renderer.c_str() };         // Textures        GL_GET_INTEGER(MAX_TEXTURE_IMAGE_UNITS);        GL_GET_INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS);         // Uniform blocks        GL_GET_INTEGER(MAX_UNIFORM_BUFFER_BINDINGS);        GL_GET_INTEGER(MAX_COMBINED_UNIFORM_BLOCKS);        GL_GET_INTEGER(MAX_UNIFORM_BLOCK_SIZE);        GL_GET_INTEGER(UNIFORM_BUFFER_OFFSET_ALIGNMENT);         GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer); // Do not try to get texture memory information on unsupported systems.#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)        qCDebug(gpugllogging) << "Automatic texture memory not supported in this configuration";        _videoCard = Unknown;        _dedicatedMemory = (size_t)(gpu->getMemory()) * BYTES_PER_MIB;        _totalMemory = _dedicatedMemory;#else        unsigned int mem;        if (vendor.contains("NVIDIA") ) {            qCDebug(gpugllogging) << "NVIDIA card detected";             GL_GET_INTEGER(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX);            GL_GET_INTEGER(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX);            GL_GET_INTEGER(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX);             qCDebug(gpugllogging) << "GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: " << GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX;            qCDebug(gpugllogging) << "GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: " << GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX;            qCDebug(gpugllogging) << "GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX: " << GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX;             _totalMemory = (size_t)(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX) * BYTES_PER_KIB;            _dedicatedMemory = (size_t)(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX) * BYTES_PER_KIB;            _videoCard = NVIDIA;          } else if (vendor.contains("ATI")) {            qCDebug(gpugllogging) << "ATI card detected";             GL_GET_INTEGER(TEXTURE_FREE_MEMORY_ATI);             // We are actually getting free memory instead of total memory            _totalMemory = (size_t)(TEXTURE_FREE_MEMORY_ATI) * BYTES_PER_KIB;            _dedicatedMemory = _totalMemory;            _videoCard = ATI;        } else if ( ::gl::queryCurrentRendererIntegerMESA(GLX_RENDERER_VIDEO_MEMORY_MESA, &mem) ) {                // This works only on Linux. queryCurrentRendererIntegerMESA will return false if the                // function is not supported because we're not on Linux, or for any other reason.                qCDebug(gpugllogging) << "MESA card detected";                _totalMemory = (size_t)(mem) * BYTES_PER_MIB;                _dedicatedMemory = _totalMemory;                _videoCard = MESA;        } else {            qCCritical(gpugllogging) << "Don't know how to get memory for OpenGL vendor " << vendor << "; renderer " << renderer << ", trying fallback";            _videoCard = Unknown;            _dedicatedMemory = (size_t)(gpu->getMemory()) * BYTES_PER_MIB;            _totalMemory = _dedicatedMemory;        }#endif         qCDebug(gpugllogging) << "dedicated: " << _dedicatedMemory;        qCDebug(gpugllogging) << "total: " << _totalMemory;          LOG_GL_CONTEXT_INFO(gpugllogging, contextInfo);          // From here on, GPUIdent::getInstance()->getMumble() should efficiently give the same answers.        qCDebug(gpugllogging) << "GPU:";        qCDebug(gpugllogging) << "\tcard:" << gpu->getName();        qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver();        qCDebug(gpugllogging) << "\ttotal memory:" << (_totalMemory / BYTES_PER_KIB) << "KB";        qCDebug(gpugllogging) << "\tdedicated memory:" << (_dedicatedMemory / BYTES_PER_KIB) << "KB";        qCDebug(gpugllogging) << "\tavailable memory:" << (getAvailableMemory()  / BYTES_PER_KIB) << "KB";        qCDebug(gpugllogging) << "Limits:";        qCDebug(gpugllogging) << "\tmax textures:" << MAX_TEXTURE_IMAGE_UNITS;        qCDebug(gpugllogging) << "\tmax texture binding:" << MAX_COMBINED_TEXTURE_IMAGE_UNITS;        qCDebug(gpugllogging) << "\tmax uniforms:" << MAX_UNIFORM_BUFFER_BINDINGS;        qCDebug(gpugllogging) << "\tmax uniform binding:" << MAX_COMBINED_UNIFORM_BLOCKS;        qCDebug(gpugllogging) << "\tmax uniform size:" << MAX_UNIFORM_BLOCK_SIZE;        qCDebug(gpugllogging) << "\tuniform alignment:" << UNIFORM_BUFFER_OFFSET_ALIGNMENT;        qCDebug(gpugllogging, "V-Sync is %s\n", (::gl::getSwapInterval() > 0 ? "ON" : "OFF"));    });} size_t GLBackend::getAvailableMemory() {    // GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX returns 1 value    // GL_TEXTURE_FREE_MEMORY_ATI returns 4 values, we only need the first    GLint mem[4] = {0,0,0,0};     switch( _videoCard ) {        case NVIDIA:#if !defined(Q_OS_ANDROID)            glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &mem[0]);#endif            return (size_t)(mem[0]) * BYTES_PER_KIB;        case ATI:#if !defined(Q_OS_ANDROID)            glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, &mem[0]);#endif            return (size_t)(mem[0]) * BYTES_PER_KIB;        case MESA:            return 0; // Don't know the current value        case Unknown:            break;    }     return 0; } bool GLBackend::availableMemoryKnown() {    switch( _videoCard ) {        case NVIDIA:            return true;        case ATI:            return true;        case MESA:            return false;        case Unknown:            return false;    }     return false;} GLBackend::GLBackend(bool syncCache) {    initShaderBinaryCache();} GLBackend::GLBackend() {    initShaderBinaryCache();} GLBackend::~GLBackend() {} void GLBackend::shutdown() {    if (_mipGenerationFramebufferId) {        glDeleteFramebuffers(1, &_mipGenerationFramebufferId);        _mipGenerationFramebufferId = 0;    }    killInput();    killTransform();    killTextureManagementStage();    killShaderBinaryCache();} void GLBackend::renderPassTransfer(const Batch& batch) {    const size_t numCommands = batch.getCommands().size();    const Batch::Commands::value_type* command = batch.getCommands().data();    const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();     _inRenderTransferPass = true;    { // Sync all the buffers        PROFILE_RANGE(render_gpu_gl_detail, "syncGPUBuffer");         for (auto& cached : batch._buffers._items) {            if (cached._data) {                syncGPUObject(*cached._data);            }        }    }     { // Sync all the transform states        PROFILE_RANGE(render_gpu_gl_detail, "syncCPUTransform");        _transform._cameras.clear();        _transform._cameraOffsets.clear();         for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {            switch (*command) {                case Batch::COMMAND_draw:                case Batch::COMMAND_drawIndexed:                case Batch::COMMAND_drawInstanced:                case Batch::COMMAND_drawIndexedInstanced:                case Batch::COMMAND_multiDrawIndirect:                case Batch::COMMAND_multiDrawIndexedIndirect:                case Batch::COMMAND_copySavedViewProjectionTransformToBuffer: // We need to store this transform state in the transform buffer                    preUpdateTransform();                    break;                 case Batch::COMMAND_disableContextStereo:                    _stereo._contextDisable = true;                    break;                 case Batch::COMMAND_restoreContextStereo:                    _stereo._contextDisable = false;                    break;                 case Batch::COMMAND_setFramebuffer:                case Batch::COMMAND_setViewportTransform:                case Batch::COMMAND_setViewTransform:                case Batch::COMMAND_setProjectionTransform:                case Batch::COMMAND_setProjectionJitterEnabled:                case Batch::COMMAND_setProjectionJitterSequence:                case Batch::COMMAND_setProjectionJitterScale:                case Batch::COMMAND_saveViewProjectionTransform:                case Batch::COMMAND_setSavedViewProjectionTransform:                case Batch::COMMAND_setContextMirrorViewCorrection:                {                    CommandCall call = _commandCalls[(*command)];                    (this->*(call))(batch, *offset);                    break;                }                 default:                    break;            }            command++;            offset++;        }    }     { // Sync the transform buffers        PROFILE_RANGE(render_gpu_gl_detail, "syncGPUTransform");        transferTransformState(batch);    }     _inRenderTransferPass = false;} void GLBackend::renderPassDraw(const Batch& batch) {    _currentDraw = -1;    _transform._camerasItr = _transform._cameraOffsets.begin();    const size_t numCommands = batch.getCommands().size();    const Batch::Commands::value_type* command = batch.getCommands().data();    const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();    for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {        switch (*command) {            // Ignore these commands on this pass, taken care of in the transfer pass            // Note we allow COMMAND_setViewportTransform to occur in both passes            // as it both updates the transform object (and thus the uniforms in the             // UBO) as well as executes the actual viewport call            case Batch::COMMAND_setModelTransform:            case Batch::COMMAND_setViewTransform:            case Batch::COMMAND_setProjectionTransform:            case Batch::COMMAND_saveViewProjectionTransform:            case Batch::COMMAND_setSavedViewProjectionTransform:            case Batch::COMMAND_setProjectionJitterSequence:                break;             case Batch::COMMAND_draw:            case Batch::COMMAND_drawIndexed:            case Batch::COMMAND_drawInstanced:            case Batch::COMMAND_drawIndexedInstanced:            case Batch::COMMAND_multiDrawIndirect:            case Batch::COMMAND_multiDrawIndexedIndirect: {#ifdef GPU_BATCH_DETAILED_TRACING                PROFILE_RANGE(render_gpu_gl_detail, "drawcall");#endif                 // updates for draw calls                ++_currentDraw;                updateInput();                updateTransform(batch);                updatePipeline();                 CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }#ifdef GPU_BATCH_DETAILED_TRACING            //case Batch::COMMAND_setModelTransform:            //case Batch::COMMAND_setViewTransform:            //case Batch::COMMAND_setProjectionTransform:            case Batch::COMMAND_setViewportTransform:            case Batch::COMMAND_setDepthRangeTransform:            case Batch::COMMAND_setContextMirrorViewCorrection:            {                PROFILE_RANGE(render_gpu_gl_detail, "transform");                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }            case Batch::COMMAND_clearFramebuffer:            {                PROFILE_RANGE(render_gpu_gl_detail, "clear");                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }            case Batch::COMMAND_blit:            {                PROFILE_RANGE(render_gpu_gl_detail, "blit");                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }            case Batch::COMMAND_setInputFormat:            case Batch::COMMAND_setInputBuffer:            case Batch::COMMAND_setIndexBuffer:            case Batch::COMMAND_setIndirectBuffer: {                PROFILE_RANGE(render_gpu_gl_detail, "input");                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }            case Batch::COMMAND_setStateBlendFactor:            case Batch::COMMAND_setStateScissorRect:            case Batch::COMMAND_setPipeline: {                PROFILE_RANGE(render_gpu_gl_detail, "pipeline");                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }            case Batch::COMMAND_setUniformBuffer:            {                PROFILE_RANGE(render_gpu_gl_detail, "ubo");                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }            case Batch::COMMAND_setResourceBuffer:            case Batch::COMMAND_setResourceTexture:            case Batch::COMMAND_setResourceTextureTable:            {                PROFILE_RANGE(render_gpu_gl_detail, "resource");                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }             case Batch::COMMAND_setResourceFramebufferSwapChainTexture:            case Batch::COMMAND_setFramebuffer:            case Batch::COMMAND_setFramebufferSwapChain:            {                PROFILE_RANGE(render_gpu_gl_detail, "framebuffer");                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }            case Batch::COMMAND_generateTextureMips:            {                PROFILE_RANGE(render_gpu_gl_detail, "genMipMaps");                 CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }            case Batch::COMMAND_beginQuery:            case Batch::COMMAND_endQuery:            case Batch::COMMAND_getQuery:            {                PROFILE_RANGE(render_gpu_gl_detail, "query");                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }#endif             default: {                CommandCall call = _commandCalls[(*command)];                (this->*(call))(batch, *offset);                break;            }        } 

Lines 1–500 of 1031.