Texture buffers and driver compatibility

Hi all,

Another tip mainly for new and new-ish Panda users. Documenting this to make it easy to find by a web search, just in case someone else runs into the same problem.

On the forums, over the years at least two approaches to creating texture buffers have been posted. This one-liner seems to be the currently (1.8.1) preferred way to create texture buffers:

buf = base.win.makeTextureBuffer("MyNameForThisBuffer",
                                 base.win.getXSize(),
                                 base.win.getYSize())

This works fine on both ATI (yes, it’s old) and Intel (tested in a laptop with Ironlake Mobile).

The following, probably older, snippet works on ATI, but does NOT work on Intel:

fbp = FrameBufferProperties(base.win.getFbProperties())
wsx = base.win.getXSize()
wsy = base.win.getYSize()
wp = WindowProperties()
wp.setSize(wsx, wsy)
texture = Texture()
buf = base.graphicsEngine.makeOutput(
               pipe=base.win.getPipe(), name="buffer", sort=-100, fb_prop=fbp, win_prop=wp,
               flags=GraphicsPipe.BFRefuseWindow, gsg=base.win.getGsg(), host=base.win)
buf.addRenderTexture(texture, GraphicsOutput.RTMBindOrCopy)

Trying to run the latter on my laptop with the Intel chip, Panda prints into the terminal window a screenful of copies of the error message

:display:x11display(error): BadMatch (invalid parameter attributes)

and the render window remains blank.

In conclusion: use the first approach, it’s more compatible across different hardware configurations.

EDIT: as rdb notes below, it’s not inherently more compatible, but it is a bad idea to copy frame buffer properties from the window, as for example windows are usually double-buffered, while double-buffering makes no sense for a buffer.

It’s not inherently more compatible. make_texture_buffer is simply a thin wrapper around make_output. In fact, this is the source code of make_texture_buffer:

  FrameBufferProperties props;
  props.set_rgb_color(1);
  props.set_color_bits(1);
  props.set_alpha_bits(1);
  props.set_depth_bits(1);

  if (fbp == NULL) {
    fbp = &props;
  }

  int flags = GraphicsPipe::BF_refuse_window;
  if (textures_power_2 != ATS_none) {
    flags |= GraphicsPipe::BF_size_power_2;
  }
  if (tex != (Texture *)NULL &&
      tex->get_texture_type() == Texture::TT_cube_map) {
    flags |= GraphicsPipe::BF_size_square;
  }

  GraphicsOutput *buffer = get_gsg()->get_engine()->
    make_output(get_gsg()->get_pipe(),
                name, get_child_sort(),
                *fbp, WindowProperties::size(x_size, y_size),
                flags, get_gsg(), get_host());

  if (buffer != (GraphicsOutput *)NULL) {
    if (buffer->get_gsg() == (GraphicsStateGuardian *)NULL || 
        buffer->get_gsg()->get_prepared_objects() != get_gsg()->get_prepared_objects()) {
      // If the newly-created buffer doesn't share texture objects
      // with the current GSG, then we will have to force the texture
      // copy to go through RAM.
      to_ram = true;
    }

    buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_bind_or_copy);
    return buffer;
  }

  return NULL;

You shouldn’t make a buffer using FrameBufferProperties(base.win.getFbProperties()), because the window is usually double-buffered, and you can’t (nor is it likely that you would want to) have a double-buffered FBO, and double-buffering is one of the flags you’re copying in like that.

Ah, I see. Thanks for the correction!

I didn’t trace into the underlying code, as both of the approaches came from existing code examples, and one of them worked, while the other one did not.

I only found out it didn’t work when I tried to run it on my laptop - the desktop machine with the ATI didn’t give any hint that anything was wrong. The result was that the script I’ve used for testing my hair physics code (and the new inker) didn’t work on the laptop, while my other scripts ran just fine. Googling for the BadMatch error, the only matches (no pun intended) referred to creating two windows - and my script wasn’t doing that.

But two of my scripts were creating buffers, and one of them was working while the other was not. Looking at the code that asked Panda to create a buffer, the difference was in the code examples posted. Testing both variants confirmed that this was causing the error. Thus, I wanted to warn others against using the non-working code, because a forum search might find that, and it looks sensible to a newcomer.

Your addition of the make_texture_buffer() source code makes this thread much more useful for others running into this problem - thanks!

Makes sense. This could be the reason it wasn’t working on the Intel.

As for the ATI, either the card is doing what was requested, or it silently disables double buffering when creating an FBO (assuming that it is indeed the double-buffering and not some other flag that is causing the problem). The same behaviour occurs both with fglrx (occurred, last year when this card was still supported :slight_smile: ) and the open-source radeon driver (in Ubuntu 12.04 LTS).

Updating this script. Added a function to export obj files. Added global, tile, and cylinder cap UV mapping types. Fixed a few bugs and refined cylinder and sphere UV mapping types.