Skip to content

Commit 0c4c57d

Browse files
committed
WIP: Use all texture units, bindless texture support
Makes the engine use all texture units and rather than rebinding textures each time sets the correct uniform. Adds support for bindless textures. Bindless textures control texture residency instead of binding them. Both approaches use texture priority which depends on the textures overall usage and usage during last frame.
1 parent 5a44a87 commit 0c4c57d

File tree

15 files changed

+1164
-140
lines changed

15 files changed

+1164
-140
lines changed

src.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ set(RENDERERLIST
102102
${ENGINE_DIR}/renderer/tr_font.cpp
103103
${ENGINE_DIR}/renderer/InternalImage.cpp
104104
${ENGINE_DIR}/renderer/InternalImage.h
105+
${ENGINE_DIR}/renderer/TextureManager.cpp
106+
${ENGINE_DIR}/renderer/TextureManager.h
105107
${ENGINE_DIR}/renderer/tr_image.cpp
106108
${ENGINE_DIR}/renderer/tr_image.h
107109
${ENGINE_DIR}/renderer/tr_image_crn.cpp
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/*
2+
===========================================================================
3+
4+
Daemon BSD Source Code
5+
Copyright (c) 2024 Daemon Developers
6+
All rights reserved.
7+
8+
This file is part of the Daemon BSD Source Code (Daemon Source Code).
9+
10+
Redistribution and use in source and binary forms, with or without
11+
modification, are permitted provided that the following conditions are met:
12+
* Redistributions of source code must retain the above copyright
13+
notice, this list of conditions and the following disclaimer.
14+
* Redistributions in binary form must reproduce the above copyright
15+
notice, this list of conditions and the following disclaimer in the
16+
documentation and/or other materials provided with the distribution.
17+
* Neither the name of the Daemon developers nor the
18+
names of its contributors may be used to endorse or promote products
19+
derived from this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
25+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+
===========================================================================
33+
*/
34+
// TextureManager.cpp
35+
36+
#include "TextureManager.h"
37+
#include "tr_local.h"
38+
39+
Texture::Texture() {
40+
}
41+
42+
Texture::~Texture() {
43+
if ( bindlessTextureResident ) {
44+
MakeNonResident();
45+
}
46+
}
47+
48+
void Texture::UpdateAdjustedPriority( const int totalFrameTextureBinds, const int totalTextureBinds ) {
49+
if ( totalFrameTextureBinds == 0 || totalTextureBinds == 0 ) {
50+
return;
51+
}
52+
53+
adjustedPriority = basePriority + frameBindCounter / totalFrameTextureBinds * 0.5 + totalBindCounter / totalTextureBinds * 1.5;
54+
}
55+
56+
bool Texture::IsResident() const {
57+
return bindlessTextureResident;
58+
}
59+
60+
void Texture::MakeResident() {
61+
glMakeTextureHandleResidentARB( bindlessTextureHandle );
62+
bindlessTextureResident = true;
63+
}
64+
65+
void Texture::MakeNonResident() {
66+
glMakeTextureHandleNonResidentARB( bindlessTextureHandle );
67+
bindlessTextureResident = false;
68+
}
69+
70+
void Texture::GenBindlessHandle() {
71+
bindlessTextureHandle = glGetTextureHandleARB( textureHandle );
72+
73+
if ( bindlessTextureHandle == 0 ) {
74+
Sys::Drop( "Failed to generate bindless texture handle" );
75+
}
76+
77+
hasBindlessHandle = true;
78+
}
79+
80+
// TextureManager textureManager;
81+
82+
TextureManager::TextureManager() {
83+
textureUnits.reserve( glConfig2.maxTextureUnits );
84+
}
85+
86+
TextureManager::~TextureManager() = default;
87+
88+
void TextureManager::UpdateAdjustedPriorities() {
89+
for ( Texture* texture : textures ) {
90+
texture->UpdateAdjustedPriority( totalFrameTextureBinds, totalTextureBinds );
91+
}
92+
// std::sort( textures.begin(), textures.end(), Texture::Compare() );
93+
94+
totalFrameTextureBinds = 0;
95+
}
96+
97+
void TextureManager::BindTexture( const GLint location, Texture *texture ) {
98+
texture->frameBindCounter++;
99+
texture->totalBindCounter++;
100+
101+
totalFrameTextureBinds++;
102+
totalTextureBinds++;
103+
104+
if( location == -1 ) {
105+
return;
106+
}
107+
108+
if ( texture->IsResident() ) {
109+
glUniformHandleui64ARB( location, texture->bindlessTextureHandle );
110+
return;
111+
}
112+
113+
if( std::find( textures.begin(), textures.end(), texture ) == textures.end() ) {
114+
textures.push_back( texture );
115+
}
116+
117+
// Use bindless textures if possible
118+
if ( glConfig2.bindlessTexturesAvailable ) {
119+
// Bindless textures make the texture state immutable, so generate the handle as late as possible
120+
if ( !texture->hasBindlessHandle ) {
121+
texture->GenBindlessHandle();
122+
}
123+
124+
texture->MakeResident();
125+
126+
// Make lowest priority textures non-resident first
127+
int i = textures.size() - 1;
128+
while ( !glIsTextureHandleResidentARB( texture->bindlessTextureHandle ) ) {
129+
if ( i < 0 ) {
130+
Sys::Drop( "No texture space available" );
131+
}
132+
133+
if ( textures[i]->IsResident() ) {
134+
textures[i]->MakeNonResident();
135+
texture->MakeResident();
136+
}
137+
i--;
138+
}
139+
140+
glUniformHandleui64ARB( location, texture->bindlessTextureHandle );
141+
142+
GL_CheckErrors();
143+
144+
return;
145+
}
146+
147+
int lowestPriorityTexture = 1;
148+
float lowestPriority = 100000.0f;
149+
GLint handle;
150+
151+
// Do a loop once so we don't have to search through it many times for each case
152+
for ( size_t i = 0; i < textureUnits.size(); i++ ) {
153+
// Already bound
154+
if ( textureUnits[i] == texture ) {
155+
glUniform1i( location, i + 1 );
156+
if ( textureSequenceStarted ) {
157+
textureSequence.insert( texture );
158+
}
159+
return;
160+
}
161+
162+
if ( textureSequenceStarted && textureSequence.find( textureUnits[i] ) != textureSequence.end() ) {
163+
continue;
164+
}
165+
166+
// Take note of the texture unit with the lowest priority texture
167+
if ( textureUnits[i] && textureUnits[i]->adjustedPriority < lowestPriority ) {
168+
lowestPriorityTexture = i;
169+
lowestPriority = textureUnits[i]->adjustedPriority;
170+
}
171+
}
172+
173+
// Slot 0 is reserved for non-rendering OpenGL calls that require textures to be bound
174+
if ( textureUnits.size() + 1 < (size_t) glConfig2.maxTextureUnits ) {
175+
textureUnits.push_back( texture );
176+
glActiveTexture( GL_TEXTURE1 + textureUnits.size() - 1 );
177+
handle = textureUnits.size() - 1;
178+
}
179+
else {
180+
// No available texture units
181+
// Bind instead of the lowest priority texture
182+
textureUnits[lowestPriorityTexture] = texture;
183+
glActiveTexture( GL_TEXTURE1 + lowestPriorityTexture );
184+
handle = lowestPriorityTexture;
185+
}
186+
187+
glBindTexture( texture->target, texture->textureHandle );
188+
glUniform1i( location, handle + 1 );
189+
if ( textureSequenceStarted ) {
190+
textureSequence.insert( texture );
191+
}
192+
193+
GL_CheckErrors();
194+
}
195+
196+
void TextureManager::AllNonResident() {
197+
for ( Texture* texture : textures ) {
198+
if ( texture->IsResident() ) {
199+
texture->MakeNonResident();
200+
}
201+
}
202+
}
203+
204+
void TextureManager::BindReservedTexture( const GLenum target, const GLuint handle ) {
205+
glActiveTexture( GL_TEXTURE0 );
206+
glBindTexture( target, handle );
207+
}
208+
209+
// Texture units used within a texture sequence will not be bound to anything else until the texture sequence ends
210+
void TextureManager::StartTextureSequence() {
211+
textureSequenceStarted = true;
212+
}
213+
214+
void TextureManager::EndTextureSequence() {
215+
textureSequenceStarted = false;
216+
/* for ( const Texture* texture : textureSequence ) {
217+
const_cast< Texture* >( texture )->MakeNonResident();
218+
} */
219+
textureSequence.clear();
220+
}
221+
222+
void TextureManager::FreeTextures() {
223+
textures.clear();
224+
textureUnits.clear();
225+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
===========================================================================
3+
4+
Daemon BSD Source Code
5+
Copyright (c) 2024 Daemon Developers
6+
All rights reserved.
7+
8+
This file is part of the Daemon BSD Source Code (Daemon Source Code).
9+
10+
Redistribution and use in source and binary forms, with or without
11+
modification, are permitted provided that the following conditions are met:
12+
* Redistributions of source code must retain the above copyright
13+
notice, this list of conditions and the following disclaimer.
14+
* Redistributions in binary form must reproduce the above copyright
15+
notice, this list of conditions and the following disclaimer in the
16+
documentation and/or other materials provided with the distribution.
17+
* Neither the name of the Daemon developers nor the
18+
names of its contributors may be used to endorse or promote products
19+
derived from this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
25+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+
===========================================================================
33+
*/
34+
// TextureManager.h
35+
36+
#ifndef TEXTURE_MANAGER_H
37+
#define TEXTURE_MANAGER_H
38+
39+
#include <vector>
40+
#include <unordered_set>
41+
#include "GL/glew.h"
42+
43+
enum {
44+
TEXTURE_PRIORITY_LOW = 0,
45+
TEXTURE_PRIORITY_MEDIUM = 1,
46+
TEXTURE_PRIORITY_HIGH = 2,
47+
TEXTURE_PRIORITY_PERSISTENT = 5,
48+
};
49+
50+
class Texture {
51+
public:
52+
GLuint textureHandle = 0;
53+
GLuint64 bindlessTextureHandle = 0;
54+
bool hasBindlessHandle = false;
55+
56+
int frameBindCounter = 0;
57+
int totalBindCounter = 0;
58+
59+
GLenum target = GL_TEXTURE_2D;
60+
61+
int basePriority = 0;
62+
float adjustedPriority = 0.0f;
63+
64+
Texture();
65+
~Texture();
66+
67+
void UpdateAdjustedPriority( const int totalFrameTextureBinds, const int totalTextureBinds );
68+
69+
bool IsResident() const;
70+
void MakeResident();
71+
void MakeNonResident();
72+
73+
void GenBindlessHandle();
74+
75+
struct Compare {
76+
bool operator() ( const Texture* lhs, const Texture* rhs ) {
77+
if ( lhs->adjustedPriority != rhs->adjustedPriority ) {
78+
return lhs->adjustedPriority > rhs->adjustedPriority;
79+
}
80+
return lhs->adjustedPriority < rhs->adjustedPriority;
81+
}
82+
};
83+
84+
private:
85+
bool bindlessTextureResident = false;
86+
};
87+
88+
class TextureManager {
89+
public:
90+
TextureManager();
91+
~TextureManager();
92+
93+
void UpdateAdjustedPriorities();
94+
95+
void BindTexture( const GLint location, Texture* texture );
96+
void AllNonResident();
97+
void BindReservedTexture( const GLenum target, const GLuint handle );
98+
void StartTextureSequence();
99+
void EndTextureSequence();
100+
void FreeTextures();
101+
102+
private:
103+
std::vector<const Texture*> textureUnits;
104+
std::vector<Texture*> textures;
105+
std::unordered_set<const Texture*> textureSequence;
106+
107+
bool textureSequenceStarted;
108+
109+
int totalFrameTextureBinds;
110+
int totalTextureBinds;
111+
};
112+
113+
// extern TextureManager textureManager;
114+
115+
#endif

0 commit comments

Comments
 (0)