Texture repetition reduces frame-rate?

I noticed something odd recently: while a (very) simple level might run at well over a hundred frames-per-second, my combat mechanic’s separate “world” ran at only around seventy frames-per-second, despite being very simple itself.

I did some profiling (hence my recent desire for a copy of PStats), and saw additional time spent in both “*->Bounds” (I think that it was) and rendering.

After some experimentation, I found that a single object seemed to be responsible for most of my trouble: the floor.

If I edited its shader to simply output pure white, the frame-rate jumped up to well over a hundred frames per second.

Curiously, a similar effect could be achieved simply by changing the texture-scale applied to it: it seemed that the more often the textures were repeated, the lower the frame-rate became. (Albeit that it never dipped below sixty, as I recall.)

The floor in this case is a simple model of thirty-three vertices (I think that it was). It has binormal- and tangent- vectors, and a material, albeit with no textures applied. Vertex colours cause it to dim at its edges, so that it fades into the black background colour.

When the combat “world” is shown, this floor is assigned two textures via calls to “setTexture”: a colour-texture, and a normal-map. It’s scaled, because for whatever reason I made the original model huge. A texture-scale is applied to the default texture-stage–the value is chosen for the given textures so that they tile as intended.

I also apply a shader-input called “texTransform”, which takes the result of “floor.getTexTransform(TextureStage.getDefault()).getMat()”, and which is updated each frame. This, alongside per-frame alterations of the object’s H-angle and texture-offset, is used to produce a floor that, while always centred beneath the player, nevertheless shifts its texture to represent the player moving about an ostensibly-larger surface. (Thus allowing a pretty-much unlimited “combat area”.)

The shader itself is for the most part pretty simple, save for applying “texTransform” to the uv-coordinates.

I’ve tried using a simple card for testing purposes, but with mixed results. (For one thing, I didn’t get normal-mapping to work; I’m guessing that generated cards lack binormal- and tangent- vectors.) However, what results I did get seemed to support the idea that repeating the texture resulted in poorer performance.

I could really use some help in figuring out why this is a problem, and what to do about it, if anyone has any thoughts. :confused:

That sounds like a textbook case of texture cache misses on the graphics hardware. Sampling a texture from memory is a very high-latency operation, so the GPU uses a cache in order to optimize access for adjacent pixels. However, when adjacent pixels on screen access parts of the texture that are further away, then those won’t be in the cache, resulting in a cache miss and therefore a need to go back to texture memory.

Enabling mipmapping will drastically help with reducing cache misses since at a further distance, a smaller mipmap level is accessed, so more of the texture will fit into the cache at one time. Reducing the texture size may help as well. I don’t know that texture compression will help in this case, since I think the texture is stored uncompressed in the cache.

To confirm that this is the issue, you should try making your floor texture very small (say, 16x16 pixels or even smaller) and seeing if you are still seeing the slowdown. If it is still just as slow, then we need to keep looking for other potential causes. It would also be helpful if you posted your shader so that we could check if there is anything obviously wrong there.

Note that if this is a hardware-side issue, you need to be using the GPU timing feature of PStats, by putting pstats-gpu-timing true in Config.prc and checking the graphs under the menu corresponding to your GPU in the PStats server, assuming your driver supports GPU timing properly. Although if the above is true, then it will just tell you that it took a long time drawing that display region, which isn’t particularly helpful.

By the way, if the floor is a flat plane, then you can probably assume the constant values (1, 0, 0), (0, 1, 0) and (0, 0, 1) for the tangent, binormal and normal vectors, respectively, which makes things simpler.

If you are interested in learning more about the low-levels of the texture cache, you can check out this post:

It seems that you were right about mip-mapping: simply setting “texture-minfilter mipmap” in my “.prc” file caused the frame-rate to jump to well above one-hundred during combat! 0_0

(And indeed, I had checked the GPU timing via PStats, and had seen just what you describe, as I recall.)

I was somewhat surprised that it wasn’t enabled already–indeed, I had reason to be pretty confident that it was enabled elsewhere in the game, I believe. The question, then, was that of why it wasn’t enabled for this model.

Having investigated, it seems that the problem lay with how I was loading the textures. Presumably, textures loaded with a model have mip-mapping enabled (or perhaps it’s specified by YABEE when exporting, or somewhere in my material settings). However, a texture loaded via “loader.loadTexture” doesn’t have it enabled by default.

Looking up the “loadTexture” method, I found that it included a “minfilter” option–and setting that seems to have done the trick! :slight_smile:

Right now I’m using “FTLinearMipmapLinear”–I don’t know what the default is, offhand, so perhaps there’s a better setting.

You make a good point regarding the constant tangent- and binormal- vectors–I might try that to see whether it produces a noticeable improvement. It may be a little superfluous given the frame-rates that I’m now seeing, but it’s a small enough change, and each little bit may help!

YABEE will respect the “MIP Map” setting in the “Image Sampling” section of the texture panel in Blender. The default for this setting is on.

The default setting for Panda3D is just linear (no mipmapping). If you wish to change this, you can set texture-minfilter linear-mipmap-linear in Config.prc. I see you’ve already found the loader.loadTexture keyword argument mipmap= as well. You can also set it using setMinfilter on the texture after loading it.

Note that mipmapping causes the textures to take up 33% more memory in VRAM, but it’s usually worth it.

Ah, I see–thank you!

Looking at an egg file produced by YABEE, I see that the specific setting produced is apparently “linear_mipmap_linear”–which happens to be the setting that I chose for my calls to “loadTexture”. :slight_smile:

I see, and thank you.

Heh, in this case I think that I’d rather have the texture take up an extra 33% than have my frame-rate drop so precipitously!