diff --git a/cobalt/renderer/backend/egl/graphics_context.cc b/cobalt/renderer/backend/egl/graphics_context.cc index ddaa5978ae72..f35718a50f37 100644 --- a/cobalt/renderer/backend/egl/graphics_context.cc +++ b/cobalt/renderer/backend/egl/graphics_context.cc @@ -31,6 +31,7 @@ #include "cobalt/renderer/backend/egl/utils.h" #include "cobalt/renderer/egl_and_gles.h" #include "starboard/configuration.h" +#include "starboard/extension/egl_context_lost_handler.h" #if defined(GLES3_SUPPORTED) #error "Support for gles3 features has been deprecated." @@ -251,6 +252,9 @@ void GraphicsContextEGL::SafeEglMakeCurrent(RenderTargetEGL* surface) { // a thread can result in global allocations being made that are never freed. ANNOTATE_SCOPED_MEMORY_LEAK; + if (error_context_lost_) { + return; + } EGLSurface egl_surface = surface->GetSurface(); // This should only be used with egl surfaces (not framebuffer objects). @@ -279,6 +283,21 @@ void GraphicsContextEGL::SafeEglMakeCurrent(RenderTargetEGL* surface) { surface->set_surface_bad(); egl_surface = null_surface_->GetSurface(); EGL_CALL(eglMakeCurrent(display_, egl_surface, egl_surface, context_)); + } else if (make_current_error == EGL_CONTEXT_LOST) { + const CobaltExtensionEglContextLostHandlerApi* context_lost_handler = + static_cast( + SbSystemGetExtension(kCobaltExtensionEglContextLostHandlerName)); + if (context_lost_handler && + strcmp(context_lost_handler->name, + kCobaltExtensionEglContextLostHandlerName) == 0 && + context_lost_handler->version >= 1) { + error_context_lost_ = true; + EGL_CALL(eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT)); + context_lost_handler->HandleEglContextLost(); + } else { + NOTREACHED() << "EGL_CONTEXT_LOST when calling eglMakeCurrent()."; + } } else { NOTREACHED() << "Unexpected error when calling eglMakeCurrent()."; } diff --git a/cobalt/renderer/backend/egl/graphics_context.h b/cobalt/renderer/backend/egl/graphics_context.h index d7116ac9fb41..d944cda2c866 100644 --- a/cobalt/renderer/backend/egl/graphics_context.h +++ b/cobalt/renderer/backend/egl/graphics_context.h @@ -167,6 +167,8 @@ class GraphicsContextEGL : public GraphicsContext { // OpenGL ES implementation. bool bgra_format_supported_; + bool error_context_lost_ = false; + // Data required to provide BlitToRenderTarget() functionality via OpenGL ES. GLuint blit_vertex_shader_; GLuint blit_fragment_shader_; diff --git a/starboard/extension/egl_context_lost_handler.h b/starboard/extension/egl_context_lost_handler.h new file mode 100644 index 000000000000..390b9eeae726 --- /dev/null +++ b/starboard/extension/egl_context_lost_handler.h @@ -0,0 +1,46 @@ +// Copyright 2025 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef STARBOARD_EXTENSION_EGL_CONTEXT_LOST_HANDLER_H_ +#define STARBOARD_EXTENSION_EGL_CONTEXT_LOST_HANDLER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define kCobaltExtensionEglContextLostHandlerName \ + "dev.cobalt.extension.EglContextLostHandler" + +typedef struct CobaltExtensionEglContextLostHandlerApi { + // Name should be the string |kCobaltExtensionEglContextLostHandlerName|. + // This helps to validate that the extension API is correct. + const char* name; + + // This specifies the version of the API that is implemented. + uint32_t version; + + // The fields below this point were added in version 1 or later. + + // Called when EGL_CONTEXT_LOST error is detected. + void (*HandleEglContextLost)(); + +} CobaltExtensionEglContextLostHandlerApi; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // STARBOARD_EXTENSION_EGL_CONTEXT_LOST_HANDLER_H_ diff --git a/starboard/extension/extension_test.cc b/starboard/extension/extension_test.cc index 79f046494eb4..d9961bb27756 100644 --- a/starboard/extension/extension_test.cc +++ b/starboard/extension/extension_test.cc @@ -17,6 +17,7 @@ #include "starboard/extension/configuration.h" #include "starboard/extension/crash_handler.h" #include "starboard/extension/cwrappers.h" +#include "starboard/extension/egl_context_lost_handler.h" #include "starboard/extension/enhanced_audio.h" #include "starboard/extension/font.h" #include "starboard/extension/free_space.h" @@ -527,5 +528,25 @@ TEST(ExtensionTest, PlayerConfiguration) { } } +TEST(ExtensionTest, EglContextLostHandler) { + typedef CobaltExtensionEglContextLostHandlerApi ExtensionApi; + const char* kExtensionName = kCobaltExtensionEglContextLostHandlerName; + + const ExtensionApi* extension_api = + static_cast(SbSystemGetExtension(kExtensionName)); + if (!extension_api) { + return; + } + + EXPECT_STREQ(extension_api->name, kExtensionName); + EXPECT_EQ(extension_api->version, 1u); + EXPECT_NE(extension_api->HandleEglContextLost, nullptr); + + const ExtensionApi* second_extension_api = + static_cast(SbSystemGetExtension(kExtensionName)); + EXPECT_EQ(second_extension_api, extension_api) + << "Extension struct should be a singleton"; +} + } // namespace extension } // namespace starboard diff --git a/starboard/xb1/BUILD.gn b/starboard/xb1/BUILD.gn index e4137bc401b4..92c9c4d6177e 100644 --- a/starboard/xb1/BUILD.gn +++ b/starboard/xb1/BUILD.gn @@ -198,6 +198,8 @@ static_library("starboard_platform") { "shared/configuration.cc", "shared/configuration.h", "shared/configuration_constants.cc", + "shared/egl_context_lost_handler.cc", + "shared/egl_context_lost_handler.h", "shared/system_get_extensions.cc", "shared/system_get_path.cc", ] diff --git a/starboard/xb1/shared/egl_context_lost_handler.cc b/starboard/xb1/shared/egl_context_lost_handler.cc new file mode 100644 index 000000000000..d8c950b04f47 --- /dev/null +++ b/starboard/xb1/shared/egl_context_lost_handler.cc @@ -0,0 +1,61 @@ +// Copyright 2025 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "starboard/xb1/shared/egl_context_lost_handler.h" + +#include "starboard/extension/egl_context_lost_handler.h" +#include "starboard/shared/starboard/media/mime_supportability_cache.h" +#include "starboard/shared/uwp/application_uwp.h" + +using starboard::shared::starboard::media::MimeSupportabilityCache; +using starboard::shared::uwp::ApplicationUwp; + +namespace starboard { +namespace xb1 { +namespace shared { + +namespace { + +void HandleEglContextLost() { + MimeSupportabilityCache::GetInstance()->ClearCachedMimeSupportabilities(); + ApplicationUwp::Get()->Inject( + new ApplicationUwp::Event(kSbEventTypeBlur, NULL, NULL)); + ApplicationUwp::Get()->Inject( + new ApplicationUwp::Event(kSbEventTypeConceal, NULL, NULL)); + ApplicationUwp::Get()->Inject( + new ApplicationUwp::Event(kSbEventTypeFreeze, NULL, NULL)); + + ApplicationUwp::Get()->Inject( + new ApplicationUwp::Event(kSbEventTypeUnfreeze, NULL, NULL)); + ApplicationUwp::Get()->Inject( + new ApplicationUwp::Event(kSbEventTypeReveal, NULL, NULL)); + ApplicationUwp::Get()->Inject( + new ApplicationUwp::Event(kSbEventTypeFocus, NULL, NULL)); +} + +const CobaltExtensionEglContextLostHandlerApi kEglContextLostHandlerApi = { + kCobaltExtensionEglContextLostHandlerName, + 1, + &HandleEglContextLost, +}; + +} // namespace + +const void* GetEglContextLostHandlerApi() { + return &kEglContextLostHandlerApi; +} + +} // namespace shared +} // namespace xb1 +} // namespace starboard diff --git a/starboard/xb1/shared/egl_context_lost_handler.h b/starboard/xb1/shared/egl_context_lost_handler.h new file mode 100644 index 000000000000..f7a2893d2817 --- /dev/null +++ b/starboard/xb1/shared/egl_context_lost_handler.h @@ -0,0 +1,28 @@ +// Copyright 2025 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef STARBOARD_XB1_SHARED_EGL_CONTEXT_LOST_HANDLER_H_ +#define STARBOARD_XB1_SHARED_EGL_CONTEXT_LOST_HANDLER_H_ + +namespace starboard { +namespace xb1 { +namespace shared { + +const void* GetEglContextLostHandlerApi(); + +} // namespace shared +} // namespace xb1 +} // namespace starboard + +#endif // STARBOARD_XB1_SHARED_EGL_CONTEXT_LOST_HANDLER_H_ diff --git a/starboard/xb1/shared/system_get_extensions.cc b/starboard/xb1/shared/system_get_extensions.cc index 009b8d78ff25..1f6b5af768c4 100644 --- a/starboard/xb1/shared/system_get_extensions.cc +++ b/starboard/xb1/shared/system_get_extensions.cc @@ -16,11 +16,13 @@ #include "starboard/common/string.h" #include "starboard/extension/configuration.h" +#include "starboard/extension/egl_context_lost_handler.h" #include "starboard/extension/graphics.h" #include "starboard/extension/media_session.h" #include "starboard/shared/uwp/xb1_media_session_client.h" #include "starboard/shared/win32/graphics.h" #include "starboard/xb1/shared/configuration.h" +#include "starboard/xb1/shared/egl_context_lost_handler.h" const void* SbSystemGetExtension(const char* name) { if (strcmp(name, kCobaltExtensionGraphicsName) == 0) { @@ -32,5 +34,8 @@ const void* SbSystemGetExtension(const char* name) { if (strcmp(name, kCobaltExtensionMediaSessionName) == 0) { return starboard::shared::uwp::GetMediaSessionApi(); } + if (strcmp(name, kCobaltExtensionEglContextLostHandlerName) == 0) { + return starboard::xb1::shared::GetEglContextLostHandlerApi(); + } return NULL; }