30#include <glbinding/Binding.h>
75 _contexts.resize( size );
76 GLUtil::ValidateSDL( SDL_GL_MakeCurrent( window.
getRawWindow(), window.userData()._glContext ) );
79 contextEntry._context = SDL_GL_CreateContext( raw );
81 GLUtil::ValidateSDL( SDL_GL_MakeCurrent( window.
getRawWindow(),
nullptr ) );
89 SDL_GL_DeleteContext( contextEntry._context );
97 assert( !_contexts.empty() );
100 if ( !contextEntry._inUse )
102 ctx = contextEntry._context;
103 contextEntry._inUse =
true;
118 _swapBufferTimer( Time::ADD_TIMER(
"Swap Buffer Timer" ) )
131 glbinding::Binding::initialize( [](
const char* proc )
noexcept
133 return (glbinding::ProcAddress)SDL_GL_GetProcAddress( proc );
142 gl46core::glEnable( gl46core::GL_DEBUG_OUTPUT );
143 gl46core::glEnable( gl46core::GL_DEBUG_OUTPUT_SYNCHRONOUS );
145 gl46core::glDebugMessageControl( gl46core::GL_DONT_CARE, gl46core::GL_DEBUG_TYPE_MARKER, gl46core::GL_DONT_CARE, 0, NULL, gl46core::GL_FALSE );
146 gl46core::glDebugMessageControl( gl46core::GL_DONT_CARE, gl46core::GL_DEBUG_TYPE_PUSH_GROUP, gl46core::GL_DONT_CARE, 0, NULL, gl46core::GL_FALSE );
147 gl46core::glDebugMessageControl( gl46core::GL_DONT_CARE, gl46core::GL_DEBUG_TYPE_POP_GROUP, gl46core::GL_DONT_CARE, 0, NULL, gl46core::GL_FALSE );
150 gl46core::glDebugMessageControl( gl46core::GL_DONT_CARE, gl46core::GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, gl46core::GL_DONT_CARE, 0, NULL, gl46core::GL_FALSE );
151 gl46core::glDebugMessageControl( gl46core::GL_DONT_CARE, gl46core::GL_DEBUG_TYPE_PORTABILITY, gl46core::GL_DONT_CARE, 0, NULL, gl46core::GL_FALSE );
152 gl46core::glDebugMessageControl( gl46core::GL_DONT_CARE, gl46core::GL_DEBUG_TYPE_PERFORMANCE, gl46core::GL_DONT_CARE, 0, NULL, gl46core::GL_FALSE );
159 if ( SDL_GL_GetCurrentContext() ==
nullptr )
166 glbinding::Binding::setCallbackMaskExcept( glbinding::CallbackMask::Before, {
"glGetError" } );
167 glbinding::Binding::setBeforeCallback( [&](
const glbinding::FunctionCall& )
177 const char* gpuVendorStr =
reinterpret_cast<const char*
>(gl46core::glGetString( gl46core::GL_VENDOR ));
178 if ( gpuVendorStr !=
nullptr )
180 if ( strstr( gpuVendorStr,
"Intel" ) != nullptr )
184 else if ( strstr( gpuVendorStr,
"NVIDIA" ) != nullptr )
188 else if ( strstr( gpuVendorStr,
"ATI" ) !=
nullptr || strstr( gpuVendorStr,
"AMD" ) != nullptr )
192 else if ( strstr( gpuVendorStr,
"Microsoft" ) != nullptr )
196 else if ( strstr( gpuVendorStr,
"Mesa" ) != nullptr )
207 gpuVendorStr =
"Unknown GPU Vendor";
211 const char* gpuRendererStr =
reinterpret_cast<const char*
>(gl46core::glGetString( gl46core::GL_RENDERER ));
212 if ( gpuRendererStr !=
nullptr )
214 if ( strstr( gpuRendererStr,
"Tegra" ) || strstr( gpuRendererStr,
"GeForce" ) || strstr( gpuRendererStr,
"NV" ) )
218 else if ( strstr( gpuRendererStr,
"PowerVR" ) || strstr( gpuRendererStr,
"Apple" ) )
223 else if ( strstr( gpuRendererStr,
"Mali" ) )
228 else if ( strstr( gpuRendererStr,
"Adreno" ) )
233 else if ( strstr( gpuRendererStr,
"AMD" ) || strstr( gpuRendererStr,
"ATI" ) )
237 else if ( strstr( gpuRendererStr,
"Intel" ) )
241 else if ( strstr( gpuRendererStr,
"Vivante" ) )
246 else if ( strstr( gpuRendererStr,
"VideoCore" ) )
251 else if ( strstr( gpuRendererStr,
"WebKit" ) || strstr( gpuRendererStr,
"Mozilla" ) || strstr( gpuRendererStr,
"ANGLE" ) )
256 else if ( strstr( gpuRendererStr,
"GDI Generic" ) )
260 else if ( strstr( gpuRendererStr,
"Mesa" ) )
271 gpuRendererStr =
"Unknown GPU Renderer";
275 Console::printfn(
LOCALE_STR(
"GL_VENDOR_STRING" ), gpuVendorStr, gpuRendererStr,
reinterpret_cast<const char*
>(gl46core::glGetString( gl46core::GL_VERSION )) );
278 deviceInformation.
_vendor = vendor;
279 deviceInformation._renderer = renderer;
291 GLUtil::getGLValue( gl46core::GL_MAX_VERTEX_ATTRIB_BINDINGS, deviceInformation._maxVertAttributeBindings );
293 GLUtil::getGLValue( gl46core::GL_MAX_TEXTURE_SIZE, deviceInformation._maxTextureSize );
297 Console::printfn(
LOCALE_STR(
"GL_MAX_VERSION" ), deviceInformation._versionInfo._major, deviceInformation._versionInfo._minor );
299 if ( deviceInformation._versionInfo._major < 4 || (deviceInformation._versionInfo._major == 4 && deviceInformation._versionInfo._minor < 6) )
306 GLUtil::getGLValue( gl46core::GL_MAX_COLOR_ATTACHMENTS, deviceInformation._maxRTColourAttachments );
308 deviceInformation._shaderCompilerThreads =
GLUtil::getGLValue( gl::GL_MAX_SHADER_COMPILER_THREADS_ARB );
310 gl::glMaxShaderCompilerThreadsARB( deviceInformation._shaderCompilerThreads );
312 gl46core::glEnable( gl46core::GL_MULTISAMPLE );
314 gl46core::glEnable( gl46core::GL_LINE_SMOOTH );
317 gl46core::glClampColor( gl46core::GL_CLAMP_READ_COLOR, gl46core::GL_FALSE );
320 gl46core::glClipControl( gl46core::GL_LOWER_LEFT, gl46core::GL_ZERO_TO_ONE );
346 deviceInformation._maxVertAttributes =
GLUtil::getGLValue( gl46core::GL_MAX_VERTEX_ATTRIBS );
350 for (
U8 i = 0u; i < 3; ++i )
352 GLUtil::getGLValue( gl46core::GL_MAX_COMPUTE_WORK_GROUP_COUNT, deviceInformation._maxWorgroupCount[i], i );
353 GLUtil::getGLValue( gl46core::GL_MAX_COMPUTE_WORK_GROUP_SIZE, deviceInformation._maxWorgroupSize[i], i );
356 deviceInformation._maxWorgroupInvocations =
GLUtil::getGLValue( gl46core::GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS );
357 deviceInformation._maxComputeSharedMemoryBytes =
GLUtil::getGLValue( gl46core::GL_MAX_COMPUTE_SHARED_MEMORY_SIZE );
360 deviceInformation._maxWorgroupCount[0], deviceInformation._maxWorgroupCount[1], deviceInformation._maxWorgroupCount[2],
361 deviceInformation._maxWorgroupSize[0], deviceInformation._maxWorgroupSize[1], deviceInformation._maxWorgroupSize[2],
362 deviceInformation._maxWorgroupInvocations );
368 deviceInformation._maxTextureUnits );
370 deviceInformation._maxVertOutputComponents =
GLUtil::getGLValue( gl46core::GL_MAX_VERTEX_OUTPUT_COMPONENTS );
375 reinterpret_cast<const char*
>( gl46core::glGetString( gl46core::GL_SHADING_LANGUAGE_VERSION ) ) );
379 GLUtil::getGLValue( gl46core::GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, deviceInformation._offsetAlignmentBytesUBO );
380 GLUtil::getGLValue( gl46core::GL_MAX_UNIFORM_BLOCK_SIZE, deviceInformation._maxSizeBytesUBO );
381 const bool UBOSizeOver1Mb = deviceInformation._maxSizeBytesUBO / 1024 > 1024;
384 (deviceInformation._maxSizeBytesUBO / 1024) / (UBOSizeOver1Mb ? 1024 : 1),
385 UBOSizeOver1Mb ?
"Mb" :
"Kb",
386 deviceInformation._offsetAlignmentBytesUBO );
394 GLUtil::getGLValue( gl46core::GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, deviceInformation._offsetAlignmentBytesSSBO );
395 GLUtil::getGLValue( gl46core::GL_MAX_SHADER_STORAGE_BLOCK_SIZE, deviceInformation._maxSizeBytesSSBO );
396 deviceInformation._maxSSBOBufferBindings =
GLUtil::getGLValue( gl46core::GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS );
398 deviceInformation._maxSSBOBufferBindings,
399 deviceInformation._maxSizeBytesSSBO / 1024 / 1024,
401 deviceInformation._offsetAlignmentBytesSSBO );
409 gl46core::GLint range[2];
416 deviceInformation._maxClipAndCullDistances =
GLUtil::getGLValue( gl46core::GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES );
417 deviceInformation._maxClipDistances =
to_U32( clipDistanceCount );
418 deviceInformation._maxCullDistances =
to_U32( cullDistanceCount );
422 gl46core::glEnable( gl46core::GL_TEXTURE_CUBE_MAP_SEAMLESS );
423 gl46core::glEnable( gl46core::GL_FRAMEBUFFER_SRGB );
425 gl46core::glEnable( gl46core::GL_CULL_FACE );
430 gl46core::glEnable(
static_cast<gl46core::GLenum
>(
static_cast<U32>(gl46core::GL_CLIP_DISTANCE0) + i) );
443 { gl46core::GL_TIME_ELAPSED, 9 },
444 { gl46core::GL_TRANSFORM_FEEDBACK_OVERFLOW, 6 },
445 { gl46core::GL_VERTICES_SUBMITTED, 6 },
446 { gl46core::GL_PRIMITIVES_SUBMITTED, 6 },
447 { gl46core::GL_VERTEX_SHADER_INVOCATIONS, 6 },
448 { gl46core::GL_SAMPLES_PASSED, 6 },
449 { gl46core::GL_ANY_SAMPLES_PASSED, 6 },
450 { gl46core::GL_PRIMITIVES_GENERATED, 6 },
451 { gl46core::GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 6 },
452 { gl46core::GL_ANY_SAMPLES_PASSED_CONSERVATIVE, 6 },
453 { gl46core::GL_TESS_CONTROL_SHADER_PATCHES, 6},
454 { gl46core::GL_TESS_EVALUATION_SHADER_INVOCATIONS, 6}
463 gl46core::glCreateVertexArrays( 1, &
_dummyVAO );
468 gl46core::glObjectLabel( gl46core::GL_VERTEX_ARRAY,
474 gl46core::glBindVertexArray(
_dummyVAO );
477 constexpr U16 ringLength = 6u;
500 gl46core::glBindVertexArray(0u);
501 gl46core::glDeleteVertexArrays(1, &
_dummyVAO );
522 allocator.deallocate();
563 GLUtil::ValidateSDL( SDL_GL_MakeCurrent( window.getRawWindow(), window.userData()._glContext ));
603 const gl46core::GLenum waitRet = gl46core::glClientWaitSync( sync.first, gl46core::SyncObjectMask::GL_NONE_BIT, 0u );
604 DIVIDE_ASSERT( waitRet != gl46core::GL_WAIT_FAILED,
"GL_API::beginFrame error: Not sure what to do here. Probably raise an exception or something." );
605 if ( waitRet == gl46core::GL_ALREADY_SIGNALED || waitRet == gl46core::GL_CONDITION_SATISFIED )
668 if ( gl46core::glGetGraphicsResetStatus() != gl46core::GL_NO_ERROR )
707 default :
return false;
729 s_lastBuffer->
draw( cmd,
nullptr );
739 thread_local std::array<TexBindEntry, GLStateTracker::MAX_BOUND_TEXTURE_UNITS> s_textureCache;
740 thread_local std::array<gl46core::GLuint, GLStateTracker::MAX_BOUND_TEXTURE_UNITS> s_textureHandles;
741 thread_local std::array<gl46core::GLuint, GLStateTracker::MAX_BOUND_TEXTURE_UNITS> s_textureSamplers;
758 constexpr bool s_useBatchBindTextures =
true;
768 if ( s_useBatchBindTextures )
771 for (
auto& it : s_textureCache )
780 s_textureCache[texEntry._slot] = texEntry;
781 minSlot = std::min( texEntry._slot, minSlot );
782 maxSlot = std::max( texEntry._slot, maxSlot );
785 U8 idx = 0u, bindOffset = minSlot, texCount = maxSlot - minSlot;
786 for (
U8 i = 0u; i < texCount + 1; ++i )
788 const U8 slot = i + minSlot;
793 s_textureHandles[idx] = it.
_handle;
794 s_textureSamplers[idx] = it.
_sampler;
844 const gl46core::GLuint srcHandle =
static_cast<const glTexture*
>(srcView.
_srcTexture)->textureHandle();
858 gl46core::glTextureView( handle,
903 switch ( cmd->type() )
929 gl46core::ClearBufferMask mask = gl46core::ClearBufferMask::GL_COLOR_BUFFER_BIT;
935 mask |= gl46core::ClearBufferMask::GL_DEPTH_BUFFER_BIT;
937 gl46core::glClear( mask );
998 const U32 typeFlag =
toBit( i + 1u );
1002 queryContext[i]._type =
static_cast<QueryType>(typeFlag);
1003 queryContext[i]._index = j++;
1007 for (
auto& queryEntry : queryContext )
1009 if ( queryEntry._query !=
nullptr )
1011 queryEntry._query->
begin();
1028 if ( queryEntry._query !=
nullptr )
1030 queryEntry._query->end();
1032 const I64 qResult = crtCmd->
_waitForResults ? queryEntry._query->getResult() : queryEntry._query->getResultNoWait();
1033 (*crtCmd->
_resultContainer)[queryEntry._index] = { queryEntry._type, qResult };
1056 if ( crtCmd->
_texture != INVALID_HANDLE<Texture> )
1075 assert( pipeline !=
nullptr );
1078 const auto handle = pipeline->descriptor()._shaderProgramHandle;
1086 const auto dumpLogs = [
this]()
1097 if ( activePipeline ==
nullptr )
1112 if ( uniforms !=
nullptr )
1151 const U16 texLayers =
IsCubeTexture( tex->descriptor()._texType ) ? tex->depth() * 6u : tex->depth();
1157 gl46core::glGenerateTextureMipmap(
static_cast<glTexture*
>(tex)->textureHandle() );
1212 Draw( currentDrawCommand );
1220 Draw(currentDrawCommand);
1247 gl46core::MemoryBarrierMask mask = gl46core::GL_NONE_BIT;
1258 const BufferFlags flags = buffer->params()._bufferParams._flags;
1260 switch ( lock.
_type )
1279 mask |= gl46core::GL_BUFFER_UPDATE_BARRIER_BIT;
1283 mask |= gl46core::GL_BUFFER_UPDATE_BARRIER_BIT | gl46core::GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT;
1293 mask |= gl46core::GL_UNIFORM_BARRIER_BIT;
1297 mask |= gl46core::GL_SHADER_STORAGE_BARRIER_BIT;
1301 mask |= gl46core::GL_COMMAND_BARRIER_BIT | gl46core::GL_SHADER_STORAGE_BARRIER_BIT;
1305 mask |= gl46core::GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
1309 mask |= gl46core::GL_ELEMENT_ARRAY_BARRIER_BIT;
1313 mask |= gl46core::GL_BUFFER_UPDATE_BARRIER_BIT | gl46core::GL_SHADER_STORAGE_BARRIER_BIT;
1320 mask |= gl46core::GL_SHADER_STORAGE_BARRIER_BIT;
1332 bool textureBarrierRequired =
false;
1335 if ( it._sourceLayout == it._targetLayout )
1340 switch ( it._targetLayout )
1344 mask |= gl46core::GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
1352 textureBarrierRequired =
true;
1356 mask |= gl46core::GL_TEXTURE_FETCH_BARRIER_BIT | gl46core::GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
1361 mask |= gl46core::GL_TEXTURE_UPDATE_BARRIER_BIT;
1367 mask |= gl46core::GL_FRAMEBUFFER_BARRIER_BIT;
1374 if ( mask != gl46core::MemoryBarrierMask::GL_NONE_BIT )
1376 gl46core::glMemoryBarrier( mask );
1378 if ( textureBarrierRequired )
1380 gl46core::glTextureBarrier();
1406 flushPushConstantsLocks();
1408 bool expected =
true;
1409 if ( s_glFlushQueued.compare_exchange_strong( expected,
false ) )
1412 gl46core::glFlush();
1415 GetStateTracker()._activeRenderTargetDimensions = _context.context().mainWindow().getDrawableSize();
1418 void GL_API::initDescriptorSets()
1423 void GL_API::onThreadCreated( [[maybe_unused]]
const std::thread::id& threadID,
const bool isMainRenderThread )
1425 if ( isMainRenderThread )
1433 assert( SDL_GL_GetCurrentContext() == NULL );
1436 assert( GLUtil::s_glSecondaryContext ==
nullptr &&
"GL_API::syncToThread: double init context for current thread!" );
1437 [[maybe_unused]]
const bool ctxFound = g_ContextPool.
getAvailableContext( GLUtil::s_glSecondaryContext );
1438 assert( ctxFound &&
"GL_API::syncToThread: context not found for current thread!" );
1440 GLUtil::ValidateSDL( SDL_GL_MakeCurrent( GLUtil::s_glMainRenderWindow->getRawWindow(), GLUtil::s_glSecondaryContext ) );
1441 glbinding::Binding::initialize( [](
const char* proc )
noexcept
1443 return (glbinding::ProcAddress)SDL_GL_GetProcAddress( proc );
1447 if constexpr( Config::ENABLE_GPU_VALIDATION )
1449 gl46core::glEnable( gl46core::GL_DEBUG_OUTPUT );
1450 gl46core::glEnable( gl46core::GL_DEBUG_OUTPUT_SYNCHRONOUS );
1451 gl46core::glDebugMessageControl( gl46core::GL_DONT_CARE, gl46core::GL_DEBUG_TYPE_MARKER, gl46core::GL_DONT_CARE, 0, NULL, gl46core::GL_FALSE );
1452 gl46core::glDebugMessageControl( gl46core::GL_DONT_CARE, gl46core::GL_DEBUG_TYPE_PUSH_GROUP, gl46core::GL_DONT_CARE, 0, NULL, gl46core::GL_FALSE );
1453 gl46core::glDebugMessageControl( gl46core::GL_DONT_CARE, gl46core::GL_DEBUG_TYPE_POP_GROUP, gl46core::GL_DONT_CARE, 0, NULL, gl46core::GL_FALSE );
1455 gl46core::glDebugMessageCallback( (gl46core::GLDEBUGPROC)GLUtil::DebugCallback, GLUtil::s_glSecondaryContext );
1458 gl::glMaxShaderCompilerThreadsARB( 0xFFFFFFFF );
1471 if ( stateTracker.
setActiveBuffer( gl46core::GL_ELEMENT_ARRAY_BUFFER, 0 ) == GLStateTracker::BindResult::FAILED )
1475 if ( stateTracker.
setActiveFB( RenderTarget::Usage::RT_READ_WRITE, 0 ) == GLStateTracker::BindResult::FAILED )
1481 for (
U8 i = 0u; i < blendCount; ++i )
1487 const vec2<U16> drawableSize = _context.context().mainWindow().getDrawableSize();
1494 if ( stateTracker.
setActiveProgram( 0u ) == GLStateTracker::BindResult::FAILED )
1502 if ( stateTracker.
setStateBlock({}) == GLStateTracker::BindResult::FAILED )
1514 if ( !
entry._isDirty )
1520 for (
U8 i = 0u; i <
entry._set->_bindingCount; ++i )
1523 const gl46core::GLubyte glBindingSlot = ShaderProgram::GetGLBindingForDescriptorSlot(
entry._usage, srcBinding.
_slot );
1527 case DescriptorSetBindingType::UNIFORM_BUFFER:
1528 case DescriptorSetBindingType::SHADER_STORAGE_BUFFER:
1541 bufferEntry._range._startOffset * glBuffer->getPrimitiveSize(),
1542 bufferEntry._range._length * glBuffer->getPrimitiveSize(),
1550 case DescriptorSetBindingType::COMBINED_IMAGE_SAMPLER:
1563 case DescriptorSetBindingType::IMAGE:
1569 gl46core::GLenum access = gl46core::GL_NONE;
1570 switch ( imageView.
_usage )
1572 case ImageUsage::SHADER_READ: access = gl46core::GL_READ_ONLY;
break;
1573 case ImageUsage::SHADER_WRITE: access = gl46core::GL_WRITE_ONLY;
break;
1574 case ImageUsage::SHADER_READ_WRITE: access = gl46core::GL_READ_WRITE;
break;
1576 case ImageUsage::UNDEFINED:
1577 case ImageUsage::CPU_READ:
1578 case ImageUsage::RT_COLOUR_ATTACHMENT:
1579 case ImageUsage::RT_DEPTH_ATTACHMENT:
1580 case ImageUsage::RT_DEPTH_STENCIL_ATTACHMENT:
1592 GL_API::s_stateTracker.bindTextureImage( glBindingSlot,
1598 glInternalFormat ) == GLStateTracker::BindResult::FAILED )
1603 case DescriptorSetBindingType::COUNT:
1614 bool GL_API::makeTextureViewResident(
const gl46core::GLubyte bindingSlot,
const ImageView& imageView,
const size_t imageViewHash,
const SamplerDescriptor sampler,
const size_t samplerHash )
const
1625 ._slot = bindingSlot
1632 entry._slot = bindingSlot;
1636 entry._handle = getGLTextureView(imageView, imageViewHash, 3u);
1648 size_t tempSampler = samplerHash;
1649 entry._sampler = GetSamplerHandle( sampler, tempSampler );
1653 if ( it._slot == bindingSlot )
1660 s_TexBindQueue.push_back(
MOV(
entry ) );
1664 bool GL_API::setViewportInternal(
const Rect<I32>& viewport )
1666 return s_stateTracker.setViewport( viewport );
1671 return s_stateTracker.setScissor( scissor );
1678 if ( s_stateTracker._activePipeline && *s_stateTracker._activePipeline == pipeline )
1680 return ShaderResult::OK;
1683 s_stateTracker._activePipeline = &pipeline;
1685 s_stateTracker.setAlphaToCoverage(pipeline.descriptor()._alphaToCoverage);
1689 PROFILE_SCOPE(
"Set Raster State", Profiler::Category::Graphics );
1690 if ( s_stateTracker.setStateBlock( pipelineDescriptor.
_stateBlock ) == GLStateTracker::BindResult::FAILED )
1696 PROFILE_SCOPE(
"Set Blending", Profiler::Category::Graphics );
1701 s_stateTracker.setBlending( i++, blendState );
1708 if ( glProgram !=
nullptr )
1711 PROFILE_SCOPE(
"Set Vertex Format", Profiler::Category::Graphics );
1713 s_stateTracker.setVertexFormat( pipelineDescriptor.
_vertexFormat, pipeline.vertexFormatHash() );
1716 PROFILE_SCOPE(
"Set Shader Program", Profiler::Category::Graphics );
1719 ret = Attorney::GLAPIShaderProgram::bind( *glProgram );
1722 if ( ret != ShaderResult::OK )
1724 if ( s_stateTracker.setActiveProgram( 0u ) == GLStateTracker::BindResult::FAILED )
1728 if ( s_stateTracker.setActiveShaderPipeline( 0u ) == GLStateTracker::BindResult::FAILED )
1732 s_stateTracker._activePipeline =
nullptr;
1736 s_stateTracker._activeShaderProgram = glProgram;
1738 context.
descriptorSet( DescriptorSetUsage::PER_DRAW ).dirty(
true);
1743 Console::errorfn(
LOCALE_STR(
"ERROR_GLSL_INVALID_HANDLE" ), handle._index, handle._generation );
1751 return s_stateTracker;
1756 assert( usage != gl46core::GL_NONE );
1757 if ( usage == gl46core::GL_SHADER_STORAGE_BUFFER )
1759 return GLUtil::GLMemory::GLMemoryType::SHADER_BUFFER;
1761 if ( usage == gl46core::GL_UNIFORM_BUFFER )
1763 return GLUtil::GLMemory::GLMemoryType::UNIFORM_BUFFER;
1765 if (usage == gl46core::GL_ELEMENT_ARRAY_BUFFER)
1767 return GLUtil::GLMemory::GLMemoryType::INDEX_BUFFER;
1770 if (usage == gl46core::GL_ARRAY_BUFFER)
1772 return GLUtil::GLMemory::GLMemoryType::VERTEX_BUFFER;
1775 return GLUtil::GLMemory::GLMemoryType::OTHER;
1780 return s_memoryAllocators[
to_base( memoryType )];
1783 void GL_API::QueueFlush() noexcept
1785 if ( Runtime::isMainThread() )
1787 gl46core::glFlush();
1791 s_glFlushQueued.store(
true );
1795 void GL_API::AddDebugMessage(
const char* message,
const U32 id )
1798 if constexpr ( Config::ENABLE_GPU_VALIDATION )
1800 gl46core::glPushDebugGroup( gl46core::GL_DEBUG_SOURCE_APPLICATION,
id, -1, message );
1801 gl46core::glPopDebugGroup();
1803 s_stateTracker._lastInsertedDebugMessage = {message,
id};
1806 void GL_API::PushDebugMessage(
const char* message,
const U32 id )
1810 if constexpr( Config::ENABLE_GPU_VALIDATION )
1812 gl46core::glPushDebugGroup( gl46core::GL_DEBUG_SOURCE_APPLICATION,
id, -1, message );
1814 assert( s_stateTracker._debugScopeDepth < Config::MAX_DEBUG_SCOPE_DEPTH );
1815 s_stateTracker._debugScope[s_stateTracker._debugScopeDepth++] = { message,
id };
1818 void GL_API::PopDebugMessage()
1822 if constexpr( Config::ENABLE_GPU_VALIDATION )
1824 gl46core::glPopDebugGroup();
1826 s_stateTracker._debugScope[s_stateTracker._debugScopeDepth--] = {};
1829 bool GL_API::DeleteShaderPrograms(
const gl46core::GLuint count, gl46core::GLuint* programs )
1831 if ( count > 0 && programs !=
nullptr )
1833 for ( gl46core::GLuint i = 0; i < count; ++i )
1835 if ( s_stateTracker._activeShaderProgramHandle == programs[i] )
1837 if ( s_stateTracker.setActiveProgram( 0u ) == GLStateTracker::BindResult::FAILED )
1842 gl46core::glDeleteProgram( programs[i] );
1845 memset( programs, 0, count *
sizeof( gl46core::GLuint ) );
1851 bool GL_API::DeleteSamplers(
const gl46core::GLuint count, gl46core::GLuint* samplers )
1853 if ( count > 0 && samplers !=
nullptr )
1856 for ( gl46core::GLuint i = 0; i < count; ++i )
1858 const gl46core::GLuint crtSampler = samplers[i];
1859 if ( crtSampler != 0 )
1861 for ( gl46core::GLuint& boundSampler : s_stateTracker._samplerBoundMap )
1863 if ( boundSampler == crtSampler )
1870 gl46core::glDeleteSamplers( count, samplers );
1871 memset( samplers, 0, count *
sizeof( gl46core::GLuint ) );
1879 bool GL_API::DeleteBuffers(
const gl46core::GLuint count, gl46core::GLuint* buffers )
1881 if ( count > 0 && buffers !=
nullptr )
1883 for ( gl46core::GLuint i = 0; i < count; ++i )
1885 const gl46core::GLuint crtBuffer = buffers[i];
1887 for ( gl46core::GLuint& boundBuffer : s_stateTracker._activeBufferID )
1889 if ( boundBuffer == crtBuffer )
1894 if ( s_stateTracker._activeVAOIB == crtBuffer )
1900 gl46core::glDeleteBuffers( count, buffers );
1901 memset( buffers, 0, count *
sizeof( gl46core::GLuint ) );
1908 bool GL_API::DeleteFramebuffers(
const gl46core::GLuint count, gl46core::GLuint* framebuffers )
1910 if ( count > 0 && framebuffers !=
nullptr )
1912 for ( gl46core::GLuint i = 0; i < count; ++i )
1914 const gl46core::GLuint crtFB = framebuffers[i];
1915 for ( gl46core::GLuint& activeFB : s_stateTracker._activeFBID )
1917 if ( activeFB == crtFB )
1923 gl46core::glDeleteFramebuffers( count, framebuffers );
1924 memset( framebuffers, 0, count *
sizeof( gl46core::GLuint ) );
1931 gl46core::GLuint GL_API::GetSamplerHandle(
const SamplerDescriptor sampler,
size_t& samplerHashInOut )
1933 thread_local size_t cached_hash = 0u;
1938 if ( samplerHashInOut == SamplerDescriptor::INVALID_SAMPLER_HASH )
1940 samplerHashInOut =
GetHash(sampler);
1944 if ( cached_hash == samplerHashInOut )
1946 return cached_handle;
1949 cached_hash = samplerHashInOut;
1954 for (
const auto& sampler : s_samplerMap )
1956 if ( sampler._hash == cached_hash )
1959 cached_handle = sampler._glHandle;
1960 return cached_handle;
1967 for (
const auto& sampler : s_samplerMap )
1969 if ( sampler._hash == cached_hash )
1972 cached_handle = sampler._glHandle;
1973 return cached_handle;
1978 cached_handle = glSamplerObject::Construct( sampler );
1979 s_samplerMap.emplace_back(cached_hash, cached_handle );
1980 return cached_handle;
1985 return s_hardwareQueryPool.get();
1988 gl46core::GLsync GL_API::CreateFenceSync()
1994 ++s_fenceSyncCounter[s_LockFrameLifetime - 1u];
1995 return gl46core::glFenceSync( gl46core::GL_SYNC_GPU_COMMANDS_COMPLETE, gl46core::UnusedMask::GL_UNUSED_BIT );
1998 void GL_API::DestroyFenceSync( gl46core::GLsync& sync )
2002 DIVIDE_ASSERT( s_fenceSyncCounter[s_LockFrameLifetime - 1u] > 0u );
2004 --s_fenceSyncCounter[s_LockFrameLifetime - 1u];
2005 gl46core::glDeleteSync( sync );
2011 return std::make_unique<glFramebuffer>( _context, descriptor );
2014 GenericVertexData_ptr GL_API::newGVD(
U32 ringBufferLength,
const std::string_view name )
const
2016 return std::make_shared<glGenericVertexData>( _context, ringBufferLength, name );
2021 return std::make_unique<glShaderBuffer>( _context, descriptor );
#define PROFILE_SCOPE_AUTO(CATEGORY)
#define PROFILE_SCOPE(NAME, CATEGORY)
WindowManager & windowManager() noexcept
static void MaxMSAASamples(const U8 maxSampleCount) noexcept
static void end(glFramebuffer &rt, const RTTransitionMask &mask)
static void begin(glFramebuffer &rt, const RTDrawDescriptor &drawPolicy, const RTClearDescriptor &clearPolicy)
static void uploadPushConstants(glShaderProgram &program, const PushConstantsStruct &pushConstants)
vec2< U16 > getDrawableSize() const noexcept
SDL_Window * getRawWindow() const noexcept
Rough around the edges Adapter pattern abstracting the actual rendering API and access to the GPU.
static bool IsSubmitCommand(GFX::CommandType type) noexcept
static const DeviceInformation & GetDeviceInformation() noexcept
GFXRTPool & renderTargetPool() noexcept
void registerDrawCalls(U32 count) noexcept
static U64 FrameCount() noexcept
static void OverrideDeviceInformation(const DeviceInformation &info) noexcept
GFXDescriptorSet & descriptorSet(DescriptorSetUsage usage) noexcept
PerformanceMetrics & getPerformanceMetrics() noexcept
RenderTarget * getRenderTarget(const RenderTargetID target) const
const vector< RenderTarget_uptr > & getRenderTargets() const noexcept
static eastl::fixed_vector< TexBindEntry, 32, false > s_TexBindQueue
static std::atomic_bool s_glFlushQueued
static void PopDebugMessage()
GL_API(GFXDevice &context)
static glHardwareQueryPool * GetHardwareQueryPool() noexcept
static void DestroyFenceSync(gl46core::GLsync &sync)
gl46core::GLuint getGLTextureView(ImageView srcView, size_t srcViewHash, U8 lifetimeInFrames) const
void onRenderThreadLoopStart() override
void clearStates(GLStateTracker &stateTracker) const
Reset as much of the GL default state as possible within the limitations given.
static gl46core::GLsync CreateFenceSync()
static std::array< size_t, to_base(GLUtil::GLMemory::GLMemoryType::COUNT)> s_memoryAllocatorSizes
static constexpr U32 s_LockFrameLifetime
static void PushDebugMessage(const char *message, U32 id=U32_MAX)
gl46core::GLuint _dummyVAO
Time::ProfileTimer & _swapBufferTimer
static void AddDebugMessage(const char *message, U32 id=U32_MAX)
eastl::fixed_vector< CachedSamplerEntry, InitialSamplerMapSize, true > SamplerObjectMap
GFX::MemoryBarrierCommand _uniformsMemCommand
void closeRenderingAPI() override
Clear everything that was setup in initRenderingAPI()
static SharedMutex s_samplerMapLock
static GLStateTracker & GetStateTracker() noexcept
bool drawToWindow(DisplayWindow &window) override
Prepare the GPU for rendering a frame.
static GLStateTracker s_stateTracker
void onRenderThreadLoopEnd() override
ErrorCode initRenderingAPI(I32 argc, char **argv, Configuration &config) override
Try and create a valid OpenGL context taking in account the specified command line arguments.
static ShaderResult BindPipeline(GFXDevice &context, const Pipeline &pipeline)
void flushPushConstantsLocks()
eastl::stack< HardwareQueryContext > _queryContext
bool frameEnded() override
std::array< glHardwareQueryRing_uptr, to_base(GlobalQueryTypes::COUNT)> _performanceQueries
Hardware query objects used for performance measurements.
void flushCommand(GFX::CommandBase *cmd) override
void flushWindow(DisplayWindow &window) override
void idle(bool fast) override
static SamplerObjectMap s_samplerMap
static U32 s_fenceSyncCounter[s_LockFrameLifetime]
@ TESSELLATION_EVAL_INVOCATIONS
void preFlushCommandBuffer(Handle< GFX::CommandBuffer > commandBuffer) override
bool frameStarted() override
static std::array< GLUtil::GLMemory::DeviceAllocator, to_base(GLUtil::GLMemory::GLMemoryType::COUNT)> s_memoryAllocators
void endPerformanceQueries()
static GLUtil::glTextureViewCache s_textureViewCache
static std::unique_ptr< glHardwareQueryPool > s_hardwareQueryPool
void prepareFlushWindow(DisplayWindow &window) override
void flushTextureBindQueue()
static bool Draw(const GenericDrawCommand &cmd)
std::pair< gl46core::GLuint, bool > allocate(size_t hash, bool retry=false)
void deallocate(gl46core::GLuint handle, U32 frameDelay=1)
FORCE_INLINE I64 getGUID() const noexcept
static size_t TotalThreadCount(TaskPoolType type) noexcept
static void CleanExpiredSyncObjects(RenderAPI api, U64 frameNumber)
static SyncObjectHandle CreateSyncObject(RenderAPI api, U8 flag=DEFAULT_SYNC_FLAG_INTERNAL)
T * find(PoolHandle handle) const
PlatformContext & context() noexcept
DisplayWindow & mainWindow() noexcept
Application & app() noexcept
Renderer Programming Interface.
U16 getWidth() const noexcept
U16 getHeight() const noexcept
static void DestroyStaticData()
bool uploadUniformData(const UniformData &data, DescriptorSet &set, GFX::MemoryBarrierCommand &memCmdInOut)
ImageView getView() const noexcept
virtual void draw(const GenericDrawCommand &command, VDIUserData *data)=0
static constexpr Handle INVALID_VDI_HANDLE
void blitFrom(RenderTarget *source, const RTBlitParams ¶ms)
glHardwareQueryRing & allocate(gl46core::GLenum queryType)
static void Destruct(gl46core::GLuint &handle)
Base class for shader uniform blocks.
bool bindByteRange(U8 bindIndex, BufferRange range, I32 readIndex=-1)
OpenGL implementation of the ShaderProgram entity.
static void Idle(PlatformContext &platformContext)
static void Copy(const glTexture *source, U8 sourceSamples, const glTexture *destination, U8 destinationSamples, const CopyTexParams ¶ms)
constexpr bool ENABLE_GPU_VALIDATION
Error callbacks, validations, buffer checks, etc. are controlled by this flag. Heavy performance impa...
constexpr U8 MAX_CLIP_DISTANCES
void OnFrameEnd(const U64 frameCount)
std::array< gl46core::GLenum, to_base(QueryType::COUNT)> glQueryTypeTable
const DisplayWindow * s_glMainRenderWindow
void getGLValue(gl46core::GLenum param, T &value, gl46core::GLint index=-1)
Wrapper for glGetIntegerv.
void SubmitRenderCommand(const GenericDrawCommand &drawCommand, const gl46core::GLenum internalFormat)
Note: If internal format is not GL_NONE, an indexed draw is issued!
bool ValidateSDL(const I32 errCode, bool assert)
void OnStartup()
Populate enumeration tables with appropriate API values.
gl46core::GLenum internalTextureType(const TextureType type, const U8 msaaSamples)
void DebugCallback(const gl46core::GLenum source, const gl46core::GLenum type, const gl46core::GLuint id, const gl46core::GLenum severity, const gl46core::GLsizei length, const gl46core::GLchar *message, const void *userParam)
Print OpenGL specific messages.
FormatAndDataType InternalFormatAndDataType(const GFXImageFormat baseFormat, const GFXDataFormat dataType, const GFXImagePacking packing) noexcept
constexpr Optick::Category::Type Graphics
Handle console commands that start with a forward slash.
@ RT_DEPTH_STENCIL_ATTACHMENT
std::array< DescriptorSetEntry, to_base(DescriptorSetUsage::COUNT)> DescriptorSetEntries
std::lock_guard< mutex > LockGuard
constexpr U32 to_U32(const T value)
static constexpr U32 RT_DEPTH_ATTACHMENT_IDX
TextureType TargetType(const ImageView &imageView) noexcept
bool isEnabledOption(const GenericDrawCommand &cmd, CmdRenderOptions option) noexcept
constexpr U64 to_U64(const T value)
constexpr RenderTargetID SCREEN_TARGET_ID
bool DebugBreak(const bool condition) noexcept
@ TRIANGLE_STRIP_ADJACENCY
bool IsCubeTexture(TextureType texType) noexcept
bool IsArrayTexture(TextureType texType) noexcept
std::shared_mutex SharedMutex
size_t GetHash(const PropertyDescriptor< T > &descriptor) noexcept
constexpr gl46core::GLuint GL_NULL_HANDLE
Invalid object value. Used to compare handles and determine if they were properly created.
eastl::vector< Type > vector
std::shared_lock< mutex > SharedLock
constexpr U8 INVALID_TEXTURE_BINDING
constexpr RenderTargetID INVALID_RENDER_TARGET_ID
void efficient_clear(eastl::fixed_vector< T, nodeCount, bEnableOverflow, OverflowAllocator > &fixed_vector)
constexpr U8 to_U8(const T value)
::value constexpr T CLAMPED(T n, T min, T max) noexcept
constexpr bool g_breakOnGLCall
::value constexpr void CLAMP(T &n, T min, T max) noexcept
Clamps value n between min and max.
FORCE_INLINE T * Get(const Handle< T > handle)
Project const SceneEntry & entry
constexpr T toBit(const T X)
Converts an arbitrary positive integer value to a bitwise value used for masks.
constexpr auto to_base(const Type value) -> Type
BufferUpdateUsage _updateUsage
BufferUsageType _usageType
BufferUpdateFrequency _updateFrequency
bool enableRenderAPIDebugging
bool enableRenderAPIBestPractices
bool assertOnRenderAPIError
struct Divide::Configuration::Debug::Renderer renderer
Divide::Configuration::Rendering::ShadowMapping::CSMSettings csm
U8 maxAnisotropicFilteringLevel
struct Divide::Configuration::Rendering::ShadowMapping shadowMapping
struct Divide::Configuration::Rendering rendering
struct Divide::Configuration::Debug debug
static NO_INLINE void errorfn(const char *format, T &&... args)
static NO_INLINE void printfn(const char *format, T &&... args)
static NO_INLINE void d_errorfn(const char *format, T &&... args)
SamplerDescriptor _sampler
DescriptorImageView _imageView
ShaderBufferEntry _buffer
DescriptorSetBindingType _type
DescriptorCombinedImageSampler _sampledImage
DescriptorSetBindingData _data
RTDrawDescriptor _descriptor
RTClearDescriptor _clearDescriptor
RenderTargetID _destination
Handle< Texture > _texture
UColour4 _clearColour
r = depth, g = stencil if target is a depth(+stencil) attachment
Handle< Texture > _texture
U8 _destinationMSAASamples
Handle< Texture > _destination
Handle< Texture > _source
vec3< U32 > _computeGroupSize
QueryResults * _resultContainer
RTTransitionMask _transitionMask
TextureLayoutChanges _textureLayoutChanges
PixelAlignment _pixelPackAlignment
Handle< Texture > _texture
DELEGATE_STD< void, const ImageReadbackData & > _callback
PushConstantsStruct _fastData
UniformData * _uniformData
gl46core::GLuint _sampler
RenderTargetID _activeRenderTargetID
eastl::queue< std::pair< gl46core::GLsync, U64 > > _endFrameFences
static constexpr U8 MAX_BOUND_TEXTURE_UNITS
BindResult setActiveBuffer(gl46core::GLenum target, gl46core::GLuint bufferHandle)
Single place to change buffer objects for every target available.
vector< gl46core::GLboolean > _blendEnabled
void setBlendColour(const UColour4 &blendColour)
Pipeline const * _activePipeline
void setBlending(const BlendingSettings &blendingProperties)
BindResult setStateBlock(const RenderStateBlock &stateBlock)
glShaderProgram * _activeShaderProgram
PrimitiveTopology _activeTopology
bool setScissor(const Rect< I32 > &newScissorRect)
void setPrimitiveTopology(PrimitiveTopology topology)
vec2< U16 > _activeRenderTargetDimensions
bool * _enabledAPIDebugging
BindResult bindTexture(gl46core::GLubyte unit, gl46core::GLuint handle, gl46core::GLuint samplerHandle=0u)
Bind a texture specified by a GL handle and GL type to the specified unit using the sampler object de...
BindResult setActiveShaderPipeline(gl46core::GLuint pipelineHandle)
Change the currently active shader pipeline. Returns false if the pipeline was already bound.
BindResult bindTextures(gl46core::GLubyte unitOffset, gl46core::GLuint textureCount, const gl46core::GLuint *textureHandles, const gl46core::GLuint *samplerHandles)
Bind multiple textures specified by an array of handles and an offset unit.
BindResult setActiveProgram(gl46core::GLuint programHandle)
Change the currently active shader program. Returns false if the program was already bound.
bool setClearColour(const FColour4 &colour)
BindResult setActiveFB(RenderTarget::Usage usage, gl46core::GLuint ID)
glFramebuffer * _activeRenderTarget
U64 _lastSyncedFrameNumber
bool setClearDepth(F32 value)
IndirectIndexedDrawCommand _cmd
GFXImageFormat _baseFormat
ImageViewDescriptor _descriptor
const Texture * _srcTexture
bool lockRange(BufferRange range, SyncObjectHandle &sync) const
PrimitiveTopology _primitiveTopology
AttributeMap _vertexFormat
Handle< ShaderProgram > _shaderProgramHandle
RTBlendStates _blendStates
RenderStateBlock _stateBlock
std::array< BlendingSettings, to_base(RTColourAttachmentSlot::COUNT)> _settings
static constexpr size_t INVALID_SYNC_ID
bool getAvailableContext(SDL_GLContext &ctx) noexcept
bool init(const size_t size, const DisplayWindow &window)
vector< SDLContextEntry > _contexts