Hi,
I can't find in Irrlicht OGL driver where material settings are being changed. I would like to optimise my renderer avoiding shader program switches by sorting my nodes by material and I was wondering if at each driver::setMaterial() call, or meshnode::render() call, the material was really updated on the GPU or some kind of verification was handled by Irrlicht before switching shaders on the GPU to avoid useless GPU uploads.
I've started my searches from IMeshSceneNode::render. It calls driver::setMaterial before rendering the data. This setMaterial function just change the driver material reference but there is not OGL call. Then when rendering the mesh data with driver::drawMeshBuffer either driver::drawHardwareBuffer or driver::drawVertexPrimitiveList is called but in those function I saw only OGL calls related to normal/vertices/color/textCoords upload to the GPU but nothing about texture/shader switches.
Where should I search? How is it working ?
Thanks a lot!
Material switches
Material switches
CuteAlien wrote:coders are well-known creatures of the night
Re: Material switches
Please see my patch in the open disc forum for sorting by material type.
It will automatically sort the solids first by mat type and secondarily by texture.
It will automatically sort the solids first by mat type and secondarily by texture.
Re: Material switches
Thanks for your response hendu.
However I'm not looking for sorting methods, my nodes are already sorted and I would like to know where the material changes are done in the OGL driver because I'm rendering the nodes by myself and I have no idea how materials are handled when using node::render() method for now...
Thanks.
However I'm not looking for sorting methods, my nodes are already sorted and I would like to know where the material changes are done in the OGL driver because I'm rendering the nodes by myself and I have no idea how materials are handled when using node::render() method for now...
Thanks.
CuteAlien wrote:coders are well-known creatures of the night
Re: Material switches
node->render calls setMaterial, which checks whether it's the same material, and if not, changes it. grep for Material in COpenGLDriver.cpp.
So if your nodes are already sorted in shader batches, irr won't do unneeded shader changes.
So if your nodes are already sorted in shader batches, irr won't do unneeded shader changes.
Re: Material switches
I didn't see any check in the setMaterial method. It just changes the driver material reference and if an overriding material is activated all properties of the material are being changed by the overriding material's one. I don't know where are the OGL calls to send material properties to the GPU.
Code: Select all
void COpenGLDriver::setMaterial(const SMaterial& material)
{
Material = material;
OverrideMaterial.apply(Material);
for (s32 i = MaxTextureUnits-1; i>= 0; --i)
{
setActiveTexture(i, material.getTexture(i));
setTransform ((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i),
Material.getTextureMatrix(i));
}
}
Code: Select all
void apply(SMaterial& material)
{
if (Enabled)
{
for (u32 i=0; i<32; ++i)
{
const u32 num=(1<<i);
if (EnableFlags & num)
{
switch (num)
{
case EMF_WIREFRAME: material.Wireframe = Material.Wireframe; break;
case EMF_POINTCLOUD: material.PointCloud = Material.PointCloud; break;
case EMF_GOURAUD_SHADING: material.GouraudShading = Material.GouraudShading; break;
case EMF_LIGHTING: material.Lighting = Material.Lighting; break;
case EMF_ZBUFFER: material.ZBuffer = Material.ZBuffer; break;
case EMF_ZWRITE_ENABLE: material.ZWriteEnable = Material.ZWriteEnable; break;
case EMF_BACK_FACE_CULLING: material.BackfaceCulling = Material.BackfaceCulling; break;
case EMF_FRONT_FACE_CULLING: material.FrontfaceCulling = Material.FrontfaceCulling; break;
case EMF_FOG_ENABLE: material.FogEnable = Material.FogEnable; break;
case EMF_NORMALIZE_NORMALS: material.NormalizeNormals = Material.NormalizeNormals; break;
case EMF_ANTI_ALIASING: material.AntiAliasing = Material.AntiAliasing; break;
case EMF_COLOR_MASK: material.ColorMask = Material.ColorMask; break;
case EMF_BILINEAR_FILTER: material.TextureLayer[0].BilinearFilter = Material.TextureLayer[0].BilinearFilter; break;
case EMF_TRILINEAR_FILTER: material.TextureLayer[0].TrilinearFilter = Material.TextureLayer[0].TrilinearFilter; break;
case EMF_ANISOTROPIC_FILTER: material.TextureLayer[0].AnisotropicFilter = Material.TextureLayer[0].AnisotropicFilter; break;
case EMF_TEXTURE_WRAP:
material.TextureLayer[0].TextureWrapU = Material.TextureLayer[0].TextureWrapU;
material.TextureLayer[0].TextureWrapV = Material.TextureLayer[0].TextureWrapV;
break;
}
}
}
}
}
CuteAlien wrote:coders are well-known creatures of the night
Re: Material switches
if (ResetRenderStates || LastMaterial != Material)
Around line 2300 or so.
Around line 2300 or so.
Re: Material switches
Oh thanks! I didn't see the setRenderStates3DMode() call in the driver::drawVertexPrimitiveList method.
So as you said, in the driver::setRenderStates3DMode method the driver checks if the material changed with the != operator. Looking at this operator definition in SMaterial I found that it returns true if any of the properties of both materials isn't the same. So for exemple if I change ZBuffer from ECFN_ALWAYS to ECFN_GREATER but keep the same shader, the material renderer will be updated :
So with at least a property change, like a texture, but no shader program change, the driver will call the OnSetMaterial method of the materialRenderer, and if I'm looking at the COpenGLShaderMaterialRenderer.cpp, OnSetMaterial function, I can see that the shader is uploaded to the GPU.
So my real question is:
If I change some properties of a material, for exemple some textures, BUT I keep the same shader all the time, will the shader be uploaded at each mesh render ? Because this is what I understood but I may misunderstand the sources.
Any advice is welcomed
So as you said, in the driver::setRenderStates3DMode method the driver checks if the material changed with the != operator. Looking at this operator definition in SMaterial I found that it returns true if any of the properties of both materials isn't the same. So for exemple if I change ZBuffer from ECFN_ALWAYS to ECFN_GREATER but keep the same shader, the material renderer will be updated :
Code: Select all
void COpenGLDriver::setRenderStates3DMode()
{
[...]
if (ResetRenderStates || LastMaterial != Material) //not all material properties are the same
{
// unset old material
if (LastMaterial.MaterialType != Material.MaterialType && //if not the same SHADER
static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
/// |--> array of SMaterialRenderer : struct [ name (str) + renderer (IMaterialRenderer) ]
// set new material.
if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial(
Material, LastMaterial, ResetRenderStates, this);
LastMaterial = Material;
ResetRenderStates = false;
}
if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD);
CurrentRenderMode = ERM_3D;
}
Code: Select all
inline bool operator!=(const SMaterial& b) const
{
bool different =
MaterialType != b.MaterialType ||
AmbientColor != b.AmbientColor ||
DiffuseColor != b.DiffuseColor ||
EmissiveColor != b.EmissiveColor ||
SpecularColor != b.SpecularColor ||
Shininess != b.Shininess ||
MaterialTypeParam != b.MaterialTypeParam ||
MaterialTypeParam2 != b.MaterialTypeParam2 ||
Thickness != b.Thickness ||
Wireframe != b.Wireframe ||
PointCloud != b.PointCloud ||
GouraudShading != b.GouraudShading ||
Lighting != b.Lighting ||
ZBuffer != b.ZBuffer ||
ZWriteEnable != b.ZWriteEnable ||
BackfaceCulling != b.BackfaceCulling ||
FrontfaceCulling != b.FrontfaceCulling ||
FogEnable != b.FogEnable ||
NormalizeNormals != b.NormalizeNormals ||
AntiAliasing != b.AntiAliasing ||
ColorMask != b.ColorMask ||
ColorMaterial != b.ColorMaterial;
for (u32 i=0; (i<MATERIAL_MAX_TEXTURES) && !different; ++i)
{
different |= (TextureLayer[i] != b.TextureLayer[i]);
}
return different;
}
Code: Select all
void COpenGLShaderMaterialRenderer::OnSetMaterial(...) {
[...]
Driver->extGlBindProgram(GL_VERTEX_PROGRAM_ARB, VertexShader);
glEnable(GL_VERTEX_PROGRAM_ARB);
[...]
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, nextShader);
glEnable(GL_FRAGMENT_PROGRAM_ARB);
[...]
}
If I change some properties of a material, for exemple some textures, BUT I keep the same shader all the time, will the shader be uploaded at each mesh render ? Because this is what I understood but I may misunderstand the sources.
Any advice is welcomed
CuteAlien wrote:coders are well-known creatures of the night
Re: Material switches
You didn't quote the if line in COpenGLShaderMaterialRenderer.cpp right before the bind calls.
if (material.MaterialType != lastMaterial.MaterialType...
BTW, that file is about the GL asm. GLSL methods are in a different file, but they too check for the mat type correctly.
if (material.MaterialType != lastMaterial.MaterialType...
BTW, that file is about the GL asm. GLSL methods are in a different file, but they too check for the mat type correctly.