Add IMaterialRendererServices::startUseProgram/stopUseProgram

This makes it possible to set high-level shader constants (which are attached to shader programs) to be set outside
of OnSetConstants.
IShaderConstantSetCallBack::OnCreate has it set automatically now so it works the same as OnSetConstants.
D3D9 and burnings both work different, so there hadn't been a problem with those.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6469 dfc29bdd-3216-0410-991c-e03cc46cb475
This commit is contained in:
cutealien 2023-04-24 14:46:09 +00:00
parent 16c960c5ed
commit c4bbbe1aaf
6 changed files with 71 additions and 18 deletions

@ -56,7 +56,7 @@ public:
{
if (UseHighLevelShaders)
{
// get shader constants id.
// Get shader constants id.
WorldViewProjID = services->getVertexShaderConstantID("mWorldViewProj");
TransWorldID = services->getVertexShaderConstantID("mTransWorld");
InvWorldID = services->getVertexShaderConstantID("mInvWorld");
@ -68,6 +68,27 @@ public:
if(driver->getDriverType() == video::EDT_OPENGL)
TextureID = services->getVertexShaderConstantID("myTexture");
}
// Set light color
// That could be set as well in OnSetConstants, but there's some cost to setting shader constants
// So when we have non-changing shader constants it's more performant to set them only once.
video::SColorf col(0.0f,1.0f,1.0f,0.0f);
if (UseHighLevelShaders)
{
services->setVertexShaderConstant(ColorID, reinterpret_cast<f32*>(&col), 4);
// Note: Since Irrlicht 1.9 it's possible to call setVertexShaderConstant
// from anywhere. To do that save the services pointer here in OnCreate, it
// won't change as long as you use one IShaderConstantSetCallBack per shader
// material. But when calling it ouside of IShaderConstantSetCallBack functions
// you have to call services->startUseProgram()stopUseProgram() before/after doing so.
// At least for high-level shader constants, low level constants are not attached
// to programs, so for those it doesn't matter.
// Doing that sometimes makes sense for performance reasons, like for constants which
// do only change once per frame or even less.
}
else
services->setVertexShaderConstant(reinterpret_cast<f32*>(&col), 9, 1);
}
virtual void OnSetConstants(video::IMaterialRendererServices* services,
@ -109,16 +130,6 @@ public:
else
services->setVertexShaderConstant(reinterpret_cast<f32*>(&pos), 8, 1);
// set light color
video::SColorf col(0.0f,1.0f,1.0f,0.0f);
if (UseHighLevelShaders)
services->setVertexShaderConstant(ColorID,
reinterpret_cast<f32*>(&col), 4);
else
services->setVertexShaderConstant(reinterpret_cast<f32*>(&col), 9, 1);
// set transposed world matrix
core::matrix4 world = driver->getTransform(video::ETS_WORLD);

@ -41,6 +41,20 @@ public:
//! Return an index constant for the vertex shader based on a name.
virtual s32 getVertexShaderConstantID(const c8* name) = 0;
//! Call when you set shader constants outside of IShaderConstantSetCallBack
/** Only for high-level shader functions, aka those using an index instead of
an register. Shader constants are attached to shader programs, so if you want
to set them you have to make sure the correct shader program is in use.
IShaderConstantSetCallBack functions like OnSetConstants do that for you,
but if you want to set shader constants outside of those (usually for performance
reasons) call startUseProgram() before doing so and stopUseProgram() afterwards.
Note: Currently only necessary in OpenGL, but no real calling costs on other drivers.
*/
virtual void startUseProgram() {}
//! Call this when you are done setting shader constants outside of OnCreate or OnSetConstants
virtual void stopUseProgram() {}
//! Sets a constant for the vertex shader based on a name.
/** This can be used if you used a high level shader language like GLSL
or HLSL to create a shader. Example: If you created a shader which has

@ -3727,7 +3727,9 @@ s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram,
r->drop();
if (callback && nr >= 0)
{
callback->OnCreate(this, userData);
}
return nr;
}
@ -3764,7 +3766,11 @@ s32 COpenGLDriver::addHighLevelShaderMaterial(
r->drop();
if (callback && nr >= 0)
{
r->startUseProgram();
callback->OnCreate(r, userData);
r->stopUseProgram();
}
return nr;
}

@ -415,6 +415,12 @@ namespace video
//! Get current material.
const SMaterial& getCurrentMaterial() const;
//! Rest renderstates forcing stuff like OnSetMaterial to be called
void DoResetRenderStates()
{
ResetRenderStates = true;
}
COpenGLCacheHandler* getCacheHandler() const;
private:

@ -237,13 +237,10 @@ void COpenGLSLMaterialRenderer::OnSetMaterial(const video::SMaterial& material,
COpenGLCacheHandler* cacheHandler = Driver->getCacheHandler();
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
if (Program2)
Driver->irrGlUseProgram(Program2);
else if (Program)
Driver->extGlUseProgramObject(Program);
}
Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
@ -572,6 +569,23 @@ void COpenGLSLMaterialRenderer::setBasicRenderStates(const SMaterial& material,
Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
}
void COpenGLSLMaterialRenderer::startUseProgram()
{
if (Program2)
Driver->irrGlUseProgram(Program2);
else if (Program)
Driver->extGlUseProgramObject(Program);
}
void COpenGLSLMaterialRenderer::stopUseProgram()
{
// Not going to reset irrGlUseProgram/extGlUseProgramObject as it shouldn't really matter
// Force reset of material to ensure OnSetMaterial will be called or we can miss
// the next UseProgram call
Driver->DoResetRenderStates();
}
s32 COpenGLSLMaterialRenderer::getVertexShaderConstantID(const c8* name)
{
return getPixelShaderConstantID(name);

@ -73,6 +73,8 @@ public:
// implementations for IMaterialRendererServices
virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial, bool resetAllRenderstates) IRR_OVERRIDE;
virtual void startUseProgram() IRR_OVERRIDE;
virtual void stopUseProgram() IRR_OVERRIDE;
virtual s32 getVertexShaderConstantID(const c8* name) IRR_OVERRIDE;
virtual s32 getPixelShaderConstantID(const c8* name) IRR_OVERRIDE;
virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) IRR_OVERRIDE;