//// 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. Load more
// // 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; } }