Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
glStateTracker.cpp
Go to the documentation of this file.
1
2
4#include "Headers/GLWrapper.h"
5
10
12
13namespace Divide
14{
15
16 namespace
17 {
18 // GL_NONE returns the count
19 FORCE_INLINE gl46core::GLint GetBufferTargetIndex( const gl46core::GLenum target ) noexcept
20 {
21 // Select the appropriate index in the array based on the buffer target
22 switch ( target )
23 {
24 case gl46core::GL_TEXTURE_BUFFER: return 0;
25 case gl46core::GL_UNIFORM_BUFFER: return 1;
26 case gl46core::GL_SHADER_STORAGE_BUFFER: return 2;
27 case gl46core::GL_PIXEL_UNPACK_BUFFER: return 3;
28 case gl46core::GL_DRAW_INDIRECT_BUFFER: return 4;
29 case gl46core::GL_ARRAY_BUFFER: return 5;
30 case gl46core::GL_PARAMETER_BUFFER: return 6;
31 case gl46core::GL_ELEMENT_ARRAY_BUFFER: return 7;
32 case gl46core::GL_PIXEL_PACK_BUFFER: return 8;
33 case gl46core::GL_TRANSFORM_FEEDBACK_BUFFER: return 9;
34 case gl46core::GL_COPY_READ_BUFFER: return 10;
35 case gl46core::GL_COPY_WRITE_BUFFER: return 11;
36 case gl46core::GL_QUERY_BUFFER: return 12;
37 case gl46core::GL_ATOMIC_COUNTER_BUFFER: return 13;
38 case gl46core::GL_NONE: return 14;
39 default: break;
40 };
41
43 return -1;
44 }
45
46 }; //namespace
47
49 {
50 _activeState = {};
51 for (auto& scope : _debugScope)
52 {
53 scope = {};
54 }
56 _attributeHash = 0u;
57 _activePipeline = nullptr;
58 _activeShaderProgram = nullptr;
60 _activeRenderTarget = nullptr;
66 _packAlignment = {};
72 _blendEnabledGlobal = gl46core::GL_FALSE;
74 _blendProperties.clear();
75 _blendEnabled.clear();
76 _blendColour = { 0, 0, 0, 0 };
77 _activeViewport = { -1, -1, -1, -1 };
78 _activeScissor = { -1, -1, -1, -1 };
80 _clearDepthValue = 1.f;
81 _imageBoundMap.clear();
82
83 _vaoBufferData = {};
84 _endFrameFences = {};
86
90 _blendPropertiesGlobal.enabled( false );
91
92 _vaoBufferData.init( GFXDevice::GetDeviceInformation()._maxVertAttributeBindings );
93
94 _imageBoundMap.resize( GFXDevice::GetDeviceInformation()._maxTextureUnits );
95
96 _blendProperties.resize( GFXDevice::GetDeviceInformation()._maxRTColourAttachments, BlendingSettings() );
97 _blendEnabled.resize( GFXDevice::GetDeviceInformation()._maxRTColourAttachments, gl46core::GL_FALSE );
98
99 _activeBufferID = create_array<13, gl46core::GLuint>( GL_NULL_HANDLE );
102 }
103
104
106 {
107 _activeTopology = topology;
108 }
109
110 void GLStateTracker::setVertexFormat( const AttributeMap& attributes, const size_t attributeHash )
111 {
113
114 if ( _attributeHash == attributeHash)
115 {
116 NOP();
117 //DebugBreak();
118 return;
119 }
120
121 _attributeHash = attributeHash;
122
123 // Update vertex attributes if needed (e.g. if offsets changed)
124 for ( U8 idx = 0u; idx < to_base( AttribLocation::COUNT ); ++idx )
125 {
126 const AttributeDescriptor& descriptor = attributes._attributes[idx];
127
128 if (descriptor != _currentAttributes[idx] )
129 {
130 if ( descriptor._dataType == GFXDataFormat::COUNT )
131 {
132 gl46core::glDisableVertexAttribArray( idx );
133 }
134 else
135 {
136 gl46core::glEnableVertexAttribArray( idx );
137 gl46core::glVertexAttribBinding( idx, descriptor._vertexBindingIndex );
138 const bool isIntegerType = descriptor._dataType != GFXDataFormat::FLOAT_16 && descriptor._dataType != GFXDataFormat::FLOAT_32;
139
140 if ( !isIntegerType || descriptor._normalized )
141 {
142 gl46core::glVertexAttribFormat( idx,
143 descriptor._componentsPerElement,
145 descriptor._normalized ? gl46core::GL_TRUE : gl46core::GL_FALSE,
146 static_cast<gl46core::GLuint>(descriptor._strideInBytes) );
147 }
148 else
149 {
150 gl46core::glVertexAttribIFormat( idx,
151 descriptor._componentsPerElement,
153 static_cast<gl46core::GLuint>(descriptor._strideInBytes) );
154 }
155 }
156 _currentAttributes[idx] = descriptor;
157 }
158 }
159
160 for ( const VertexBinding& vertBinding : attributes._vertexBindings )
161 {
162 const bool perInstanceDivisor = !vertBinding._perVertexInputRate;
163 if ( _vaoBufferData.instanceDivisorFlag( vertBinding._bufferBindIndex ) != perInstanceDivisor )
164 {
165 gl46core::glVertexBindingDivisor( vertBinding._bufferBindIndex, perInstanceDivisor ? 1u : 0u );
166 _vaoBufferData.instanceDivisorFlag( vertBinding._bufferBindIndex, perInstanceDivisor );
167 }
168 }
169 }
170
172 {
174
175 // Activate the new render state block in an rendering API dependent way
176 if (activateStateBlock( stateBlock ))
177 {
179 }
180
182 }
183
186 {
188
189 // Keep track if we actually affect any OpenGL state
190 bool changed = false;
191 if ( _packAlignment._alignment != pixelPackAlignment._alignment )
192 {
193 gl46core::glPixelStorei( gl46core::GL_PACK_ALIGNMENT, (gl46core::GLint)pixelPackAlignment._alignment );
194 changed = true;
195 }
196
197 if ( _packAlignment._rowLength != pixelPackAlignment._rowLength )
198 {
199 gl46core::glPixelStorei( gl46core::GL_PACK_ROW_LENGTH, (gl46core::GLint)pixelPackAlignment._rowLength );
200 changed = true;
201 }
202
203 if ( _packAlignment._skipRows != pixelPackAlignment._skipRows )
204 {
205 gl46core::glPixelStorei( gl46core::GL_PACK_SKIP_ROWS, (gl46core::GLint)pixelPackAlignment._skipRows );
206 changed = true;
207 }
208
209 if ( _packAlignment._skipPixels != pixelPackAlignment._skipPixels )
210 {
211 gl46core::glPixelStorei( gl46core::GL_PACK_SKIP_PIXELS, (gl46core::GLint)pixelPackAlignment._skipPixels );
212 changed = true;
213 }
214
215 if ( changed )
216 {
217 _packAlignment = pixelPackAlignment;
218 }
219
220 // We managed to change at least one entry
221 return changed;
222 }
223
225 bool GLStateTracker::setPixelUnpackAlignment( const PixelAlignment& pixelUnpackAlignment )
226 {
228
229 // Keep track if we actually affect any OpenGL state
230 bool changed = false;
231 if ( _unpackAlignment._alignment != SIZE_MAX && _unpackAlignment._alignment != pixelUnpackAlignment._alignment )
232 {
233 gl46core::glPixelStorei( gl46core::GL_UNPACK_ALIGNMENT, (gl46core::GLint)pixelUnpackAlignment._alignment );
234 changed = true;
235 }
236
237 if ( pixelUnpackAlignment._rowLength != SIZE_MAX && _unpackAlignment._rowLength != pixelUnpackAlignment._rowLength )
238 {
239 gl46core::glPixelStorei( gl46core::GL_UNPACK_ROW_LENGTH, (gl46core::GLint)pixelUnpackAlignment._rowLength );
240 changed = true;
241 }
242
243 if ( pixelUnpackAlignment._skipRows != SIZE_MAX && _unpackAlignment._skipRows != pixelUnpackAlignment._skipRows )
244 {
245 gl46core::glPixelStorei( gl46core::GL_UNPACK_SKIP_ROWS, (gl46core::GLint)pixelUnpackAlignment._skipRows );
246 changed = true;
247 }
248
249 if ( pixelUnpackAlignment._skipPixels != SIZE_MAX && _unpackAlignment._skipPixels != pixelUnpackAlignment._skipPixels )
250 {
251 gl46core::glPixelStorei( gl46core::GL_UNPACK_SKIP_PIXELS, (gl46core::GLint)pixelUnpackAlignment._skipPixels );
252 changed = true;
253 }
254
255 if ( changed )
256 {
257 _unpackAlignment = pixelUnpackAlignment;
258 }
259 // We managed to change at least one entry
260 return changed;
261 }
262
263 GLStateTracker::BindResult GLStateTracker::bindSamplers( const gl46core::GLubyte unitOffset,
264 const gl46core::GLuint samplerCount,
265 const gl46core::GLuint* const samplerHandles )
266 {
268
270
271 if ( samplerCount > 0 && unitOffset + samplerCount < GFXDevice::GetDeviceInformation()._maxTextureUnits )
272 {
273 if ( samplerCount == 1 )
274 {
275 gl46core::GLuint& handle = _samplerBoundMap[unitOffset];
276 const gl46core::GLuint targetHandle = samplerHandles ? samplerHandles[0] : 0u;
277 if ( handle != targetHandle )
278 {
279 gl46core::glBindSampler( unitOffset, targetHandle );
280 handle = targetHandle;
281 result = BindResult::JUST_BOUND;
282 }
284 }
285 else
286 {
287 // Update bound map
288 bool newBinding = false;
289 for ( gl46core::GLubyte idx = 0u; idx < samplerCount; ++idx )
290 {
291 const U8 slot = unitOffset + idx;
292 const gl46core::GLuint targetHandle = samplerHandles ? samplerHandles[idx] : 0u;
293 gl46core::GLuint& crtHandle = _samplerBoundMap[slot];
294 if ( crtHandle != targetHandle )
295 {
296 crtHandle = targetHandle;
297 newBinding = true;
298 }
299 }
300
301 if ( !newBinding )
302 {
304 }
305 else
306 {
307 gl46core::glBindSamplers( unitOffset, samplerCount, samplerHandles );
308 result = BindResult::JUST_BOUND;
309 }
310 }
311 }
312
313 return result;
314 }
315
316 bool GLStateTracker::unbindTexture( [[maybe_unused]] const TextureType type, const gl46core::GLuint handle )
317 {
319
320 for ( U8 idx = 0u; idx < MAX_BOUND_TEXTURE_UNITS; ++idx )
321 {
322 if ( _textureBoundMap[idx] == handle )
323 {
325 gl46core::glBindTextureUnit( idx, 0u );
326 if ( bindSamplers( idx, 1, nullptr ) == BindResult::FAILED )
327 {
329 }
330 return true;
331 }
332 }
333
334 return false;
335 }
336
338 {
340
343
344 gl46core::glBindTextures( 0u, GFXDevice::GetDeviceInformation()._maxTextureUnits - 1, nullptr );
345 gl46core::glBindSamplers( 0u, GFXDevice::GetDeviceInformation()._maxTextureUnits - 1, nullptr );
346
347 return true;
348 }
349
351 GLStateTracker::BindResult GLStateTracker::bindTexture( const gl46core::GLubyte unit, const gl46core::GLuint handle, const gl46core::GLuint samplerHandle )
352 {
354
355 // Fail if we specified an invalid unit. Assert instead of returning false because this might be related to a bad algorithm
356 DIVIDE_ASSERT( unit < GFXDevice::GetDeviceInformation()._maxTextureUnits, "GLStates error: invalid texture unit specified as a texture binding slot!" );
357
359
360 gl46core::GLuint& crtEntry = _textureBoundMap[unit];
361 if ( crtEntry != handle )
362 {
363 crtEntry = handle;
364 gl46core::glBindTextureUnit( unit, handle );
365 result = BindResult::JUST_BOUND;
366 }
367
368 gl46core::GLuint& crtSampler = _samplerBoundMap[unit];
369 if ( crtSampler != samplerHandle )
370 {
371 crtSampler = samplerHandle;
372 gl46core::glBindSampler( unit, samplerHandle );
373 result = BindResult::JUST_BOUND;
374 }
375
376 return result;
377 }
378
379 GLStateTracker::BindResult GLStateTracker::bindTextures( const gl46core::GLubyte unitOffset,
380 const gl46core::GLuint textureCount,
381 const gl46core::GLuint* const textureHandles,
382 const gl46core::GLuint* const samplerHandles )
383 {
385
386 if ( textureCount == 1 )
387 {
388 return bindTexture( unitOffset,
389 textureHandles == nullptr ? 0u : textureHandles[0],
390 samplerHandles == nullptr ? 0u : samplerHandles[0] );
391 }
393
394 if ( textureCount > 0u && unitOffset + textureCount < GFXDevice::GetDeviceInformation()._maxTextureUnits )
395 {
396 // Update bound map
397 bool newBinding = false;
398 for ( gl46core::GLubyte idx = 0u; idx < textureCount; ++idx )
399 {
400 const U8 slot = unitOffset + idx;
401 const gl46core::GLuint targetHandle = textureHandles ? textureHandles[idx] : 0u;
402 gl46core::GLuint& crtHandle = _textureBoundMap[slot];
403 if ( crtHandle != targetHandle )
404 {
405 crtHandle = targetHandle;
406 newBinding = true;
407 }
408 }
409
410 if ( !newBinding )
411 {
413 }
414 else
415 {
416 gl46core::glBindTextures( unitOffset, textureCount, textureHandles );
417 result = BindResult::JUST_BOUND;
418 }
419
420 const BindResult samplerResult = bindSamplers( unitOffset, textureCount, samplerHandles );
421 // Even if the textures are already bound, the samplers might differ (and that affects the result)
422 if ( samplerResult == BindResult::FAILED || samplerResult == BindResult::JUST_BOUND )
423 {
424 result = samplerResult;
425 }
426 }
427
428 return result;
429 }
430
431 GLStateTracker::BindResult GLStateTracker::bindTextureImage( const gl46core::GLubyte unit, const gl46core::GLuint handle, const gl46core::GLint level,
432 const bool layered, const gl46core::GLint layer, const gl46core::GLenum access,
433 const gl46core::GLenum format )
434 {
436
437 DIVIDE_ASSERT( handle != GL_NULL_HANDLE );
438
439 const ImageBindSettings tempSettings =
440 {
441 ._texture = handle,
442 ._level = level,
443 ._layer = layer,
444 ._access = access,
445 ._format = format,
446 ._layered = layered ? gl46core::GL_TRUE : gl46core::GL_FALSE
447 };
448
449 ImageBindSettings& settings = _imageBoundMap[unit];
450 if ( settings != tempSettings )
451 {
452 glBindImageTexture( unit, handle, level, layered ? gl46core::GL_TRUE : gl46core::GL_FALSE, layer, access, format );
453 settings = tempSettings;
455 }
456
458 }
459
461 GLStateTracker::BindResult GLStateTracker::bindActiveBuffer( const gl46core::GLuint location, gl46core::GLuint bufferID, size_t offset, size_t stride )
462 {
464
466 const VAOBindings::BufferBindingParams currentParams
467 {
468 ._id = bufferID,
469 ._offset = offset,
470 ._stride = stride
471 };
472
473 if ( bindings != currentParams )
474 {
475 // Bind the specified buffer handle to the desired buffer target
476 gl46core::glBindVertexBuffer( location, bufferID, static_cast<gl46core::GLintptr>(offset), static_cast<gl46core::GLsizei>(stride) );
477 // Remember the new binding for future reference
478 _vaoBufferData.bindingParams( location, currentParams );
480 }
481
483 }
484
485 GLStateTracker::BindResult GLStateTracker::bindActiveBuffers( const gl46core::GLuint location, const gl46core::GLsizei count, gl46core::GLuint* bufferIDs, gl46core::GLintptr* offsets, gl46core::GLsizei* strides )
486 {
488
489 bool needsBind = false;
490 for ( gl46core::GLsizei i = 0u; i < count; ++i )
491 {
493 const VAOBindings::BufferBindingParams currentParams
494 {
495 ._id = bufferIDs[i],
496 ._offset = to_size(offsets[i]),
497 ._stride = to_size(strides[i])
498 };
499 if ( bindings != currentParams )
500 {
501 _vaoBufferData.bindingParams( location + i, currentParams );
502 needsBind = true;
503 }
504 }
505 if ( needsBind )
506 {
507 gl46core::glBindVertexBuffers( location, count, bufferIDs, offsets, strides );
509 }
510
512 }
513
515 {
516 gl46core::GLuint temp = 0;
517 return setActiveFB( usage, ID, temp );
518 }
519
522 GLStateTracker::BindResult GLStateTracker::setActiveFB( const RenderTarget::Usage usage, gl46core::GLuint ID, gl46core::GLuint& previousID )
523 {
525
526 // We may query the active framebuffer handle and get an invalid handle in
527 // return and then try to bind the queried handle
528 // This is, for example, in save/restore FB scenarios. An invalid handle
529 // will just reset the buffer binding
530 if ( ID == GL_NULL_HANDLE )
531 {
532 ID = 0;
533 }
534 previousID = _activeFBID[to_U32( usage )];
535
536 // Prevent double bind
537 if ( _activeFBID[to_U32( usage )] == ID )
538 {
540 {
543 {
545 }
546 }
547 else
548 {
550 }
551 }
552
553 // Bind the requested buffer to the appropriate target
554 switch ( usage )
555 {
557 {
558 // According to documentation this is equivalent to independent calls to
559 // bindFramebuffer(read, ID) and bindFramebuffer(write, ID)
560 gl46core::glBindFramebuffer( gl46core::GL_FRAMEBUFFER, ID );
561 // This also overrides the read and write bindings
564 } break;
566 {
567 gl46core::glBindFramebuffer( gl46core::GL_READ_FRAMEBUFFER, ID );
568 } break;
570 {
571 gl46core::glBindFramebuffer( gl46core::GL_DRAW_FRAMEBUFFER, ID );
572 } break;
573 default: DIVIDE_UNEXPECTED_CALL(); break;
574 };
575
576 // Remember the new binding state for future reference
577 _activeFBID[to_U32( usage )] = ID;
578
580 }
581
583 GLStateTracker::BindResult GLStateTracker::setActiveBuffer( const gl46core::GLenum target, const gl46core::GLuint bufferHandle, gl46core::GLuint& previousID )
584 {
586
587 gl46core::GLuint& crtBinding = target != gl46core::GL_ELEMENT_ARRAY_BUFFER
588 ? _activeBufferID[GetBufferTargetIndex( target )]
589 : _activeVAOIB;
590 previousID = crtBinding;
591
592 // Prevent double bind (hope that this is the most common case. Should be.)
593 if ( previousID == bufferHandle )
594 {
596 }
597
598 // Remember the new binding for future reference
599 crtBinding = bufferHandle;
600 // Bind the specified buffer handle to the desired buffer target
601 glBindBuffer( target, bufferHandle );
603 }
604
605 GLStateTracker::BindResult GLStateTracker::setActiveBuffer( const gl46core::GLenum target, const gl46core::GLuint bufferHandle )
606 {
607 gl46core::GLuint temp = 0u;
608 return setActiveBuffer( target, bufferHandle, temp );
609 }
610
611 GLStateTracker::BindResult GLStateTracker::setActiveBufferIndexRange( const gl46core::GLenum target, const gl46core::GLuint bufferHandle, const gl46core::GLuint bindIndex, const size_t offsetInBytes, const size_t rangeInBytes, gl46core::GLuint& previousID )
612 {
614
615 BindConfig& crtConfig = _currentBindConfig[GetBufferTargetIndex( target )];
616 DIVIDE_ASSERT( bindIndex < crtConfig.size() );
617
618 BindConfigEntry& entry = crtConfig[bindIndex];
619
620 if ( entry._handle != bufferHandle ||
621 entry._offset != offsetInBytes ||
622 entry._range != rangeInBytes )
623 {
624 previousID = entry._handle;
625 entry = { bufferHandle, offsetInBytes, rangeInBytes };
626 if ( offsetInBytes == 0u && rangeInBytes == 0u )
627 {
628 gl46core::glBindBufferBase( target, bindIndex, bufferHandle );
629 }
630 else
631 {
632 gl46core::glBindBufferRange( target, bindIndex, bufferHandle, offsetInBytes, rangeInBytes );
633 }
635 }
636
638 }
639
640 GLStateTracker::BindResult GLStateTracker::setActiveBufferIndex( const gl46core::GLenum target, const gl46core::GLuint bufferHandle, const gl46core::GLuint bindIndex )
641 {
642 gl46core::GLuint temp = 0u;
643 return setActiveBufferIndex( target, bufferHandle, bindIndex, temp );
644 }
645
646 GLStateTracker::BindResult GLStateTracker::setActiveBufferIndex( const gl46core::GLenum target, const gl46core::GLuint bufferHandle, const gl46core::GLuint bindIndex, gl46core::GLuint& previousID )
647 {
648 return setActiveBufferIndexRange( target, bufferHandle, bindIndex, 0u, 0u, previousID );
649 }
650
651 GLStateTracker::BindResult GLStateTracker::setActiveBufferIndexRange( const gl46core::GLenum target, const gl46core::GLuint bufferHandle, const gl46core::GLuint bindIndex, const size_t offsetInBytes, const size_t rangeInBytes )
652 {
653 gl46core::GLuint temp = 0u;
654 return setActiveBufferIndexRange( target, bufferHandle, bindIndex, offsetInBytes, rangeInBytes, temp );
655 }
656
658 GLStateTracker::BindResult GLStateTracker::setActiveProgram( const gl46core::GLuint programHandle )
659 {
661
662 // Check if we are binding a new program or unbinding all shaders
663 // Prevent double bind
664 if ( _activeShaderProgramHandle != programHandle )
665 {
667 {
669 }
670
671 // Remember the new binding for future reference
672 _activeShaderProgramHandle = programHandle;
673 // Bind the new program
674 gl46core::glUseProgram( programHandle );
675 if ( programHandle == 0u )
676 {
677 _activeShaderProgram = nullptr;
678 }
680 }
681
683 }
684
687 {
689
690 // Check if we are binding a new program or unbinding all shaders
691 // Prevent double bind
692 if ( _activeShaderPipelineHandle != pipelineHandle )
693 {
695 {
697 }
698
699 // Remember the new binding for future reference
700 _activeShaderPipelineHandle = pipelineHandle;
701 // Bind the new pipeline
702 gl46core::glBindProgramPipeline( pipelineHandle );
703 if ( pipelineHandle == 0u )
704 {
705 _activeShaderProgram = nullptr;
706 }
708 }
709
711 }
712
713 void GLStateTracker::setBlendColour( const UColour4& blendColour )
714 {
715 if ( _blendColour != blendColour )
716 {
717 _blendColour.set( blendColour );
718
719 const FColour4 floatColour = Util::ToFloatColour( blendColour );
720 gl46core::glBlendColor( floatColour.r, floatColour.g, floatColour.b, floatColour.a );
721 }
722 }
723
724 void GLStateTracker::setBlending( const BlendingSettings& blendingProperties )
725 {
727
728 const bool enable = blendingProperties.enabled();
729
730 if ( _blendEnabledGlobal == gl46core::GL_TRUE != enable )
731 {
732 enable ? gl46core::glEnable( gl46core::GL_BLEND ) : gl46core::glDisable( gl46core::GL_BLEND );
733 _blendEnabledGlobal = enable ? gl46core::GL_TRUE : gl46core::GL_FALSE;
734 std::fill( std::begin( _blendEnabled ), std::end( _blendEnabled ), _blendEnabledGlobal );
735 }
736
737 if ( enable && _blendPropertiesGlobal != blendingProperties )
738 {
739 if ( blendingProperties.blendOpAlpha() != BlendOperation::COUNT )
740 {
741 if ( blendingProperties.blendSrc() != _blendPropertiesGlobal.blendSrc() ||
742 blendingProperties.blendDest() != _blendPropertiesGlobal.blendDest() ||
743 blendingProperties.blendSrcAlpha() != _blendPropertiesGlobal.blendSrcAlpha() ||
744 blendingProperties.blendDestAlpha() != _blendPropertiesGlobal.blendDestAlpha() )
745 {
746 gl46core::glBlendFuncSeparate( GLUtil::glBlendTable[to_base( blendingProperties.blendSrc() )],
747 GLUtil::glBlendTable[to_base( blendingProperties.blendDest() )],
748 GLUtil::glBlendTable[to_base( blendingProperties.blendSrcAlpha() )],
749 GLUtil::glBlendTable[to_base( blendingProperties.blendDestAlpha() )] );
750 }
751
752 if ( blendingProperties.blendOp() != _blendPropertiesGlobal.blendOp() ||
753 blendingProperties.blendOpAlpha() != _blendPropertiesGlobal.blendOpAlpha() )
754 {
755 gl46core::glBlendEquationSeparate( GLUtil::glBlendOpTable[blendingProperties.blendOp() != BlendOperation::COUNT
756 ? to_base( blendingProperties.blendOp() )
758 GLUtil::glBlendOpTable[to_base( blendingProperties.blendOpAlpha() )] );
759 }
760 }
761 else
762 {
763 if ( blendingProperties.blendSrc() != _blendPropertiesGlobal.blendSrc() ||
764 blendingProperties.blendDest() != _blendPropertiesGlobal.blendDest() )
765 {
766 gl46core::glBlendFunc( GLUtil::glBlendTable[to_base( blendingProperties.blendSrc() )],
767 GLUtil::glBlendTable[to_base( blendingProperties.blendDest() )] );
768 }
769 if ( blendingProperties.blendOp() != _blendPropertiesGlobal.blendOp() )
770 {
771 gl46core::glBlendEquation( GLUtil::glBlendOpTable[blendingProperties.blendOp() != BlendOperation::COUNT
772 ? to_base( blendingProperties.blendOp() )
774 }
775
776 }
777
778 _blendPropertiesGlobal = blendingProperties;
779
780 std::fill( std::begin( _blendProperties ), std::end( _blendProperties ), _blendPropertiesGlobal );
781 }
782 }
783
784 void GLStateTracker::setBlending( const gl46core::GLuint drawBufferIdx, const BlendingSettings& blendingProperties )
785 {
787
788 const bool enable = blendingProperties.enabled();
789
790 assert( drawBufferIdx < GFXDevice::GetDeviceInformation()._maxRTColourAttachments );
791
792 if ( _blendEnabled[drawBufferIdx] == gl46core::GL_TRUE != enable )
793 {
794 enable ? gl46core::glEnablei( gl46core::GL_BLEND, drawBufferIdx ) : gl46core::glDisablei( gl46core::GL_BLEND, drawBufferIdx );
795 _blendEnabled[drawBufferIdx] = enable ? gl46core::GL_TRUE : gl46core::GL_FALSE;
796 if ( !enable )
797 {
798 _blendEnabledGlobal = gl46core::GL_FALSE;
799 }
800 }
801
802 BlendingSettings& crtProperties = _blendProperties[drawBufferIdx];
803
804 if ( enable && crtProperties != blendingProperties )
805 {
806 if ( blendingProperties.blendOpAlpha() != BlendOperation::COUNT )
807 {
808 if ( blendingProperties.blendSrc() != crtProperties.blendSrc() ||
809 blendingProperties.blendDest() != crtProperties.blendDest() ||
810 blendingProperties.blendSrcAlpha() != crtProperties.blendSrcAlpha() ||
811 blendingProperties.blendDestAlpha() != crtProperties.blendDestAlpha() )
812 {
813 gl46core::glBlendFuncSeparatei( drawBufferIdx,
814 GLUtil::glBlendTable[to_base( blendingProperties.blendSrc() )],
815 GLUtil::glBlendTable[to_base( blendingProperties.blendDest() )],
816 GLUtil::glBlendTable[to_base( blendingProperties.blendSrcAlpha() )],
817 GLUtil::glBlendTable[to_base( blendingProperties.blendDestAlpha() )] );
818
819 _blendPropertiesGlobal.blendSrc() = blendingProperties.blendSrc();
820 _blendPropertiesGlobal.blendDest() = blendingProperties.blendDest();
821 _blendPropertiesGlobal.blendSrcAlpha() = blendingProperties.blendSrcAlpha();
822 _blendPropertiesGlobal.blendDestAlpha() = blendingProperties.blendDestAlpha();
823 }
824
825 if ( blendingProperties.blendOp() != crtProperties.blendOp() ||
826 blendingProperties.blendOpAlpha() != crtProperties.blendOpAlpha() )
827 {
828 gl46core::glBlendEquationSeparatei( drawBufferIdx,
829 GLUtil::glBlendOpTable[blendingProperties.blendOp() != BlendOperation::COUNT
830 ? to_base( blendingProperties.blendOp() )
832 GLUtil::glBlendOpTable[to_base( blendingProperties.blendOpAlpha() )] );
833
834 _blendPropertiesGlobal.blendOp() = blendingProperties.blendOp();
835 _blendPropertiesGlobal.blendOpAlpha() = blendingProperties.blendOpAlpha();
836 }
837 }
838 else
839 {
840 if ( blendingProperties.blendSrc() != crtProperties.blendSrc() ||
841 blendingProperties.blendDest() != crtProperties.blendDest() )
842 {
843 gl46core::glBlendFunci( drawBufferIdx,
844 GLUtil::glBlendTable[to_base( blendingProperties.blendSrc() )],
845 GLUtil::glBlendTable[to_base( blendingProperties.blendDest() )] );
846
847 _blendPropertiesGlobal.blendSrc() = blendingProperties.blendSrc();
848 _blendPropertiesGlobal.blendDest() = blendingProperties.blendDest();
849 }
850
851 if ( blendingProperties.blendOp() != crtProperties.blendOp() )
852 {
853 gl46core::glBlendEquationi( drawBufferIdx,
854 GLUtil::glBlendOpTable[blendingProperties.blendOp() != BlendOperation::COUNT
855 ? to_base( blendingProperties.blendOp() )
857 _blendPropertiesGlobal.blendOp() = blendingProperties.blendOp();
858 }
859 }
860
861 crtProperties = blendingProperties;
862 }
863 }
864
867 {
868 if ( viewport.z > 0 && viewport.w > 0 && viewport != _activeViewport )
869 {
870 gl46core::glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
871 _activeViewport.set( viewport );
872 return true;
873 }
874
875 return false;
876 }
877
879 {
880 if ( colour != _activeClearColour )
881 {
882 gl46core::glClearColor( colour.r, colour.g, colour.b, colour.a );
883 _activeClearColour.set( colour );
884 return true;
885 }
886
887 return false;
888 }
889
891 {
892 if ( !COMPARE( _clearDepthValue, value ) )
893 {
894 gl46core::glClearDepth( value );
895 _clearDepthValue = value;
896 return true;
897 }
898
899 return false;
900 }
901
903 {
904 if ( rect != _activeScissor )
905 {
906 gl46core::glScissor( rect.x, rect.y, rect.z, rect.w );
907 _activeScissor.set( rect );
908 return true;
909 }
910
911 return false;
912 }
913
914 bool GLStateTracker::setAlphaToCoverage( const bool state )
915 {
916 if ( _alphaToCoverageEnabled != state )
917 {
919 if ( state )
920 {
921 gl46core::glEnable( gl46core::GL_SAMPLE_ALPHA_TO_COVERAGE );
922 }
923 else
924 {
925 gl46core::glDisable( gl46core::GL_SAMPLE_ALPHA_TO_COVERAGE );
926 }
927
928 return true;
929 }
930
931 return false;
932 }
933
934 gl46core::GLuint GLStateTracker::getBoundTextureHandle( const U8 slot ) const noexcept
935 {
936 return _textureBoundMap[slot];
937 }
938
939 gl46core::GLuint GLStateTracker::getBoundSamplerHandle( const U8 slot ) const noexcept
940 {
941 return _samplerBoundMap[slot];
942 }
943
944 gl46core::GLuint GLStateTracker::getBoundProgramHandle() const noexcept
945 {
947 }
948
949 gl46core::GLuint GLStateTracker::getBoundBuffer( const gl46core::GLenum target, const gl46core::GLuint bindIndex ) const noexcept
950 {
951 size_t offset, range;
952 return getBoundBuffer( target, bindIndex, offset, range );
953 }
954
955 gl46core::GLuint GLStateTracker::getBoundBuffer( const gl46core::GLenum target, const gl46core::GLuint bindIndex, size_t& offsetOut, size_t& rangeOut ) const noexcept
956 {
957 const BindConfigEntry& entry = _currentBindConfig[GetBufferTargetIndex( target )][bindIndex];
958 offsetOut = entry._offset;
959 rangeOut = entry._range;
960 return entry._handle;
961 }
962
963 void GLStateTracker::getActiveViewport( Rect<I32>& viewportOut ) const noexcept
964 {
965 viewportOut = _activeViewport;
966 }
967
968 bool GLStateTracker::setDepthWrite( const bool state )
969 {
970 if ( _activeState._depthWriteEnabled != state )
971 {
972 gl46core::glDepthMask( state ? gl46core::GL_TRUE : gl46core::GL_FALSE );
973 return true;
974 }
975
976 return false;
977 }
978
982 {
984
985 bool ret = false;
987 {
988 newBlock._stencilEnabled ? gl46core::glEnable( gl46core::GL_STENCIL_TEST ) : gl46core::glDisable( gl46core::GL_STENCIL_TEST );
989 ret = true;
990 }
991
993 {
994 newBlock._depthTestEnabled ? gl46core::glEnable( gl46core::GL_DEPTH_TEST ) : gl46core::glDisable( gl46core::GL_DEPTH_TEST );
995 ret = true;
996 }
997
999 {
1000 newBlock._scissorTestEnabled ? gl46core::glEnable( gl46core::GL_SCISSOR_TEST ) : gl46core::glDisable( gl46core::GL_SCISSOR_TEST );
1001 ret = true;
1002 }
1003
1004 if ( setDepthWrite( newBlock._depthWriteEnabled ) )
1005 {
1006 ret = true;
1007 }
1008
1009
1011 {
1012 newBlock._rasterizationEnabled ? gl46core::glDisable( gl46core::GL_RASTERIZER_DISCARD )
1013 : gl46core::glEnable( gl46core::GL_RASTERIZER_DISCARD );
1014 ret = true;
1015 }
1016
1017 // Toggle primitive restart on or off
1019 {
1020 newBlock._primitiveRestartEnabled ? gl46core::glEnable( gl46core::GL_PRIMITIVE_RESTART_FIXED_INDEX )
1021 : gl46core::glDisable( gl46core::GL_PRIMITIVE_RESTART_FIXED_INDEX );
1022 ret = true;
1023 }
1024 // Check culling mode (back (CW) / front (CCW) by default)
1025 if ( _activeState._cullMode != newBlock._cullMode )
1026 {
1027 if ( newBlock._cullMode != CullMode::NONE )
1028 {
1030 {
1031 gl46core::glEnable( gl46core::GL_CULL_FACE );
1032 }
1033
1034 gl46core::glCullFace( GLUtil::glCullModeTable[to_U32( newBlock._cullMode )] );
1035 }
1036 else
1037 {
1038 gl46core::glDisable( gl46core::GL_CULL_FACE );
1039 }
1040 ret = true;
1041 }
1042
1043 if ( _activeState._frontFaceCCW != newBlock._frontFaceCCW )
1044 {
1045 gl46core::glFrontFace( newBlock._frontFaceCCW ? gl46core::GL_CCW : gl46core::GL_CW );
1046 ret = true;
1047 }
1048
1049 // Check rasterization mode
1050 if ( _activeState._fillMode != newBlock._fillMode )
1051 {
1052 gl46core::glPolygonMode( gl46core::GL_FRONT_AND_BACK, GLUtil::glFillModeTable[to_U32( newBlock._fillMode )] );
1053 ret = true;
1054 }
1055
1057 {
1058 gl46core::glPatchParameteri( gl46core::GL_PATCH_VERTICES, newBlock._tessControlPoints );
1059 ret = true;
1060 }
1061
1062 // Check the depth function
1063 if ( _activeState._zFunc != newBlock._zFunc )
1064 {
1065 gl46core::glDepthFunc( GLUtil::glCompareFuncTable[to_U32( newBlock._zFunc )] );
1066 ret = true;
1067 }
1068
1069 // Check if we need to change the stencil mask
1071 {
1072 gl46core::glStencilMask( newBlock._stencilWriteMask );
1073 ret = true;
1074 }
1075
1076 // Stencil function is dependent on 3 state parameters set together
1077 if ( _activeState._stencilFunc != newBlock._stencilFunc ||
1078 _activeState._stencilRef != newBlock._stencilRef ||
1080 {
1081 gl46core::glStencilFunc( GLUtil::glCompareFuncTable[to_U32( newBlock._stencilFunc )],
1082 newBlock._stencilRef,
1083 newBlock._stencilMask );
1084 ret = true;
1085 }
1086 // Stencil operation is also dependent on 3 state parameters set together
1087 if ( _activeState._stencilFailOp != newBlock._stencilFailOp ||
1090 {
1091 glStencilOp( GLUtil::glStencilOpTable[to_U32( newBlock._stencilFailOp )],
1094 ret = true;
1095 }
1096
1097 // Check and set polygon offset
1098 if ( !COMPARE( _activeState._zBias, newBlock._zBias ) )
1099 {
1100 if ( IS_ZERO( newBlock._zBias ) )
1101 {
1102 gl46core::glDisable( gl46core::GL_POLYGON_OFFSET_FILL );
1103 }
1104 else
1105 {
1106 gl46core::glEnable( gl46core::GL_POLYGON_OFFSET_FILL );
1107 if ( !COMPARE( _activeState._zBias, newBlock._zBias ) || !COMPARE( _activeState._zUnits, newBlock._zUnits ) )
1108 {
1109 gl46core::glPolygonOffset( newBlock._zBias, newBlock._zUnits );
1110 }
1111 }
1112 ret = true;
1113 }
1114
1115 // Check and set colour mask
1116 if ( _activeState._colourWrite.i != newBlock._colourWrite.i )
1117 {
1118 const P32 cWrite = newBlock._colourWrite;
1119 gl46core::glColorMask( cWrite.b[0] == 1 ? gl46core::GL_TRUE : gl46core::GL_FALSE, // R
1120 cWrite.b[1] == 1 ? gl46core::GL_TRUE : gl46core::GL_FALSE, // G
1121 cWrite.b[2] == 1 ? gl46core::GL_TRUE : gl46core::GL_FALSE, // B
1122 cWrite.b[3] == 1 ? gl46core::GL_TRUE : gl46core::GL_FALSE ); // A
1123
1124 ret = true;
1125 }
1126
1127 if ( ret )
1128 {
1129 _activeState = newBlock;
1130 }
1131
1132 return ret;
1133 }
1134
1135} //namespace Divide
#define DIVIDE_ASSERT(...)
#define DIVIDE_UNEXPECTED_CALL()
#define NOP()
#define FORCE_INLINE
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
static const DeviceInformation & GetDeviceInformation() noexcept
Definition: GFXDevice.inl:158
void init(U32 maxBindings) noexcept
Definition: glResources.cpp:27
const BufferBindingParams & bindingParams(gl46core::GLuint index)
Definition: glResources.cpp:54
bool instanceDivisorFlag(gl46core::GLuint index)
Definition: glResources.cpp:32
void set(const T *v) noexcept
set the 4 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:1241
std::array< gl46core::GLenum, to_base(StencilOperation::COUNT)> glStencilOpTable
Definition: glResources.cpp:89
std::array< gl46core::GLenum, to_base(BlendOperation::COUNT)> glBlendOpTable
Definition: glResources.cpp:87
std::array< gl46core::GLenum, to_base(GFXDataFormat::COUNT)> glDataFormatTable
Definition: glResources.cpp:94
std::array< gl46core::GLenum, to_base(BlendProperty::COUNT)> glBlendTable
Definition: glResources.cpp:86
std::array< gl46core::GLenum, to_base(FillMode::COUNT)> glFillModeTable
Definition: glResources.cpp:91
std::array< gl46core::GLenum, to_base(CullMode::COUNT)> glCullModeTable
Definition: glResources.cpp:90
std::array< gl46core::GLenum, to_base(ComparisonFunction::COUNT)> glCompareFuncTable
Definition: glResources.cpp:88
constexpr Optick::Category::Type Graphics
Definition: Profiler.h:60
FColour4 ToFloatColour(const UColour4 &byteColour) noexcept
Definition: MathHelper.cpp:268
FORCE_INLINE gl46core::GLint GetBufferTargetIndex(const gl46core::GLenum target) noexcept
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
bool IS_ZERO(const T X) noexcept
constexpr U32 to_U32(const T value)
uint8_t U8
constexpr gl46core::GLuint GL_NULL_HANDLE
Invalid object value. Used to compare handles and determine if they were properly created.
Definition: glResources.h:105
@ COUNT
Place all properties above this.
constexpr RenderTargetID INVALID_RENDER_TARGET_ID
constexpr size_t to_size(const T value)
bool COMPARE(T X, U Y) noexcept
Project const SceneEntry & entry
Definition: DefaultScene.h:41
constexpr auto to_base(const Type value) -> Type
VertexBindings _vertexBindings
gl46core::GLuint getBoundBuffer(gl46core::GLenum target, gl46core::GLuint bindIndex) const noexcept
RenderTargetID _activeRenderTargetID
gl46core::GLuint getBoundProgramHandle() const noexcept
void setVertexFormat(const AttributeMap &attributes, const size_t attributeHash)
BindResult setActiveBufferIndex(gl46core::GLenum target, gl46core::GLuint bufferHandle, gl46core::GLuint bindIndex)
BlendingSettings _blendPropertiesGlobal
eastl::queue< std::pair< gl46core::GLsync, U64 > > _endFrameFences
static constexpr U8 MAX_BOUND_TEXTURE_UNITS
bool setAlphaToCoverage(bool state)
BindResult setActiveBuffer(gl46core::GLenum target, gl46core::GLuint bufferHandle)
Single place to change buffer objects for every target available.
vector< gl46core::GLboolean > _blendEnabled
RenderStateBlock _activeState
BindResult bindTextureImage(gl46core::GLubyte unit, gl46core::GLuint handle, gl46core::GLint level, bool layered, gl46core::GLint layer, gl46core::GLenum access, gl46core::GLenum format)
void setBlendColour(const UColour4 &blendColour)
bool setViewport(const Rect< I32 > &viewport)
Change the current viewport area. Redundancy check is performed in GFXDevice class.
Pipeline const * _activePipeline
PerBufferConfig _currentBindConfig
void setBlending(const BlendingSettings &blendingProperties)
BindResult setStateBlock(const RenderStateBlock &stateBlock)
bool unbindTexture(TextureType type, gl46core::GLuint handle)
Returns true if the texture was bound. If the texture was not bound, no state is changed.
BindResult bindActiveBuffer(gl46core::GLuint location, gl46core::GLuint bufferID, size_t offset, size_t stride)
Modify buffer bindings for the active vao.
gl46core::GLuint _activeShaderPipelineHandle
gl46core::GLuint _activeFBID[3]
0 - current framebuffer, 1 - current read only framebuffer, 2 - current write only framebuffer
BindResult setActiveBufferIndexRange(gl46core::GLenum target, gl46core::GLuint bufferHandle, gl46core::GLuint bindIndex, size_t offsetInBytes, size_t rangeInBytes)
Same as normal setActiveBuffer but handles proper binding of different ranges.
PixelAlignment _unpackAlignment
gl46core::GLboolean _blendEnabledGlobal
bool activateStateBlock(const RenderStateBlock &newBlock)
glShaderProgram * _activeShaderProgram
bool setPixelPackAlignment(const PixelAlignment &pixelPackAlignment)
Pixel pack alignment is usually changed by textures, PBOs, etc.
TextureBoundMapDef _textureBoundMap
gl46core::GLuint _activeVAOIB
BindResult bindActiveBuffers(gl46core::GLuint location, gl46core::GLsizei count, gl46core::GLuint *bufferIDs, gl46core::GLintptr *offset, gl46core::GLsizei *strides)
PrimitiveTopology _activeTopology
bool setScissor(const Rect< I32 > &newScissorRect)
void getActiveViewport(Rect< I32 > &viewportOut) const noexcept
void setPrimitiveTopology(PrimitiveTopology topology)
vec2< U16 > _activeRenderTargetDimensions
BindResult bindSamplers(gl46core::GLubyte unitOffset, gl46core::GLuint samplerCount, const gl46core::GLuint *samplerHandles)
gl46core::GLuint _activeShaderProgramHandle
ImageBoundMapDef _imageBoundMap
bool setPixelUnpackAlignment(const PixelAlignment &pixelUnpackAlignment)
Pixel unpack alignment is usually changed by textures, PBOs, etc.
AttributeSettings _currentAttributes
gl46core::GLuint getBoundTextureHandle(U8 slot) const noexcept
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...
SamplerBoundMapDef _samplerBoundMap
BindResult setActiveShaderPipeline(gl46core::GLuint pipelineHandle)
Change the currently active shader pipeline. Returns false if the pipeline was already bound.
bool setDepthWrite(bool state)
DebugScope _debugScope[Config::MAX_DEBUG_SCOPE_DEPTH]
std::array< BindConfigEntry, 32 > BindConfig
std::array< gl46core::GLuint, 13 > _activeBufferID
VB, IB, SB, TB, UB, PUB, DIB.
vector< BlendingSettings > _blendProperties
PixelAlignment _packAlignment
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
bool setClearDepth(F32 value)
gl46core::GLuint getBoundSamplerHandle(U8 slot) const noexcept
gl46core::GLuint _texture
Definition: glResources.h:61
StencilOperation _stencilZFailOp
StencilOperation _stencilFailOp
ComparisonFunction _stencilFunc
StencilOperation _stencilPassOp
ComparisonFunction _zFunc