java.lang.UnsupportedOperationException: FrameBuffer already initialized. when setting numSamples on FilterPostProcessor

Hi,

I receive this error when adding a DirectionalLightShadowFilter on a FilterPostProcessor.

SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.UnsupportedOperationException: FrameBuffer already initialized.
	at com.jme3.texture.FrameBuffer.setDepthTexture(FrameBuffer.java:473)
	at com.jme3.post.FilterPostProcessor.initFilter(FilterPostProcessor.java:183)
	at com.jme3.post.FilterPostProcessor.addFilter(FilterPostProcessor.java:116)
	at org.impstack.litw.tool.DlsfError$MyDirecationalLightShadowFilterState.update(DlsfError.java:86)
	at com.jme3.app.state.AppStateManager.update(AppStateManager.java:287)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:236)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:197)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
	at java.lang.Thread.run(Thread.java:748)

my test case:

public class DlsfError extends SimpleApplication {

    public static void main(String[] args) {
        new DlsfError().start();
    }

    @Override
    public void simpleInitApp() {
        getStateManager().attachAll(new MySceneProcesserState(), new MyDirectionalLightShadowFilterState());
    }

    class MySceneProcesserState extends BaseAppState {
        FilterPostProcessor fpp;

        @Override
        protected void initialize(Application app) {
            fpp = new FilterPostProcessor(app.getAssetManager());
            fpp.setNumSamples(app.getContext().getSettings().getSamples());

            System.out.println("#samples: " + app.getContext().getSettings().getSamples());

            app.getViewPort().addProcessor(fpp);
        }

        @Override
        protected void onEnable() {
        }

        @Override
        protected void onDisable() {
        }

        @Override
        protected void cleanup(Application app) {
            app.getViewPort().removeProcessor(fpp);
        }

        public FilterPostProcessor getFpp() {
            return fpp;
        }
    }

    class MyDirectionalLightShadowFilterState extends BaseAppState {

        DirectionalLightShadowFilter dlsf;
        DirectionalLight directionalLight;

        long start;
        boolean attached = false;

        @Override
        protected void initialize(Application app) {
            directionalLight = new DirectionalLight(new Vector3f(-1, -1, 1).normalizeLocal(), ColorRGBA.White);
        }

        @Override
        protected void onEnable() {
            ((SimpleApplication) getApplication()).getRootNode().addLight(directionalLight);
            start = System.currentTimeMillis();
        }

        @Override
        public void update(float tpf) {
            if (System.currentTimeMillis() - start >= 1000 && !attached) {
                dlsf = new DirectionalLightShadowFilter(getAssetManager(), 1024, 4);
                dlsf.setLight(directionalLight);
                dlsf.setEnabled(true);
                dlsf.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON);
                dlsf.setEdgesThickness(2);
                dlsf.setShadowIntensity(0.75f);
                dlsf.setLambda(0.65f);
                dlsf.setShadowZExtend(50);

                getState(MySceneProcesserState.class).getFpp().addFilter(dlsf);

                attached = true;

                System.out.println("attached!");
            }
        }

        @Override
        protected void onDisable() {
        }

        @Override
        protected void cleanup(Application app) {
            getState(MySceneProcesserState.class).getFpp().removeFilter(dlsf);
        }
    }
}

When you remove this line when setting up the FilterPostProcessor:
fpp.setNumSamples(app.getContext().getSettings().getSamples());
the error is gone and everything just works.

Am I doing something wrong here?

The way I am doing this in application states, is because I have the FilterPostProcessor setup on the viewport in an Application state. Other State’s can then grab the FilterPostProcessor to add filters they require. I simulate this behaviour in the testcase by waiting a bit before attaching the filter to the FilterPostProcessor.

I’ll look into it

Hello, I can’t reproduce the issue with your test case.
It works fine on my end.
Could you give me more details? like what hardware / os / jme version / java version you use?

Hi @nehon

I’m running on a mac, macOS High Sierra (v10.13.1)

INFO: Running on jMonkeyEngine 3.2-stable
 * Branch: HEAD
 * Git Hash: f85624a
 * Build Date: 2018-01-21
apr 05, 2018 10:31:53 AM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: LWJGL 2.9.3 context running on thread jME3 Main
 * Graphics Adapter: null
 * Driver Version: null
 * Scaling Factor: 1
apr 05, 2018 10:31:53 AM com.jme3.renderer.opengl.GLRenderer loadCapabilitiesCommon
INFO: OpenGL Renderer Information
 * Vendor: Intel Inc.
 * Renderer: Intel(R) Iris(TM) Graphics 6100
 * OpenGL Version: 2.1 INTEL-10.28.29
 * GLSL Version: 1.20
 * Profile: Compatibility
Zion:~ remy$ java -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

I did some extra tests, these are my results:
this works (1 sample on OPENGL2):

public static void main(String[] args) {
        DlsfError dlsfError = new DlsfError();
        dlsfError.setShowSettings(false);
        AppSettings settings = new AppSettings(true);
        settings.setSamples(1);
        settings.setRenderer(AppSettings.LWJGL_OPENGL2);
        dlsfError.setSettings(settings);
        dlsfError.start();
    }

this doesn’t work (2 samples on OPENGL2):

public static void main(String[] args) {
        DlsfError dlsfError = new DlsfError();
        dlsfError.setShowSettings(false);
        AppSettings settings = new AppSettings(true);
        settings.setSamples(2);
        settings.setRenderer(AppSettings.LWJGL_OPENGL2);
        dlsfError.setSettings(settings);
        dlsfError.start();
    }

stacktrace:

SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.UnsupportedOperationException: FrameBuffer already initialized.
	at com.jme3.texture.FrameBuffer.setDepthTexture(FrameBuffer.java:473)
	at com.jme3.post.FilterPostProcessor.initFilter(FilterPostProcessor.java:183)
	at com.jme3.post.FilterPostProcessor.addFilter(FilterPostProcessor.java:116)
	at org.impstack.litw.tool.DlsfError$MyDirectionalLightShadowFilterState.update(DlsfError.java:93)
	at com.jme3.app.state.AppStateManager.update(AppStateManager.java:287)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:236)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:197)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
	at java.lang.Thread.run(Thread.java:748)

this works (1 sample on OPENGL3):

public static void main(String[] args) {
        DlsfError dlsfError = new DlsfError();
        dlsfError.setShowSettings(false);
        AppSettings settings = new AppSettings(true);
        settings.setSamples(1);
        settings.setRenderer(AppSettings.LWJGL_OPENGL3);
        dlsfError.setSettings(settings);
        dlsfError.start();
    }

this doesn’t work (2 samples on OPENGL3):

public static void main(String[] args) {
        DlsfError dlsfError = new DlsfError();
        dlsfError.setShowSettings(false);
        AppSettings settings = new AppSettings(true);
        settings.setSamples(2);
        settings.setRenderer(AppSettings.LWJGL_OPENGL3);
        dlsfError.setSettings(settings);
        dlsfError.start();
    }

stacktrace:

SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.NullPointerException
	at com.jme3.post.FilterPostProcessor.renderFilterChain(FilterPostProcessor.java:294)
	at com.jme3.post.FilterPostProcessor.postFrame(FilterPostProcessor.java:334)
	at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:1114)
	at com.jme3.renderer.RenderManager.render(RenderManager.java:1158)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:253)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:197)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
	at java.lang.Thread.run(Thread.java:748)

the NPE is here (tex = null on the tex.getImage().getMultiSumples() > 1 line in the FilterPostProcessor):

if (filter.isRequiresSceneTexture()) {
    mat.setTexture("Texture", tex);
    if (tex.getImage().getMultiSamples() > 1) {
        mat.setInt("NumSamples", tex.getImage().getMultiSamples());
    } else {
        mat.clearParam("NumSamples");
    }
}

I’ll try to debug a bit more.

I’m having the same issue with any filter that requires a depth texture.

It can be reproduced whenever the FPP is initialized + contains a non-depth-texture-required filter and a depth-texture-required filter is added.

If the FPP isn’t initialized or it doesn’t contains a non-depth-texture-required filter there is no problem.

A very simple example test-case:

public class Main extends SimpleApplication implements ActionListener {

    public static void main(String[] args) { new Main().start(); }

    FilterPostProcessor fpp;

    @Override
    public void simpleInitApp() {
        fpp = new FilterPostProcessor(assetManager);
        fpp.addFilter(new BloomFilter());

        viewPort.addProcessor(fpp);

        inputManager.addListener(this, "add");
        inputManager.addMapping("add", new KeyTrigger(KeyInput.KEY_F));
    }

    @Override
    public void onAction(String name, boolean isPressed, float tpf) {
        if(isPressed) return;

        System.out.println("Adding filter");
        fpp.addFilter(new FogFilter());
    }
}

When we press the F key to add a new filter, we get the exception. If we replace the BloomFilter (doesn’t require depth) by the DepthOfFieldFilter (requires depth) or we don’t add any, the exception is gone.
If we replace the FogFilter by the RadialBlurFilter the exception is also gone.

My system specs are (Ubuntu 18.04):

INFO: Running on jMonkeyEngine 3.2-stable
 * Branch: HEAD
 * Git Hash: f85624a
 * Build Date: 2018-01-21
INFO: LWJGL 2.9.3 context running on thread jME3 Main
 * Graphics Adapter: null
 * Driver Version: null
 * Scaling Factor: 1
INFO: OpenGL Renderer Information
 * Vendor: NVIDIA Corporation
 * Renderer: GeForce GTX 980 Ti/PCIe/SSE2
 * OpenGL Version: 4.6.0 NVIDIA 390.48
 * GLSL Version: 4.60 NVIDIA
 * Profile: Compatibility

The same happens with lwjgl3:

INFO: LWJGL 3.1.2 build 29 context running on thread main
 * Graphics Adapter: GLFW 3.3.0 X11 GLX EGL clock_gettime /dev/js shared

This issue appears to be there for long now. This other post seems to be related: Post processor filters' order

2 Likes

Has an issue been opened at GitHub yet?

No, I didn’t opened an issue back then and I didn’t investigated further into the issue, I was under the assumption there where some issues with antialiasing on filters in versions lower then opengl 3. Don’t know why I think this though…

edit: I guess I read it in the source code:

1 Like

I’ve just opened an issue on github.

1 Like