Add off-screen GL context

This commit is contained in:
Pedro J. Estébanez 2021-09-24 14:07:44 +02:00
parent 25f01cb09d
commit abdf931832
25 changed files with 252 additions and 23 deletions

View File

@ -719,6 +719,12 @@ const char *OS::get_video_driver_name(int p_driver) const {
} }
} }
bool OS::is_offscreen_gl_available() const {
return false;
}
void OS::set_offscreen_gl_current(bool p_current) {}
int OS::get_audio_driver_count() const { int OS::get_audio_driver_count() const {
return AudioDriverManager::get_driver_count(); return AudioDriverManager::get_driver_count();
} }

View File

@ -191,6 +191,9 @@ public:
virtual const char *get_video_driver_name(int p_driver) const; virtual const char *get_video_driver_name(int p_driver) const;
virtual int get_current_video_driver() const = 0; virtual int get_current_video_driver() const = 0;
virtual bool is_offscreen_gl_available() const;
virtual void set_offscreen_gl_current(bool p_current);
virtual int get_audio_driver_count() const; virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const; virtual const char *get_audio_driver_name(int p_driver) const;

View File

@ -407,6 +407,18 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
} }
} }
public boolean createOffscreenGL() {
return mView.createOffscreenGL();
}
public void destroyOffscreenGL() {
mView.destroyOffscreenGL();
}
public void setOffscreenGLCurrent(boolean p_current) {
mView.setOffscreenGLCurrent(p_current);
}
public void setKeepScreenOn(final boolean p_enabled) { public void setKeepScreenOn(final boolean p_enabled) {
runOnUiThread(() -> { runOnUiThread(() -> {
if (p_enabled) { if (p_enabled) {

View File

@ -72,10 +72,9 @@ public class GodotLib {
/** /**
* Invoked on the GL thread when the underlying Android surface is created or recreated. * Invoked on the GL thread when the underlying Android surface is created or recreated.
* @param p_32_bits
* @see android.opengl.GLSurfaceView.Renderer#onSurfaceCreated(GL10, EGLConfig) * @see android.opengl.GLSurfaceView.Renderer#onSurfaceCreated(GL10, EGLConfig)
*/ */
public static native void newcontext(boolean p_32_bits); public static native void newcontext();
/** /**
* Forward {@link Activity#onBackPressed()} event from the main thread to the GL thread. * Forward {@link Activity#onBackPressed()} event from the main thread to the GL thread.

View File

@ -76,7 +76,7 @@ class GodotRenderer implements GLSurfaceView.Renderer {
} }
public void onSurfaceCreated(GL10 gl, EGLConfig config) { public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GodotLib.newcontext(GLUtils.use_32); GodotLib.newcontext();
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onGLSurfaceCreated(gl, config); plugin.onGLSurfaceCreated(gl, config);
} }

View File

@ -49,6 +49,10 @@ import android.view.GestureDetector;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
/** /**
* A simple GLSurfaceView sub-class that demonstrate how to perform * A simple GLSurfaceView sub-class that demonstrate how to perform
* OpenGL ES 2.0 rendering into a GL Surface. Note the following important * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
@ -75,6 +79,10 @@ public class GodotView extends GLSurfaceView {
private final GestureDetector detector; private final GestureDetector detector;
private final GodotRenderer godotRenderer; private final GodotRenderer godotRenderer;
private EGLConfigChooser eglConfigChooser;
private EGLContextFactory eglContextFactory;
private EGLContext eglSecondaryContext;
public GodotView(Context context, Godot godot, XRMode xrMode, boolean p_use_gl3, public GodotView(Context context, Godot godot, XRMode xrMode, boolean p_use_gl3,
boolean p_use_32_bits, boolean p_use_debug_opengl, boolean p_translucent) { boolean p_use_32_bits, boolean p_use_debug_opengl, boolean p_translucent) {
super(context); super(context);
@ -123,10 +131,10 @@ public class GodotView extends GLSurfaceView {
switch (xrMode) { switch (xrMode) {
case OVR: case OVR:
// Replace the default egl config chooser. // Replace the default egl config chooser.
setEGLConfigChooser(new OvrConfigChooser()); eglConfigChooser = new OvrConfigChooser();
// Replace the default context factory. // Replace the default context factory.
setEGLContextFactory(new OvrContextFactory()); eglContextFactory = new OvrContextFactory();
// Replace the default window surface factory. // Replace the default window surface factory.
setEGLWindowSurfaceFactory(new OvrWindowSurfaceFactory()); setEGLWindowSurfaceFactory(new OvrWindowSurfaceFactory());
@ -147,7 +155,7 @@ public class GodotView extends GLSurfaceView {
/* Setup the context factory for 2.0 rendering. /* Setup the context factory for 2.0 rendering.
* See ContextFactory class definition below * See ContextFactory class definition below
*/ */
setEGLContextFactory(new RegularContextFactory()); eglContextFactory = new RegularContextFactory();
/* We need to choose an EGLConfig that matches the format of /* We need to choose an EGLConfig that matches the format of
* our surface exactly. This is going to be done in our * our surface exactly. This is going to be done in our
@ -156,24 +164,49 @@ public class GodotView extends GLSurfaceView {
*/ */
if (GLUtils.use_32) { if (GLUtils.use_32) {
setEGLConfigChooser(translucent eglConfigChooser = translucent
? new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil, ? new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil,
new RegularConfigChooser(8, 8, 8, 8, 16, stencil)) new RegularConfigChooser(8, 8, 8, 8, 16, stencil))
: new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil, : new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil,
new RegularConfigChooser(5, 6, 5, 0, 16, stencil))); new RegularConfigChooser(5, 6, 5, 0, 16, stencil));
} else { } else {
setEGLConfigChooser(translucent eglConfigChooser = translucent
? new RegularConfigChooser(8, 8, 8, 8, 16, stencil) ? new RegularConfigChooser(8, 8, 8, 8, 16, stencil)
: new RegularConfigChooser(5, 6, 5, 0, 16, stencil)); : new RegularConfigChooser(5, 6, 5, 0, 16, stencil);
} }
break; break;
} }
setEGLConfigChooser(eglConfigChooser);
setEGLContextFactory(eglContextFactory);
/* Set the renderer responsible for frame rendering */ /* Set the renderer responsible for frame rendering */
setRenderer(godotRenderer); setRenderer(godotRenderer);
} }
public boolean createOffscreenGL() {
EGL10 egl = (EGL10)EGLContext.getEGL();
EGLConfig eglConfig = eglConfigChooser.chooseConfig(egl, egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY));
eglSecondaryContext = eglContextFactory.createContext(egl, egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY), eglConfig);
if (eglSecondaryContext == EGL10.EGL_NO_CONTEXT) {
eglSecondaryContext = null;
}
return eglSecondaryContext != null;
}
public void setOffscreenGLCurrent(boolean p_current) {
EGL10 egl = (EGL10)EGLContext.getEGL();
egl.eglMakeCurrent(egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY), EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, p_current ? eglSecondaryContext : EGL10.EGL_NO_CONTEXT);
}
public void destroyOffscreenGL() {
if (eglSecondaryContext != null) {
EGL10 egl = (EGL10)EGLContext.getEGL();
eglContextFactory.destroyContext(egl, egl.eglGetCurrentDisplay(), eglSecondaryContext);
eglSecondaryContext = null;
}
}
public void onBackPressed() { public void onBackPressed() {
godot.onBackPressed(); godot.onBackPressed();
} }

View File

@ -152,6 +152,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env
delete godot_io_java; delete godot_io_java;
} }
if (godot_java) { if (godot_java) {
godot_java->destroy_offscreen_gl(env);
delete godot_java; delete godot_java;
} }
if (input_handler) { if (input_handler) {
@ -212,11 +213,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j
os_android->set_display_size(Size2(width, height)); os_android->set_display_size(Size2(width, height));
} }
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jboolean p_32_bits) { JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz) {
if (os_android) { if (os_android) {
if (step.get() == 0) { if (step.get() == 0) {
// During startup // During startup
os_android->set_context_is_16_bits(!p_32_bits); os_android->set_offscreen_gl_available(godot_java->create_offscreen_gl(env));
} else { } else {
// GL context recreated because it was lost; restart app to let it reload everything // GL context recreated because it was lost; restart app to let it reload everything
step.set(-1); // Ensure no further steps are attempted and no further events are sent step.set(-1); // Ensure no further steps are attempted and no further events are sent

View File

@ -41,7 +41,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jint width, jint height); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jint width, jint height);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jboolean p_32_bits); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask = 0, jfloat vertical_factor = 0, jfloat horizontal_factor = 0); void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask = 0, jfloat vertical_factor = 0, jfloat horizontal_factor = 0);

View File

@ -59,6 +59,9 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
// get some Godot method pointers... // get some Godot method pointers...
_on_video_init = p_env->GetMethodID(godot_class, "onVideoInit", "()V"); _on_video_init = p_env->GetMethodID(godot_class, "onVideoInit", "()V");
_create_offscreen_gl = p_env->GetMethodID(godot_class, "createOffscreenGL", "()Z");
_destroy_offscreen_gl = p_env->GetMethodID(godot_class, "destroyOffscreenGL", "()V");
_set_offscreen_gl_current = p_env->GetMethodID(godot_class, "setOffscreenGLCurrent", "(Z)V");
_restart = p_env->GetMethodID(godot_class, "restart", "()V"); _restart = p_env->GetMethodID(godot_class, "restart", "()V");
_finish = p_env->GetMethodID(godot_class, "forceQuit", "()V"); _finish = p_env->GetMethodID(godot_class, "forceQuit", "()V");
_set_keep_screen_on = p_env->GetMethodID(godot_class, "setKeepScreenOn", "(Z)V"); _set_keep_screen_on = p_env->GetMethodID(godot_class, "setKeepScreenOn", "(Z)V");
@ -131,6 +134,29 @@ void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
} }
} }
bool GodotJavaWrapper::create_offscreen_gl(JNIEnv *p_env) {
if (_create_offscreen_gl) {
return p_env->CallBooleanMethod(godot_instance, _create_offscreen_gl);
} else {
return false;
}
}
void GodotJavaWrapper::destroy_offscreen_gl(JNIEnv *p_env) {
if (_destroy_offscreen_gl) {
p_env->CallBooleanMethod(godot_instance, _destroy_offscreen_gl);
}
}
void GodotJavaWrapper::set_offscreen_gl_current(JNIEnv *p_env, bool p_current) {
if (_set_offscreen_gl_current) {
if (p_env == NULL)
p_env = get_jni_env();
ERR_FAIL_COND(p_env == nullptr);
p_env->CallVoidMethod(godot_instance, _set_offscreen_gl_current, p_current);
}
}
void GodotJavaWrapper::on_godot_setup_completed(JNIEnv *p_env) { void GodotJavaWrapper::on_godot_setup_completed(JNIEnv *p_env) {
if (_on_godot_setup_completed) { if (_on_godot_setup_completed) {
if (p_env == NULL) { if (p_env == NULL) {

View File

@ -48,6 +48,9 @@ private:
jclass activity_class; jclass activity_class;
jmethodID _on_video_init = 0; jmethodID _on_video_init = 0;
jmethodID _create_offscreen_gl = 0;
jmethodID _destroy_offscreen_gl = 0;
jmethodID _set_offscreen_gl_current = 0;
jmethodID _restart = 0; jmethodID _restart = 0;
jmethodID _finish = 0; jmethodID _finish = 0;
jmethodID _set_keep_screen_on = 0; jmethodID _set_keep_screen_on = 0;
@ -77,6 +80,9 @@ public:
jobject get_class_loader(); jobject get_class_loader();
void gfx_init(bool gl2); void gfx_init(bool gl2);
bool create_offscreen_gl(JNIEnv *p_env);
void destroy_offscreen_gl(JNIEnv *p_env);
void set_offscreen_gl_current(JNIEnv *p_env, bool p_current);
void on_video_init(JNIEnv *p_env = NULL); void on_video_init(JNIEnv *p_env = NULL);
void on_godot_setup_completed(JNIEnv *p_env = NULL); void on_godot_setup_completed(JNIEnv *p_env = NULL);
void on_godot_main_loop_started(JNIEnv *p_env = NULL); void on_godot_main_loop_started(JNIEnv *p_env = NULL);

View File

@ -484,10 +484,18 @@ String OS_Android::get_system_dir(SystemDir p_dir, bool p_shared_storage) const
return godot_io_java->get_system_dir(p_dir, p_shared_storage); return godot_io_java->get_system_dir(p_dir, p_shared_storage);
} }
void OS_Android::set_context_is_16_bits(bool p_is_16) { void OS_Android::set_offscreen_gl_available(bool p_available) {
//use_16bits_fbo = p_is_16; secondary_gl_available = p_available;
//if (rasterizer) }
// rasterizer->set_force_16_bits_fbo(p_is_16);
bool OS_Android::is_offscreen_gl_available() const {
return secondary_gl_available;
}
void OS_Android::set_offscreen_gl_current(bool p_current) {
if (secondary_gl_available) {
godot_java->set_offscreen_gl_current(nullptr, p_current);
}
} }
bool OS_Android::is_joy_known(int p_device) { bool OS_Android::is_joy_known(int p_device) {

View File

@ -45,7 +45,7 @@ class OS_Android : public OS_Unix {
bool use_gl2; bool use_gl2;
bool use_apk_expansion; bool use_apk_expansion;
bool use_16bits_fbo; bool secondary_gl_available = false;
VisualServer *visual_server; VisualServer *visual_server;
@ -137,7 +137,9 @@ public:
void set_opengl_extensions(const char *p_gl_extensions); void set_opengl_extensions(const char *p_gl_extensions);
void set_display_size(Size2 p_size); void set_display_size(Size2 p_size);
void set_context_is_16_bits(bool p_is_16); void set_offscreen_gl_available(bool p_available);
virtual bool is_offscreen_gl_available() const;
virtual void set_offscreen_gl_current(bool p_current);
virtual void set_screen_orientation(ScreenOrientation p_orientation); virtual void set_screen_orientation(ScreenOrientation p_orientation);
virtual ScreenOrientation get_screen_orientation() const; virtual ScreenOrientation get_screen_orientation() const;

View File

@ -53,6 +53,7 @@ bool gles3_available = true;
GLint backingHeight; GLint backingHeight;
EAGLContext *context; EAGLContext *context;
EAGLContext *context_offscreen;
GLuint viewRenderbuffer, viewFramebuffer; GLuint viewRenderbuffer, viewFramebuffer;
GLuint depthRenderbuffer; GLuint depthRenderbuffer;
} }
@ -75,6 +76,9 @@ bool gles3_available = true;
gles3_available = false; gles3_available = false;
fallback_gl2 = true; fallback_gl2 = true;
NSLog(@"Failed to create OpenGL ES 3.0 context. Falling back to OpenGL ES 2.0"); NSLog(@"Failed to create OpenGL ES 3.0 context. Falling back to OpenGL ES 2.0");
} else {
context_offscreen = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
OSIPhone::get_singleton()->set_offscreen_gl_context(context_offscreen);
} }
} }
@ -130,6 +134,9 @@ bool gles3_available = true;
if (context) { if (context) {
context = nil; context = nil;
} }
if (context_offscreen) {
context_offscreen = nil;
}
} }
- (BOOL)createFramebuffer { - (BOOL)createFramebuffer {

View File

@ -61,6 +61,8 @@ private:
VideoMode video_mode; VideoMode video_mode;
EAGLContext *offscreen_gl_context;
virtual int get_video_driver_count() const; virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const; virtual const char *get_video_driver_name(int p_driver) const;
@ -162,6 +164,10 @@ public:
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const; virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
void set_offscreen_gl_context(EAGLContext *p_context);
virtual bool is_offscreen_gl_available() const;
virtual void set_offscreen_gl_current(bool p_current);
virtual void set_keep_screen_on(bool p_enabled); virtual void set_keep_screen_on(bool p_enabled);
virtual bool can_draw() const; virtual bool can_draw() const;

View File

@ -417,6 +417,22 @@ void OSIPhone::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) c
p_list->push_back(video_mode); p_list->push_back(video_mode);
} }
void OSIPhone::set_offscreen_gl_context(EAGLContext *p_context) {
offscreen_gl_context = p_context;
}
bool OSIPhone::is_offscreen_gl_available() const {
return offscreen_gl_context;
}
void OSIPhone::set_offscreen_gl_current(bool p_current) {
if (p_current) {
[EAGLContext setCurrentContext:offscreen_gl_context];
} else {
[EAGLContext setCurrentContext:nil];
}
}
bool OSIPhone::can_draw() const { bool OSIPhone::can_draw() const {
if (native_video_is_playing()) if (native_video_is_playing())
return false; return false;
@ -683,6 +699,7 @@ OSIPhone::OSIPhone(String p_data_dir, String p_cache_dir) {
main_loop = NULL; main_loop = NULL;
visual_server = NULL; visual_server = NULL;
offscreen_gl_context = NULL;
// can't call set_data_dir from here, since it requires DirAccess // can't call set_data_dir from here, since it requires DirAccess
// which is initialized in initialize_core // which is initialized in initialize_core

View File

@ -115,6 +115,7 @@ public:
id cursor; id cursor;
NSOpenGLPixelFormat *pixelFormat; NSOpenGLPixelFormat *pixelFormat;
NSOpenGLContext *context; NSOpenGLContext *context;
NSOpenGLContext *context_offscreen;
Vector<Vector2> mpath; Vector<Vector2> mpath;
bool layered_window; bool layered_window;
@ -250,6 +251,9 @@ public:
virtual VideoMode get_video_mode(int p_screen = 0) const; virtual VideoMode get_video_mode(int p_screen = 0) const;
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const; virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
virtual bool is_offscreen_gl_available() const;
virtual void set_offscreen_gl_current(bool p_current);
virtual String get_executable_path() const; virtual String get_executable_path() const;
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr); virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);

View File

@ -1666,6 +1666,8 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
[window_view setOpenGLContext:context]; [window_view setOpenGLContext:context];
context_offscreen = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
[context makeCurrentContext]; [context makeCurrentContext];
GLint dim[2]; GLint dim[2];
@ -2427,6 +2429,18 @@ OS::VideoMode OS_OSX::get_video_mode(int p_screen) const {
void OS_OSX::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const { void OS_OSX::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
} }
bool OS_OSX::is_offscreen_gl_available() const {
return context_offscreen != nil;
}
void OS_OSX::set_offscreen_gl_current(bool p_current) {
if (p_current) {
[context makeCurrentContext];
} else {
[NSOpenGLContext clearCurrentContext];
}
}
int OS_OSX::get_screen_count() const { int OS_OSX::get_screen_count() const {
NSArray *screenArray = [NSScreen screens]; NSArray *screenArray = [NSScreen screens];
return [screenArray count]; return [screenArray count];
@ -3426,6 +3440,7 @@ OS_OSX *OS_OSX::singleton = NULL;
OS_OSX::OS_OSX() { OS_OSX::OS_OSX() {
context = nullptr; context = nullptr;
context_offscreen = nullptr;
memset(cursors, 0, sizeof(cursors)); memset(cursors, 0, sizeof(cursors));
key_event_pos = 0; key_event_pos = 0;

View File

@ -58,6 +58,18 @@ void ContextGL_Windows::make_current() {
wglMakeCurrent(hDC, hRC); wglMakeCurrent(hDC, hRC);
} }
bool ContextGL_Windows::is_offscreen_available() const {
return hRC_offscreen != NULL;
}
void ContextGL_Windows::make_offscreen_current() {
ERR_FAIL_COND(!wglMakeCurrent(hDC, hRC_offscreen));
}
void ContextGL_Windows::release_offscreen_current() {
ERR_FAIL_COND(!wglMakeCurrent(hDC, NULL));
}
HDC ContextGL_Windows::get_hdc() { HDC ContextGL_Windows::get_hdc() {
return hDC; return hDC;
} }
@ -205,6 +217,8 @@ Error ContextGL_Windows::initialize() {
{ {
return ERR_CANT_CREATE; // Return FALSE return ERR_CANT_CREATE; // Return FALSE
} }
hRC_offscreen = wglCreateContextAttribsARB(hDC, 0, attribs);
} }
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
@ -217,6 +231,7 @@ Error ContextGL_Windows::initialize() {
ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) { ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) {
opengl_3_context = p_opengl_3_context; opengl_3_context = p_opengl_3_context;
hWnd = hwnd; hWnd = hwnd;
hRC_offscreen = NULL;
use_vsync = false; use_vsync = false;
vsync_via_compositor = false; vsync_via_compositor = false;
} }

View File

@ -47,6 +47,7 @@ typedef int(APIENTRY *PFNWGLGETSWAPINTERVALEXTPROC)(void);
class ContextGL_Windows { class ContextGL_Windows {
HDC hDC; HDC hDC;
HGLRC hRC; HGLRC hRC;
HGLRC hRC_offscreen;
unsigned int pixel_format; unsigned int pixel_format;
HWND hWnd; HWND hWnd;
bool opengl_3_context; bool opengl_3_context;
@ -63,6 +64,10 @@ public:
void make_current(); void make_current();
bool is_offscreen_available() const;
void make_offscreen_current();
void release_offscreen_current();
HDC get_hdc(); HDC get_hdc();
HGLRC get_hglrc(); HGLRC get_hglrc();

View File

@ -1672,6 +1672,24 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
return OK; return OK;
} }
bool OS_Windows::is_offscreen_gl_available() const {
#if defined(OPENGL_ENABLED)
return gl_context->is_offscreen_available();
#else
return false;
#endif
}
void OS_Windows::set_offscreen_gl_current(bool p_current) {
#if defined(OPENGL_ENABLED)
if (p_current) {
return gl_context->make_offscreen_current();
} else {
return gl_context->release_offscreen_current();
}
#endif
}
void OS_Windows::set_clipboard(const String &p_text) { void OS_Windows::set_clipboard(const String &p_text) {
// Convert LF line endings to CRLF in clipboard content // Convert LF line endings to CRLF in clipboard content
// Otherwise, line endings won't be visible when pasted in other software // Otherwise, line endings won't be visible when pasted in other software

View File

@ -386,6 +386,9 @@ protected:
virtual void initialize_core(); virtual void initialize_core();
virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
virtual bool is_offscreen_gl_available() const;
virtual void set_offscreen_gl_current(bool p_current);
virtual void set_main_loop(MainLoop *p_main_loop); virtual void set_main_loop(MainLoop *p_main_loop);
virtual void delete_main_loop(); virtual void delete_main_loop();

View File

@ -47,6 +47,7 @@ typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLX
struct ContextGL_X11_Private { struct ContextGL_X11_Private {
::GLXContext glx_context; ::GLXContext glx_context;
::GLXContext glx_context_offscreen;
}; };
void ContextGL_X11::release_current() { void ContextGL_X11::release_current() {
@ -57,6 +58,18 @@ void ContextGL_X11::make_current() {
glXMakeCurrent(x11_display, x11_window, p->glx_context); glXMakeCurrent(x11_display, x11_window, p->glx_context);
} }
bool ContextGL_X11::is_offscreen_available() const {
return p->glx_context_offscreen;
}
void ContextGL_X11::make_offscreen_current() {
glXMakeCurrent(x11_display, x11_window, p->glx_context_offscreen);
}
void ContextGL_X11::release_offscreen_current() {
glXMakeCurrent(x11_display, None, NULL);
}
void ContextGL_X11::swap_buffers() { void ContextGL_X11::swap_buffers() {
glXSwapBuffers(x11_display, x11_window); glXSwapBuffers(x11_display, x11_window);
} }
@ -181,6 +194,7 @@ Error ContextGL_X11::initialize() {
p->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, nullptr, true, context_attribs); p->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, nullptr, true, context_attribs);
ERR_FAIL_COND_V(ctxErrorOccurred || !p->glx_context, ERR_UNCONFIGURED); ERR_FAIL_COND_V(ctxErrorOccurred || !p->glx_context, ERR_UNCONFIGURED);
p->glx_context_offscreen = glXCreateContextAttribsARB(x11_display, fbconfig, nullptr, true, context_attribs);
} break; } break;
} }
@ -275,12 +289,16 @@ ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, c
glx_minor = glx_major = 0; glx_minor = glx_major = 0;
p = memnew(ContextGL_X11_Private); p = memnew(ContextGL_X11_Private);
p->glx_context = nullptr; p->glx_context = nullptr;
p->glx_context_offscreen = nullptr;
use_vsync = false; use_vsync = false;
} }
ContextGL_X11::~ContextGL_X11() { ContextGL_X11::~ContextGL_X11() {
release_current(); release_current();
glXDestroyContext(x11_display, p->glx_context); glXDestroyContext(x11_display, p->glx_context);
if (p->glx_context_offscreen) {
glXDestroyContext(x11_display, p->glx_context_offscreen);
}
memdelete(p); memdelete(p);
} }

View File

@ -69,6 +69,10 @@ public:
int get_window_height(); int get_window_height();
void *get_glx_context(); void *get_glx_context();
bool is_offscreen_available() const;
void make_offscreen_current();
void release_offscreen_current();
Error initialize(); Error initialize();
void set_use_vsync(bool p_use); void set_use_vsync(bool p_use);

View File

@ -869,6 +869,24 @@ void OS_X11::finalize() {
args.clear(); args.clear();
} }
bool OS_X11::is_offscreen_gl_available() const {
#if defined(OPENGL_ENABLED)
return context_gl->is_offscreen_available();
#else
return false;
#endif
}
void OS_X11::set_offscreen_gl_current(bool p_current) {
#if defined(OPENGL_ENABLED)
if (p_current) {
return context_gl->make_offscreen_current();
} else {
return context_gl->release_offscreen_current();
}
#endif
}
void OS_X11::set_mouse_mode(MouseMode p_mode) { void OS_X11::set_mouse_mode(MouseMode p_mode) {
if (p_mode == mouse_mode) { if (p_mode == mouse_mode) {
return; return;

View File

@ -239,6 +239,9 @@ protected:
virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
virtual void finalize(); virtual void finalize();
virtual bool is_offscreen_gl_available() const;
virtual void set_offscreen_gl_current(bool p_current);
virtual void set_main_loop(MainLoop *p_main_loop); virtual void set_main_loop(MainLoop *p_main_loop);
void _window_changed(XEvent *event); void _window_changed(XEvent *event);