(2.2) mapping staging texture to each face of a cubemap

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
Post Reply
User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

(2.2) mapping staging texture to each face of a cubemap

Post by SolarPortal »

Hi, been a while.i have started porting our engine to ogre 2.2 and so far so good. Back to development now as my caring role ended.

I am wondering though how to use map region of a staging texture to each face of a cubemap so I can upload a 2d texture into the face using staging textures...e.g. sky box.

From what I see though map region can only map number slices.

If someone has an example or time to write a quick snippet that would be great.

Thanks in advance and Stay safe :)
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

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

Re: (2.2) mapping staging texture to each face of a cubemap

Post by dark_sylinc »

IrradianceVolume::updateIrradianceVolumeTexture has a straightforward example, BUT cubemaps (and texture 2d arrays) are special case due to moronic D3D11 rules.

A couple notes:
  • IrradianceVolume::updateIrradianceVolumeTexture uploads everything (all slices) at once, in one call
  • IrradianceVolume handles a 3D texture, you want to handle a cubemap texture. The two main differences are that 3D depth gets smaller with mipmaps, slices don't; the second difference is that one uses getDepth() the other getNumSlices()
  • Cubemap (and 2D array textures) larger than 2048x2048 must call mapRegion 1 slice at a time (and hence they will also have to call upload once per slice). This is single-handedly the most annoying limitation imposed by D3D11
  • You can upload from a single StagingTexture, but there is no rule saying so. You could call getStagingTexture for each individual slice (remember to pass '1' in num slices instead of '6') and upload one at a time from different StagingTexture
The interface Image2::uploadTo has been written to handle all these oddities (thus its code is harder to read): it tries to map all at once if it can, but if it cannot, it uploads one slice at a time and it may even use multiple StagingTextures. After uploading everything, it starts calling upload() (it's more efficient that way).
Note that uploadTo is synchronous (well, once stagingTexture->upload is called, that part happens asynchronously in the GPU).

If you want to stream every frame, you may want to hold into the same StagingTexture rather than rely on uploadTo.

If you already have the data in memory you may want to let Ogre upload it asynchronously. You may want to check this thread where I suggest to look at UpdatingDecalsAndAreaLightTexGameState.
If the content is static (i.e. not updated every frame) you can basically follow the same procedure as loading from disk, but from an Image2 instead, since TextureGpu::scheduleTransitionTo accepts an optional Image2 pointer.

Or you could register a ResourceLoadingListener to ResourceGroupManager, and overload grouplessResourceExists, grouplessResourceLoading & grouplessResourceOpened if you want to procedurally generate the data in a background thread and have Ogre pretend it comes from disk. The two main differences from using the scheduleTransitionTo with an Image2 approach are:
  1. grouplessResourceOpened gets called from the background thread, and until the contents are ready a white texture will be displayed.
  2. The Image2 approach is 'fire and forget'. If the texture later gets sent to OnStorage (e.g. device lost), it won't know how to get back to Resident. With the listener, the listener will be called again if it wants to go back to Resident
Cheers!

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: (2.2) mapping staging texture to each face of a cubemap

Post by SolarPortal »

Thanks for the information, i managed to get it working with staging textures.
The thing i was missing was that if you want to upload to a slice on the destination texture that you have to provide a destination texture box to the upload whereas i was trying to set the stagingtexture boxes with the slice offset.. oh well :P

just for someones reference when they come across this themselves:
it has our own classes but the format is practically the same. ( wrapped stagingtexture so i didnt have to write out the width, height, format, depth, slices everytime i wanted to just upload to a texture lol )

Code: Select all

// SkyStagingTexture is a wrapper of Ogre::StagingTexture but automates a lot of the entries so you dont have to put all the variables in for simple mapping and uploading of texture data.

	SkyStagingTexture stagingTex(tex, false); 
	stagingTex.startMapping();
	Ogre::TextureBox srcBox[6];
	Ogre::TextureBox dstBox[6];

	for (int i = 0; i < 6; i++) {
		int face = i;
		switch (i) { case 0: face = 4; break; case 1: face = 5; break; case 2: face = 1; break; case 3: face = 0; break; case 4: face = 2; break; case 5: face = 3; break; }

		Ogre::Image2 subImg;
		skyResource.loadFileResource(data.diffuseTextureNames[i].first, resourceGroup);
		subImg.load(data.diffuseTetxureNames[i].first, resourceGroup);

		srcBox[i] = stagingTex.map(subImg.getWidth(), subImg.getHeight(), 1, 1); 
		srcBox[i].copyFrom(subImg.getData(0));

		dstBox[i] = tex->getEmptyBox(0);
		dstBox[i].sliceStart = face;
	}
						
	stagingTex.stopMapping();
						
	for (int i = 0; i < 6; i++) {
		// Pretty close to the ogre one but you can just put srcbox if its a Type2D and all region is mapped as the class stores the rest.
		stagingTex.upload(&srcBox[i], tex, 0, 0, &dstBox[i]); 
	}
	stagingTex.finish(); // Deletes and notifies the texture
ok, another question: could you for instance, call start mapping and stop mapping more than once on the staging texture per frame. there was something similar in 2.1 but you had to regress the counter if edited more than once per frame e.g..

Code: Select all

create

startmapping..
mapregion - slice 1
box edit
stopmapping
upload - box, dstBox

startmapping..
mapregion - slice 2
box edit
stopmapping
upload - box, dstBox

finish / notify texture
or would this cause some internal issue as i have noticed that when map region is called, the z is automatically increasing by 1 which i suspect is due to the mapped regions needing to be accessible in the background thread.

Been on 2.2 a couple weeks and have looked through most of the source and gotten use to it but understanding the depth, slices and z didnt quite click at first, most everything else seems fine.. loving the fact that texture gpu and the manager cover what so many of the older classes did in the 2.1 version and already done some tweaks for our engine to allow duplicate texture/resource/datablock names which we had in our previous version of the engine running 2.1.

But yeah, pat yourself on the back because it does seem like a more advanced beast than it was.
Haven't quite got my head around msaa and explicit resolves yet though. but bit at a time :P

Thanks again for the quick responses and help :)
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

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

Re: (2.2) mapping staging texture to each face of a cubemap

Post by dark_sylinc »

SolarPortal wrote:
Sun Jun 07, 2020 2:22 pm
ok, another question: could you for instance, call start mapping and stop mapping more than once on the staging texture per frame. there was something similar in 2.1 but you had to regress the counter if edited more than once per frame e.g..
You can but you should aim to call start/stop as fewer as possible.

But once you've called upload(), then startMapRegion could stall. You can check this via uploadWillStall()

TextureGpuManager::getStagingTexture works by iterating through available (but not yet destroyed) StagingTextures calling uploadWillStall, and selects the one that returns false and is also the smallest one that can fulfill the request.
or would this cause some internal issue as i have noticed that when map region is called, the z is automatically increasing by 1 which i suspect is due to the mapped regions needing to be accessible in the background thread.
Actually that's an implementation detail very specific to D3D11, it's so bizarre it needed its own section in the documentation.
it but understanding the depth, slices and z didnt quite click at first
Most of the time 'z/depth' and 'slicesIdx/numSlices' are the same thing, because it's a 3rd axis. In fact often they share the same variable ('DepthOrSlices').
However they bifurcate when it comes to handling mipmapping because z/depth shrinks with each mip level; while sliceIdx/numSlices doesn't.

That's it :)
Haven't quite got my head around msaa and explicit resolves yet though
Imagine an explicit resolve like this:
You want to render at 1920x1080 4x MSAA. You need two textures:
  • The 4x MSAA texture, which when it comes to VRAM storage, it costs as much as 3840x2160 (because 1920x2 x 1080x2, that is 4 times the area, 4x MSAA).
    • But you can't sample from this texture directly
    • Your shader needs to specifically use a Texture2DMS, and it can only read the individual subpixels; which can be quite slow because it will consume as much performance and bandwidth as reading a regular texture at 3840x2160 resolution.
  • A 1920x1080 regular texture you can sample from, and this is will be the resolve target
So you will render to the "1920x1080 4x MSAA" target; but once you're done render and want to read from it; you want to resolve it to the regular 1920x1080.

That's it.

With implicit resolving, this happens behind the scenes without you having to know about it. With explicit resolves you need to be aware of this and manually setup an RTV (RenderTargetView) in the compositor. The RTV tells Ogre:
  • to what texture to render
  • to which slice (e.g. +Y slice in a cubemap, the 8th slice in a 3D texture)
  • to which mipmap (was previously impossible in Ogre 2.1)
  • to what texture to resolve to (and which slice/mipmap; it doesn't have to match the slice/mipmap you render to)
Most of the time explicit resolves are there so you can access the MSAA content directly; which is useful for proper HDR+MSAA, handling SSAO, and a few other postprocessing effects.

This is mostly because depth buffers don't get automatically resolved (averaging depth makes no sense) but you still want to do something. For example our SSAO sample "resolves" the depth buffer by just assuming there is 1 subsample. This is wrong/inaccurate, but good enough for SSAO and other effects. We could "unpack it" into a 3840x2160 texture, but that'd be overkill and could still be wrong depending on how it's used. Others use two depth buffers one with min() of all 4 subsamples, another with max() of all 4 subsamples. Each approach has a different trade off. These problems are very similar to the ones described in mixed resolution particle rendering in GPU Gems 3

If you're interested in more, you can read A quick overview of MSAA

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: (2.2) mapping staging texture to each face of a cubemap

Post by SolarPortal »

ahh!!.. thank you, extremely good writeup, i already am starting to understand msaa now and will probably have a good read over those documents tomorrow.

Also thanks to the answer on the question regarding start/stop mapping. Certainly dont want to be adding stalls, so i shall stick to mapping and uploading as seperate events of the staging texture.

Thanks again for the help :) Now have full skyboxes and full skydomes with .exr / .hdr images and standard textures :)
Good job with what you have done with 2.2 so far.. i';m certainly impressed with most of the main core changes so far. Haven't got around to the fancy and shiny features yet lol :P
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

Post Reply