Skip to content

Commit a8c27e4

Browse files
committed
Pack material data, material system clean-up
Uniforms are now tightly packed into the material struct where possible, e. g. it will try to put a 1-component uniform after a vec3.
1 parent b50aa92 commit a8c27e4

3 files changed

Lines changed: 88 additions & 136 deletions

File tree

src/engine/renderer/Material.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,7 @@ void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pSta
13131313

13141314
material.bspSurface = surface->bspSurface;
13151315
pStage->materialProcessor( &material, pStage, surface );
1316-
pStage->paddedSize = material.shader->GetPaddedSize();
1316+
pStage->paddedSize = material.shader->GetSTD430Size();
13171317

13181318
// HACK: Copy the shaderStage_t and MaterialSurface that we need into the material, so we can use it with glsl_restart
13191319
material.refStage = pStage;

src/engine/renderer/gl_shader.cpp

Lines changed: 58 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,10 +1523,10 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str
15231523
std::string newShaderText;
15241524
std::string materialStruct = "\nstruct Material {\n";
15251525
// 6 kb for materials
1526-
const uint32_t count = ( 4096 + 2048 ) / shader->GetPaddedSize();
1526+
const uint32_t count = ( 4096 + 2048 ) / shader->GetSTD430Size();
15271527
std::string materialBlock = "layout(std140, binding = "
1528-
+ std::to_string( BufferBind::MATERIALS )
1529-
+ ") uniform materialsUBO {\n"
1528+
+ std::to_string( BufferBind::MATERIALS )
1529+
+ ") uniform materialsUBO {\n"
15301530
" Material materials[" + std::to_string( count ) + "]; \n"
15311531
"};\n\n";
15321532

@@ -1582,45 +1582,19 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str
15821582
* #define uniformx materials[baseInstance].uniformx
15831583
*/
15841584

1585-
for( GLUniform* uniform : shader->_uniforms ) {
1586-
if ( uniform->IsGlobal() ) {
1587-
continue;
1588-
}
1589-
1590-
if ( !uniform->IsTexture() ) {
1591-
materialStruct += " " + uniform->GetType() + " " + uniform->GetName();
1592-
1593-
if ( uniform->GetComponentSize() ) {
1594-
materialStruct += "[ " + std::to_string( uniform->GetComponentSize() ) + " ]";
1595-
}
1596-
materialStruct += ";\n";
1597-
1598-
// vec3 is aligned to 4 components, so just pad it with int
1599-
// TODO: Try to move 1 component uniforms here to avoid wasting memory
1600-
if ( uniform->GetSTD430Size() == 3 ) {
1601-
materialStruct += " int ";
1602-
materialStruct += uniform->GetName();
1603-
materialStruct += "_padding;\n";
1604-
}
1605-
}
1585+
for( GLUniform* uniform : shader->_materialSystemUniforms ) {
1586+
materialStruct += " " + uniform->GetType() + " " + uniform->GetName();
16061587

1607-
if ( uniform->IsTexture() ) {
1608-
continue;
1588+
if ( uniform->GetComponentSize() ) {
1589+
materialStruct += "[" + std::to_string( uniform->GetComponentSize() ) + "]";
16091590
}
1591+
materialStruct += ";\n";
16101592

16111593
materialDefines += "#define ";
16121594
materialDefines += uniform->GetName();
16131595

1614-
if ( uniform->IsTexture() ) { // Driver bug: AMD compiler crashes when using the SSBO value directly
1615-
materialDefines += "_initial uvec2("; // We'll need this to create sampler objects later
1616-
}
1617-
16181596
materialDefines += " materials[baseInstance & 0xFFF].";
16191597
materialDefines += uniform->GetName();
1620-
1621-
if ( uniform->IsTexture() ) {
1622-
materialDefines += " )";
1623-
}
16241598

16251599
materialDefines += "\n";
16261600
}
@@ -1645,13 +1619,11 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str
16451619
while( std::getline( shaderTextStream, line, '\n' ) ) {
16461620
bool skip = false;
16471621
if ( line.find( "uniform" ) < line.find( "//" ) && line.find( ";" ) != std::string::npos ) {
1648-
for ( GLUniform* uniform : shader->_uniforms ) {
1649-
if ( !uniform->IsGlobal() ) {
1650-
const size_t pos = line.find( uniform->GetName() );
1651-
if ( pos != std::string::npos && !Str::cisalpha( line[pos + strlen( uniform->GetName() )] ) ) {
1652-
skip = true;
1653-
break;
1654-
}
1622+
for ( GLUniform* uniform : shader->_materialSystemUniforms ) {
1623+
const size_t pos = line.find( uniform->GetName() );
1624+
if ( pos != std::string::npos && !Str::cisalpha( line[pos + strlen( uniform->GetName() )] ) ) {
1625+
skip = true;
1626+
break;
16551627
}
16561628
}
16571629
}
@@ -1665,7 +1637,7 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str
16651637

16661638
materialDefines += "\n";
16671639

1668-
newShaderText = "#define USE_MATERIAL_SYSTEM\n" + materialStruct + materialBlock + texDataBlock + materialDefines; // + shaderMain;
1640+
newShaderText = "#define USE_MATERIAL_SYSTEM\n" + materialStruct + materialBlock + texDataBlock + materialDefines;
16691641
shaderMain.insert( offset, newShaderText );
16701642
return shaderMain;
16711643
}
@@ -2113,71 +2085,73 @@ uint32_t* GLUniform::WriteToBuffer( uint32_t* buffer ) {
21132085

21142086
void GLShader::RegisterUniform( GLUniform* uniform ) {
21152087
_uniforms.push_back( uniform );
2116-
textureCount += uniform->IsTexture();
21172088
}
21182089

21192090
GLint GLShader::GetUniformLocation( const GLchar *uniformName ) const {
21202091
ShaderProgramDescriptor* p = GetProgram();
21212092
return glGetUniformLocation( p->id, uniformName );
21222093
}
21232094

2095+
static int FindUniformForAlignment( std::vector<GLUniform*>& uniforms, const GLuint alignment ) {
2096+
for ( uint32_t i = 0; i < uniforms.size(); i++ ) {
2097+
if ( uniforms[i]->GetSTD430Size() == alignment ) {
2098+
return i;
2099+
}
2100+
}
2101+
2102+
if ( uniforms[uniforms.size() - 1]->GetSTD430Size() < alignment ) {
2103+
return uniforms.size() - 1;
2104+
}
2105+
2106+
return -1;
2107+
}
2108+
21242109
// Compute std430 size/alignment and sort uniforms from highest to lowest alignment
21252110
void GLShader::PostProcessUniforms() {
21262111
if ( !_useMaterialSystem ) {
21272112
return;
21282113
}
21292114

2130-
std::vector<GLUniform*> tmp;
2131-
2132-
std::vector<GLUniform*> globalUniforms;
21332115
for ( GLUniform* uniform : _uniforms ) {
2134-
if ( uniform->IsGlobal() || uniform->IsTexture() ) {
2135-
globalUniforms.emplace_back( uniform );
2116+
if ( !uniform->IsGlobal() ) {
2117+
_materialSystemUniforms.emplace_back( uniform );
21362118
}
21372119
}
2138-
for ( GLUniform* uniform : globalUniforms ) {
2139-
_uniforms.erase( std::remove( _uniforms.begin(), _uniforms.end(), uniform ), _uniforms.end() );
2140-
}
2120+
2121+
std::sort( _materialSystemUniforms.begin(), _materialSystemUniforms.end(),
2122+
[]( const GLUniform* lhs, const GLUniform* rhs ) {
2123+
return lhs->GetSTD430Size() > rhs->GetSTD430Size();
2124+
}
2125+
);
21412126

21422127
// Sort uniforms from highest to lowest alignment so we don't need to pad uniforms (other than vec3s)
2143-
const uint numUniforms = _uniforms.size();
2144-
GLuint structSize = 0;
2128+
const uint numUniforms = _materialSystemUniforms.size();
2129+
std::vector<GLUniform*> tmp;
21452130
while ( tmp.size() < numUniforms ) {
21462131
// Higher-alignment uniforms first to avoid wasting memory
2147-
GLuint highestAlignment = 0;
2148-
int highestUniform = 0;
2149-
for( uint i = 0; i < _uniforms.size(); i++ ) {
2150-
if ( _uniforms[i]->GetSTD430Alignment() > highestAlignment ) {
2151-
highestAlignment = _uniforms[i]->GetSTD430Alignment();
2152-
highestUniform = i;
2153-
}
2132+
GLuint size = _materialSystemUniforms[0]->GetSTD430Size();
2133+
GLuint components = _materialSystemUniforms[0]->GetComponentSize();
2134+
size = components ? 4 * components : size;
2135+
GLuint alignmentConsume = 4 - size % 4;
21542136

2155-
if ( highestAlignment == 4 ) {
2156-
break; // 4-component is the highest alignment in std430
2157-
}
2158-
}
2159-
2160-
const GLuint size = _uniforms[highestUniform]->GetSTD430Size();
2161-
if ( _uniforms[highestUniform]->GetComponentSize() != 0 ) {
2162-
structSize += ( size == 3 ) ? 4 * _uniforms[highestUniform]->GetComponentSize() :
2163-
size * _uniforms[highestUniform]->GetComponentSize();
2164-
} else {
2165-
structSize += ( size == 3 ) ? 4 : size;
2137+
tmp.emplace_back( _materialSystemUniforms[0] );
2138+
_materialSystemUniforms.erase( _materialSystemUniforms.begin() );
2139+
2140+
int uniform;
2141+
while ( ( alignmentConsume & 3 ) && _materialSystemUniforms.size()
2142+
&& ( uniform = FindUniformForAlignment( _materialSystemUniforms, alignmentConsume ) ) != -1 ) {
2143+
alignmentConsume -= _materialSystemUniforms[uniform]->GetSTD430Size();
2144+
2145+
tmp.emplace_back( _materialSystemUniforms[uniform] );
2146+
_materialSystemUniforms.erase( _materialSystemUniforms.begin() + uniform );
21662147
}
21672148

2168-
tmp.emplace_back( _uniforms[highestUniform] );
2169-
_uniforms.erase( _uniforms.begin() + highestUniform );
2149+
size = PAD( size, 4 );
2150+
std430Size += size;
2151+
padding = alignmentConsume;
21702152
}
2171-
_uniforms = tmp;
21722153

2173-
const GLuint structAlignment = 4; // Material buffer is now a UBO, so it uses std140 layout, which is aligned to vec4
2174-
if ( structSize > 0 ) {
2175-
padding = ( structAlignment - ( structSize % structAlignment ) ) % structAlignment;
2176-
}
2177-
std430Size = structSize;
2178-
for ( GLUniform* uniform : globalUniforms ) {
2179-
_uniforms.emplace_back( uniform );
2180-
}
2154+
_materialSystemUniforms = tmp;
21812155
}
21822156

21832157
uint32_t GLShader::GetUniqueCompileMacros( size_t permutation, const int type ) const {
@@ -2361,10 +2335,8 @@ void GLShader::SetRequiredVertexPointers()
23612335

23622336
void GLShader::WriteUniformsToBuffer( uint32_t* buffer ) {
23632337
uint32_t* bufPtr = buffer;
2364-
for ( GLUniform* uniform : _uniforms ) {
2365-
if ( !uniform->IsGlobal() && !uniform->IsTexture() ) {
2366-
bufPtr = uniform->WriteToBuffer( bufPtr );
2367-
}
2338+
for ( GLUniform* uniform : _materialSystemUniforms ) {
2339+
bufPtr = uniform->WriteToBuffer( bufPtr );
23682340
}
23692341
}
23702342

0 commit comments

Comments
 (0)