- Added SDL_WINDOW_TRANSPARENT to request a window with transparent framebuffer

- Remove SDL_VIDEO_EGL_ALLOW_TRANSPARENCY hint, EGL now checks 'window->flags & SDL_WINDOW_TRANSPARENT'
main
Sylvain 2023-03-11 13:53:14 +01:00 committed by Sylvain Becker
parent 4dededd345
commit 2cafa52598
30 changed files with 136 additions and 103 deletions

View File

@ -1602,17 +1602,6 @@ extern "C" {
*/ */
#define SDL_HINT_VIDEO_DOUBLE_BUFFER "SDL_VIDEO_DOUBLE_BUFFER" #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. * \brief If eglGetPlatformDisplay fails, fall back to calling eglGetDisplay.
* *

View File

@ -152,6 +152,7 @@ typedef enum
SDL_WINDOW_KEYBOARD_GRABBED = 0x00100000, /**< window has grabbed keyboard input */ SDL_WINDOW_KEYBOARD_GRABBED = 0x00100000, /**< window has grabbed keyboard input */
SDL_WINDOW_VULKAN = 0x10000000, /**< window usable for Vulkan surface */ SDL_WINDOW_VULKAN = 0x10000000, /**< window usable for Vulkan surface */
SDL_WINDOW_METAL = 0x20000000, /**< window usable for Metal view */ SDL_WINDOW_METAL = 0x20000000, /**< window usable for Metal view */
SDL_WINDOW_TRANSPARENT = 0x40000000, /**< window with transparent buffer */
} SDL_WindowFlags; } SDL_WindowFlags;

View File

@ -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 the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
if (data->egl_surface == EGL_NO_SURFACE) { 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 */ /* GL Context handling is done in the event loop because this function is run from the Java thread */

View File

@ -33,7 +33,8 @@ static const char *video_usage[] = {
"[--logical-presentation disabled|match|stretch|letterbox|overscan|integer_scale]", "[--logical-presentation disabled|match|stretch|letterbox|overscan|integer_scale]",
"[--logical-scale-quality nearest|linear|best]", "[--logical-scale-quality nearest|linear|best]",
"[--scale N]", "[--depth N]", "[--refresh R]", "[--vsync]", "[--noframe]", "[--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]", "[--hidden]", "[--input-focus]", "[--mouse-focus]",
"[--flash-on-focus-loss]", "[--allow-highdpi]", "[--confine-cursor X,Y,W,H]", "[--flash-on-focus-loss]", "[--allow-highdpi]", "[--confine-cursor X,Y,W,H]",
"[--usable-bounds]" "[--usable-bounds]"
@ -490,6 +491,10 @@ int SDLTest_CommonArg(SDLTest_CommonState *state, int index)
state->window_flags |= SDL_WINDOW_RESIZABLE; state->window_flags |= SDL_WINDOW_RESIZABLE;
return 1; return 1;
} }
if (SDL_strcasecmp(argv[index], "--transparent") == 0) {
state->window_flags |= SDL_WINDOW_TRANSPARENT;
return 1;
}
if (SDL_strcasecmp(argv[index], "--minimize") == 0) { if (SDL_strcasecmp(argv[index], "--minimize") == 0) {
state->window_flags |= SDL_WINDOW_MINIMIZED; state->window_flags |= SDL_WINDOW_MINIMIZED;
return 1; return 1;

View File

@ -1218,7 +1218,7 @@ int SDL_EGL_DeleteContext(_THIS, SDL_GLContext context)
} }
EGLSurface * EGLSurface *
SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) SDL_EGL_CreateSurface(_THIS, SDL_Window *window, NativeWindowType nw)
{ {
#if SDL_VIDEO_DRIVER_ANDROID #if SDL_VIDEO_DRIVER_ANDROID
EGLint format_wanted; EGLint format_wanted;
@ -1260,7 +1260,10 @@ SDL_EGL_CreateSurface(_THIS, NativeWindowType nw)
#ifdef EGL_EXT_present_opaque #ifdef EGL_EXT_present_opaque
if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "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++] = EGL_PRESENT_OPAQUE_EXT;
attribs[attr++] = allow_transparent ? EGL_FALSE : EGL_TRUE; attribs[attr++] = allow_transparent ? EGL_FALSE : EGL_TRUE;
} }

View File

@ -129,7 +129,7 @@ extern int SDL_EGL_ChooseConfig(_THIS);
extern int SDL_EGL_SetSwapInterval(_THIS, int interval); extern int SDL_EGL_SetSwapInterval(_THIS, int interval);
extern int SDL_EGL_GetSwapInterval(_THIS, int *interval); extern int SDL_EGL_GetSwapInterval(_THIS, int *interval);
extern int SDL_EGL_DeleteContext(_THIS, SDL_GLContext context); 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 void SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface);
extern EGLSurface SDL_EGL_CreateOffscreenSurface(_THIS, int width, int height); extern EGLSurface SDL_EGL_CreateOffscreenSurface(_THIS, int width, int height);

View File

@ -206,6 +206,7 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U
{ {
SDL_RendererInfo info; SDL_RendererInfo info;
SDL_WindowTextureData *data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); SDL_WindowTextureData *data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
const int transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? SDL_TRUE : SDL_FALSE;
int i; int i;
int w, h; int w, h;
@ -274,12 +275,12 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U
SDL_free(data->pixels); SDL_free(data->pixels);
data->pixels = NULL; 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]; *format = info.texture_formats[0];
for (i = 0; i < (int)info.num_texture_formats; ++i) { for (i = 0; i < (int)info.num_texture_formats; ++i) {
if (!SDL_ISPIXELFORMAT_FOURCC(info.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]; *format = info.texture_formats[i];
break; break;
} }
@ -1646,7 +1647,7 @@ Uint32 SDL_GetWindowPixelFormat(SDL_Window *window)
} }
#define CREATE_FLAGS \ #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) static SDL_INLINE SDL_bool IsAcceptingDragAndDrop(void)
{ {

View File

@ -79,7 +79,7 @@ int Android_CreateWindow(_THIS, SDL_Window *window)
incompatible with vkCreateAndroidSurfaceKHR */ incompatible with vkCreateAndroidSurfaceKHR */
#if SDL_VIDEO_OPENGL_EGL #if SDL_VIDEO_OPENGL_EGL
if (window->flags & SDL_WINDOW_OPENGL) { 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) { if (data->egl_surface == EGL_NO_SURFACE) {
ANativeWindow_release(data->native_window); ANativeWindow_release(data->native_window);

View File

@ -43,7 +43,8 @@
- (instancetype)initWithFrame:(NSRect)frame - (instancetype)initWithFrame:(NSRect)frame
highDPI:(BOOL)highDPI highDPI:(BOOL)highDPI
windowID:(Uint32)windowID; windowID:(Uint32)windowID
opaque:(BOOL)opaque;
- (void)updateDrawableSize; - (void)updateDrawableSize;
- (NSView *)hitTest:(NSPoint)point; - (NSView *)hitTest:(NSPoint)point;

View File

@ -76,7 +76,8 @@ static int SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event)
- (instancetype)initWithFrame:(NSRect)frame - (instancetype)initWithFrame:(NSRect)frame
highDPI:(BOOL)highDPI highDPI:(BOOL)highDPI
windowID:(Uint32)windowID; windowID:(Uint32)windowID
opaque:(BOOL)opaque
{ {
self = [super initWithFrame:frame]; self = [super initWithFrame:frame];
if (self != nil) { if (self != nil) {
@ -87,6 +88,8 @@ static int SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event)
/* Allow resize. */ /* Allow resize. */
self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
self.layer.opaque = opaque;
SDL_AddEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self)); SDL_AddEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self));
[self updateDrawableSize]; [self updateDrawableSize];
@ -136,13 +139,15 @@ Cocoa_Metal_CreateView(_THIS, SDL_Window *window)
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata; SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata;
NSView *view = data.nswindow.contentView; NSView *view = data.nswindow.contentView;
BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
BOOL opaque = (window->flags & SDL_WINDOW_TRANSPARENT) == 0;
Uint32 windowID = SDL_GetWindowID(window); Uint32 windowID = SDL_GetWindowID(window);
SDL_cocoametalview *newview; SDL_cocoametalview *newview;
SDL_MetalView metalview; SDL_MetalView metalview;
newview = [[SDL_cocoametalview alloc] initWithFrame:view.frame newview = [[SDL_cocoametalview alloc] initWithFrame:view.frame
highDPI:highDPI highDPI:highDPI
windowID:windowID]; windowID:windowID
opaque:opaque];
if (newview == nil) { if (newview == nil) {
SDL_OutOfMemory(); SDL_OutOfMemory();
return NULL; return NULL;

View File

@ -270,6 +270,7 @@ SDL_GLContext Cocoa_GL_CreateContext(_THIS, SDL_Window *window)
int glversion_minor; int glversion_minor;
NSOpenGLPixelFormatAttribute profile; NSOpenGLPixelFormatAttribute profile;
int interval; int interval;
int opaque;
if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
#if SDL_VIDEO_OPENGL_EGL #if SDL_VIDEO_OPENGL_EGL
@ -381,6 +382,9 @@ SDL_GLContext Cocoa_GL_CreateContext(_THIS, SDL_Window *window)
interval = 0; interval = 0;
[context setValues:&interval forParameter:NSOpenGLCPSwapInterval]; [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) { if (Cocoa_GL_MakeCurrent(_this, window, sdlcontext) < 0) {
SDL_GL_DeleteContext(sdlcontext); SDL_GL_DeleteContext(sdlcontext);
SDL_SetError("Failed making OpenGL context current"); SDL_SetError("Failed making OpenGL context current");

View File

@ -137,7 +137,7 @@ int Cocoa_GLES_SetupWindow(_THIS, SDL_Window *window)
/* Create the GLES window surface */ /* Create the GLES window surface */
v = windowdata.nswindow.contentView; 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) { if (windowdata.egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface"); return SDL_SetError("Could not create GLES window surface");

View File

@ -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 /* 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 white until the app is ready to draw. In practice on modern macOS, this
only gets called for window creation and other extraordinary events. */ only gets called for window creation and other extraordinary events. */
BOOL transparent = (_sdlWindow->flags & SDL_WINDOW_TRANSPARENT) != 0;
if ([NSGraphicsContext currentContext]) { if ([NSGraphicsContext currentContext]) {
[[NSColor blackColor] setFill]; NSColor *fillColor = transparent ? [NSColor clearColor] : [NSColor blackColor];
[fillColor setFill];
NSRectFill(dirtyRect); NSRectFill(dirtyRect);
} else if (self.layer) { } 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); 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 /* 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 white until the app is ready to draw. In practice on modern macOS, this
only gets called for window creation and other extraordinary events. */ 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); ScheduleContextUpdates((__bridge SDL_CocoaWindowData *)_sdlWindow->driverdata);
SDL_SendWindowEvent(_sdlWindow, SDL_EVENT_WINDOW_EXPOSED, 0, 0); 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 /* SDL_CocoaWindowData will be holding a strong reference to the NSWindow, and
* it will also call [NSWindow close] in DestroyWindow before releasing the * it will also call [NSWindow close] in DestroyWindow before releasing the
* NSWindow, so the extra release provided by releasedWhenClosed isn't * NSWindow, so the extra release provided by releasedWhenClosed isn't
@ -1841,6 +1852,12 @@ int Cocoa_CreateWindow(_THIS, SDL_Window *window)
[nswindow setLevel:NSFloatingWindowLevel]; [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 */ /* Create a default view for this window */
rect = [nswindow contentRectForFrameRect:[nswindow frame]]; rect = [nswindow contentRectForFrameRect:[nswindow frame]];
contentView = [[SDLView alloc] initWithFrame:rect]; contentView = [[SDLView alloc] initWithFrame:rect];

View File

@ -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 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. */ and we won't see the first frame. */
SDL_EGL_SetRequiredVisualId(_this, surface_fmt); 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) { if (windata->egl_surface == EGL_NO_SURFACE) {
ret = SDL_SetError("Could not create EGL window surface"); ret = SDL_SetError("Could not create EGL window surface");

View File

@ -287,7 +287,7 @@ int RPI_CreateWindow(_THIS, SDL_Window *window)
return -1; 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) { if (wdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface"); return SDL_SetError("Could not create GLES window surface");

View File

@ -275,7 +275,7 @@ int VITA_CreateWindow(_THIS, SDL_Window *window)
_this->gl_config.minor_version = 1; _this->gl_config.minor_version = 1;
_this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; _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) { if (wdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface"); return SDL_SetError("Could not create GLES window surface");
} }

View File

@ -267,7 +267,7 @@ int VIVANTE_CreateWindow(_THIS, SDL_Window *window)
#if SDL_VIDEO_OPENGL_EGL #if SDL_VIDEO_OPENGL_EGL
if (window->flags & SDL_WINDOW_OPENGL) { 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) { if (data->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("VIVANTE: Can't create EGL surface"); return SDL_SetError("VIVANTE: Can't create EGL surface");
} }

View File

@ -948,7 +948,6 @@ int Wayland_VideoInit(_THIS)
WAYLAND_wl_display_flush(data->display); WAYLAND_wl_display_flush(data->display);
Wayland_InitKeyboard(_this); Wayland_InitKeyboard(_this);
Wayland_InitWin(data);
data->initializing = SDL_FALSE; data->initializing = SDL_FALSE;
@ -981,7 +980,6 @@ static void Wayland_VideoCleanup(_THIS)
SDL_VideoData *data = _this->driverdata; SDL_VideoData *data = _this->driverdata;
int i, j; int i, j;
Wayland_QuitWin(data);
Wayland_FiniMouse(data); Wayland_FiniMouse(data);
for (i = _this->num_displays - 1; i >= 0; --i) { for (i = _this->num_displays - 1; i >= 0; --i) {

View File

@ -97,7 +97,6 @@ struct SDL_VideoData
char *classname; char *classname;
int relative_mouse_mode; int relative_mouse_mode;
SDL_bool egl_transparency_enabled;
}; };
struct SDL_DisplayData struct SDL_DisplayData

View File

@ -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); 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); region = wl_compositor_create_region(viddata->compositor);
wl_region_add(region, 0, 0, wl_region_add(region, 0, 0,
data->wl_window_width, data->wl_window_height); 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 */ #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) { if (window->flags & SDL_WINDOW_OPENGL) {
data->egl_window = WAYLAND_wl_egl_window_create(data->surface, data->drawable_width, data->drawable_height); data->egl_window = WAYLAND_wl_egl_window_create(data->surface, data->drawable_width, data->drawable_height);
#if SDL_VIDEO_OPENGL_EGL #if SDL_VIDEO_OPENGL_EGL
/* Create the GLES window surface */ /* 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) { if (data->egl_surface == EGL_NO_SURFACE) {
return -1; /* SDL_EGL_CreateSurface should have set error */ return -1; /* SDL_EGL_CreateSurface should have set error */
@ -2247,43 +2253,4 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window)
window->driverdata = NULL; 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 */ #endif /* SDL_VIDEO_DRIVER_WAYLAND */

View File

@ -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_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
extern int Wayland_FlashWindow(_THIS, SDL_Window *window, SDL_FlashOperation operation); 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_ */ #endif /* SDL_waylandwindow_h_ */

View File

@ -125,7 +125,7 @@ int WIN_GLES_SetupWindow(_THIS, SDL_Window *window)
} }
/* Create the GLES window surface */ /* 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) { if (windowdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface"); return SDL_SetError("Could not create GLES window surface");

View File

@ -345,7 +345,7 @@ static void X11_GL_InitExtensions(_THIS)
const char *(*glXQueryExtensionsStringFunc)(Display *, int); const char *(*glXQueryExtensionsStringFunc)(Display *, int);
const char *extensions; const char *extensions;
vinfo = X11_GL_GetVisual(_this, display, screen); vinfo = X11_GL_GetVisual(_this, display, screen, SDL_FALSE);
if (vinfo) { if (vinfo) {
GLXContext (*glXGetCurrentContextFunc)(void) = GLXContext (*glXGetCurrentContextFunc)(void) =
(GLXContext(*)(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 * In case of failure, if that pointer is not NULL, set that pointer to None
* and try again. * 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; int i = 0;
const int MAX_ATTRIBUTES = 64; const int MAX_ATTRIBUTES = 64;
@ -583,14 +583,16 @@ 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; attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT : GLX_SLOW_VISUAL_EXT;
} }
/* Un-wanted when we request a transparent buffer */
if (!transparent) {
/* If we're supposed to use DirectColor visuals, and we've got the /* If we're supposed to use DirectColor visuals, and we've got the
EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */ EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
if (X11_UseDirectColorVisuals() && if (X11_UseDirectColorVisuals() && _this->gl_data->HAS_GLX_EXT_visual_info) {
_this->gl_data->HAS_GLX_EXT_visual_info) {
pvistypeattr = &attribs[i]; pvistypeattr = &attribs[i];
attribs[i++] = GLX_X_VISUAL_TYPE_EXT; attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
attribs[i++] = GLX_DIRECT_COLOR_EXT; attribs[i++] = GLX_DIRECT_COLOR_EXT;
} }
}
attribs[i++] = None; attribs[i++] = None;
@ -603,7 +605,7 @@ static int X11_GL_GetAttributes(_THIS, Display *display, int screen, int *attrib
return i; 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. */ /* 64 seems nice. */
int attribs[64]; int attribs[64];
@ -620,13 +622,30 @@ XVisualInfo *X11_GL_GetVisual(_THIS, Display *display, int screen)
GLXFBConfig *framebuffer_config = NULL; GLXFBConfig *framebuffer_config = NULL;
int fbcount = 0; 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); framebuffer_config = _this->gl_data->glXChooseFBConfig(display, screen, attribs, &fbcount);
if (!framebuffer_config && (pvistypeattr != NULL)) { if (!framebuffer_config && (pvistypeattr != NULL)) {
*pvistypeattr = None; *pvistypeattr = None;
framebuffer_config = _this->gl_data->glXChooseFBConfig(display, screen, attribs, &fbcount); 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) { if (framebuffer_config) {
vinfo = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[0]); vinfo = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[0]);
} }
@ -635,7 +654,7 @@ XVisualInfo *X11_GL_GetVisual(_THIS, Display *display, int screen)
} }
if (!vinfo) { 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); vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
if (!vinfo && (pvistypeattr != NULL)) { if (!vinfo && (pvistypeattr != NULL)) {
@ -696,6 +715,7 @@ SDL_GLContext X11_GL_CreateContext(_THIS, SDL_Window *window)
XVisualInfo v, *vinfo; XVisualInfo v, *vinfo;
int n; int n;
GLXContext context = NULL, share_context; 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) { if (_this->gl_config.share_with_current_context) {
share_context = (GLXContext)SDL_GL_GetCurrentContext(); share_context = (GLXContext)SDL_GL_GetCurrentContext();
@ -716,7 +736,7 @@ SDL_GLContext X11_GL_CreateContext(_THIS, SDL_Window *window)
if (vinfo) { if (vinfo) {
if (_this->gl_config.major_version < 3 && if (_this->gl_config.major_version < 3 &&
_this->gl_config.profile_mask == 0 && _this->gl_config.profile_mask == 0 &&
_this->gl_config.flags == 0) { _this->gl_config.flags == 0 && !transparent) {
/* Create legacy context */ /* Create legacy context */
context = context =
_this->gl_data->glXCreateContext(display, vinfo, share_context, True); _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 fbcount = 0;
int *pvistypeattr = NULL; 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) { if (_this->gl_data->glXChooseFBConfig) {
framebuffer_config = _this->gl_data->glXChooseFBConfig(display, framebuffer_config = _this->gl_data->glXChooseFBConfig(display,

View File

@ -72,7 +72,7 @@ extern int X11_GL_LoadLibrary(_THIS, const char *path);
extern SDL_FunctionPointer X11_GL_GetProcAddress(_THIS, const char *proc); extern SDL_FunctionPointer X11_GL_GetProcAddress(_THIS, const char *proc);
extern void X11_GL_UnloadLibrary(_THIS); extern void X11_GL_UnloadLibrary(_THIS);
extern SDL_bool X11_GL_UseEGL(_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 SDL_GLContext X11_GL_CreateContext(_THIS, SDL_Window *window);
extern int X11_GL_MakeCurrent(_THIS, SDL_Window *window, extern int X11_GL_MakeCurrent(_THIS, SDL_Window *window,
SDL_GLContext context); SDL_GLContext context);

View File

@ -56,7 +56,7 @@ int X11_GLES_LoadLibrary(_THIS, const char *path)
} }
XVisualInfo * XVisualInfo *
X11_GLES_GetVisual(_THIS, Display *display, int screen) X11_GLES_GetVisual(_THIS, Display *display, int screen, SDL_bool transparent)
{ {
XVisualInfo *egl_visualinfo = NULL; XVisualInfo *egl_visualinfo = NULL;
@ -79,6 +79,23 @@ X11_GLES_GetVisual(_THIS, Display *display, int screen)
egl_visualinfo = X11_XGetVisualInfo(display, egl_visualinfo = X11_XGetVisualInfo(display,
VisualScreenMask, VisualScreenMask,
&vi_in, &out_count); &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 { } else {
vi_in.screen = screen; vi_in.screen = screen;
vi_in.visualid = visual_id; vi_in.visualid = visual_id;

View File

@ -44,7 +44,7 @@ typedef struct SDL_PrivateGLESData
#define X11_GLES_DeleteContext SDL_EGL_DeleteContext #define X11_GLES_DeleteContext SDL_EGL_DeleteContext
extern int X11_GLES_LoadLibrary(_THIS, const char *path); 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 SDL_GLContext X11_GLES_CreateContext(_THIS, SDL_Window *window);
extern int X11_GLES_SwapWindow(_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); extern int X11_GLES_MakeCurrent(_THIS, SDL_Window *window, SDL_GLContext context);

View File

@ -431,6 +431,7 @@ int X11_CreateWindow(_THIS, SDL_Window *window)
SDL_WindowData *windowdata; SDL_WindowData *windowdata;
Display *display = data->display; Display *display = data->display;
int screen = displaydata->screen; int screen = displaydata->screen;
const int transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? SDL_TRUE : SDL_FALSE;
Visual *visual; Visual *visual;
int depth; int depth;
XSetWindowAttributes xattr; XSetWindowAttributes xattr;
@ -477,12 +478,12 @@ int X11_CreateWindow(_THIS, SDL_Window *window)
&& (!_this->gl_data || X11_GL_UseEGL(_this)) && (!_this->gl_data || X11_GL_UseEGL(_this))
#endif #endif
) { ) {
vinfo = X11_GLES_GetVisual(_this, display, screen); vinfo = X11_GLES_GetVisual(_this, display, screen, transparent);
} else } else
#endif #endif
{ {
#if SDL_VIDEO_OPENGL_GLX #if SDL_VIDEO_OPENGL_GLX
vinfo = X11_GL_GetVisual(_this, display, screen); vinfo = X11_GL_GetVisual(_this, display, screen, transparent);
#endif #endif
} }
@ -720,7 +721,7 @@ int X11_CreateWindow(_THIS, SDL_Window *window)
} }
/* Create the GLES window surface */ /* 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) { if (windowdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface"); return SDL_SetError("Could not create GLES window surface");

View File

@ -92,7 +92,7 @@ static void Render(void)
}; };
/* Do our drawing, too. */ /* 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.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ctx.glBegin(GL_QUADS); ctx.glBegin(GL_QUADS);

View File

@ -126,7 +126,7 @@ static void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite)
} }
/* Draw a gray background */ /* Draw a gray background */
SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0x00 /* used with --transparent */);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
/* Test points */ /* Test points */

View File

@ -624,6 +624,7 @@ static SDL_bool createSwapchain(void)
int w, h; int w, h;
VkSwapchainCreateInfoKHR createInfo = { 0 }; VkSwapchainCreateInfoKHR createInfo = { 0 };
VkResult result; VkResult result;
Uint32 flags;
// pick an image count // pick an image count
vulkanContext->swapchainDesiredImageCount = vulkanContext->surfaceCapabilities.minImageCount + 1; vulkanContext->swapchainDesiredImageCount = vulkanContext->surfaceCapabilities.minImageCount + 1;
@ -651,6 +652,9 @@ static SDL_bool createSwapchain(void)
// get size // get size
SDL_GetWindowSizeInPixels(vulkanContext->window, &w, &h); SDL_GetWindowSizeInPixels(vulkanContext->window, &w, &h);
// get flags
flags = SDL_GetWindowFlags(vulkanContext->window);
// Clamp the size to the allowable image extent. // Clamp the size to the allowable image extent.
// SDL_GetWindowSizeInPixels()'s result it not always in this range (bug #3287) // SDL_GetWindowSizeInPixels()'s result it not always in this range (bug #3287)
vulkanContext->swapchainSize.width = SDL_clamp((uint32_t)w, 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.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.preTransform = vulkanContext->surfaceCapabilities.currentTransform; createInfo.preTransform = vulkanContext->surfaceCapabilities.currentTransform;
if (flags & SDL_WINDOW_TRANSPARENT) {
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
} else {
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
}
createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
createInfo.clipped = VK_TRUE; createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = vulkanContext->swapchain; 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[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[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[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); rerecordCommandBuffer(frameIndex, &clearColor);
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1; submitInfo.waitSemaphoreCount = 1;