Carmack's Virtualized Textures (QuakeCon 2007)

Started by
64 comments, last by xen2 16 years, 6 months ago
Well, I started a topic about this a year or two back, but at that point there was next to no information to go on. John has given us a bit more information about the technique, and since it's one that I'm very curious about, I'd like the resurrect the subject. Most of you have probably heard about idTech5, id Softwares new engine which will be powering their next game, Rage. The primary new feature that they've been showcasing is "Virtualize Textures", which is basically an paging system for textures that will determine the textures (and mipmap level) that are required to render the current frame and load only those into memory. In "non-geek" terms, this essentially means that you can have infinite texture detail with no performance hit. The only previous algorithm that I'm aware of that attempts something like this is Clipmapping, but it is designed to work only with perturbed plane (like a heightmap) whereas this method apparently works on any surface. So how do you think it's being accomplished? During Carmacks Quakecon 07 keynotes (Keynote, Q&A) he mentioned a few things that should help determine how: 1) It's being done with DirectX 9 level hardware (OpenGL on the PC), so no DX10-only techniques are needed 2) Carmack said that the engine wasn't going to be ported to the Wii, because it wasn't designed for the hardware. He also said, however, that the memory/processing requirements were pretty modest. That would imply that approach is reasonably shader dependent. (Fairly obvious, but made more so by the Wii being fixed function only) 3)One of the more interesting bits of the QA session was when he mentioned that theoretically every scene could be rendered with only 3 draw calls, and that the only reason it wasn't was for culling granularity. This was possible, he said, because (among other things) the virtualized texture system naturally created a texture atlas. So essentially it would seem that he is allocating one or two large textures and manually loading texture portions into different segments of it. 4) Combining the two above items, the obvious approach would be that while the mesh stores the "standard" texture coordinates the shaders that it is run through do a lookup into the texture atlas and modify the coordinates to point to the appropriate sub-map. Pretty logical. Everything above makes sense to me, but there's one big missing piece: How to determine what textures and the mip levels of those texture to load? My best guess is that you could do a pre-pass of the scene using a specially color-coded texture (which is sampled normally) where each mip level uses a different color. You could then use the color that's actually rendered to determine which mip level to read in. This approach wouldn't work directly unless every mesh used the same sized texture, though, which would defeat the purpous. Also, you would need to combine it with another pass that told you which textures are actually needed for the scene, and that seems like a lot of pre-pass for what is supposed to be a low-impact technique. So what are your thoughts? Anyone see something I don't?
Advertisement
How does he handle texture tiling without edge color overlap?
Author Freeworld3Dhttp://www.freeworld3d.org
Hm... good question. From the sounds of it, it would seem like he only ever has cached the appropriate mip level for any given texture anyway. If that's the case, and you weren't letting the GPU do the mip generation, wouldn't that potentially eliminate most border artifacts? If not, I don't suppose it would be too much hassle to simply surround everything with a 1 pixel wide border.
Quote:One of the more interesting bits of the QA session was when he mentioned that theoretically every scene could be rendered with only 3 draw calls, and that the only reason it wasn't was for culling granularity. This was possible, he said, because (among other things) the virtualized texture system naturally created a texture atlas. So essentially it would seem that he is allocating one or two large textures and manually loading texture portions into different segments of it.

I don't see how these mega-textures can result in every scene getting rendered in only 3 draw calls, since texture switches are not the only batch-breaking state changes and while creating texture atlases can result in less state switches, they can not totally remove them and decrease the number of DP calls to 3. Some of those state changes are not even texture-related. What about different vertex layouts, shaders, shader parameters or just every other state change?
Quote:
One of the more interesting bits of the QA session was when he mentioned that theoretically every scene could be rendered with only 3 draw calls...

I'd say only 3 draw calls might be very theoretical but possible if you use uber shaders (much like the mega texture where many shaders are contained in one), not that many different parameters, hardware instancing, the same vertex layout etc.

In practice, as you said, there would be more state changes und thus more draw calls.

If I was helpful, feel free to rate me up ;)If I wasn't and you feel to rate me down, please let me know why!
Quote:Original post by Ashkan
I don't see how these mega-textures can result in every scene getting rendered in only 3 draw calls...

I think he's only talking about the static environment here, i.e. the racing track in the demo. That might be possible to draw with 3 draw calls: it's a textured terrain, so one shader, one vertex layout, and thus one huge texture. Note that the MegaTexture has all kinds of effect baked in.
Then, for actors etc. you'd need some extra draw calls, since you need a different shader, vertex formats that support skinning etc.
Quote:Original post by Lord_Evil
I'd say only 3 draw calls might be very theoretical but possible if you use uber shaders (much like the mega texture where many shaders are contained in one), not that many different parameters, hardware instancing, the same vertex layout etc.

In practice, as you said, there would be more state changes und thus more draw calls.


Actually, from what he said in the keynotes, it sounds like you're pretty dead on.

I'll attempt to transcribe a bit:

Quote:John Carmack (Quakecon '07) - 24:20 in the Q&A vid linked above
"It turns out that the entire world, just about, could be drawn with three draw calls in this: One for land surfaces, one for non-land opaque surfaces, and one for non-land translucent surfaces. Almost everything end up being done like that.

One of the interesting things is that in addition to virtualizing the textures to let you have kind of unlimited resources, it's also the ultimate infinite atlasing system where, since everything is using the same virtual texture page pool, they can all use the same material. And you can wind up taking, you know, in this room you would have the podiums, the floors, the stands, the lights. All of these things wind up, while they're separate models and you can move them around and position them separately, but when you're ready to "go fast" they all get built into the same model. So you've got one draw call because they all use the same virtual materials on there.

The only reason you end up breaking it up is for culling granularity. You really literally could have three calls that draw just about everything except for a few glowing things and the sky and the few things that are not conventional surfaces in there. But you still want to break it up so you can do culling on visibility and frustum culling and things like that."


I'm guessing that when he says "the lights" as part of the models, he's referring to the physical light casings, not lights in the illuminating, shadow casting sense :)
I still don`t get one thing. does he need to create new texture(atlas) every frame and then send it to GPU? it would consume some time.

also, wouldn`t it be better to for example, divide level using some grid, have unique texture and mesh for each grid unit, and then simply load/free these resources as player moves? hmm, i`m not so sure it would work well, becouse i think Oblivion used such aproach and landscape that was far away used low-res textures and it looked blurred.(http://oblivion.bonusweb.cz/obrazek.html?obrazek=oblivion20030604.jpg) it consumed a lots of memory too. what do you guys think?
Quote:Original post by MassacrerAL
I still don`t get one thing. does he need to create new texture(atlas) every frame and then send it to GPU? it would consume some time.

I think you highly underestimate how much data would have to be sent and how fast AGP8x/PCIe bandwidth is. Even on a PCI board, if you had a 1024x768 screen and only diffuse textures, you'd only need 16MB of memory, and enough bandwidth is provided that you could do an entire refresh of the atlas in less than a sixtieth of a second.
Quote:also, wouldn`t it be better to for example, divide level using some grid, have unique texture and mesh for each grid unit, and then simply load/free these resources as player moves? hmm, i`m not so sure it would work well, becouse i think Oblivion used such aproach and landscape that was far away used low-res textures and it looked blurred.(http://oblivion.bonusweb.cz/obrazek.html?obrazek=oblivion20030604.jpg) it consumed a lots of memory too. what do you guys think?

The virtual texturing of idtech5, if it is what I think it is, is much more interesting than that, since it's able to take into account partial/entire occlusion of geometry, and is able to do much more precise determinisim of what mips of what parts of the texture is needed. With a proper virtual texturing setup like what I think idtech5 has, you could have nigh-infininte resolution textures with multiple channels (i.e. diffuse, normal, specular coef, spec exponent, fresnel coef/exponent, and hell probably even scattering coef/exponent) on a 64MB video card while still having space leftover to do some shadow mapping, store a low-res (e.g. 640x480 or 800x600?) backbuffer with some AA, and other miscellaneous stuff. Like he mentions in the keynote, it really is appalling that GPU makers are even thinking about going beyond 512MB when maybe half of that is really required for 1080p resolutions.

Quote:Everything above makes sense to me, but there's one big missing piece: How to determine what textures and the mip levels of those texture to load? My best guess is that you could do a pre-pass of the scene using a specially color-coded texture (which is sampled normally) where each mip level uses a different color. You could then use the color that's actually rendered to determine which mip level to read in. This approach wouldn't work directly unless every mesh used the same sized texture, though, which would defeat the purpous. Also, you would need to combine it with another pass that told you which textures are actually needed for the scene, and that seems like a lot of pre-pass for what is supposed to be a low-impact technique.

I have a pretty good idea on what the answer to that question is, but I haven't had time to make a demo that uses it to fully convince myself that the answer does work (fwiw, the idea would only need probably DX7 level tech). The idea that you've suggested probably wouldn't work though, since you need to analyze those results in a manner.
Quote:Original post by Cypher19

I have a pretty good idea on what the answer to that question is, but I haven't had time to make a demo that uses it to fully convince myself that the answer does work (fwiw, the idea would only need probably DX7 level tech).


Really? DX7? I'd be very interested in hearing more about that idea, wether or not it actually works :)

And yes, I know that you would have to read the results of my idea somehow. I meant to imply that it could be rendered to a texture then read back out, which isn't terribly uncommon, but which also isn't terribly fast. :P I really don't think that's it.

This topic is closed to new replies.

Advertisement