Textures failing with Threads

Hello.
I encountered a strange bug, reason seems “deep inside”.

on my system, LWJGL works fine…

…except until i try texturing with multithreading.
I am aware of the fact that OpenGL is a state machine, so ALL LWJGL commands are used in-order by just one thread.
The only thing i do in fact “multithreaded” is writing the byte buffer for texturing.
As result, textures vanish entirely as if glBindTextture / glTexImage would never been called.

anyone any idea? seems to be inside java native code for the buffer or lwjgl native :frowning:

snippets of the code:



/*
 * Created on 06.03.2005
 *
 */
package org.dronus.concept.gl;

import java.nio.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

/**
 * @author Paul
 *
 */
public class Texture implements Renderer{
       
    final int       level=0, internalformat=3, border=0, 
                      format=GL11.GL_RGBA, type=GL11.GL_UNSIGNED_BYTE;
//    final int MAXSIZE=1024;
    
      protected int width,height,size;
      public ByteBuffer pixels;
    int texid;
    
    boolean ready=false;
      
    public Texture(){
        IntBuffer idbuf = BufferUtils.createIntBuffer(1); 
        GL11.glGenTextures(idbuf);
        texid = idbuf.get(0);
      }
    
      public void setSize(int s){
                        height=width=s;
            size=width*height*4;
            if (pixels==null){
                  if (size<=0) throw new RuntimeException("setSize() first!");
                  pixels = ByteBuffer.allocateDirect(size); 
              pixels.order(ByteOrder.nativeOrder()); 
            }            
      }
      public void putPixels(byte[] bytes){
            pixels.put(bytes);
      }
      public void putPixel(int r, int g, int b, int a){                        
            pixels.put((byte)r);pixels.put((byte)g); pixels.put((byte)b); pixels.put((byte)a);
      }
      public ByteBuffer getBuffer(){return pixels;}
      public void update() {                        
            if (pixels!=null) {
                  pixels.flip();
                  GL11.glBindTexture(GL11.GL_TEXTURE_2D,texid);
              GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
              GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
              GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);                  
                  GL11.glTexImage2D(GL11.GL_TEXTURE_2D,level,internalformat,width,height,border,format,type,pixels);
                  pixels=null;
            }else throw new RuntimeException("nothing to update!");
            ready=true;
      }

      public void render() {
            if (ready) GL11.glBindTexture(GL11.GL_TEXTURE_2D,texid);
      };
}

and


/*
 * Created on 07.03.2005
 *
 */
package org.dronus.concept.gl;

import org.dronus.concept.RandomEngine;
import org.dronus.gloom.space.renderers.Detail;

/**
 * @author Paul
 *
 */
abstract public class GeneratedTexture extends Texture implements Runnable{
      RandomEngine seed;
      double time; Detail detail;
      boolean needsupdate;
      static boolean generating;
//      static GeneratedTexture generating;
      
      public GeneratedTexture(RandomEngine seed) {
            this.seed=seed;            
      }
      /* (non-Javadoc)
       * @see org.dronus.concept.gl.Texture#render(double)
       */
      public void update(double time, Detail detail) {
            if (needsupdate ) {
                  update();
                  needsupdate=false;
                  generating=false;
            }
            
            if(width<detail.getTextureSize() && !generating) {                  
                  needsupdate=false;
                  generating=true;
                  this.time=time; 
                  this.detail=new Detail(detail);                                                      
                  Thread updater=new Thread(this);
                  updater.start();
                  //updater.run();
            }
      }
      boolean running;
      public void run(){
            
                  setSize(this.detail.getTextureSize());
                  genTex(seed, time, detail);
                  //      System.out.println("Size now "+width);
                  needsupdate=true;
      }
      
      abstract public void genTex(RandomEngine seed, double t,  Detail d);
}


the buffer is written inside genTex.

by replacing updater.start(); with updater.run(); it runs reliable. also it runs sometimes, if started “fresh”, eg. opengl not used for longer times, but mostly not.
it also works more often if amount or size of textures is heavily increased.

strange, eh?

i would be grateful for eny idea
Paul

The “sometimes it works, sometimes it don’t” description smels like a threading bug. Can you provide the complete source of a stripped down version that reproduces the bug?

hello
bug gone…
but don’t know why. “cleaning” my code i changed some details, maybe execution order or something else, mostly in unposted code… and don’t encountered the bug again.
i checked it for a while for “maybe relevant” changes but found none to my honest opinion.

the only thread-interaction to my view is the “other thread fills buffer” thing, which is still there unchanged.

sorry for the inconvinience

if it reappears or i got any clue i’ll post again.

sorry & thanks
Paul

Quick guess: if another thread is filling the byte buffer, its almost certainly messing with the position/limit in that buffer. And since LWJGL methods pay attention to them as to where to pull the data, it’ll be getting different subsets of your buffer depending on the other thread.

You can still share the buffer, just as long as you do .duplicate() so you’ve got two views (and hence two positions) on the same data.