Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic support for Transform Feedback #1078

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

TehLeo
Copy link
Contributor

@TehLeo TehLeo commented Apr 25, 2019

Adds basic support for Transform Feedback (TF).
As part of discussion on discord

  • new class BufferObject was added which manages BufferObjects
  • VertexBuffer now extends BufferObject
  • jme3.shader.BufferObject was renamed to UniformBufferObject and now extends BufferObject

To support basic transform feedback.

  • setTransformFeedbackOutput(TransformFeedbackOutput output) method was added to the Renderer interface

The use of this method is similar to how rendering of framebuffers is handled in jme. This method is called to enable transform feedback, after which rendered geometry's TF ouput will be captured to the specified output buffers. Calling it will null, disables transform feedback.

In order to use TF, a shader has to specify the output variables which will be outputted to TF. This is accomplished by specifying the output variables in Technique block of .j3md file. Syntax is:

TransformFeedback [Off | Interleaved | Separate | InShader] varying1 varying2 varying3 ...

For example a vertex/geometry shader contains the ouput:

out mat4 TransformFeedback;

A technique can be written as:

Technique {
    VertexShader GLSL130: jme3test/renderer/TestTR.vert
    GeometryShader GLSL150: jme3test/renderer/TestTR.geom
    RenderState {
        RasterizerDiscard On
    }
    TransformFeedback Interleaved TransformFeedback
}
  • added Render State RasterizerDiscard - when enabled Fragment Processing stage is skipped,
  • added QueryObject, retrieve the number of written primitives for TF operation
  • added TF testcase jme3test.renderer.TestTransformFeedback

Awaiting your feedback.

@@ -34,6 +34,8 @@
import com.jme3.export.*;
import com.jme3.scene.Mesh;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused imports

Copy link
Contributor Author

@TehLeo TehLeo Oct 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for pointing them out, i'll fix these with next commit

public static boolean supports(Collection<Caps> caps, QueryObject query) {
switch(query.getType()) {
case SamplesPassed:
//GL1.5 is available or (GL_ARB_occlusion_query)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So.. are we supposed to test if 1.5 is available?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am under the impression JME is GL 2.0+ so no need to test?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about GL ES?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will have to be investigated, a quick check I made, it seems gl es 2.0 might not support occlusion queries.

import com.jme3.scene.VertexBuffer;
import com.jme3.shader.BufferObject;
import com.jme3.shader.UniformBufferObject;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import

/**
* Started queries.
*/
public int[] startedQueries = new int[6/*QueryObject.Type.values().length*/];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point of this? Just to remember which queries where started? Do we really need it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, unless a query is started issuing a glEndQuery or checking for result yield a glerror. This is here to prevent that. Furthermore, take a look at the following

void glBeginQuery(GLenum target, GLuint id);
void glEndQuery( GLenum target);

Do you see something off about the functions above?
The off thing about them is that glEndQuery does not take query id as a parameter!

Thus in other words lets say I make two timer queries:

queryT1 = new QueryObject(app.getRenderer(), QueryObject.Type.TimeElapsed);
queryT2 = new QueryObject(app.getRenderer(), QueryObject.Type.TimeElapsed);

If you run the following code:

queryT1.begin();
queryT2.begin();
//some work
queryT2.end();
queryT1.end();

You will correctly get a RenderException (at line queryT2.begin();)

com.jme3.renderer.RendererException: Query of type TimeElapsed already started.

Without the render exception you would get gl error. In other words you are not allowed to nest the same type of query.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but this is never exposed outside of the core. So maybe we don't need those checks ...

Copy link
Contributor Author

@TehLeo TehLeo Oct 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you saying that users will not be able to use QueryObject? I believe we do need them as otherwise its pretty easy to get gl errors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As usual there is nothing stopping you from using internals in jme, but imo this is not an end user feature so maybe we can avoid having all those extra checks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not have the checks? Those checks are not expensive. You are not starting 10 thousands of queries per frame. They only bring robustness. So I do not see a reason for them not to be there.
Also even if it was used just in internals, there's always a risk that you can nest some queries and this would be a nightmare for figuring out such error.
Eg. Imagine you use TimerQuery while you also have DetailedProfiler attached. And there you go... nested queries.

package com.jme3.renderer;

import com.jme3.util.NativeObject;
import java.util.EnumMap;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import?

*/
CanEnd
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refer to the answer above, in short, to prevent gl errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants