diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 552d59234..1d2bf9b53 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -1602,17 +1602,6 @@ extern "C" { */ #define SDL_HINT_VIDEO_DOUBLE_BUFFER "SDL_VIDEO_DOUBLE_BUFFER" -/** - * \brief A variable controlling whether the EGL window is allowed to be - * composited as transparent, rather than opaque. - * - * Most window systems will always render windows opaque, even if the surface - * format has an alpha channel. This is not always true, however, so by default - * SDL will try to enforce opaque composition. To override this behavior, you - * can set this hint to "1". - */ -#define SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY "SDL_VIDEO_EGL_ALLOW_TRANSPARENCY" - /** * \brief If eglGetPlatformDisplay fails, fall back to calling eglGetDisplay. * diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h index b0f6dbd62..be7289625 100644 --- a/include/SDL3/SDL_video.h +++ b/include/SDL3/SDL_video.h @@ -152,6 +152,7 @@ typedef enum SDL_WINDOW_KEYBOARD_GRABBED = 0x00100000, /**< window has grabbed keyboard input */ SDL_WINDOW_VULKAN = 0x10000000, /**< window usable for Vulkan surface */ SDL_WINDOW_METAL = 0x20000000, /**< window usable for Metal view */ + SDL_WINDOW_TRANSPARENT = 0x40000000, /**< window with transparent buffer */ } SDL_WindowFlags; diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 20f8b35c4..8a927fc22 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -1057,7 +1057,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv *env, j /* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */ if (data->egl_surface == EGL_NO_SURFACE) { - data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)data->native_window); + data->egl_surface = SDL_EGL_CreateSurface(_this, Android_Window, (NativeWindowType)data->native_window); } /* GL Context handling is done in the event loop because this function is run from the Java thread */ diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 69fa33003..b90e05ea0 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -33,7 +33,8 @@ static const char *video_usage[] = { "[--logical-presentation disabled|match|stretch|letterbox|overscan|integer_scale]", "[--logical-scale-quality nearest|linear|best]", "[--scale N]", "[--depth N]", "[--refresh R]", "[--vsync]", "[--noframe]", - "[--resizable]", "[--minimize]", "[--maximize]", "[--grab]", "[--keyboard-grab]", + "[--resizable]", "[--transparent]", + "[--minimize]", "[--maximize]", "[--grab]", "[--keyboard-grab]", "[--hidden]", "[--input-focus]", "[--mouse-focus]", "[--flash-on-focus-loss]", "[--allow-highdpi]", "[--confine-cursor X,Y,W,H]", "[--usable-bounds]" @@ -490,6 +491,10 @@ int SDLTest_CommonArg(SDLTest_CommonState *state, int index) state->window_flags |= SDL_WINDOW_RESIZABLE; return 1; } + if (SDL_strcasecmp(argv[index], "--transparent") == 0) { + state->window_flags |= SDL_WINDOW_TRANSPARENT; + return 1; + } if (SDL_strcasecmp(argv[index], "--minimize") == 0) { state->window_flags |= SDL_WINDOW_MINIMIZED; return 1; diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c index ea9a1d372..857dbce17 100644 --- a/src/video/SDL_egl.c +++ b/src/video/SDL_egl.c @@ -1218,7 +1218,7 @@ int SDL_EGL_DeleteContext(_THIS, SDL_GLContext context) } EGLSurface * -SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) +SDL_EGL_CreateSurface(_THIS, SDL_Window *window, NativeWindowType nw) { #if SDL_VIDEO_DRIVER_ANDROID EGLint format_wanted; @@ -1260,7 +1260,10 @@ SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) #ifdef EGL_EXT_present_opaque if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_EXT_present_opaque")) { - const SDL_bool allow_transparent = SDL_GetHintBoolean(SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, SDL_FALSE); + SDL_bool allow_transparent = SDL_FALSE; + if (window && (window->flags & SDL_WINDOW_TRANSPARENT)) { + allow_transparent = SDL_TRUE; + } attribs[attr++] = EGL_PRESENT_OPAQUE_EXT; attribs[attr++] = allow_transparent ? EGL_FALSE : EGL_TRUE; } diff --git a/src/video/SDL_egl_c.h b/src/video/SDL_egl_c.h index e177b8fd8..603b21663 100644 --- a/src/video/SDL_egl_c.h +++ b/src/video/SDL_egl_c.h @@ -129,7 +129,7 @@ extern int SDL_EGL_ChooseConfig(_THIS); extern int SDL_EGL_SetSwapInterval(_THIS, int interval); extern int SDL_EGL_GetSwapInterval(_THIS, int *interval); extern int SDL_EGL_DeleteContext(_THIS, SDL_GLContext context); -extern EGLSurface *SDL_EGL_CreateSurface(_THIS, NativeWindowType nw); +extern EGLSurface *SDL_EGL_CreateSurface(_THIS, SDL_Window *window, NativeWindowType nw); extern void SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface); extern EGLSurface SDL_EGL_CreateOffscreenSurface(_THIS, int width, int height); diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 762eb7746..fa3ffe68a 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -206,6 +206,7 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U { SDL_RendererInfo info; SDL_WindowTextureData *data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); + const int transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? SDL_TRUE : SDL_FALSE; int i; int w, h; @@ -274,12 +275,12 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U SDL_free(data->pixels); data->pixels = NULL; - /* Find the first format without an alpha channel */ + /* Find the first format with or without an alpha channel */ *format = info.texture_formats[0]; for (i = 0; i < (int)info.num_texture_formats; ++i) { if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) && - !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) { + transparent == SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) { *format = info.texture_formats[i]; break; } @@ -1646,7 +1647,7 @@ Uint32 SDL_GetWindowPixelFormat(SDL_Window *window) } #define CREATE_FLAGS \ - (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL) + (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL | SDL_WINDOW_TRANSPARENT) static SDL_INLINE SDL_bool IsAcceptingDragAndDrop(void) { diff --git a/src/video/android/SDL_androidwindow.c b/src/video/android/SDL_androidwindow.c index c932c34c5..6abc585a7 100644 --- a/src/video/android/SDL_androidwindow.c +++ b/src/video/android/SDL_androidwindow.c @@ -79,7 +79,7 @@ int Android_CreateWindow(_THIS, SDL_Window *window) incompatible with vkCreateAndroidSurfaceKHR */ #if SDL_VIDEO_OPENGL_EGL if (window->flags & SDL_WINDOW_OPENGL) { - data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)data->native_window); + data->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)data->native_window); if (data->egl_surface == EGL_NO_SURFACE) { ANativeWindow_release(data->native_window); diff --git a/src/video/cocoa/SDL_cocoametalview.h b/src/video/cocoa/SDL_cocoametalview.h index d53fc30f9..2712dadd6 100644 --- a/src/video/cocoa/SDL_cocoametalview.h +++ b/src/video/cocoa/SDL_cocoametalview.h @@ -43,7 +43,8 @@ - (instancetype)initWithFrame:(NSRect)frame highDPI:(BOOL)highDPI - windowID:(Uint32)windowID; + windowID:(Uint32)windowID + opaque:(BOOL)opaque; - (void)updateDrawableSize; - (NSView *)hitTest:(NSPoint)point; diff --git a/src/video/cocoa/SDL_cocoametalview.m b/src/video/cocoa/SDL_cocoametalview.m index 71509aec5..d2e3e2ec6 100644 --- a/src/video/cocoa/SDL_cocoametalview.m +++ b/src/video/cocoa/SDL_cocoametalview.m @@ -76,7 +76,8 @@ static int SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event) - (instancetype)initWithFrame:(NSRect)frame highDPI:(BOOL)highDPI - windowID:(Uint32)windowID; + windowID:(Uint32)windowID + opaque:(BOOL)opaque { self = [super initWithFrame:frame]; if (self != nil) { @@ -87,6 +88,8 @@ static int SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event) /* Allow resize. */ self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + self.layer.opaque = opaque; + SDL_AddEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self)); [self updateDrawableSize]; @@ -136,13 +139,15 @@ Cocoa_Metal_CreateView(_THIS, SDL_Window *window) SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata; NSView *view = data.nswindow.contentView; BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; + BOOL opaque = (window->flags & SDL_WINDOW_TRANSPARENT) == 0; Uint32 windowID = SDL_GetWindowID(window); SDL_cocoametalview *newview; SDL_MetalView metalview; newview = [[SDL_cocoametalview alloc] initWithFrame:view.frame highDPI:highDPI - windowID:windowID]; + windowID:windowID + opaque:opaque]; if (newview == nil) { SDL_OutOfMemory(); return NULL; diff --git a/src/video/cocoa/SDL_cocoaopengl.m b/src/video/cocoa/SDL_cocoaopengl.m index 553cfaf62..175dffb16 100644 --- a/src/video/cocoa/SDL_cocoaopengl.m +++ b/src/video/cocoa/SDL_cocoaopengl.m @@ -270,6 +270,7 @@ SDL_GLContext Cocoa_GL_CreateContext(_THIS, SDL_Window *window) int glversion_minor; NSOpenGLPixelFormatAttribute profile; int interval; + int opaque; if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { #if SDL_VIDEO_OPENGL_EGL @@ -381,6 +382,9 @@ SDL_GLContext Cocoa_GL_CreateContext(_THIS, SDL_Window *window) interval = 0; [context setValues:&interval forParameter:NSOpenGLCPSwapInterval]; + opaque = (window->flags & SDL_WINDOW_TRANSPARENT) ? 0 : 1; + [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; + if (Cocoa_GL_MakeCurrent(_this, window, sdlcontext) < 0) { SDL_GL_DeleteContext(sdlcontext); SDL_SetError("Failed making OpenGL context current"); diff --git a/src/video/cocoa/SDL_cocoaopengles.m b/src/video/cocoa/SDL_cocoaopengles.m index 46c0f66c6..8206fe66b 100644 --- a/src/video/cocoa/SDL_cocoaopengles.m +++ b/src/video/cocoa/SDL_cocoaopengles.m @@ -137,7 +137,7 @@ int Cocoa_GLES_SetupWindow(_THIS, SDL_Window *window) /* Create the GLES window surface */ v = windowdata.nswindow.contentView; - windowdata.egl_surface = SDL_EGL_CreateSurface(_this, (__bridge NativeWindowType)[v layer]); + windowdata.egl_surface = SDL_EGL_CreateSurface(_this, window, (__bridge NativeWindowType)[v layer]); if (windowdata.egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create GLES window surface"); diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 02fd42096..c1d4c5946 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -1600,11 +1600,14 @@ static int Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL_ /* Force the graphics context to clear to black so we don't get a flash of white until the app is ready to draw. In practice on modern macOS, this only gets called for window creation and other extraordinary events. */ + BOOL transparent = (_sdlWindow->flags & SDL_WINDOW_TRANSPARENT) != 0; if ([NSGraphicsContext currentContext]) { - [[NSColor blackColor] setFill]; + NSColor *fillColor = transparent ? [NSColor clearColor] : [NSColor blackColor]; + [fillColor setFill]; NSRectFill(dirtyRect); } else if (self.layer) { - self.layer.backgroundColor = CGColorGetConstantColor(kCGColorBlack); + CFStringRef color = transparent ? kCGColorClear : kCGColorBlack; + self.layer.backgroundColor = CGColorGetConstantColor(color); } SDL_SendWindowEvent(_sdlWindow, SDL_EVENT_WINDOW_EXPOSED, 0, 0); @@ -1621,7 +1624,9 @@ static int Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL_ /* Force the graphics context to clear to black so we don't get a flash of white until the app is ready to draw. In practice on modern macOS, this only gets called for window creation and other extraordinary events. */ - self.layer.backgroundColor = CGColorGetConstantColor(kCGColorBlack); + BOOL transparent = (_sdlWindow->flags & SDL_WINDOW_TRANSPARENT) != 0; + CFStringRef color = transparent ? kCGColorClear : kCGColorBlack; + self.layer.backgroundColor = CGColorGetConstantColor(color); ScheduleContextUpdates((__bridge SDL_CocoaWindowData *)_sdlWindow->driverdata); SDL_SendWindowEvent(_sdlWindow, SDL_EVENT_WINDOW_EXPOSED, 0, 0); } @@ -1744,6 +1749,12 @@ static int SetupWindowData(_THIS, SDL_Window *window, NSWindow *nswindow, NSView } } + if (nswindow.isOpaque) { + window->flags &= ~SDL_WINDOW_TRANSPARENT; + } else { + window->flags |= SDL_WINDOW_TRANSPARENT; + } + /* SDL_CocoaWindowData will be holding a strong reference to the NSWindow, and * it will also call [NSWindow close] in DestroyWindow before releasing the * NSWindow, so the extra release provided by releasedWhenClosed isn't @@ -1841,6 +1852,12 @@ int Cocoa_CreateWindow(_THIS, SDL_Window *window) [nswindow setLevel:NSFloatingWindowLevel]; } + if (window->flags & SDL_WINDOW_TRANSPARENT) { + nswindow.opaque = NO; + nswindow.hasShadow = NO; + nswindow.backgroundColor = [NSColor clearColor]; + } + /* Create a default view for this window */ rect = [nswindow contentRectForFrameRect:[nswindow frame]]; contentView = [[SDLView alloc] initWithFrame:rect]; diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c index 24b66e92e..d8ac3f583 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c @@ -1198,7 +1198,7 @@ int KMSDRM_CreateSurfaces(_THIS, SDL_Window *window) but we need an EGL surface NOW, or GL won't be able to render into any surface and we won't see the first frame. */ SDL_EGL_SetRequiredVisualId(_this, surface_fmt); - windata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windata->gs); + windata->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)windata->gs); if (windata->egl_surface == EGL_NO_SURFACE) { ret = SDL_SetError("Could not create EGL window surface"); diff --git a/src/video/raspberry/SDL_rpivideo.c b/src/video/raspberry/SDL_rpivideo.c index 6c4af7d09..e9a584799 100644 --- a/src/video/raspberry/SDL_rpivideo.c +++ b/src/video/raspberry/SDL_rpivideo.c @@ -287,7 +287,7 @@ int RPI_CreateWindow(_THIS, SDL_Window *window) return -1; } } - wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)&wdata->dispman_window); + wdata->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)&wdata->dispman_window); if (wdata->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create GLES window surface"); diff --git a/src/video/vita/SDL_vitavideo.c b/src/video/vita/SDL_vitavideo.c index 6712e2cde..05e647cf3 100644 --- a/src/video/vita/SDL_vitavideo.c +++ b/src/video/vita/SDL_vitavideo.c @@ -275,7 +275,7 @@ int VITA_CreateWindow(_THIS, SDL_Window *window) _this->gl_config.minor_version = 1; _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; } - wdata->egl_surface = SDL_EGL_CreateSurface(_this, &win); + wdata->egl_surface = SDL_EGL_CreateSurface(_this, window, &win); if (wdata->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create GLES window surface"); } diff --git a/src/video/vivante/SDL_vivantevideo.c b/src/video/vivante/SDL_vivantevideo.c index ccf5b4e6f..41da76ebf 100644 --- a/src/video/vivante/SDL_vivantevideo.c +++ b/src/video/vivante/SDL_vivantevideo.c @@ -267,7 +267,7 @@ int VIVANTE_CreateWindow(_THIS, SDL_Window *window) #if SDL_VIDEO_OPENGL_EGL if (window->flags & SDL_WINDOW_OPENGL) { - data->egl_surface = SDL_EGL_CreateSurface(_this, data->native_window); + data->egl_surface = SDL_EGL_CreateSurface(_this, window, data->native_window); if (data->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("VIVANTE: Can't create EGL surface"); } diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index aa4ec89a0..1f42324e0 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -948,7 +948,6 @@ int Wayland_VideoInit(_THIS) WAYLAND_wl_display_flush(data->display); Wayland_InitKeyboard(_this); - Wayland_InitWin(data); data->initializing = SDL_FALSE; @@ -981,7 +980,6 @@ static void Wayland_VideoCleanup(_THIS) SDL_VideoData *data = _this->driverdata; int i, j; - Wayland_QuitWin(data); Wayland_FiniMouse(data); for (i = _this->num_displays - 1; i >= 0; --i) { diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index 12530ad49..46fd82dc9 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -97,7 +97,6 @@ struct SDL_VideoData char *classname; int relative_mouse_mode; - SDL_bool egl_transparency_enabled; }; struct SDL_DisplayData diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 46f5891a5..70ef278b4 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -224,7 +224,7 @@ static void ConfigureWindowGeometry(SDL_Window *window) xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, data->wl_window_width, data->wl_window_height); } - if (!viddata->egl_transparency_enabled) { + if (!(window->flags & SDL_WINDOW_TRANSPARENT)) { region = wl_compositor_create_region(viddata->compositor); wl_region_add(region, 0, 0, data->wl_window_width, data->wl_window_height); @@ -2010,12 +2010,18 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) } #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + if (window->flags & SDL_WINDOW_TRANSPARENT) { + if (_this->gl_config.alpha_size == 0) { + _this->gl_config.alpha_size = 8; + } + } + if (window->flags & SDL_WINDOW_OPENGL) { data->egl_window = WAYLAND_wl_egl_window_create(data->surface, data->drawable_width, data->drawable_height); #if SDL_VIDEO_OPENGL_EGL /* Create the GLES window surface */ - data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)data->egl_window); + data->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)data->egl_window); if (data->egl_surface == EGL_NO_SURFACE) { return -1; /* SDL_EGL_CreateSurface should have set error */ @@ -2247,43 +2253,4 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window) window->driverdata = NULL; } -static void EGLTransparencyChangedCallback(void *userdata, const char *name, const char *oldValue, const char *newValue) -{ - const SDL_bool oldval = SDL_GetStringBoolean(oldValue, SDL_FALSE); - const SDL_bool newval = SDL_GetStringBoolean(newValue, SDL_FALSE); - - if (oldval != newval) { - SDL_Window *window; - SDL_VideoData *viddata = (SDL_VideoData *)userdata; - SDL_VideoDevice *dev = SDL_GetVideoDevice(); - - viddata->egl_transparency_enabled = newval; - - /* Iterate over all windows and update the surface opaque regions */ - for (window = dev->windows; window != NULL; window = window->next) { - SDL_WindowData *wind = window->driverdata; - - if (!newval) { - struct wl_region *region = wl_compositor_create_region(wind->waylandData->compositor); - wl_region_add(region, 0, 0, wind->wl_window_width, wind->wl_window_height); - wl_surface_set_opaque_region(wind->surface, region); - wl_region_destroy(region); - } else { - wl_surface_set_opaque_region(wind->surface, NULL); - } - } - } -} - -void Wayland_InitWin(SDL_VideoData *data) -{ - data->egl_transparency_enabled = SDL_GetHintBoolean(SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, SDL_FALSE); - SDL_AddHintCallback(SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, EGLTransparencyChangedCallback, data); -} - -void Wayland_QuitWin(SDL_VideoData *data) -{ - SDL_DelHintCallback(SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, EGLTransparencyChangedCallback, data); -} - #endif /* SDL_VIDEO_DRIVER_WAYLAND */ diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index 16271056b..7d17be72a 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -155,7 +155,4 @@ extern int Wayland_GetWindowWMInfo(_THIS, SDL_Window *window, SDL_SysWMinfo *inf extern int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled); extern int Wayland_FlashWindow(_THIS, SDL_Window *window, SDL_FlashOperation operation); -extern void Wayland_InitWin(SDL_VideoData *data); -extern void Wayland_QuitWin(SDL_VideoData *data); - #endif /* SDL_waylandwindow_h_ */ diff --git a/src/video/windows/SDL_windowsopengles.c b/src/video/windows/SDL_windowsopengles.c index c05b53b15..7d1819540 100644 --- a/src/video/windows/SDL_windowsopengles.c +++ b/src/video/windows/SDL_windowsopengles.c @@ -125,7 +125,7 @@ int WIN_GLES_SetupWindow(_THIS, SDL_Window *window) } /* Create the GLES window surface */ - windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windowdata->hwnd); + windowdata->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)windowdata->hwnd); if (windowdata->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create GLES window surface"); diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c index 0c09a8c70..8f35b0cab 100644 --- a/src/video/x11/SDL_x11opengl.c +++ b/src/video/x11/SDL_x11opengl.c @@ -345,7 +345,7 @@ static void X11_GL_InitExtensions(_THIS) const char *(*glXQueryExtensionsStringFunc)(Display *, int); const char *extensions; - vinfo = X11_GL_GetVisual(_this, display, screen); + vinfo = X11_GL_GetVisual(_this, display, screen, SDL_FALSE); if (vinfo) { GLXContext (*glXGetCurrentContextFunc)(void) = (GLXContext(*)(void)) @@ -484,7 +484,7 @@ static void X11_GL_InitExtensions(_THIS) * In case of failure, if that pointer is not NULL, set that pointer to None * and try again. */ -static int X11_GL_GetAttributes(_THIS, Display *display, int screen, int *attribs, int size, Bool for_FBConfig, int **_pvistypeattr) +static int X11_GL_GetAttributes(_THIS, Display *display, int screen, int *attribs, int size, Bool for_FBConfig, int **_pvistypeattr, SDL_bool transparent) { int i = 0; const int MAX_ATTRIBUTES = 64; @@ -583,13 +583,15 @@ static int X11_GL_GetAttributes(_THIS, Display *display, int screen, int *attrib attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT : GLX_SLOW_VISUAL_EXT; } - /* If we're supposed to use DirectColor visuals, and we've got the - EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */ - if (X11_UseDirectColorVisuals() && - _this->gl_data->HAS_GLX_EXT_visual_info) { - pvistypeattr = &attribs[i]; - attribs[i++] = GLX_X_VISUAL_TYPE_EXT; - attribs[i++] = GLX_DIRECT_COLOR_EXT; + /* Un-wanted when we request a transparent buffer */ + if (!transparent) { + /* If we're supposed to use DirectColor visuals, and we've got the + EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */ + if (X11_UseDirectColorVisuals() && _this->gl_data->HAS_GLX_EXT_visual_info) { + pvistypeattr = &attribs[i]; + attribs[i++] = GLX_X_VISUAL_TYPE_EXT; + attribs[i++] = GLX_DIRECT_COLOR_EXT; + } } attribs[i++] = None; @@ -603,7 +605,7 @@ static int X11_GL_GetAttributes(_THIS, Display *display, int screen, int *attrib return i; } -XVisualInfo *X11_GL_GetVisual(_THIS, Display *display, int screen) +XVisualInfo *X11_GL_GetVisual(_THIS, Display *display, int screen, SDL_bool transparent) { /* 64 seems nice. */ int attribs[64]; @@ -620,13 +622,30 @@ XVisualInfo *X11_GL_GetVisual(_THIS, Display *display, int screen) GLXFBConfig *framebuffer_config = NULL; int fbcount = 0; - X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_TRUE, &pvistypeattr); + X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_TRUE, &pvistypeattr, transparent); framebuffer_config = _this->gl_data->glXChooseFBConfig(display, screen, attribs, &fbcount); if (!framebuffer_config && (pvistypeattr != NULL)) { *pvistypeattr = None; framebuffer_config = _this->gl_data->glXChooseFBConfig(display, screen, attribs, &fbcount); } + if (transparent) { + /* Return the first transparent Visual */ + int i; + for (i = 0; i < fbcount; i++) { + Uint32 format; + vinfo = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[i]); + format = X11_GetPixelFormatFromVisualInfo(display, vinfo); + if (SDL_ISPIXELFORMAT_ALPHA(format)) { /* found! */ + X11_XFree(framebuffer_config); + framebuffer_config = NULL; + break; + } + X11_XFree(vinfo); + vinfo = NULL; + } + } + if (framebuffer_config) { vinfo = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[0]); } @@ -635,7 +654,7 @@ XVisualInfo *X11_GL_GetVisual(_THIS, Display *display, int screen) } if (!vinfo) { - X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr); + X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr, transparent); vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs); if (!vinfo && (pvistypeattr != NULL)) { @@ -696,6 +715,7 @@ SDL_GLContext X11_GL_CreateContext(_THIS, SDL_Window *window) XVisualInfo v, *vinfo; int n; GLXContext context = NULL, share_context; + const int transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? SDL_TRUE : SDL_FALSE; if (_this->gl_config.share_with_current_context) { share_context = (GLXContext)SDL_GL_GetCurrentContext(); @@ -716,7 +736,7 @@ SDL_GLContext X11_GL_CreateContext(_THIS, SDL_Window *window) if (vinfo) { if (_this->gl_config.major_version < 3 && _this->gl_config.profile_mask == 0 && - _this->gl_config.flags == 0) { + _this->gl_config.flags == 0 && !transparent) { /* Create legacy context */ context = _this->gl_data->glXCreateContext(display, vinfo, share_context, True); @@ -776,7 +796,7 @@ SDL_GLContext X11_GL_CreateContext(_THIS, SDL_Window *window) int fbcount = 0; int *pvistypeattr = NULL; - X11_GL_GetAttributes(_this, display, screen, glxAttribs, 64, SDL_TRUE, &pvistypeattr); + X11_GL_GetAttributes(_this, display, screen, glxAttribs, 64, SDL_TRUE, &pvistypeattr, transparent); if (_this->gl_data->glXChooseFBConfig) { framebuffer_config = _this->gl_data->glXChooseFBConfig(display, diff --git a/src/video/x11/SDL_x11opengl.h b/src/video/x11/SDL_x11opengl.h index af6c13664..08569739a 100644 --- a/src/video/x11/SDL_x11opengl.h +++ b/src/video/x11/SDL_x11opengl.h @@ -72,7 +72,7 @@ extern int X11_GL_LoadLibrary(_THIS, const char *path); extern SDL_FunctionPointer X11_GL_GetProcAddress(_THIS, const char *proc); extern void X11_GL_UnloadLibrary(_THIS); extern SDL_bool X11_GL_UseEGL(_THIS); -extern XVisualInfo *X11_GL_GetVisual(_THIS, Display *display, int screen); +extern XVisualInfo *X11_GL_GetVisual(_THIS, Display *display, int screen, SDL_bool transparent); extern SDL_GLContext X11_GL_CreateContext(_THIS, SDL_Window *window); extern int X11_GL_MakeCurrent(_THIS, SDL_Window *window, SDL_GLContext context); diff --git a/src/video/x11/SDL_x11opengles.c b/src/video/x11/SDL_x11opengles.c index ffa68869b..fd5801523 100644 --- a/src/video/x11/SDL_x11opengles.c +++ b/src/video/x11/SDL_x11opengles.c @@ -56,7 +56,7 @@ int X11_GLES_LoadLibrary(_THIS, const char *path) } XVisualInfo * -X11_GLES_GetVisual(_THIS, Display *display, int screen) +X11_GLES_GetVisual(_THIS, Display *display, int screen, SDL_bool transparent) { XVisualInfo *egl_visualinfo = NULL; @@ -79,6 +79,23 @@ X11_GLES_GetVisual(_THIS, Display *display, int screen) egl_visualinfo = X11_XGetVisualInfo(display, VisualScreenMask, &vi_in, &out_count); + + /* Return the first transparent Visual */ + if (transparent) { + int i; + for (i = 0; i < out_count; i++) { + XVisualInfo *v = &egl_visualinfo[i]; + Uint32 format = X11_GetPixelFormatFromVisualInfo(display, v); + if (SDL_ISPIXELFORMAT_ALPHA(format)) { /* found! */ + /* re-request it to have a copy that can be X11_XFree'ed later */ + vi_in.screen = screen; + vi_in.visualid = v->visualid; + X11_XFree(egl_visualinfo); + egl_visualinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &vi_in, &out_count); + return egl_visualinfo; + } + } + } } else { vi_in.screen = screen; vi_in.visualid = visual_id; diff --git a/src/video/x11/SDL_x11opengles.h b/src/video/x11/SDL_x11opengles.h index 9c64fd220..c63a083af 100644 --- a/src/video/x11/SDL_x11opengles.h +++ b/src/video/x11/SDL_x11opengles.h @@ -44,7 +44,7 @@ typedef struct SDL_PrivateGLESData #define X11_GLES_DeleteContext SDL_EGL_DeleteContext extern int X11_GLES_LoadLibrary(_THIS, const char *path); -extern XVisualInfo *X11_GLES_GetVisual(_THIS, Display *display, int screen); +extern XVisualInfo *X11_GLES_GetVisual(_THIS, Display *display, int screen, SDL_bool transparent); extern SDL_GLContext X11_GLES_CreateContext(_THIS, SDL_Window *window); extern int X11_GLES_SwapWindow(_THIS, SDL_Window *window); extern int X11_GLES_MakeCurrent(_THIS, SDL_Window *window, SDL_GLContext context); diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 0117d5b16..867dc0e6e 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -431,6 +431,7 @@ int X11_CreateWindow(_THIS, SDL_Window *window) SDL_WindowData *windowdata; Display *display = data->display; int screen = displaydata->screen; + const int transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? SDL_TRUE : SDL_FALSE; Visual *visual; int depth; XSetWindowAttributes xattr; @@ -477,12 +478,12 @@ int X11_CreateWindow(_THIS, SDL_Window *window) && (!_this->gl_data || X11_GL_UseEGL(_this)) #endif ) { - vinfo = X11_GLES_GetVisual(_this, display, screen); + vinfo = X11_GLES_GetVisual(_this, display, screen, transparent); } else #endif { #if SDL_VIDEO_OPENGL_GLX - vinfo = X11_GL_GetVisual(_this, display, screen); + vinfo = X11_GL_GetVisual(_this, display, screen, transparent); #endif } @@ -720,7 +721,7 @@ int X11_CreateWindow(_THIS, SDL_Window *window) } /* Create the GLES window surface */ - windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)w); + windowdata->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)w); if (windowdata->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create GLES window surface"); diff --git a/test/testgl.c b/test/testgl.c index 7d042c795..f082f022a 100644 --- a/test/testgl.c +++ b/test/testgl.c @@ -92,7 +92,7 @@ static void Render(void) }; /* Do our drawing, too. */ - ctx.glClearColor(0.0, 0.0, 0.0, 1.0); + ctx.glClearColor(0.0, 0.0, 0.0, 0.0 /* used with --transparent */); ctx.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ctx.glBegin(GL_QUADS); diff --git a/test/testsprite.c b/test/testsprite.c index 75ac45d14..175d81dc9 100644 --- a/test/testsprite.c +++ b/test/testsprite.c @@ -126,7 +126,7 @@ static void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite) } /* Draw a gray background */ - SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); + SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0x00 /* used with --transparent */); SDL_RenderClear(renderer); /* Test points */ diff --git a/test/testvulkan.c b/test/testvulkan.c index 690f577d2..27194485e 100644 --- a/test/testvulkan.c +++ b/test/testvulkan.c @@ -624,6 +624,7 @@ static SDL_bool createSwapchain(void) int w, h; VkSwapchainCreateInfoKHR createInfo = { 0 }; VkResult result; + Uint32 flags; // pick an image count vulkanContext->swapchainDesiredImageCount = vulkanContext->surfaceCapabilities.minImageCount + 1; @@ -651,6 +652,9 @@ static SDL_bool createSwapchain(void) // get size SDL_GetWindowSizeInPixels(vulkanContext->window, &w, &h); + // get flags + flags = SDL_GetWindowFlags(vulkanContext->window); + // Clamp the size to the allowable image extent. // SDL_GetWindowSizeInPixels()'s result it not always in this range (bug #3287) vulkanContext->swapchainSize.width = SDL_clamp((uint32_t)w, @@ -677,7 +681,11 @@ static SDL_bool createSwapchain(void) createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.preTransform = vulkanContext->surfaceCapabilities.currentTransform; - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + if (flags & SDL_WINDOW_TRANSPARENT) { + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; + } else { + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + } createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; createInfo.clipped = VK_TRUE; createInfo.oldSwapchain = vulkanContext->swapchain; @@ -1037,7 +1045,7 @@ static SDL_bool render(void) clearColor.float32[0] = (float)(0.5 + 0.5 * SDL_sin(currentTime)); clearColor.float32[1] = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 2 / 3)); clearColor.float32[2] = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 4 / 3)); - clearColor.float32[3] = 1; + clearColor.float32[3] = 0.5; // for SDL_WINDOW_TRANSPARENT, ignored with VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR rerecordCommandBuffer(frameIndex, &clearColor); submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.waitSemaphoreCount = 1;