diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h index 13bb8e4a7..1000ee5f3 100644 --- a/cogl/cogl-context-private.h +++ b/cogl/cogl-context-private.h @@ -222,6 +222,11 @@ struct _CoglContext CoglGLES2Context *current_gles2_context; GQueue gles2_context_stack; + /* This becomes TRUE the first time the context is bound to an + * onscreen buffer. This is used by cogl-framebuffer-gl to determine + * when to initialise the glDrawBuffer state */ + CoglBool was_bound_to_onscreen; + /* Primitives */ CoglPath *current_path; CoglPipeline *stencil_pipeline; diff --git a/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/driver/gl/cogl-framebuffer-gl.c index 03a4a1255..c0f094d58 100644 --- a/cogl/driver/gl/cogl-framebuffer-gl.c +++ b/cogl/driver/gl/cogl-framebuffer-gl.c @@ -255,6 +255,35 @@ _cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target) /* glBindFramebuffer is an an extension with OpenGL ES 1.1 */ if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) GE (ctx, glBindFramebuffer (target, 0)); + + /* Initialise the glDrawBuffer state the first time the context + * is bound to the default framebuffer. If the winsys is using a + * surfaceless context for the initial make current then the + * default draw buffer will be GL_NONE so we need to correct + * that. We can't do it any earlier because binding GL_BACK when + * there is no default framebuffer won't work */ + if (!ctx->was_bound_to_onscreen) + { + if (ctx->glDrawBuffer) + { + GE (ctx, glDrawBuffer (GL_BACK)); + } + else if (ctx->glDrawBuffers) + { + /* glDrawBuffer isn't available on GLES 3.0 so we need + * to be able to use glDrawBuffers as well. On GLES 2 + * neither is available but the state should always be + * GL_BACK anyway so we don't need to set anything. On + * desktop GL this must be GL_BACK_LEFT instead of + * GL_BACK but as this code path will only be hit for + * GLES we can just use GL_BACK. */ + static const GLenum buffers[] = { GL_BACK }; + + GE (ctx, glDrawBuffers (G_N_ELEMENTS (buffers), buffers)); + } + + ctx->was_bound_to_onscreen = TRUE; + } } } diff --git a/cogl/gl-prototypes/cogl-all-functions.h b/cogl/gl-prototypes/cogl-all-functions.h index e3c81d503..dda08f762 100644 --- a/cogl/gl-prototypes/cogl-all-functions.h +++ b/cogl/gl-prototypes/cogl-all-functions.h @@ -318,3 +318,11 @@ COGL_EXT_FUNCTION (void, glDeleteSync, (GLsync sync)) COGL_EXT_END () #endif + +COGL_EXT_BEGIN (draw_buffers, 2, 0, + COGL_EXT_IN_GLES3, + "ARB\0EXT\0", + "draw_buffers\0") +COGL_EXT_FUNCTION (void, glDrawBuffers, + (GLsizei n, const GLenum *bufs)) +COGL_EXT_END () diff --git a/cogl/winsys/cogl-winsys-egl-feature-functions.h b/cogl/winsys/cogl-winsys-egl-feature-functions.h index dab52c839..17a99f269 100644 --- a/cogl/winsys/cogl-winsys-egl-feature-functions.h +++ b/cogl/winsys/cogl-winsys-egl-feature-functions.h @@ -141,3 +141,9 @@ COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglDestroySync, EGLSyncKHR sync)) COGL_WINSYS_FEATURE_END () #endif + +COGL_WINSYS_FEATURE_BEGIN (surfaceless_context, + "KHR\0", + "surfaceless_context\0", + COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) +COGL_WINSYS_FEATURE_END () diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c index ec54095c6..a475c55a7 100644 --- a/cogl/winsys/cogl-winsys-egl-kms.c +++ b/cogl/winsys/cogl-winsys-egl-kms.c @@ -782,29 +782,35 @@ _cogl_winsys_egl_context_created (CoglDisplay *display, CoglRendererEGL *egl_renderer = renderer->winsys; CoglRendererKMS *kms_renderer = egl_renderer->platform; - kms_display->dummy_gbm_surface = gbm_surface_create (kms_renderer->gbm, - 16, 16, - GBM_FORMAT_XRGB8888, - GBM_BO_USE_RENDERING); - if (!kms_display->dummy_gbm_surface) + if ((egl_renderer->private_features & + COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0) { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_CONTEXT, - "Failed to create dummy GBM surface"); - return FALSE; - } + kms_display->dummy_gbm_surface = + gbm_surface_create (kms_renderer->gbm, + 16, 16, + GBM_FORMAT_XRGB8888, + GBM_BO_USE_RENDERING); + if (!kms_display->dummy_gbm_surface) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to create dummy GBM surface"); + return FALSE; + } - egl_display->dummy_surface = - eglCreateWindowSurface (egl_renderer->edpy, - egl_display->egl_config, - (EGLNativeWindowType) kms_display->dummy_gbm_surface, - NULL); - if (egl_display->dummy_surface == EGL_NO_SURFACE) - { - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_CONTEXT, - "Failed to create dummy EGL surface"); - return FALSE; + egl_display->dummy_surface = + eglCreateWindowSurface (egl_renderer->edpy, + egl_display->egl_config, + (EGLNativeWindowType) + kms_display->dummy_gbm_surface, + NULL); + if (egl_display->dummy_surface == EGL_NO_SURFACE) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Failed to create dummy EGL surface"); + return FALSE; + } } if (!_cogl_winsys_egl_make_current (display, diff --git a/cogl/winsys/cogl-winsys-egl-private.h b/cogl/winsys/cogl-winsys-egl-private.h index 8a668cf6d..5d21b4f4e 100644 --- a/cogl/winsys/cogl-winsys-egl-private.h +++ b/cogl/winsys/cogl-winsys-egl-private.h @@ -99,7 +99,8 @@ typedef enum _CoglEGLWinsysFeature COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_WAYLAND_BUFFER =1L<<2, COGL_EGL_WINSYS_FEATURE_CREATE_CONTEXT =1L<<3, COGL_EGL_WINSYS_FEATURE_BUFFER_AGE =1L<<4, - COGL_EGL_WINSYS_FEATURE_FENCE_SYNC =1L<<5 + COGL_EGL_WINSYS_FEATURE_FENCE_SYNC =1L<<5, + COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT =1L<<6 } CoglEGLWinsysFeature; typedef struct _CoglRendererEGL diff --git a/cogl/winsys/cogl-winsys-egl-wayland.c b/cogl/winsys/cogl-winsys-egl-wayland.c index 2b359cb1d..93a845192 100644 --- a/cogl/winsys/cogl-winsys-egl-wayland.c +++ b/cogl/winsys/cogl-winsys-egl-wayland.c @@ -64,8 +64,8 @@ typedef struct _CoglRendererWayland typedef struct _CoglDisplayWayland { - struct wl_surface *wayland_surface; - struct wl_egl_window *wayland_egl_native_window; + struct wl_surface *dummy_wayland_surface; + struct wl_egl_window *dummy_wayland_egl_native_window; } CoglDisplayWayland; typedef struct _CoglOnscreenWayland @@ -324,8 +324,8 @@ _cogl_winsys_egl_display_destroy (CoglDisplay *display) } static CoglBool -_cogl_winsys_egl_context_created (CoglDisplay *display, - CoglError **error) +make_dummy_surface (CoglDisplay *display, + CoglError **error) { CoglRenderer *renderer = display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; @@ -334,19 +334,19 @@ _cogl_winsys_egl_context_created (CoglDisplay *display, CoglDisplayWayland *wayland_display = egl_display->platform; const char *error_message; - wayland_display->wayland_surface = + wayland_display->dummy_wayland_surface = wl_compositor_create_surface (wayland_renderer->wayland_compositor); - if (!wayland_display->wayland_surface) + if (!wayland_display->dummy_wayland_surface) { error_message= "Failed to create a dummy wayland surface"; goto fail; } - wayland_display->wayland_egl_native_window = - wl_egl_window_create (wayland_display->wayland_surface, + wayland_display->dummy_wayland_egl_native_window = + wl_egl_window_create (wayland_display->dummy_wayland_surface, 1, 1); - if (!wayland_display->wayland_egl_native_window) + if (!wayland_display->dummy_wayland_egl_native_window) { error_message= "Failed to create a dummy wayland native egl surface"; goto fail; @@ -356,7 +356,7 @@ _cogl_winsys_egl_context_created (CoglDisplay *display, eglCreateWindowSurface (egl_renderer->edpy, egl_display->egl_config, (EGLNativeWindowType) - wayland_display->wayland_egl_native_window, + wayland_display->dummy_wayland_egl_native_window, NULL); if (egl_display->dummy_surface == EGL_NO_SURFACE) { @@ -364,22 +364,42 @@ _cogl_winsys_egl_context_created (CoglDisplay *display, goto fail; } + return TRUE; + + fail: + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "%s", error_message); + + return FALSE; +} + +static CoglBool +_cogl_winsys_egl_context_created (CoglDisplay *display, + CoglError **error) +{ + CoglRenderer *renderer = display->renderer; + CoglRendererEGL *egl_renderer = renderer->winsys; + CoglDisplayEGL *egl_display = display->winsys; + + if ((egl_renderer->private_features & + COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0 && + !make_dummy_surface(display, error)) + return FALSE; + if (!_cogl_winsys_egl_make_current (display, egl_display->dummy_surface, egl_display->dummy_surface, egl_display->egl_context)) { - error_message = "Unable to eglMakeCurrent with dummy surface"; - goto fail; + _cogl_set_error (error, + COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "%s", + "Unable to eglMakeCurrent with dummy surface"); } return TRUE; - - fail: - _cogl_set_error (error, COGL_WINSYS_ERROR, - COGL_WINSYS_ERROR_CREATE_CONTEXT, - "%s", error_message); - return FALSE; } static void @@ -396,16 +416,16 @@ _cogl_winsys_egl_cleanup_context (CoglDisplay *display) egl_display->dummy_surface = EGL_NO_SURFACE; } - if (wayland_display->wayland_egl_native_window) + if (wayland_display->dummy_wayland_egl_native_window) { - wl_egl_window_destroy (wayland_display->wayland_egl_native_window); - wayland_display->wayland_egl_native_window = NULL; + wl_egl_window_destroy (wayland_display->dummy_wayland_egl_native_window); + wayland_display->dummy_wayland_egl_native_window = NULL; } - if (wayland_display->wayland_surface) + if (wayland_display->dummy_wayland_surface) { - wl_surface_destroy (wayland_display->wayland_surface); - wayland_display->wayland_surface = NULL; + wl_surface_destroy (wayland_display->dummy_wayland_surface); + wayland_display->dummy_wayland_surface = NULL; } } diff --git a/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/winsys/cogl-winsys-egl-x11.c index 5d2a858e5..26c960689 100644 --- a/cogl/winsys/cogl-winsys-egl-x11.c +++ b/cogl/winsys/cogl-winsys-egl-x11.c @@ -611,39 +611,47 @@ _cogl_winsys_egl_context_created (CoglDisplay *display, AllocNone); attrs.border_pixel = 0; - xlib_display->dummy_xwin = - XCreateWindow (xlib_renderer->xdpy, - DefaultRootWindow (xlib_renderer->xdpy), - -100, -100, 1, 1, - 0, - xvisinfo->depth, - CopyFromParent, - xvisinfo->visual, - CWOverrideRedirect | - CWColormap | - CWBorderPixel, - &attrs); + if ((egl_renderer->private_features & + COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0) + { + xlib_display->dummy_xwin = + XCreateWindow (xlib_renderer->xdpy, + DefaultRootWindow (xlib_renderer->xdpy), + -100, -100, 1, 1, + 0, + xvisinfo->depth, + CopyFromParent, + xvisinfo->visual, + CWOverrideRedirect | + CWColormap | + CWBorderPixel, + &attrs); + + egl_display->dummy_surface = + eglCreateWindowSurface (egl_renderer->edpy, + egl_display->egl_config, + (EGLNativeWindowType) xlib_display->dummy_xwin, + NULL); + + if (egl_display->dummy_surface == EGL_NO_SURFACE) + { + error_message = "Unable to create an EGL surface"; + XFree (xvisinfo); + goto fail; + } + } XFree (xvisinfo); - egl_display->dummy_surface = - eglCreateWindowSurface (egl_renderer->edpy, - egl_display->egl_config, - (EGLNativeWindowType) xlib_display->dummy_xwin, - NULL); - - if (egl_display->dummy_surface == EGL_NO_SURFACE) - { - error_message = "Unable to create an EGL surface"; - goto fail; - } - if (!_cogl_winsys_egl_make_current (display, egl_display->dummy_surface, egl_display->dummy_surface, egl_display->egl_context)) { - error_message = "Unable to eglMakeCurrent with dummy surface"; + if (egl_display->dummy_surface == EGL_NO_SURFACE) + error_message = "Unable to eglMakeCurrent with no surface"; + else + error_message = "Unable to eglMakeCurrent with dummy surface"; goto fail; }