processing4 icon indicating copy to clipboard operation
processing4 copied to clipboard

java.lang.RuntimeException: Waited 5000ms

Open clankill3r opened this issue 3 years ago • 5 comments

When using P2D or P3D you have to run draw within 5 seconds, else you get a RuntimeException. I think 5 seconds is a bit short from time to time. Also it is really hardware depending if 5 seconds is enough. I know it's easy to work around this and just do all the setup work in the first frame of draw, but I think it would be better if the limit would be one minute or no limit at all.

clankill3r avatar Jan 13 '22 12:01 clankill3r

I got some students running into this problem last year (with Processing 3).

First of all, you may do setup heavy stuff (i.e createShape) prior to run Size() or FullScreen(), which should occur at the very end of your setup.

If this is not enough (some students got very slow computers), I suggested a work around to prepare their heavy setup stuff in a separate thread :

boolean ready;
PShape small;

void setup() {
  this.ready = false;
  thread("prepare");
  size(200, 200, P2D);
}

void draw() {
  background(0x00);
  if (!this.ready) {
    textSize(12);
    textAlign(CENTER, CENTER);
    text("Loading " + String.valueOf(round(millis()/100.0f)/10.0f), width/2, height/2); 
  } else {
    shape(this.small);
  }
}

void prepare() {
  this.small = createShape();
  this.small.beginShape(LINE_STRIP);
  this.small.noFill();
  this.small.stroke(0xFF);
  this.small.strokeWeight(1.0f);
  this.small.vertex(10.0f, 10.0f);
  this.small.vertex(width-10.0f, height-10.0f);
  this.small.endShape();
  // Wait 5 seconds
  try { 
    Thread.sleep(5000);
  } 
  catch (InterruptedException e) {
  }
  this.ready = true;
}

In this example Thread.sleep(5000); ensures that setup stuff last more than 5000ms, you can of course remove the try/catch bloc in your own sketch.

Hope this helps

yblake avatar Mar 08 '22 13:03 yblake

First of all, you may do setup heavy stuff (i.e createShape) prior to run Size() or FullScreen(), which should occur at the very end of your setup.

Pretty sure this won't matter, cause the precompiler checks for the size() call and put's it in settings(). That's why you can't use things like size(img.width, img.height) anymore or even simple math like size(200 * 2, 200);.

clankill3r avatar Mar 09 '22 08:03 clankill3r

Pretty sure this won't matter, cause the precompiler checks for the size() call and put's it in settings(). That's why you can't use things like size(img.width, img.height) anymore or even simple math like size(200 * 2, 200);.

Absolutely right, my bad. And calling createShape() in settings() prior to size() will issue a null pointer exception...

If you don't want to use a separate thread, I think the easiest way is to load heavy stuff prior to draw first frame as you mentionned before :

PShape small;

void setup() {
  background(0x00);
  noStroke();
  fill(0xFF);
  size(200, 200, P2D);
  textSize(12);
  textAlign(CENTER, CENTER);
  text("Loading...", width/2, height/2); 
}

void draw() {
  if (frameCount == 1) {
    this.prepare();
  }
  background(0x00);
  shape(this.small);
}

void prepare() {
  this.small = createShape();
  this.small.beginShape(LINE_STRIP);
  this.small.noFill();
  this.small.stroke(0xFF);
  this.small.strokeWeight(1.0f);
  this.small.vertex(10.0f, 10.0f);
  this.small.vertex(width-10.0f, height-10.0f);
  this.small.endShape();
  // Wait 5 seconds to simulate a long setup
  try {
    Thread.sleep(5000);
  }
  catch (InterruptedException e) {
  }
}

I agree with you that it would be nice to be able to change this 5 sec. delay somewhere, either globally in Processing preferences, or in a sketch thru some variables (additionnal argument to Size/FullScreen ?) or function. Meanwhile extending to something like 30 sec. would handle most of cases...

yblake avatar Mar 09 '22 10:03 yblake

I had a case where using a thread did not work due to the things that setup had to do. (My guess is that creating graphics caused the problem, but I don't want to bother figuring this out).

com.jogamp.opengl.GLException: Thread-4: This context is not current. Current context: null, this context WindowsWGLContext [Version 4.6 (Core profile, arb, compat[ES2, ES3, ES31, ES32], FBO, hardware) - 4.6.0 NVIDIA 536.67 [GL 4.6.0, vendor 536.67.0 (NVIDIA 536.67)], options 0x7c05, this 0x27dd193c, handle 0x10002, isShared true, jogamp.opengl.gl4.GL4bcImpl@5b3c7608,
         quirks: [NoDoubleBufferedBitmap, NoSurfacelessCtx],
        Drawable: WindowsOnscreenWGLDrawable[Realized true,
        Factory   jogamp.opengl.windows.wgl.WindowsWGLDrawableFactory@6c8dd25,
        Handle    0x0,
        Surface   jogamp.newt.driver.windows.WindowDriver[State [visible, focused, repositionable], supported [visible, child, focused, undecor, aontop, aonbottom, unsticky, repositionable, resizable, max[h, v], fullscreen[true], pointer[visible, confined]]; Window[1080/360 1280x720 wu, 1280x720 pixel] handle 0x2c1024, surfaceHandle 0x0, children 0; ParentWindow null (handle 0x0),
  NEWT-Screen[.windows_nil-1-s0, idx 0, refCount 2, vsize [ 0 / 0  3440 x 1440 ] [pixels], [ 0 / 0  3440 x 1440 ] [window], DefaultGraphicsScreen[WindowsGraphicsDevice[type .windows, connection decon, unitID 0, handle 0x0, owner false, NullToolkitLock[obj 0x238fa0e3]], idx 0], NEWT-Display[.windows_nil-1, excl false, refCount 2, hasEDT true, edtRunning true, WindowsGraphicsDevice[type .windows, connection decon, unitID 0, handle 0x0, 
owner false, NullToolkitLock[obj 0x238fa0e3]]], monitors: [Monitor[Id 0x300 [name '\\.\DISPLAY4\Monitor0', handle 0x10139, primary], 800 x 335 mm, pixelScale [1.0, 1.0], viewport[pixel [ 0 / 0  3440 x 1440 ], window [ 0 / 0  3440 x 1440 ]], orig [Id 0x0, [ 3440 x 1440 pixels x 32 bpp ] @ 60.0 Hz, flags [], 0 degr], curr [Id 0x0, [ 3440 x 1440 pixels x 32 bpp ] @ 60.0 Hz, flags [], 0 degr], modeChanged false, modeCount 256]]],
  Config WindowsWGLGraphicsConfiguration[DefaultGraphicsScreen[WindowsGraphicsDevice[type .windows, connection decon, unitID 0, handle 0x0, owner 
false, NullToolkitLock[obj 0x238fa0e3]], idx 0], pfdID 28, ARB-Choosen true,
        requested GLCaps[rgba 8/8/8/8, opaque, accum-rgba 0/0/0/0, dp/st/ms 24/8/2, sample-ext default, dbl, mono  , hw, GLProfile[GL4/GL4.hw], on-scr[.]],
        chosen    GLCaps[wgl vid 28 arb: rgba 8/8/8/8, opaque, accum-rgba 16/16/16/16, dp/st/ms 24/8/2, sample-ext default, dbl, mono  , hw, GLProfile[GL4/GL4.hw], on-scr[.]]],
  WrappedSurface null,
  SurfaceUpdatedListeners num 0 [],
  WindowListeners num 2 [com.jogamp.newt.opengl.GLWindow$2@1ac74dea, processing.opengl.PSurfaceJOGL$NEWTWindowListener@6c579d98, ],
  MouseListeners num 1 [processing.opengl.PSurfaceJOGL$NEWTMouseListener@16337fd1, ],
  PointerGestures default true, custom 0 [],
  KeyListeners num 1 [processing.opengl.PSurfaceJOGL$NEWTKeyListener@2e07d729, ],
  windowLock <e0f671e, 5ee4901a>[count 0, qsz 0, owner <NULL>], surfaceLockCount 0]]]
        at com.jogamp.opengl.GLContext.validateCurrent(GLContext.java:529)
        at jogamp.opengl.GLContextImpl.setSwapInterval(GLContextImpl.java:2811)
        at jogamp.opengl.gl4.GL4bcImpl.setSwapInterval(GL4bcImpl.java:40191)
        at processing.opengl.PJOGL.setFps(PJOGL.java:198)
        at processing.opengl.PSurfaceJOGL.setFrameRate(PSurfaceJOGL.java:795)
        at processing.core.PApplet.frameRate(PApplet.java:3056)
        at room_activity.Room_Activity.actual_setup(Room_Activity.java:227)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at processing.core.PApplet.method(PApplet.java:3450)
        at processing.core.PApplet.lambda$thread$0(PApplet.java:3508)
        at java.base/java.lang.Thread.run(Thread.java:840)

My solution is to do the setup process over multiple frames:


public void draw() {

    if (!setup_done) {
        // background(255, 0, 0);
        multi_frame_setup();
        return;    
    }
    ...
}

boolean setup_done = false;


// https://github.com/benfry/processing4/issues/340
void multi_frame_setup() {
    if (frameCount == 1) {
        background(0);
        fill(255);
        text("Setting up input source", 50, 50);
    }
    else if (frameCount == 2) {
        
        // fix gstreamer stuff
        // https://github.com/processing/processing-video/issues/223

        if (PApplet.platform == MACOS) {
            throw new RuntimeException("TODO set java.library.path!");
        }
        else if (PApplet.platform == LINUX) {
            throw new RuntimeException("TODO set java.library.path!");
        }
        else if (PApplet.platform == WINDOWS) {
            System.setProperty("java.library.path", System.getProperty("java.library.path")+";"+sketchPath()+"/lib/video/library/windows-amd64");
        }
        else {
            throw new RuntimeException("Unsupported platform");
        }

        // init input source

        switch (INPUT_SOURCE) {
            case MOVIE:
                movie = new Movie(this, "movement_top.mov");
                movie.loop();
                movie.volume(0);
                source = movie;
                break;
            case CAMERA:
                String[] cameras = Capture.list();
                printArray(cameras);
                // https://github.com/processing/processing-video/issues/224
                // printArray(Capture.getCapabilities(cameras[0]));
                // Would be nice to get the width and height of the webcam but we are using processing.
                // One way is to set a breakpoint in `parseCaps` in Capture.java and inspect the string.
                // int width = 1280; // TODO retreive width and height someday...
                // int height = 720;
                int width = 640; // TODO retreive width and height someday...
                int height = 480;
                cam = new Capture(this, width, height, cameras[1]);
                cam.start();
                source = cam;
                break;
        }
    }
    else if (frameCount == 3) {
        background(0);
        fill(255);
        text("Setting up osc", 50, 50);
    }
    else if (frameCount == 4) {
        osc = new OscP5(this, OSC_IP, OSC_PORT, OscP5.MULTICAST);
    }
    else if (frameCount == 5) {
        background(0);
        fill(255);
        text("loading shaders", 50, 50);
    }
    else if (frameCount == 6) {
        s_threshold = loadShader("shaders/threshold.glsl");
        s_blur = loadShader("shaders/blur.glsl");
        s_background_subtraction = loadShader("shaders/background_subtraction_frag.glsl");
        s_bilinear_scale = loadShader("shaders/bilinear.glsl");
    }
    else {
        background = createGraphics(source.width, source.height, P2D);

        passes[0] = createGraphics(source.width, source.height, P2D);
        passes[1] = createGraphics(source.width, source.height, P2D);
        passes[2] = createGraphics(source.width, source.height, P2D);
        passes[3] = createGraphics(source.width, source.height, P2D);
        
        downscaled_lookup = createGraphics(DOWNSCALED_LOOKUP_WIDTH, DOWNSCALED_LOOKUP_HEIGHT, P2D);

        frameRate(999);

        setup_done = true;
    }
    
}

clankill3r avatar Feb 13 '24 14:02 clankill3r

Nice. I just got past the issue in a similar way. Thanks D!

rapatski avatar Mar 06 '24 21:03 rapatski