Page 1 of 4

[Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sun Mar 08, 2015 12:36 pm
by Jayray
I am currently trying to migrate CEGUI to OGRE 2.1.
I currently have a working version of CEGUI for OGRE 2.0, where the v1 viewports have been replaced by the v2 compositor. This version is available on the CEGUI official repository.

From what I have seen, 2 aspects make CEGUI incompatible with OGRE 2.1 without changes:
- CEGUI sets all the blend and rendering options using functions that have been removed (RenderSystem::_setSceneBlending, RenderSystem::_setCullingMode, etc.)
- CEGUI is using either the fixed pipeline or HLSL/GLSL shaders incompatible with DX11 / GL3+

My first thought was "No problem, HLMS addresses both aspects, it will be easy to port CEGUI to use HLMS!"
Well... it turns out that it is not as easy as I thought...

My big issue is that CEGUI directly calls the RenderSystem::_render function with the render operation as parameter.
As such, I have not yet figured out how I could provide the HLMS information to the RenderSystem without important changes.

From my understanding, here is what happens when a render operation is done:
- The HLMS macroblock is passed to the RS using the RenderSystem::_setHlmsMacroblock function
- The HLMS blendblock is passed to the RS using the RenderSystem::_setHlmsBlendblock function
- The HLMS shaders are retrieved using the HLMS::getMaterial function and passed to the RS using the RenderSystem::_setProgramsFromHlms

I could pass the macroblock and the blendblock to the render system, but I do not know how to get the shaders as I do not have any Renderable object.
Can they be retrieved from another way?


However, I feel this would be a "quick and dirty" port.
I feel that the correct way to do it would be to:
- Replace all the v1 classes by v2 classes (using the VAO)
- Create a Renderable object for the GUI and use the render queue to render it

Am I right?
Or would it be better on a performance point of view to keep calling low level functions like RenderSystem::_render? In this case, would it change anything to use the VAO instead of the v1 classes?

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sun Mar 08, 2015 12:46 pm
by Jayray
Additional precisions : at the moment, I have created a datablock using the HLMS Unlit.
My idea was to use this datablock to feed the render system with the macroblock, the blencblock and the shaders.

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sun Mar 08, 2015 7:50 pm
by dark_sylinc
CEGUI always used manual rendering to do its stuff on Ogre, which wasn't exactly the best idea on 1.x; but as a quick hack, it worked.

If there's a D3D11 port of CEGUI, then the macro and blendblocks can translate to rasterizer and blend states. You might want to take a look at that.

As for rendering:
IIRC CEGUI doesn't need a world transform matrix because it updates the vertices directly (correct me if I'm wrong). You could indeed use one Renderable & MovableObject per widget to make the Hlms happy.
But if you want it quick and dirty; you could have a dummy Renderable & MovableObject (to provide to fillBufferForV2), and draw every widget yourself replicating the functionality that is on RenderQueue::renderGL3.

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sun Mar 08, 2015 11:02 pm
by Jayray
Thanks a lot for your answer!

I have tried the quick and dirty version, but it's reaaaaaaally dirty :roll:

Code: Select all

	
	// Apply the HLMS blocks to the render system
	d_pimpl->d_renderSystem->_setHlmsBlendblock(d_pimpl->d_hlmsDatablock->getBlendblock());
	d_pimpl->d_renderSystem->_setHlmsMacroblock(d_pimpl->d_hlmsDatablock->getMacroblock());

	// Create a dummy renderable / movable object to retrieve the shaders
	Ogre::SceneManager* sceneManager = d_pimpl->d_ogreRoot->getSceneManagerIterator().getNext();
	Ogre::v1::SimpleRenderable dummyRenderable((Ogre::IdType)0, &sceneManager->_getEntityMemoryManager(Ogre::SCENE_DYNAMIC), sceneManager);
	dummyRenderable.setRenderOperation(renderOp);
	dummyRenderable.setDatablock(d_pimpl->d_hlmsDatablock);
	sceneManager->getRootSceneNode()->attachObject(&dummyRenderable);

	// Fill the dummy queued renderable
	Ogre::QueuedRenderable queuedRenderable;
	queuedRenderable.movableObject = &dummyRenderable;
	queuedRenderable.renderable = &dummyRenderable;
	d_pimpl->d_hlmsDatablock->calculateHash();
	queuedRenderable.hash = d_pimpl->d_hlmsDatablock->mTextureHash;

	Ogre::Hlms *hlms = d_pimpl->d_ogreRoot->getHlmsManager()->getHlms(static_cast<Ogre::HlmsTypes>(d_pimpl->d_hlmsDatablock->mType));

	const Ogre::HlmsCache *hlmsCache = hlms->getMaterial(&Ogre::HlmsCache(), Ogre::HlmsCache(), queuedRenderable, false);

	// Pass the shader to the render system
	d_pimpl->d_renderSystem->_setProgramsFromHlms(hlmsCache);

	// Fill the buffers
	Ogre::CommandBuffer commandBuffer;
	hlms->fillBuffersForV1(hlmsCache, queuedRenderable, false, 0, &commandBuffer);

	sceneManager->getRootSceneNode()->detachObject(&dummyRenderable);
By doing this, I have an assertion in OgreHlmsBufferManager.cpp, on this line:

Code: Select all

shaderBufferCmd->bufferPacked == texBuffer

So I think I will try the clean version ^^
From what I have understood from CEGUI, it uses a world transform matrix, but the calculation is already done:

Code: Select all

void OgreGeometryBuffer::updateMatrix() const
{
    // translation to position geometry and offset to pivot point
    Ogre::Matrix4 trans;
    trans.makeTrans(d_translation.d_x + d_pivot.d_x,
                    d_translation.d_y + d_pivot.d_y,
                    d_translation.d_z + d_pivot.d_z);

    // rotation
    Ogre::Matrix4 rot(Ogre::Quaternion(
        d_rotation.d_w, d_rotation.d_x, d_rotation.d_y, d_rotation.d_z));

    // translation to remove rotation pivot offset
    Ogre::Matrix4 inv_pivot_trans;
    inv_pivot_trans.makeTrans(-d_pivot.d_x, -d_pivot.d_y, -d_pivot.d_z);

    // calculate final matrix
    d_matrix = trans * rot * inv_pivot_trans;

    d_matrixValid = true;
}

I will keep you informed. Thanks for the help!

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Mon Mar 09, 2015 10:56 pm
by Jayray
Big step forward: the GUI is displaying, but... not exactly as expected :roll:
Might need some adjustements :)

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Mon Mar 09, 2015 11:09 pm
by N0vember
How did you do setup the transparency ? In the neighbour thread Porting Gorilla xrgo is having problem with porting Gorilla to Ogre 2.1, he seems to be stuck on the transparency. I didn't have time to look into it myself.

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Mon Mar 09, 2015 11:25 pm
by Jayray
Actually, I replaced the shaders / fixed pipeline used in CEGUI by the HLMS Unlit system.
I also applied the blending settings used by CEGUI on the HLMS datablock:

Code: Select all

	// Blend parameters
	if (d_pimpl->d_activeBlendMode == BM_RTT_PREMULTIPLIED)
	{
		d_pimpl->d_hlmsBlendblock.mSourceBlendFactor = Ogre::SBF_ONE;
		d_pimpl->d_hlmsBlendblock.mDestBlendFactor = Ogre::SBF_ONE_MINUS_SOURCE_ALPHA;
	}
	else
	{
		d_pimpl->d_hlmsBlendblock.mSeparateBlend = true;
		d_pimpl->d_hlmsBlendblock.mSourceBlendFactor = Ogre::SBF_SOURCE_ALPHA;
		d_pimpl->d_hlmsBlendblock.mDestBlendFactor = Ogre::SBF_ONE_MINUS_SOURCE_ALPHA;
		d_pimpl->d_hlmsBlendblock.mSourceBlendFactorAlpha = Ogre::SBF_ONE_MINUS_DEST_ALPHA;
		d_pimpl->d_hlmsBlendblock.mDestBlendFactorAlpha = Ogre::SBF_ONE;
	}
Then, when I set a texture with alpha using the HLMSUnlitDatablock::setTexture function, the transparency gets rendered automatically.

The hard part is to replace all the manual drawing operations by a "HLMS compatible" operation.
To do this, I had to create a MovableObject and multiple Renderable objects. For each Renderable, a HLMSUnlitDatablock is set.
When the Renderable objects are assigned to the "mRenderables" field of the MovableObject, they are renderend automatically (if the MovableObject is attached to the scene).

I will upload my code once it is working :)

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sat Mar 14, 2015 4:31 pm
by Jayray
Finally, I have managed to display a GUI on OGRE 2.1 using CEGUI!

In the end, the way to make it work was easier than what I had first tried.
It seems that the shaders in the 0.8.4 version of CEGUI are already compatible with OpenGL 3+, so I was able to use them to display the GUI instead of using the HLMS Unlit component.
I only used the HLMS macroblock and blendblock to pass the rendering parameters to the rendering system before calling the _render function.

By doing this, only few changes are required in CEGUI, and it even seems better on a performance point of view because it avoids all the HLMS mecanisms that are not necessary for CEGUI (auto-instanciating, etc.).

However, I still have 3 things to do before I can say that CEGUI is successfully ported to OGRE 2.1:
- Use the HLMS samplerblock for the texture filtering parameters
- Make it work on D3D11 (not tested yet)
- Resolve the clipping bug that can be seen in the attached screenshot

Concerning this bug, my first guess is that it comes from the scissors test.
In CEGUI 0.8.4, the scissors test is used this way:

Code: Select all

 d_renderSystem.setScissorTest(
                i->clip, d_clipRect.left(), d_clipRect.top(),
                         d_clipRect.right(), d_clipRect.bottom());
I have replaced this code by the following:

Code: Select all

Ogre::RenderTarget* renderTarget = d_owner.getOgreRenderTarget();
for (int index = 0; index < renderTarget->getNumViewports(); ++index)
{
	if (i->clip)
	{
		renderTarget->getViewport(index)->setScissors(d_clipRect.left(), d_clipRect.top(),
													d_clipRect.right(), d_clipRect.bottom());
	}
}
But the issue is still present...
Does someone have a clue on how I could fix this?

Thanks!

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sat Mar 14, 2015 8:06 pm
by dark_sylinc
Messing up with the Viewport can have unintended consequences because it could be shared by other compositor passes (specially since you're trying to modify all of them rather than the active one). Of course if the viewport is later restored to its original values after you're done, you can avoid these unintended consequences.

The reason it failed is because the actual scissor rects are set when RenderSystem::_setViewport is called.
After you've changed the viewport's scissors, you need to call _setViewport( vp ) again. Mind you this is probably slow.

I removed RenderSystem::setScissorTest because it was being abused; causing important slowdowns. Therefore it was moved to where API docs recommend it should be set: on a more global scale, like per pass (hence the data lives in the compositor).
There are other ways to filter stuff, like clipping in the pixel shader, clamping vertices to the edges, or use the stencil buffer.
Setting the scissor test can be a performance gain if you will be rendering a lot of widgets inside its parent widget. But usually its children will contain more children which means more scissor test changes...

Edit: Forgot to congratulate you for getting it running on 2.1!!! Congrats!!! :D

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sun Mar 15, 2015 4:25 pm
by Jayray
Thanks :D And thanks for your help!
The scissors test is now also working \o/

On OpenGL 3+, there is only one thing that is not working: texture filtering.
I have replaced this code:

Code: Select all

    d_renderSystem._setTextureUnitFiltering(0, FO_LINEAR, FO_LINEAR, FO_POINT);
    d_renderSystem._setTextureAddressingMode(0, S_textureAddressMode);
    d_renderSystem._setTextureMatrix(0, Matrix4::IDENTITY);
    d_renderSystem._setAlphaRejectSettings(CMPF_ALWAYS_PASS, 0, false);
    d_renderSystem._setTextureBlendMode(0, S_colourBlendMode);
    d_renderSystem._setTextureBlendMode(0, S_alphaBlendMode);
    d_renderSystem._disableTextureUnitsFrom(1);
By this code:

Code: Select all

    d_renderSystem._setTextureMatrix(0, Matrix4::IDENTITY);
    d_renderSystem._setTextureBlendMode(0, S_colourBlendMode);
    d_renderSystem._setTextureBlendMode(0, S_alphaBlendMode);
    d_renderSystem._disableTextureUnitsFrom(1);

    Ogre::HlmsSamplerblock samplerblock;
    samplerblock.mMinFilter = FO_LINEAR;
    samplerblock.mMagFilter = FO_LINEAR;
    samplerblock.mMipFilter = FO_POINT;
    samplerblock.mU = TAM_CLAMP;
    samplerblock.mV = TAM_CLAMP;
    samplerblock.mW = TAM_CLAMP;
    samplerblock.mCompareFunction = CMPF_ALWAYS_PASS;

    d_renderSystem._setHlmsSamplerblock(0, &samplerblock);
But the texture still not seem to be filtered (cf. attachment), although this code is called after the RenderSystem::_setTexture function, as stated in the RenderSystem::_setHlmsSamplerblock documentation.

Any idea of what I have missed?

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sun Mar 15, 2015 5:22 pm
by dark_sylinc
You need to create the samplerblock via HlsmManager::getSamplerblock like any other block.
Beware that:
  • getSamplerblock increases the block's reference count. When you're done using it call destroyBlendblock
  • getSamplerblock runs a linear search. You probably don't want to call this function every frame for every object. Cache the result when creating the widget.
Cheers

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sun Mar 15, 2015 11:04 pm
by Jayray
Yes! You are right, that was the issue, thanks again!
I have also corrected the creation of the macroblock and blendblock :)

I have seen your new asserts to force creating HLMS blocks using the get*block function, good idea :)
However, it seems that the _hlmsBlendblockCreated function is not overridden by the GL3+ renderer, so the assert is triggered in debug mode.
I guess this function should be added in the GL3+ renderer, even if it only fills a "dummy" mRsData?

Anyway, in release mode, CEGUI now works perfectly on my project with OGRE 2.1 on the Open GL3+ renderer!
It does not work yet on D3D11, the shaders are too old :) I need to take the shaders in the D3D11 CEGUI renderer.

I was wondering: do I have the rights to upload my CEGUI source files on this forum, as attachment?

I have created a post on the CEGUI forum too, I hope my changes will be accepted as a pull request for CEGUI 0.8.x :roll:

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Mon Mar 16, 2015 1:45 am
by dark_sylinc
Jayray wrote:I have seen your new asserts to force creating HLMS blocks using the get*block function, good idea :)
However, it seems that the _hlmsBlendblockCreated function is not overridden by the GL3+ renderer, so the assert is triggered in debug mode.
Ouch! Will fix it when I get back.

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Mon Mar 16, 2015 9:02 pm
by Jayray
Thanks!
For those who want a CEGUI version compatible with OGRE 2.1 (OpenGL 3+ rendersystem only atm), here is the thread I have created on the official CEGUI forum : http://cegui.org.uk/forum/viewtopic.php ... 388#p33388
And the link to the pull request: https://bitbucket.org/cegui/cegui/pull- ... -with/diff

One step left: making it work with the D3D11 rendersystem! :)

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Mon Mar 16, 2015 11:06 pm
by Jayray
Damn, D3D11 is also a bit recalcitrant...
I have replaced the shaders with D3D11-compatible shaders, but I get the following error when rendering:
OGRE EXCEPTION(3:RenderingAPIException): D3D11 device cannot draw
Error Description:ID3D11DeviceContext::Draw: A Vertex Shader is always required when drawing, but none is currently bound.
in D3D11RenderSystem::_render at F:/Dev/Add-ons/OGRE/Ogre_v2.1_Src/RenderSystems/Direct3D11/src/OgreD3D11RenderSystem.cpp (line 3067)
The shaders are bound using the RenderSystem::bindGpuProgram function. I have seen that the code that binds the shaders to the D3D11 context is commented in the D3D11RenderSystem::bindGpuProgram function, is it normal?

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Tue Mar 17, 2015 4:21 am
by dark_sylinc
Mmm... bindGpuProgram is another vestige floating around. I don't think it's in use. Probably dead code (though may still be useful for Compute Shaders).
The new way is to use _setProgramsFromHlms. You can create a dummy HlmsCache in which you store the actual needed ptrs, if you want.

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Tue Apr 21, 2015 8:41 pm
by Jayray
Hi,

I have finally managed to take some time to continue the CEGUI porting on the D3D11 render system.
Using _setProgramsFromHlms with a dummy HlmsCache, I am now able to use the CEGUI HLSL shaders with Ogre 2.1.

However, it seems that the texture passed to the pixel shader is always null: all the texture.Sample() function always returns (0, 0, 0, 0)...

I do not think that the issue comes from the shaders as they are very basic and my tests tend to show that they are OK, but I can post them if needed.

The texture is passed to the render system with this code:

Code: Select all

    d_renderSystem._setTexture(0, true, i->texture.get());

    d_renderSystem._setTextureCoordCalculation(0, TEXCALC_NONE);
    d_renderSystem._setTextureCoordSet(0, 0);
    d_renderSystem._setTextureMatrix(0, Matrix4::IDENTITY);
    d_renderSystem._setTextureBlendMode(0, S_colourBlendMode);
    d_renderSystem._setTextureBlendMode(0, S_alphaBlendMode);
    d_renderSystem._disableTextureUnitsFrom(1);

    d_renderSystem._setHlmsSamplerblock(0, d_owner.getHlmsSamplerblock());

    d_renderSystem._render(d_renderOp);
Then, the shaders parameters are bound using this code:

Code: Select all

    if (d_pimpl->d_useGLSL)
    {
        if(d_pimpl->d_useGLSLCore)
        {
            d_pimpl->d_vertexShaderParameters->
                setNamedConstant("modelViewPerspMatrix", getWorldViewProjMatrix());    

            d_pimpl->d_renderSystem->
                bindGpuProgramParameters(Ogre::GPT_VERTEX_PROGRAM,
                                            d_pimpl->d_vertexShaderParameters,
                                            Ogre::GPV_ALL);
        }

        d_pimpl->d_pixelShaderParameters->
            setNamedConstant("texture0", 0);

        d_pimpl->d_renderSystem->
            bindGpuProgramParameters(Ogre::GPT_FRAGMENT_PROGRAM,
                                        d_pimpl->d_pixelShaderParameters,
                                        Ogre::GPV_ALL);
    }
    else
    {
        d_pimpl->d_vertexShaderParameters->
            setNamedConstant("worldViewProjMatrix", getWorldViewProjMatrix());

        d_pimpl->d_renderSystem->
            bindGpuProgramParameters(Ogre::GPT_VERTEX_PROGRAM,
                                        d_pimpl->d_vertexShaderParameters,
                                        Ogre::GPV_ALL);
    }
As this works for the OpenGL3+ render system, I suppose that I am only missing a step to pass the texture information to the D3D11 render system, but I cannot find which one...
I have analyzed the RenderQueue::renderSingleObject() and the HlmsLowLevel::fillBuffersFor() functions, but I cannot find what I am missing :(

Maybe the call to _setTextureUnitSettings? But I do not have a pass, so I have no TextureUnitState object.
Or some fragment program parameters that I have to pass using the bindGpuProgramParameters function?

Any help would greatly appreciated (as always :) )

Thanks!

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Wed Apr 22, 2015 6:14 am
by dark_sylinc
D3D11 needs a texture and a sampler.

C++ side, you need to call RenderSystem::setTexture & RenderSystem::_setHlmsSamplerblock.
HLSL side, you need to use register( t0 ) to use the texture at slot 0; and register( s0 ) to use the sampler at slot 0. (In D3D11 you can use the same sampler for many different textures if you want, whereas in GL you are tied to one sampler per texture).

If you're doing that ok, then I suggest RenderDoc. It even supports debugging HLSL code. Should be a no brainer once you hook it.

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Wed Apr 22, 2015 8:02 am
by Jayray
I will try that, thanks! :)

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Sat Apr 25, 2015 9:09 am
by Jayray
I finally got CEGUI working on the D3D11 renderer!

RenderDoc confirmed what I thought: the texture passed to my shader was "null", meaning all pixels had the (0, 0, 0, 0) value.
After some digging in the D3D11 render system, I found out that the texture was filled differently depending on the "dynamic" flag (HBU_STATIC or HBU_DYNAMIC). By default, this flag is set as static when creating a texture using the Ogre::TextureManager::createManual() function. When changing it to dynamic, the textures are well filled and displayed!

But this leads me to some questions:
- What is the exact role of this flag? Is it comparable to the SCENE_STATIC flag, i.e. a performance optimisation for textures that can be updated but should not be updated too often?
- If this is the case, does that mean that there is a bug in the D3D11 render system causing the textures with this flag to be not updated? Or should a function be called each time the texture is updated? (the textures are well filled in OpenGL3+ however)
- In the case of a UI engine like CEGUI, what flag is recommended? Dynamic as some textures might be updated often, or static as there are many static images? Or both, depending on the texture type? (static for images, dynamic for textures that will be updated)

Thanks again for your help! :)

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Mon Apr 27, 2015 9:51 pm
by Jayray
Apparently my post has been eclipsed by all the other posts of the week-end ^^

Just to be sure before I send a pull request for CEGUI: should I set the dynamic flag for the CEGUI textures, or should the static flag work as well and there is a bug in the D3D11 render system for static textures?

Thanks!

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Mon Apr 27, 2015 10:19 pm
by dark_sylinc
If you were uploading your texture using blitToMemory, I fixed a bug in D3D11 last week that could be causing what you describe.

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Tue Apr 28, 2015 8:04 am
by Jayray
The texture is indeed uploaded using blitToMemory, but I was already using the latest source including your commit.
But with the HBU_DYNAMIC flag set, everything is OK, the issue is only present with the HBU_STATIC flag.
Is there a drawback to setting the HBU_DYNAMIC flag instead of HBU_STATIC?

Thanks!

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Tue Apr 28, 2015 12:25 pm
by N0vember
Are you comparing HBU_STATIC and HBU_DYNAMIC here, or the default and HBU_DYNAMIC ?
From the source :

Code: Select all

TU_DEFAULT = TU_AUTOMIPMAP | TU_STATIC_WRITE_ONLY
So the default is not only set to HBU_STATIC, but also to HBU_WRITE_ONLY

Re: [Ogre 2.1] Porting CEGUI to OGRE 2.1

Posted: Tue Apr 28, 2015 4:30 pm
by dark_sylinc
Jayray wrote:Is there a drawback to setting the HBU_DYNAMIC flag instead of HBU_STATIC?
Any, all, or none of the following may happen:
  • The memory is placed in system RAM. So when the GPU wants to read, it has to do across the PCIe bridge every time (Slower).
  • The memory is placed in GPU RAM but some component (e.g. cache) is snooping around for possible changes (Slower).
  • The runtime API/driver reserves more RAM in preparation for discard being called (often). This will waste RAM, and can take away space from other dynamic buffers that actually need to be updated very often. Taking away space is critical because if the API runs out of reserved space, the discard will just cause a stall instead of returning immediately.
This is true for any dynamic buffer, thing is, these disadvantages are nothing compared to the gains of being able to update efficiently at high frequency from CPU to GPU.
But if you won't be updating it often, you're then just getting the disadvantages, with no advantages.