[Ogre 2.1] Porting CEGUI to OGRE 2.1

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
crancran
Greenskin
Posts: 138
Joined: Wed May 05, 2010 3:36 pm
x 6

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by crancran »

dark_sylinc,

I am running into a small problem when working with render to textures while porting CEGUI to 2.2 and I'm not sure what could be the cause. When I render under OGRE 2.1, I see things get rendered like this:
Image
But when I attempt to render this under OGRE 2.2, I see this:
Image
Now if I attempt to resize the black area which is where the window widget should exist, I see the grey window widget being painted on the main viewport, upside down, and also reversed (e.g. text is backward) and quickly erased with the blue compositor background. This makes me think I am not doing something right in my port code for handling RenderToTexture things.

A little background, whenever CEGUI wants to render something like a basic window that could be resized and/or moved on screen, it would create a manual texture of type TU_RENDERTARGET, construct a Viewport object and associate the texture's render target to that viewport. Something akin to this very trimmed down code set.

Code: Select all

TexturePtr rtt = TextureManager::getSingleton().createManual(
  getUniqueTextureName(), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
  TEX_TYPE_2D, width, height, 1, 0, PF_A8R8G8B8, TU_RENDERTARGET );
  
RenderTarget *rt = rtt->getBuffer()->getRenderTarget();

if ( vp_ )
{
  // since we create a new RTT, if a viewport exists, destroy it.
  // we have to create a new one with the new RTT.
  delete vp_;
  vp_ = 0;
}
  
vp_ = OGRE_NEW Viewport( rt, 0, 0, 1, 1 );
vp_->setDimensions(
  vpDims.left() / rt->getWidth(), 
  vpDims.top() / rt->getHeight(), 
  vpDims.getWidth() / rt->getWidth(),
  vpDims.getHeight() / rt->getHeight() );
  
Ogre::Viewport *cvp = renderSystem->_getViewport();
renderSystem->_setViewport( vp_ );
renderSystem->clearFrameBuffer( Ogre::FBT_COLOUR, ColourValue::Black );
renderSystem->_setViewport( cvp );
Now obviously setting up a render-to-texture is quite simple too under 2.2

Code: Select all

TextureGpuManager* textureManager = d_renderSystem.getTextureGpuManager();
TextureGpu* rtt= textureManager->createTexture(
  getUniqueTextureName(), GpuPageOutStrategy::Discard, TextureFlags::RenderToTexture, 
  TextureTypes::Type2D, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
rtt->setResolution( width, height, 1u );
rtt->setNumMipmaps( 0 );
rtt->setPixelFormat( Ogre::PFG_RGBA8_UNORM );
rtt->_transitionTo( GpuResidency::Resident, nullptr );
rtt->_setNextResidencyStatus( GpuResidency::Resident );
The nice thing under Ogre 2.2 is it seems I no longer would need to destroy & create new viewports as they did in the past. With the API changes on the viewport, allowing me to specify the TextureGpu when I define the dimensions, I can simply modify the existing viewport if I understand correctly.

Code: Select all

Vector4 dims(
  vpDims.left() / rtt->getWidth(), 
  vpDims.top() / rtt->getHeight(), 
  vpDims.getWidth() / rtt->getWidth(),
  vpDims.getHeight() / rtt->getHeight() );
vp_->setDimensions( rtt, dims, dims );
What I am not understanding is what am I doing incorrectly here to cause the black surface area during the render pass but then the flicker of the expected content in the black area on the main viewport but in the odd inverted fashion.

I have forked the CEGUI repository and added a OGRE 2.2 specific branch here that contains a new RendererModule called OgreNext. This module is designed solely to work with Ogre 2.2 allowing me to remove all the fluff from legacy v1 and early v2 ports for just a clear view on whats needed. Perhaps you could point out my mistake? FWIW, OgreTextureTarget and its parent clas is where this functionality mostly resides.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4519
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 945
Contact:

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by dark_sylinc »

First:

Code: Select all

rtt->setNumMipmaps( 0 );
That's wrong. 0 is invalid. Old code mipmaps didn't count the base mip; new code does; so the equivalent should be rtt->setNumMipmaps( 1 );

The code you posted:

Code: Select all

Ogre::Viewport *cvp = renderSystem->_getViewport();
renderSystem->_setViewport( vp_ );
renderSystem->clearFrameBuffer( Ogre::FBT_COLOUR, ColourValue::Black );
renderSystem->_setViewport( cvp );
is explicitly clearing the RTT to black.

The equivalent would be:

Code: Select all

renderSystem->clearFrameBuffer( renderPassDesc, textureGpu );
Although as the manual explains, this wouldn't be Mobile friendly. But if CEGUI does it this way... should do it that way.

As for the rest you mention, I don't know; but the "upside down" sounds like a GL issue. RenderTextures in GL are upside down (vs RenderWindows), and we use a projection matrix trick to flip them. TextureGpu::requiresTextureFlipping and RenderPassDescriptor::requiresTextureFlipping takes care of that (previously it was RenderTarget::requiresTextureFlipping).
The RenderPassDescriptor's value is filled at runtime (RenderPassDescriptor::mRequiresTextureFlipping) inside RenderPassDescriptor::checkRequiresTextureFlipping. Perhaps it's not getting called for some reason, or the value getting corrupted.

crancran
Greenskin
Posts: 138
Joined: Wed May 05, 2010 3:36 pm
x 6

Re: [Ogre 2.2] Porting CEGUI to OGRE 2.2

Post by crancran »

I decided it might be better to work from a very simple example that I believe follows how I see CEGUI at least using RTT in the compositor pass. This might at least help identify something I have missed or misunderstood.

RenderTextureExample.hpp

Code: Select all

#include <OgreWindow.h>
#include <OgrePsoCacheHelper.h>
#include <Compositor/OgreCompositorWorkspace.h>
#include <Compositor/OgreCompositorWorkspaceListener.h>

class RenderTextureExample : public Ogre::CompositorWorkspaceListener
{
public:
	RenderTextureExample();
	virtual ~RenderTextureExample();

	//! Call right before main loop with the render window.
	//! This sets up the environment for this example to fire on each frame rendered.
	void Start(Ogre::Window *window);

	//! Call immediately after main loop to cleanup the example.
	void Shutdown();

	//! CompositorWorkspaceListener overrides
	void passPreExecute(Ogre::CompositorPass *pass) override;

private:
	//! This method effectively builds a compositor workspace script in code that we
	//! will use for rendering content in the scene pass.
	void InitializeCompositorDefinitions();

	//! Bind the compositor workspace.
	void BindCompositorWorkspace(Ogre::TextureGpu *render_target);

	//! Sets up the render to texture
	void SetupRenderToTexture();

	//! Helper method for uploading a file into the supplied texture.
	void UploadImageBufferToTexture(Ogre::TextureGpu *texture, const Ogre::String &name);

	//! Build our very simple draw call
	void BuildGeometry();

	//! Renders the RTT on the scene.
	void Render();

private:
	Ogre::SceneManager *scene_manager_;		//< Compositor scene manager
	Ogre::Camera *camera_;					//< Compositor camera
	Ogre::CompositorWorkspace *workspace_;		//< Compositor workspace

	Ogre::PsoCacheHelper *pso_cache_;			//< PSO cache helper
	Ogre::CbDrawCallIndexed *draw_call_;		//< The geometry draw call, simple quad.

	Ogre::TextureGpu *rtt_;					//< The RTT, filled with an image.
	Ogre::Viewport *viewport_;				//< The viewport that contains the RTT

	Ogre::HlmsMacroblock *macro_block_;		//< default macro block
	Ogre::HlmsBlendblock *blend_block_;		//< default blend block
};
RenderTextureExample.cpp

Code: Select all

#include "RenderTextureExample.hpp"

#include <OgreRoot.h>
#include <OgreHlms.h>
#include <OgreTextureGpuManager.h>
#include <OgreStagingTexture.h>
#include <OgrePixelFormatGpuUtils.h>
#include <CommandBuffer/OgreCbDrawCall.h>
#include <Compositor/OgreCompositorManager2.h>
#include <Compositor/OgreCompositorNodeDef.h>
#include <Compositor/Pass/PassClear/OgreCompositorPassClearDef.h>

RenderTextureExample::RenderTextureExample()
{
	macro_block_ = nullptr;
	blend_block_ = nullptr;

	scene_manager_ = nullptr;
	camera_ = nullptr;

	workspace_ = nullptr;
	pso_cache_ = nullptr;
	draw_call_ = nullptr;

	rtt_ = nullptr;
	viewport_ = nullptr;
}

RenderTextureExample::~RenderTextureExample()
{
	Shutdown();
}

void RenderTextureExample::Start(Ogre::Window *window)
{
	//! todo: do we need to initialize these with anything beyond defaults?
	macro_block_ = new Ogre::HlmsMacroblock();
	blend_block_ = new Ogre::HlmsBlendblock();

	pso_cache_ = new Ogre::PsoCacheHelper( Ogre::Root::getSingleton().getRenderSystem() );

	InitializeCompositorDefinitions();

	BindCompositorWorkspace( window->getTexture() );

	SetupRenderToTexture();

	BuildGeometry();
}

void RenderTextureExample::Shutdown()
{
	Ogre::Root *root = Ogre::Root::getSingletonPtr();

	if ( workspace_ )
	{
		Ogre::CompositorManager2 *compositorManager = root->getCompositorManager2();
		compositorManager->removeWorkspace( workspace_ );
		compositorManager->removeNodeDefinition( "RTE_rendernode" );
		compositorManager->removeWorkspaceDefinition( "RTE_workspace" );
		workspace_ = nullptr;
	}

	if ( camera_ )
	{
		scene_manager_->destroyCamera( camera_ );
		camera_ = nullptr;
	}

	if ( scene_manager_ )
	{
		root->destroySceneManager( scene_manager_ );
		scene_manager_ = nullptr;
	}

	delete pso_cache_;
	pso_cache_ = nullptr;
}

void RenderTextureExample::InitializeCompositorDefinitions()
{
	Ogre::CompositorManager2 *compositorManager = Ogre::Root::getSingleton().getCompositorManager2();

	Ogre::CompositorWorkspaceDef *workspace = compositorManager->addWorkspaceDefinition( "RTE_workspace" );

	Ogre::CompositorNodeDef *render_node = compositorManager->addNodeDefinition( "RTE_rendernode" );
	render_node->addTextureSourceName( "renderwindow", 0, Ogre::TextureDefinitionBase::TEXTURE_INPUT );
	render_node->setNumTargetPass( 1 );

	Ogre::CompositorTargetDef *target = render_node->addTargetPass( "renderwindow" );
	target->setNumPasses( 2 );

	//! During this pass, we only want to clear the depth & stencil buffers
	//! This is because we want to render on top of an existing image in the buffer.
	Ogre::CompositorPassDef *clear_pass = target->addPass( Ogre::PASS_CLEAR );
	Ogre::uint32 buffers = Ogre::RenderPassDescriptor::Depth | Ogre::RenderPassDescriptor::Stencil;
	static_cast<Ogre::CompositorPassClearDef*>( clear_pass )->setBuffersToClear( buffers );

	//! Setup the scene pass to render the view
	Ogre::CompositorPassDef *scene_pass = target->addPass( Ogre::PASS_SCENE );

	//! Link the target and nodes
	workspace->connectExternal( 0, "RTE_rendernode", 0 );
}

void RenderTextureExample::BindCompositorWorkspace(Ogre::TextureGpu *render_target)
{
	scene_manager_ = Ogre::Root::getSingleton().createSceneManager( Ogre::ST_INTERIOR, 1, "RTE_SceneManager" );
	camera_ = scene_manager_->createCamera( "RTE_Camera" );

	Ogre::CompositorManager2 *compositorManager = Ogre::Root::getSingleton().getCompositorManager2();

	workspace_ = compositorManager->addWorkspace( scene_manager_, render_target, camera_, "RTE_workspace", true );
	workspace_->setListener( this );
}

void RenderTextureExample::SetupRenderToTexture()
{
	Ogre::TextureGpuManager *textureGpuManager = Ogre::Root::getSingleton().getRenderSystem()->getTextureGpuManager();

	rtt_ = textureGpuManager->createTexture(
			"RTT",
			Ogre::GpuPageOutStrategy::Discard,
			Ogre::TextureFlags::RenderToTexture,
			Ogre::TextureTypes::Type2D );

	rtt_->setResolution( 800, 600, 1u );
	rtt_->setNumMipmaps( 1 );
	rtt_->setPixelFormat( Ogre::PixelFormatGpu::PFG_RGBA8_UNORM );

	//! initialize the render to texture with an empty texture buffer
	UploadImageBufferToTexture( rtt_, "Images\\BFA.jpg" );

	//! Traditionally in CEGUI, it would just create a viewport the size of the screen.
	//! Then the UI objects would make a call into a resize function to define the actual dimensions.
	viewport_ = new Ogre::Viewport( 0, 0, 1, 1 );

	//! Now set the size of the viewport and associate the rtt to it.
	Ogre::Vector4 dims( 0, 0, 1, 1 );
	viewport_->setDimensions( rtt_, dims, dims );
}

void RenderTextureExample::UploadImageBufferToTexture(Ogre::TextureGpu *texture, const Ogre::String &name)
{
	//! this method assumes the texture's metadata has been initialized.
	//! it also uploads an image into the RTT

	using namespace Ogre;

	TextureGpuManager *textureGpuManager = Root::getSingleton().getRenderSystem()->getTextureGpuManager();

	//! Load the image
	Image2 image;
	image.load( name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );

	//! Get the texture bounding boxes for image and render texture.
	TextureBox image_box = image.getData( 0 );
	TextureBox empty_box = texture->getEmptyBox( 0 );

	//! Determine the maximum bounds based on the minimum dimension of the two boxes.
	Ogre::uint32 width = std::min<Ogre::uint32>( image_box.getMaxX(), empty_box.getMaxX() );
	Ogre::uint32 height = std::min<Ogre::uint32>( image_box.getMaxY(), empty_box.getMaxY() );

	//! Create a staging texture bounded by the minimum dimensions
	StagingTexture *staging = textureGpuManager->getStagingTexture(
			width, height, empty_box.depth, empty_box.numSlices, image.getPixelFormat() );

	staging->startMapRegion();

	//! Upload the image data based on the bounded width and height.
	//! We use the raw data pointer rather than the image_box to influence the width/height dimensions
	//! based on the bounded values we determined between the render texture and the image.
	TextureBox dst = staging->mapRegion(
			width,
			height,
			image_box.depth,
			image_box.numSlices,
			image.getPixelFormat() );
	dst.copyFrom( image_box.data, width, height, image_box.bytesPerRow );

	staging->stopMapRegion();

	texture->_transitionTo( GpuResidency::Resident, nullptr );
	texture->_setNextResidencyStatus( GpuResidency::Resident );

	staging->upload( dst, texture, 0, nullptr, true );

	textureGpuManager->removeStagingTexture( staging );
	texture->notifyDataIsReady();
}

void RenderTextureExample::passPreExecute(Ogre::CompositorPass *pass)
{
	if ( pass->getType() == Ogre::PASS_SCENE )
	{
		Render();
	}
}

void RenderTextureExample::BuildGeometry()
{
	Ogre::VaoManager *vaoManager = Ogre::Root::getSingleton().getRenderSystem()->getVaoManager();

	//!--------------------------------------
	//! Build vertex buffer data
	//!
	std::vector<Ogre::Vector3> vertices;
	vertices.emplace_back( -2.f, +2.f, 0.f );
	vertices.emplace_back( +2.f, +2.f, 0.f );
	vertices.emplace_back( -2.f, -2.f, 0.f );
	vertices.emplace_back( +2.f, -2.f, 0.f );

	std::vector<Ogre::Vector2> uvs;
	uvs.emplace_back( 0, 1 );
	uvs.emplace_back( 1, 1 );
	uvs.emplace_back( 0, 0 );
	uvs.emplace_back( 1, 0 );

	Ogre::VertexElement2Vec elements;
	elements.emplace_back( Ogre::VET_FLOAT3, Ogre::VES_POSITION );
	elements.emplace_back( Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES );

	void *vdata = OGRE_MALLOC_SIMD( vaoManager->calculateVertexSize( elements ) * vertices.size(),
									Ogre::MEMCATEGORY_GEOMETRY );
	Ogre::Real *vb_ptr = reinterpret_cast<Ogre::Real *>( vdata );

	for ( size_t i = 0; i < vertices.size(); ++i )
	{
		const Ogre::Vector3 &pos = vertices[ i ];
		*vb_ptr++ = pos.x;
		*vb_ptr++ = pos.y;
		*vb_ptr++ = pos.z;

		const Ogre::Vector2 &uv = uvs[ i ];
		*vb_ptr++ = uv.x;
		*vb_ptr++ = uv.y;
	}

	Ogre::VertexBufferPacked *vb = vaoManager->createVertexBuffer(
			elements,
			vertices.size(),
			Ogre::BT_IMMUTABLE,
			vdata,
			false );

	//!--------------------------------------
	//! Build index buffer data
	//!
	std::vector<Ogre::uint16> indices;
	indices.push_back( 2 );
	indices.push_back( 0 );
	indices.push_back( 1 );
	indices.push_back( 1 );
	indices.push_back( 3 );
	indices.push_back( 2 );

	void *idata = OGRE_MALLOC_SIMD( sizeof( Ogre::uint16 ) * indices.size(), Ogre::MEMCATEGORY_GEOMETRY );
	Ogre::uint16 *ib_ptr = reinterpret_cast<Ogre::uint16 *>( idata );

	for ( size_t i = 0; i < indices.size(); ++i )
		*ib_ptr++ = indices[ i ];

	Ogre::IndexBufferPacked *ib = vaoManager->createIndexBuffer(
			Ogre::IndexBufferPacked::IT_16BIT,
			indices.size(),
			Ogre::BT_IMMUTABLE,
			idata,
			false );

	//!--------------------------------------
	//! Setup VAO and draw call
	//!
	Ogre::VertexBufferPackedVec vbs;
	vbs.push_back( vb );
	Ogre::VertexArrayObject *vao = vaoManager->createVertexArrayObject( vbs, ib, Ogre::OT_TRIANGLE_LIST );

	draw_call_ = new Ogre::CbDrawCallIndexed( 0, vao, nullptr );
}

void RenderTextureExample::Render()
{
	Ogre::RenderSystem *render_system = Ogre::Root::getSingletonPtr()->getRenderSystem();

	//! In CEGUI, before anything can be drawn for a RTT, we must first activate the
	//! render target and its rendering area.  This is done by changing the viewport
	//! in the render system.
	//!
	//! Currently CEGUI does not cache the current viewport before changing it and
	//! later restoring it.  Could this present issues?
	render_system->_setViewport( viewport_ );

	//! In OGRE 2.1, CEGUI had to set the render target
	//! Now we pass the current render pass descriptor object.
	Ogre::RenderPassDescriptor *descriptor = render_system->getCurrentPassDescriptor();
	pso_cache_->setRenderTarget( descriptor );

	//! At this point the UI has everything setup and its prepared to dump its geometry.
	//! This is where a call into OgreGeometry::Draw() happens.

	//!	1. Vertex/Pixel shader programs are bound to the pso cache
	//! In our case presently, there are none.

	//!	2. The HLMS blend and macro blocks get bound to the pso cache
	pso_cache_->setMacroblock( macro_block_ );
	pso_cache_->setBlendblock( blend_block_ );

	//!	3. The vertex format gets bound to the pso cache
	Ogre::VertexArrayObject *vao = draw_call_->vao;
	pso_cache_->setVertexFormat( vao->getVertexDeclaration(), vao->getOperationType(), false );

	//!	4. The HlmsPso gets bound to the render system
	render_system->_setPipelineStateObject( pso_cache_->getPso() );

	//!	5. Shader parameters get set.
	//! In our case presently, there are none.

	//! 6. Set the v1 render operation
	//! In our case we aren't using v1, so we do nothing
	//! render_system->_setRenderOperation( v1renderOp );

	//!	7. Render the operation
	//!		In this example, I am using a CbDrawCallIndexed rather than a v1 object.
	render_system->_render( draw_call_ );
}
The problem here is nothing gets rendered and I am at a loss as to what I am doing incorrectly.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4519
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 945
Contact:

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by dark_sylinc »

I have spotted a few issues:

Code: Select all

macro_block_ = new Ogre::HlmsMacroblock();
blend_block_ = new Ogre::HlmsBlendblock();
...

pso_cache_->setMacroblock( macro_block_ );
pso_cache_->setBlendblock( blend_block_ );
The PSO cache expects pointers created by the HlmsManager. You need to create your blocks this way:

Code: Select all

Ogre::HlmsMacroblock macroblockRef;
macroblockRef.mCullMode = CULL_NONE; //Prevent silly bugs caused by wrong winding in your vertex buffer
macro_block_ = hlmsManager->getMacroblock( macroblockRef );
blend_block_ = hlmsManager->getBlendblock( Ogre::HlmsBlendblock() );
As for this:

Code: Select all

Ogre::uint32 buffers = Ogre::RenderPassDescriptor::Depth | Ogre::RenderPassDescriptor::Stencil;
I'm just checking that you actually want to clear just depth and stencil but not colour.

Code: Select all

rtt_ = textureGpuManager->createTexture(
        "RTT",
        Ogre::GpuPageOutStrategy::Discard,
        Ogre::TextureFlags::RenderToTexture,
        Ogre::TextureTypes::Type2D );

rtt_->setResolution( 800, 600, 1u );
rtt_->setNumMipmaps( 1 );
rtt_->setPixelFormat( Ogre::PixelFormatGpu::PFG_RGBA8_UNORM );

//! initialize the render to texture with an empty texture buffer
UploadImageBufferToTexture( rtt_, "Images\\BFA.jpg" );
I don't think I ever tried to upload data from CPU to a RenderToTexture texture, so it's not impossible this is not actually working (not your fault; but directly uploading from CPU to a RenderTexture is not desirable though).
RenderDoc can tell if the data was uploaded successfully though (make sure to tick "Ref all Resources" before capturing)

Code: Select all

void RenderTextureExample::passPreExecute(Ogre::CompositorPass *pass)
{
	if ( pass->getType() == Ogre::PASS_SCENE )
	{
		Render();
	}
}
This isn't your fault, passPreExecute runs before binding the RenderPassDesc; so whatever you're reading from render_system->getCurrentPassDescriptor() must be a leftover from a previous pass (judging from your setup, it should still work in your case because the RenderPassDescriptor bound should be a valid one coming from the clear pass that ran before).

Is it possible for me to run the whole sample you mention? Looks like simple code. If I'm able to run it I could troubleshoot what went wrong.

crancran
Greenskin
Posts: 138
Joined: Wed May 05, 2010 3:36 pm
x 6

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by crancran »

crancran wrote:
Tue Apr 10, 2018 5:49 pm
Is it possible for me to run the whole sample you mention? Looks like simple code. If I'm able to run it I could troubleshoot what went wrong.
Absolutely, it should be easy to adapt to any of the samples I would think. The scope of this small example is to upload an image to the RTT and then during the SCENE_PASS, overlay that RTT atop of the existing scene at a predefined x/y offset with a given width/height dimension.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4519
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 945
Contact:

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by dark_sylinc »

Ah! I spotted the main reason it isn't working. v2 needs a little more setup work.

GL3PlusRenderSystem::_render & _renderEmulated expect paratemers stored in an IndirectBuffer from CbDrawCallIndexed.

Code: Select all

bool supportsIndirectBuffers = mVaoManager->supportsIndirectBuffers();

IndirectBufferPacked *indirectBuffer = 0;
unsigned char *indirectDraw = 0;
unsigned char *startIndirectDraw = 0;

if( supportsIndirectBuffers )
{
    indirectDraw = static_cast<unsigned char*>(
                indirectBuffer->map( 0, indirectBuffer->getNumElements() ) );
}
else
{
    indirectDraw = indirectBuffer->getSwBufferPtr();
}

void *offset = reinterpret_cast<void*>( indirectBuffer->_getFinalBufferStart() + (indirectDraw - startIndirectDraw) );

int baseInstanceAndIndirectBuffers = 0;
if( mVaoManager->supportsIndirectBuffers() )
    baseInstanceAndIndirectBuffers = 2;
else if( mVaoManager->supportsBaseInstance() )
    baseInstanceAndIndirectBuffers = 1;

CbDrawIndexed *drawIndexedPtr = reinterpret_cast<CbDrawIndexed*>( indirectDraw );
indirectDraw += sizeof( CbDrawIndexed );

drawIndexedPtr->primCount       = vao->mPrimCount;
drawIndexedPtr->instanceCount   = 1;
drawIndexedPtr->firstVertexIndex= vao->mIndexBuffer->_getFinalBufferStart() + vao->mPrimStart;
drawIndexedPtr->baseVertex      = vao->mBaseVertexBuffer->_getFinalBufferStart();
drawIndexedPtr->baseInstance    = baseInstance;

drawCall = CbDrawCallIndexed( baseInstanceAndIndirectBuffers, vao, offset );

if( baseInstanceAndIndirectBuffers == 0 )
   render_system_->_renderEmulatedNoBaseInstance( drawCall );
else if( baseInstanceAndIndirectBuffers == 1 )
   render_system_->_renderEmulated( drawCall );
else
   render_system_->_render( drawCall );

//Don't forget to unmap indirect buffer
Checkout RenderQueue::render & RenderQueue::renderGL3 for reference.
Of course the idea behind v2 is not that you do this for every widget in CEGUI, but rather fill the indirect buffer with as many widgets as possible, record the PSO changes (e.g. with the help of CommandBuffer), and then fire up all commands. If this is overkill or too complex (it may not work well if CEGUI's design doesn't help) then perhaps v1 is an easier option.

crancran
Greenskin
Posts: 138
Joined: Wed May 05, 2010 3:36 pm
x 6

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by crancran »

Whelp, I found the bug in the 2.2 port, partially my own fault for not knowing what was needed going from 2.1->2.2:

Under OGRE 2.1, it did this:

Code: Select all

pso_cache->setRenderTarget( target /* the render target being rendered to */ );
and that resulted in the viewport being rendered as:
Image

I needed to replace that with the following:

Code: Select all

Ogre::RenderPassDescriptor *descriptor = render_system->createRenderPassDescriptor();
descriptor->mColour[0].texture = texture;
descriptor->mColour[0].loadAction = Ogre::LoadAction::Load;
descriptor->mColour[0].storeAction = Ogre::StoreAction::Store;
descriptor->entriesModified( 1 );
pso_cache->setRenderTarget( descriptor /* the render pass descriptor */ );
and that resulted in the viewport being rendered as:
Image
The only issue now is trying to understand the aspect ratio being wonky and why it doesn't render on DX11.

crancran
Greenskin
Posts: 138
Joined: Wed May 05, 2010 3:36 pm
x 6

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by crancran »

crancran wrote:
Wed Apr 11, 2018 1:22 am
The only issue now is trying to understand the aspect ratio being wonky and why it doesn't render on DX11.
dark_sylinc,

I decided to check the code inside the _setViewport methods in the OpenGL and DX11 implementations and I see a large section that is excluded when being compiled on the OGRE 2.2 branch. I decided to add that code back in locally to see if that addressed the scaling concerns and things drew at the right ratio.

If this code is going away entirely, whats the proper way to make sure that I get the glViewport/glScissors call to happen as a part of my render pass to make sure that the texture gets drawn at the right ratio?

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4519
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 945
Contact:

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by dark_sylinc »

The code you're calling has mostly been moved to beginRenderPassDescriptor. You should even recognize it once you go there.

Perhaps the wrong values are passed to that function, or they're in the wrong unit of measure, or they get overriden by another call to the same function.

Update: Before posting I just saw in beginRenderPassDescriptor:

Code: Select all

if( mCurrentRenderViewport.coversEntireTarget() )
if( !desc->requiresTextureFlipping() )
{
	// Convert "upper-left" corner to "lower-left"
	y = anyTarget->getHeight() - h - y;
}
That is definitely fishy (wrong brackets or indentation).
Edit: That weird line was removed

crancran
Greenskin
Posts: 138
Joined: Wed May 05, 2010 3:36 pm
x 6

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by crancran »

dark_sylinc wrote:
Wed Apr 11, 2018 10:09 pm
The code you're calling has mostly been moved to beginRenderPassDescriptor. You should even recognize it once you go there.
When you said this, something clicked and I want to clarify if my understanding is accurate.

Prior to 2.2, CEGUI would create a RTT for a variety of window surfaces that it would need to draw. Each RTT would have an associated viewport that got created which effectively wraps the RTT's underlying RenderTarget. Right before drawing the geometry for that window, we'd do this:

Code: Select all

// Cache the prior viewport
Viewport *prior_viewport = render_system_->_getViewport();

// Set the viewport in the render system for which our RTT is linked with
render_system_->_setViewport( rttViewport );
/* issue draw calls here */

// Restore prior viewport
render_system_->_setViewport( prior_viewport );
In 2.2 terms after reading beginRenderPassDescriptor, should I instead be creating a new RenderPassDescriptor and call beginRenderPassDescriptor and specify my RTT and the necessary viewport and scissor dimensions instead?

My apologies for all the questions, I'm just trying to make a correlation between the new additions in 2.2 versus prior versions.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4519
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 945
Contact:

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by dark_sylinc »

crancran wrote:
Wed Apr 11, 2018 11:04 pm
In 2.2 terms after reading beginRenderPassDescriptor, should I instead be creating a new RenderPassDescriptor and call beginRenderPassDescriptor and specify my RTT and the necessary viewport and scissor dimensions instead?
Old viewport settings don't need to be restored.
In fact if the GUI is being rendered after or before the geometry / other passes, then you don't even need to restore previous RenderPassDescs either.
Restoring RenderPassDescs wouldn't always make sense: e.g. if existing RPDescriptor had LoadAction::Clear, then restoring it may cause us to clear twice.

As for "should I instead be creating a new RenderPassDescriptor?" probably, maybe you already have that RPD. You don't need one per Viewport settings since the VP settings are provided alongside the RPD, and not inside of it.

crancran
Greenskin
Posts: 138
Joined: Wed May 05, 2010 3:36 pm
x 6

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by crancran »

Alright, I have CEGUI and OGRE 2.2 working quite well with the exception of one artifact I cannot seem to dodge wrt clearing the RTT.

I presently clear the RTT using this method:

Code: Select all

RenderPassDescriptor *descriptor = renderSystem->createRenderPassDescriptor();
descriptor->mColour[0].texture = my_rtt;
descriptor->mColour[0].loadAction = LoadAction::Clear;
descriptor->mColour[0].storeAction = StoreAction::Store;
descriptor->entriesModified( 1 );
renderSystem.clearFrameBuffer( descriptor, my_rtt );
Presently I draw the onto the RTT by using this descriptor:

Code: Select all

RenderPassDescriptor *descriptor = renderSystem->createRenderPassDescriptor();
descriptor->mColour[0].texture = texture;
descriptor->mColour[0].loadAction = Ogre::LoadAction::Load;
descriptor->mColour[0].storeAction = Ogre::StoreAction::Store;
descriptor->entriesModified( 1 );

Vector4 vpSize = OgreViewportUtil::getDimensions(*viewport);
Vector4 vpScissors = OgreViewportUtil::getScissors(*viewport);

renderSystem->beginRenderPassDescriptor( descriptor, texture, vpSize, vpScissors, false, false );
So I get my FrameWindow, but its drawn with this black aura around it, shown here:
Image
From what I can tell, the black outline is coming from me calling clearFrameBuffer, so I believe my settings are inaccurate for that somehow. What I ultimately need is to do that so that the window effectively looks seamless on the blue background and so then when I collapse the frame window to just a titlebar, I don't get the black area as shown here:
Image
If I eliminate the clearFrameBuffer call all together, then I solve the black aura around the FrameWindow, but then when I collapse to just the titlebar, the bottom portion of the RTT remains visible because the RTT isn't being cleared.
Image
Any thoughts on what I might be doing wrong?

crancran
Greenskin
Posts: 138
Joined: Wed May 05, 2010 3:36 pm
x 6

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Post by crancran »

The problem was entirely my mistake. I needed to be explicit on the clear colour to enforce transparency. iow:

Code: Select all

descriptor->setClearColour( 0, ColourValue( 0.f, 0.f, 0.f, 0.f ) );
Sorry for the noise :).

Post Reply