Page 1 of 1
[1.11.2] Dynamic Resolution
Posted: Mon Feb 22, 2021 3:38 am
by rpgplayerrobin
Ogre Version: 1.11.2
Operating System: Windows 10
Render System: Direct3D9
Hello!
I am trying to get dynamic resolution working, but it seems I have went into a dead end.
I have searched for an hour without seeing anyone attempting to do this in Ogre.
As far as I understand, there is a default scene compositor that renders everything to the backbuffer in the window (createOriginalScene / _getOriginalSceneCompositor), but it seems to be very troublesome to change that compositor.
If possible, I would want to replace the default scene compositor with another one, like:
Code: Select all
compositor DynamicResolution
{
technique
{
texture scene 1024 512 PF_R8G8B8
target scene
{
input none
pass clear
{
}
pass render_scene
{
}
}
target_output
{
input none
pass render_quad
{
material DynamicResolution
input 0 scene
}
}
}
}
But it seems to be very hard to actually switch this out... How do I actually do this?
Is there an easier way of doing all this?
I altered the resolution of the viewport, but that only changes where it actually renders on the backbuffer, which does me no good...
Re: [1.11.2] Dynamic Resolution
Posted: Mon Feb 22, 2021 12:47 pm
by paroj
whats wrong with
Code: Select all
Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, "DynamicResolution", true);
Re: [1.11.2] Dynamic Resolution
Posted: Mon Feb 22, 2021 1:10 pm
by rpgplayerrobin
The problem is that the original scene will still be rendered, right? That code will not disable the default compositor I guess.
I want the original render to render at a lower resolution.
Having a dynamic resolution is meant to bring the FPS up in intensive situations, so having the exact same performance (or even worse) by just enabling it on top on the other compositors is something I do not want.
Re: [1.11.2] Dynamic Resolution
Posted: Mon Feb 22, 2021 1:32 pm
by paroj
rpgplayerrobin wrote: Mon Feb 22, 2021 1:10 pm
The problem is that the original scene will still be rendered, right?
no. the "original scene" is only used for "input previous" of the first compositor in a chain.
Re: [1.11.2] Dynamic Resolution
Posted: Mon Feb 22, 2021 1:44 pm
by rpgplayerrobin
I don't see how that is right... The compositor chain has a default compositor created by "createOriginalScene", which creates "mOriginalScene".
That is always used.
I tried the code you showed me, but the FPS stayed the same (or even got worse).
However, when I alter the default compositor (created by "createOriginalScene") I do get much higher FPS.
To be clear, I want to alter the FIRST render, not create a new compositor, but alter the first render itself.
Otherwise dynamic resolution (to save performance) would never work.
Re: [1.11.2] Dynamic Resolution
Posted: Mon Feb 22, 2021 4:55 pm
by paroj
sounds like a bug. It should not be triggered if we dont need the results.
Anyway.. try this as a workaround
Re: [1.11.2] Dynamic Resolution
Posted: Mon Feb 22, 2021 5:10 pm
by rpgplayerrobin
I tried it your way now, and it did increase FPS, but not by that much at all for some reason, only by around 10% more FPS when I lowered it to 128 x 64. I did it like this:
Code: Select all
compositor DynamicResolution
{
technique
{
texture scene 128 64 PF_R8G8B8
target scene
{
input previous
}
target_output
{
input none
pass render_quad
{
material DynamicResolution
input 0 scene
}
}
}
}
And by doing this in the code once:
CompositorManager::getSingleton().addCompositor(app->m_Camera->getViewport(), "DynamicResolution");
CompositorManager::getSingleton().setCompositorEnabled(app->m_Camera->getViewport(), "DynamicResolution", true);
But it seems I found another rather OK way of doing all of this. It works, but it is a bit of a hack.
When I do 128 x 64 here, the FPS is increased by around 40%, so it seems this code is better than trying it with a new compositor than altering the existing one.
Here is the code:
Code: Select all
// Constructor for the CDynamicResolutionManager
CDynamicResolutionManager::CDynamicResolutionManager()
{
// Reset the last render scale value
m_lastRenderScaleValue = 100;
// Set that we are using the default compositor
m_isUsingDefaultCompositor = true;
}
// Destructor for the CDynamicResolutionManager
CDynamicResolutionManager::~CDynamicResolutionManager()
{
}
// Setups the compositor
void CDynamicResolutionManager::SetupCompositor()
{
// Get the compositor chain from the camera and check if it is valid
CompositorChain* tmpCompositorChain = CompositorManager::getSingleton().getCompositorChain(app->m_Camera->getViewport());
if (tmpCompositorChain)
{
// Get the compositor instance and check if it is valid
CompositorInstance* tmpCompositorInstance = tmpCompositorChain->_getOriginalSceneCompositor();
if (tmpCompositorInstance)
{
// Get the compositor technique and check if it is valid
CompositionTechnique* tmpCompositorTechnique = tmpCompositorInstance->getTechnique();
if (tmpCompositorTechnique)
{
// Get the material scheme and visibility mask from the camera
CString tmpMaterialScheme = app->m_Camera->getViewport()->getMaterialScheme();
uint tmpVisibilityMask = app->m_Camera->getViewport()->getVisibilityMask();
// Clear the compositor
tmpCompositorTechnique->removeAllTargetPasses();
tmpCompositorTechnique->removeAllTextureDefinitions();
CompositionTargetPass* tmpOutputTargetPass = tmpCompositorTechnique->getOutputTargetPass();
if (tmpOutputTargetPass)
tmpOutputTargetPass->removeAllPasses();
// Check if we should use the default compositor
if (m_isUsingDefaultCompositor)
{
/*
target_output
{
pass clear
{
/// Clear frame
}
pass render_scene
{
visibility_mask FFFFFFFF
render_queues SKIES_EARLY SKIES_LATE
}
}
*/
CompositionTargetPass* tmpCompositionTargetPass = tmpCompositorTechnique->getOutputTargetPass();
tmpCompositionTargetPass->setVisibilityMask(0xFFFFFFFF);
CompositionPass* tmpCompositionPass = tmpCompositionTargetPass->createPass();
tmpCompositionPass->setType(CompositionPass::PT_CLEAR);
tmpCompositionPass = tmpCompositionTargetPass->createPass();
tmpCompositionPass->setType(CompositionPass::PT_RENDERSCENE);
tmpCompositionPass->setFirstRenderQueue(RENDER_QUEUE_BACKGROUND);
tmpCompositionPass->setLastRenderQueue(RENDER_QUEUE_SKIES_LATE);
}
else
{
/*
texture scene 1024 512 PF_R8G8B8
target scene
{
input none
pass clear
{
}
pass render_scene
{
}
}
target_output
{
input none
pass render_quad
{
material DynamicResolution
input 0 scene
}
}
*/
CompositionTechnique::TextureDefinition* tmpTextureDefinition = tmpCompositorTechnique->createTextureDefinition("scene");
tmpTextureDefinition->width = 10;
tmpTextureDefinition->height = 10;
tmpTextureDefinition->formatList.push_back(Ogre::PF_R8G8B8);
CompositionTargetPass* tmpCompositionTargetPass = tmpCompositorTechnique->createTargetPass();
tmpCompositionTargetPass->setInputMode(CompositionTargetPass::IM_NONE);
tmpCompositionTargetPass->setOutputName("scene");
CompositionPass* tmpCompositionPass = tmpCompositionTargetPass->createPass();
tmpCompositionPass->setType(CompositionPass::PT_CLEAR);
tmpCompositionPass = tmpCompositionTargetPass->createPass();
tmpCompositionPass->setType(CompositionPass::PT_RENDERSCENE);
tmpCompositionPass->setFirstRenderQueue(RENDER_QUEUE_BACKGROUND);
tmpCompositionPass->setLastRenderQueue(RENDER_QUEUE_SKIES_LATE);
tmpOutputTargetPass->setInputMode(CompositionTargetPass::IM_NONE);
tmpCompositionPass = tmpOutputTargetPass->createPass();
tmpCompositionPass->setType(CompositionPass::PT_RENDERQUAD);
tmpCompositionPass->setMaterialName("DynamicResolution");
tmpCompositionPass->setInput(0, "scene");
}
// Update the material schemes and visibility masks
if (tmpOutputTargetPass)
{
tmpOutputTargetPass->setMaterialScheme(tmpMaterialScheme);
tmpOutputTargetPass->setVisibilityMask(tmpVisibilityMask);
}
CompositionTechnique::TargetPasses tmpTargetPasses = tmpCompositorInstance->getTechnique()->getTargetPasses();
for (size_t n = 0; n < tmpTargetPasses.size(); n++)
{
tmpTargetPasses[n]->setMaterialScheme(tmpMaterialScheme);
tmpTargetPasses[n]->setVisibilityMask(tmpVisibilityMask);
}
// Make sure the textures are destroyed (they are created later when setting the real resolution)
tmpCompositorInstance->setAlive(false);
// Compile the compositor chain
//tmpCompositorChain->_compile();
}
}
}
}
// Updates the CDynamicResolutionManager
void CDynamicResolutionManager::Update()
{
// Check if the render scale value has changed
int tmpCurrentRenderScaleValue = 100;
if (app->m_Keyboard->isKeyDown(OIS::KC_1)) tmpCurrentRenderScaleValue = 90;
if (app->m_Keyboard->isKeyDown(OIS::KC_2)) tmpCurrentRenderScaleValue = 80;
if (app->m_Keyboard->isKeyDown(OIS::KC_3)) tmpCurrentRenderScaleValue = 70;
if (app->m_Keyboard->isKeyDown(OIS::KC_4)) tmpCurrentRenderScaleValue = 60;
if (app->m_Keyboard->isKeyDown(OIS::KC_5)) tmpCurrentRenderScaleValue = 50;
if (app->m_Keyboard->isKeyDown(OIS::KC_6)) tmpCurrentRenderScaleValue = 40;
if (app->m_Keyboard->isKeyDown(OIS::KC_7)) tmpCurrentRenderScaleValue = 30;
if (app->m_Keyboard->isKeyDown(OIS::KC_8)) tmpCurrentRenderScaleValue = 20;
if (app->m_Keyboard->isKeyDown(OIS::KC_9)) tmpCurrentRenderScaleValue = 10;
if(m_lastRenderScaleValue != tmpCurrentRenderScaleValue)
{
// Set the new last render scale value value
m_lastRenderScaleValue = tmpCurrentRenderScaleValue;
// Check if we have changed the compositor target
bool tmpUseDefaultCompositor = m_lastRenderScaleValue == 100;
if (tmpUseDefaultCompositor != m_isUsingDefaultCompositor)
{
// Setup the compositor
m_isUsingDefaultCompositor = tmpUseDefaultCompositor;
SetupCompositor();
}
// Check if we are not using the default compositor
if (!m_isUsingDefaultCompositor)
{
// Get the compositor chain from the camera and check if it is valid
CompositorChain* tmpCompositorChain = CompositorManager::getSingleton().getCompositorChain(app->m_Camera->getViewport());
if (tmpCompositorChain)
{
// Get the compositor instance and check if it is valid
CompositorInstance* tmpCompositorInstance = tmpCompositorChain->_getOriginalSceneCompositor();
if (tmpCompositorInstance)
{
// Get the compositor technique and check if it is valid
CompositionTechnique* tmpCompositorTechnique = tmpCompositorInstance->getTechnique();
if (tmpCompositorTechnique)
{
// Get the scene texture definition and check if it is valid
CompositionTechnique::TextureDefinition* tmpTextureDefinition = tmpCompositorTechnique->getTextureDefinition("scene");
if (tmpTextureDefinition)
{
// Update the compositor render scale
tmpTextureDefinition->width = size_t(float(app->m_Window->getWidth()) * (float(m_lastRenderScaleValue) * 0.01f));
tmpTextureDefinition->height = size_t(float(app->m_Window->getHeight()) * (float(m_lastRenderScaleValue) * 0.01f));
// Adjust the pixels to become as close to the wanted aspect ratio of the window
const int tmpMinMaxValue = 10;
if (tmpTextureDefinition->width > tmpMinMaxValue &&
tmpTextureDefinition->height > tmpMinMaxValue)
{
float tmpWantedAspectRatio = float(app->m_Window->getWidth()) / float(app->m_Window->getHeight());
float tmpBeforeAspectRatio = float(tmpTextureDefinition->width) / float(tmpTextureDefinition->height);
float tmpClosest = FLT_MAX;
int tmpClosestX = 0;
int tmpClosestY = 0;
for (int x = -tmpMinMaxValue; x <= tmpMinMaxValue; x++)
{
for (int y = -tmpMinMaxValue; y <= tmpMinMaxValue; y++)
{
float tmpCurrentAspectRatio = float(tmpTextureDefinition->width + x) / float(tmpTextureDefinition->height + y);
float tmpDistanceCurrent = abs(tmpWantedAspectRatio - tmpCurrentAspectRatio);
if (tmpDistanceCurrent < tmpClosest)
{
tmpClosest = tmpDistanceCurrent;
tmpClosestX = x;
tmpClosestY = y;
}
}
}
if (tmpClosest != FLT_MAX)
{
tmpTextureDefinition->width += tmpClosestX;
tmpTextureDefinition->height += tmpClosestY;
}
}
// Make sure the textures are created
tmpCompositorInstance->setAlive(false);
tmpCompositorInstance->setAlive(true);
}
}
}
}
}
}
}
Holding the 1-9 keys will show that it works to do dynamic resolution this way, which is pretty nice.
Now just to actually do an automatic system for this to keep a wanted FPS.
The "DynamicResolution" material is just a basic material that looks like this:
Code: Select all
material DynamicResolution
{
technique
{
pass
{
lighting off
cull_hardware none
cull_software none
depth_check off
polygon_mode_overrideable false
texture_unit
{
filtering none
}
}
}
}
Re: [1.11.2] Dynamic Resolution
Posted: Tue Feb 23, 2021 6:25 pm
by paroj
I would of course prefer, if you could find the root-cause in Ogre so we can fix this for everybody instead of everybody having to apply this workaround.
Re: [1.11.2] Dynamic Resolution
Posted: Wed Feb 24, 2021 1:55 am
by rpgplayerrobin
It seems there is no bug, doing it
correctly (

) in the code with a compositor seems to be equal to altering the original (createOriginalScene) compositor.
I found that it matters where I use the CompositorManager::getSingleton().addCompositor.
When I wrote that using it as a real compositor only increased FPS by 10%, that was because it was not added as the first compositor (another compositor was added before this one).
When I add it as the first compositor, I do get the same results as when I altered the "createOriginalScene" compositor.
So it seems to only be an application-specific issue.
Though I do not understand how that compositor can make the original (createOriginalScene) compositor not have any effect, but as you said, it is only used for "input previous", so I guess it looks on my real compositor and sees that while only rendering it at the scale I want it rendered at, and ignoring the first full-window render that it would have used normally.
Below is an adjusted version (so it should work for anyone) of my "minimum FPS with dynamic resolution" feature.
Just supply the "m_dynamicResolution" with a minimum FPS value (0 is disabled and is default in the code).
Compositor:
Code: Select all
compositor DynamicResolution
{
technique
{
texture scene 1 1 PF_R8G8B8
target scene
{
input previous
}
target_output
{
input none
pass render_quad
{
material DynamicResolution
input 0 scene
}
}
}
}
Material:
Code: Select all
material DynamicResolution
{
technique
{
pass
{
lighting off
cull_hardware none
cull_software none
depth_check off
polygon_mode_overrideable false
texture_unit
{
filtering none
}
}
}
}
C++:
Code: Select all
class CDynamicResolution
{
public:
float m_lastRenderScaleValue;
clock_t m_lastTime;
int m_updateCounter;
bool m_active;
bool m_compositorAdded;
int m_dynamicResolution;
Camera* m_camera;
RenderWindow* m_window;
// Constructor for the CDynamicResolution
CDynamicResolution(Camera* camera, RenderWindow* window)
{
// Get the camera
m_camera = camera;
// Get the window
m_window = window;
// Reset the last render scale value
m_lastRenderScaleValue = 1.0f;
// Reset the last time
m_lastTime = clock();
// Reset the update counter
m_updateCounter = 0;
// Set that we are not active
m_active = false;
// Add the compositor to the main camera
m_compositorAdded = CompositorManager::getSingleton().addCompositor(m_camera->getViewport(), "DynamicResolution", 0) != NULL;
// Reset the dynamic resolution option
m_dynamicResolution = 0;
}
// Destructor for the CDynamicResolution
~CDynamicResolution()
{
// Check if the current validated effect is a valid compositor
if (m_compositorAdded && CompositorManager::getSingleton().getByName("DynamicResolution"))
// Remove the current compositor
CompositorManager::getSingleton().removeCompositor(m_camera->getViewport(), "DynamicResolution");
}
// Updates the CDynamicResolutionManager
void Update()
{
// Check if we are using the dynamic resolution option
if (m_dynamicResolution > 0)
// Set that we are active
m_active = true;
// Check if we are not active
if (!m_active)
// Return the function, we are done
return;
// Add one to the number of updates
m_updateCounter++;
// Check if enough time has elapsed
int tmpFPS = 0;
clock_t tmpCurrentTime = clock();
const clock_t tmpWaitTime = 100;
if (tmpCurrentTime - m_lastTime > tmpWaitTime)
{
// Calculate the FPS
tmpFPS = int(float(m_updateCounter) / (float(tmpWaitTime) * 0.001f));
// Reset the last time
m_lastTime = tmpCurrentTime;
// Reset the update counter
m_updateCounter = 0;
}
else
// Return the function, we are done
return;
// Set the current render scale value
float tmpCurrentRenderScaleValue = m_lastRenderScaleValue;
// Check if we are using dynamic resolution
if (m_dynamicResolution > 0)
{
// Check if the FPS is far off from the wanted FPS
float tmpPercentageOff = float(min(tmpFPS, m_dynamicResolution)) / float(max(tmpFPS, m_dynamicResolution));
if (tmpPercentageOff < 0.8f) // 47 / 60 = 0.78, so this will then alter the render scale
{
// Check if the FPS is lower than the wanted FPS
if (tmpFPS < m_dynamicResolution)
// Make the render scale lower
tmpCurrentRenderScaleValue = m_lastRenderScaleValue * 0.8f;
else
// Make the render scale higher
tmpCurrentRenderScaleValue = m_lastRenderScaleValue * 1.1f;
}
}
else
// Set the render scale value to its maximum value
tmpCurrentRenderScaleValue = 1.0f;
// Limit the render scale
tmpCurrentRenderScaleValue = max(tmpCurrentRenderScaleValue, 0.2f);
tmpCurrentRenderScaleValue = min(tmpCurrentRenderScaleValue, 1.0f);
// Check if the render scale value has changed
if (m_lastRenderScaleValue != tmpCurrentRenderScaleValue)
{
// Set the new last render scale value value
bool tmpOldUseCompositor = m_lastRenderScaleValue != 1.0f;
m_lastRenderScaleValue = tmpCurrentRenderScaleValue;
// Check if we have changed the compositor target
bool tmpUseCompositor = m_lastRenderScaleValue != 1.0f;
if (tmpUseCompositor != tmpOldUseCompositor)
// Enable/disable the compositor
CompositorManager::getSingleton().setCompositorEnabled(m_camera->getViewport(), "DynamicResolution", tmpUseCompositor);
// Check if we are using the compositor
if (tmpUseCompositor)
{
// Get the compositor chain from the camera and check if it is valid
CompositorChain* tmpCompositorChain = CompositorManager::getSingleton().getCompositorChain(m_camera->getViewport());
if (tmpCompositorChain)
{
// Get the compositor instance and check if it is valid
CompositorInstance* tmpCompositorInstance = tmpCompositorChain->getCompositor("DynamicResolution");
if (tmpCompositorInstance)
{
// Get the compositor technique and check if it is valid
CompositionTechnique* tmpCompositorTechnique = tmpCompositorInstance->getTechnique();
if (tmpCompositorTechnique)
{
// Get the scene texture definition and check if it is valid
CompositionTechnique::TextureDefinition* tmpTextureDefinition = tmpCompositorTechnique->getTextureDefinition("scene");
if (tmpTextureDefinition)
{
// Update the compositor render scale
tmpTextureDefinition->width = size_t(float(m_window->getWidth()) * m_lastRenderScaleValue);
tmpTextureDefinition->height = size_t(float(m_window->getHeight()) * m_lastRenderScaleValue);
// Adjust the pixels to become as close to the wanted aspect ratio of the window
const int tmpMinMaxValue = 10;
if (tmpTextureDefinition->width > tmpMinMaxValue &&
tmpTextureDefinition->height > tmpMinMaxValue)
{
//float tmpBeforeAspectRatio = float(tmpTextureDefinition->width) / float(tmpTextureDefinition->height);
float tmpWantedAspectRatio = float(m_window->getWidth()) / float(m_window->getHeight());
float tmpClosest = FLT_MAX;
int tmpClosestX = 0;
int tmpClosestY = 0;
for (int x = -tmpMinMaxValue; x <= tmpMinMaxValue; x++)
{
for (int y = -tmpMinMaxValue; y <= tmpMinMaxValue; y++)
{
float tmpCurrentAspectRatio = float(tmpTextureDefinition->width + x) / float(tmpTextureDefinition->height + y);
float tmpDistanceCurrent = abs(tmpWantedAspectRatio - tmpCurrentAspectRatio);
if (tmpDistanceCurrent < tmpClosest)
{
tmpClosest = tmpDistanceCurrent;
tmpClosestX = x;
tmpClosestY = y;
}
}
}
if (tmpClosest != FLT_MAX)
{
tmpTextureDefinition->width += tmpClosestX;
tmpTextureDefinition->height += tmpClosestY;
}
}
// Make sure the textures are created
tmpCompositorInstance->setAlive(false);
tmpCompositorInstance->setAlive(true);
tmpCompositorInstance->setEnabled(true);
}
}
}
}
}
else
// Set that we are not active
m_active = false;
}
}
};
Re: [1.11.2] Dynamic Resolution
Posted: Wed Feb 24, 2021 1:38 pm
by paroj
rpgplayerrobin wrote: Wed Feb 24, 2021 1:55 am
I found that it matters where I use the CompositorManager::getSingleton().addCompositor.
yeah, thats a shorthand for getCompositorChain().addCompositor(), which probably explains what is going on.
rpgplayerrobin wrote: Wed Feb 24, 2021 1:55 am
Though I do not understand how that compositor can make the original (createOriginalScene) compositor not have any effect, but as you said, it is only used for "input previous", so I guess it looks on my real compositor and sees that while only rendering it at the scale I want it rendered at, and ignoring the first full-window render that it would have used normally.
once you enable compositors, you are in full control. If you only have an empty target_output pass, ogre will not render anything. The only exception is "input previous", which is treated as a shorthand for render_scene at position 0.