Open qq1053831109 opened 11 months ago
it is 4.0.0 version.
Can you try to use at least 4.0.1 version? There were a lot of async canvas fixes.
Also, is the problem only with these artifacts, or are there other problems? Are you resizing these Canvas?
@qq1053831109 I can't help you without feedback
Check version 4.0.3, there are some more changes related to this.
the only happened on some laptops. The testing cycle is relatively long. It was submitted to me by my product user. My desktop computer won't have a splash screen. More feedback requires a longer cycle to obtain
I will be using 4.03 in the next version and it is expected to take a month to receive feedback on whether to fix it
the 4.05 It's hard to upgrade, it's hard to hook up. My usage is very complex and requires me to use my own context management method in different situations
More open public is needed, do not use internal. we need extends your class
If deep integration into the library is required, then it is better to simply clone it and change it to suit you. The library's internal mechanisms will not be exposed, as they may confuse other developers.
Also, if you decribe me your case, I may be able to help you to find the best solution.
package ose.core.sglfx.impl;
import com.badlogic.gdx.graphics.GL20;
import com.huskerdev.ojgl.GLContext;
import com.huskerdev.openglfx.GLExecutor;
import com.huskerdev.openglfx.canvas.GLProfile;
import com.huskerdev.openglfx.internal.fbo.Framebuffer;
import com.huskerdev.openglfx.internal.fbo.MultiSampledFramebuffer;
import com.sun.prism.Graphics;
import com.sun.prism.GraphicsPipeline;
import com.sun.prism.PixelFormat;
import com.sun.prism.Texture;
import ose.core.sglfx.GLThread;
import ose.core.sglfx.SGLContext;
import ose.core.sglfx.SolarGlFx;
import ose.core.sglfx.SolarOpenGLCanvas;
import ose.core.sglfx.addons.PassthroughShader;
import ose.core.sglfx.addons.SGlFxUtil;
import ose.core.sglfx.addons.Size;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.huskerdev.openglfx.GLExecutor.glFinish;
import static com.huskerdev.openglfx.GLExecutor.glViewport;
public class SolarAsyncSharedImpl extends SolarOpenGLCanvas {
private GLExecutor executor;
{
setMinSize(16, 16);
}
public SolarAsyncSharedImpl(GLExecutor executor) {
super(true);
this.executor = executor;
}
public SolarAsyncSharedImpl(GLExecutor executor, GLProfile profile, boolean flipY, int msaa) {
super(true);
this.executor = executor;
}
private Object paintLock = new Object();
private Object blitLock = new Object();
private Size lastDrawSize = new Size(-1, -1);
private Size lastResultSize = new Size(-1, -1);
private static SGLContext parallelContext = null;
// private static GLContext parallelContext = null;
private static GLContext resultContext = null;
private static GLContext fxContext = null;
private Framebuffer resultFBO;
private Framebuffer interThreadFBO;
private Framebuffer fbo;
private MultiSampledFramebuffer msaaFBO;
private Texture fxTexture;
private AtomicBoolean needsBlit = new AtomicBoolean(false);
private PassthroughShader passthroughShader;
private void initializeThread() {
fxContext = GLContext.current();
GLContext.clear();
// parallelContext = GLContext.create(fxContext, true);
parallelContext = SGLContext.create(fxContext.getHandle(), true);
resultContext = GLContext.create(fxContext, true);
fxContext.makeCurrent();
}
private void addUpdateCallBack() {
GLThread.getGLThread(() -> {
SGLContext.gdxContextThread = Thread.currentThread();
parallelContext.makeCurrent();
executor.initGLFunctions();
SolarGlFx.solarGameApp.create();
}).addUpdateCallBack(() -> {
try {
if (!getDisposed() && needRender()) {
if (System.currentTimeMillis() - lastRendedTime < limitedRenderTime) {
return;
}
lastRendedTime = System.currentTimeMillis();
paint();
synchronized (blitLock) {
fbo.blitTo(interThreadFBO.getId());
}
needsBlit.set(true);
// synchronized (paintLock) {
// paintLock.wait();
// }
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
private void paint() {
lastDrawSize.onDifference((int) getScaledWidth(), (int) getScaledHeight(), () -> {
updateDrawFramebufferSize(getScaledWidth(), getScaledHeight());
fireReshapeEvent(getScaledWidth(), getScaledHeight());
});
glViewport(0, 0, lastDrawSize.width, lastDrawSize.height);
if (input != null) {
input.update();
}
SolarGlFx.glFxApp.executedRunnables();
if (getMsaa() == 0) {
executor.glBindFramebuffer(GL20.GL_FRAMEBUFFER, fbo.getId());
fireRenderEvent(fbo.getId());
} else {
executor.glBindFramebuffer(GL20.GL_FRAMEBUFFER, msaaFBO.getId());
fireRenderEvent(msaaFBO.getId());
msaaFBO.blitTo(fbo.getId());
}
glFinish();
}
private boolean _needAddUpdate2GLThread = true;
protected void onNGRender(Graphics g) {
if (getWidth() == 0 || getHeight() == 0)
return;
if (fxContext == null) {
initializeThread();
}
if (_needAddUpdate2GLThread) {
addUpdateCallBack();
_needAddUpdate2GLThread = false;
}
needRenderTime = System.currentTimeMillis() + 1000;
if (needsBlit.getAndSet(false)) {
resultContext.makeCurrent();
if (passthroughShader == null) {
passthroughShader = new PassthroughShader();
}
lastResultSize.onDifference((int) getScaledWidth(), (int) getScaledHeight(), () -> {
updateResultFramebufferSize(getScaledWidth(), getScaledHeight());
});
glViewport(0, 0, lastResultSize.width, lastResultSize.height);
synchronized (blitLock) {
passthroughShader.copy(interThreadFBO, resultFBO);
}
fxContext.makeCurrent();
}
if (fxTexture != null) {
drawResultTexture(g, fxTexture);
}
}
private void updateResultFramebufferSize(int width, int height) {
if (resultFBO != null) {
resultFBO.delete();
}
// Create JavaFX texture
if (fxTexture != null) {
fxTexture.dispose();
}
fxTexture = GraphicsPipeline.getDefaultResourceFactory()
.createTexture(PixelFormat.BYTE_BGRA_PRE, Texture.Usage.DYNAMIC, Texture.WrapMode.CLAMP_TO_EDGE, width, height);
fxTexture.makePermanent();
// Create framebuffer that connected to JavaFX's texture
resultFBO = new Framebuffer(width, height, SGlFxUtil.getGLTextureId(fxTexture), 0xDE1);
}
private void updateDrawFramebufferSize(int width, int height) {
if (fbo != null) {
fbo.delete();
if (getMsaa() != 0) msaaFBO.delete();
}
// Create 'buffer' framebuffer
interThreadFBO = new Framebuffer(width, height, -1, 0xDE1);
// Create framebuffer
fbo = new Framebuffer(width, height, -1, 0xDE1);
fbo.bindFramebuffer();
// Create multi-sampled framebuffer
if (getMsaa() != 0) {
msaaFBO = new MultiSampledFramebuffer(getMsaa(), width, height);
msaaFBO.bindFramebuffer();
}
}
@Override
public int getFbo() {
if (fbo == null) {
return 0;
}
return fbo.getId();
}
public void repaint() {
synchronized (paintLock) {
paintLock.notifyAll();
}
}
public void timerTick() {
if (needsBlit != null && needsBlit.get())
markDirty();
}
public void dispose() {
super.dispose();
synchronized (paintLock) {
paintLock.notifyAll();
}
// GLContext.delete(parallelContext);
GLContext.delete(resultContext);
}
}```
like javafx all pane in one javafx Thread. gl need in one Thread。not every gl panel has independent thread. I have 100 gl panels at the same time.The underlying layers are all in one libgdx thread
For a large amount of async GLCanvas having an independent thread is not good. I can make some kind of shared thread that can be applied to several GLCanvas. This way you can divide a large number of GLCanvas into groups and reduce the number of threads.
Like regular OpenGL, it can run on different threads. I can't suggest anything without analyzing the application code. I made a module for LibGDX, but it hasn't been tested yet.