Browse Source

Android OpenGL context loss handling.

Lasse Öörni 13 years ago
parent
commit
8cc2a83e48

+ 7 - 1
Android/src/org/libsdl/app/SDLActivity.java

@@ -152,6 +152,8 @@ public class SDLActivity extends Activity {
                                             int action, float x,
                                             int action, float x,
                                             float y, float p);
                                             float y, float p);
     public static native void onNativeAccel(float x, float y, float z);
     public static native void onNativeAccel(float x, float y, float z);
+    public static native void onNativeSurfaceDestroyed();
+    public static native void onNativeSurfaceCreated();
     public static native void nativeRunAudioThread();
     public static native void nativeRunAudioThread();
 
 
 
 
@@ -453,8 +455,11 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
     public void surfaceCreated(SurfaceHolder holder) {
     public void surfaceCreated(SurfaceHolder holder) {
         Log.v("SDL", "surfaceCreated()");
         Log.v("SDL", "surfaceCreated()");
         holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
         holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
-        SDLActivity.createEGLSurface();
         enableSensor(Sensor.TYPE_ACCELEROMETER, true);
         enableSensor(Sensor.TYPE_ACCELEROMETER, true);
+        SDLActivity.onNativeSurfaceCreated();
+        
+        // Note: we must not recreate the OpenGL context here, but wait for the application call initEGL() again
+        // from its own thread, to ensure the context is made current to the correct thread
     }
     }
 
 
     // Called when we lose the surface
     // Called when we lose the surface
@@ -462,6 +467,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         Log.v("SDL", "surfaceDestroyed()");
         Log.v("SDL", "surfaceDestroyed()");
         SDLActivity.nativePause();
         SDLActivity.nativePause();
         enableSensor(Sensor.TYPE_ACCELEROMETER, false);
         enableSensor(Sensor.TYPE_ACCELEROMETER, false);
+        SDLActivity.onNativeSurfaceDestroyed();
     }
     }
 
 
     // Called when the surface is resized
     // Called when the surface is resized

+ 32 - 28
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -322,9 +322,7 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool vsync, bool
     SDL_GL_SwapWindow(impl_->window_);
     SDL_GL_SwapWindow(impl_->window_);
     
     
     // Let GPU objects restore themselves
     // Let GPU objects restore themselves
-    for (Vector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
-        (*i)->OnDeviceReset();
-    
+    Restore();
     CheckFeatureSupport();
     CheckFeatureSupport();
     
     
     if (multiSample > 1)
     if (multiSample > 1)
@@ -377,9 +375,9 @@ bool Graphics::TakeScreenShot(Image& destImage)
 
 
 bool Graphics::BeginFrame()
 bool Graphics::BeginFrame()
 {
 {
-    if (!IsInitialized())
+    if (!IsInitialized() || !impl_->context_)
         return false;
         return false;
-
+    
     // If we should be fullscreen, but are not currently active, do not render
     // If we should be fullscreen, but are not currently active, do not render
     if (fullscreen_ && (SDL_GetWindowFlags(impl_->window_) & SDL_WINDOW_MINIMIZED))
     if (fullscreen_ && (SDL_GetWindowFlags(impl_->window_) & SDL_WINDOW_MINIMIZED))
         return false;
         return false;
@@ -524,7 +522,7 @@ void Graphics::Draw(PrimitiveType type, unsigned vertexStart, unsigned vertexCou
 
 
 void Graphics::Draw(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount)
 void Graphics::Draw(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount)
 {
 {
-    if (!indexCount || !indexBuffer_)
+    if (!indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObject())
         return;
         return;
     
     
     if (impl_->fboDirty_)
     if (impl_->fboDirty_)
@@ -608,7 +606,7 @@ bool Graphics::SetVertexBuffers(const Vector<VertexBuffer*>& buffers, const PODV
         elementMasks_[i] = elementMask;
         elementMasks_[i] = elementMask;
         changed = true;
         changed = true;
         
         
-        if (!buffer)
+        if (!buffer || !buffer->GetGPUObject())
             continue;
             continue;
         
         
         glBindBuffer(GL_ARRAY_BUFFER, buffer->GetGPUObject());
         glBindBuffer(GL_ARRAY_BUFFER, buffer->GetGPUObject());
@@ -695,7 +693,7 @@ bool Graphics::SetVertexBuffers(const Vector<SharedPtr<VertexBuffer> >& buffers,
         elementMasks_[i] = elementMask;
         elementMasks_[i] = elementMask;
         changed = true;
         changed = true;
         
         
-        if (!buffer)
+        if (!buffer || !buffer->GetGPUObject())
             continue;
             continue;
         
         
         glBindBuffer(GL_ARRAY_BUFFER, buffer->GetGPUObject());
         glBindBuffer(GL_ARRAY_BUFFER, buffer->GetGPUObject());
@@ -1744,29 +1742,13 @@ void Graphics::Release(bool clearGPUObjects, bool closeWindow)
     
     
     if (clearGPUObjects)
     if (clearGPUObjects)
     {
     {
-        // Shutting down: release all GPU objects that still exist, then delete the context
+        // Shutting down: release all GPU objects that still exist
         for (Vector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
         for (Vector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
             (*i)->Release();
             (*i)->Release();
         gpuObjects_.Clear();
         gpuObjects_.Clear();
-        
-        if (impl_->context_)
-        {
-            MutexLock lock(GetStaticMutex());
-            SDL_GL_DeleteContext(impl_->context_);
-            impl_->context_ = 0;
-        }
-        
-        CleanupFramebuffers(true);
     }
     }
     else
     else
     {
     {
-        if (impl_->context_)
-        {
-            MutexLock lock(GetStaticMutex());
-            SDL_GL_DeleteContext(impl_->context_);
-            impl_->context_ = 0;
-        }
-        
         // We are not shutting down, but recreating the context: mark GPU objects lost
         // We are not shutting down, but recreating the context: mark GPU objects lost
         for (Vector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
         for (Vector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
             (*i)->OnDeviceLost();
             (*i)->OnDeviceLost();
@@ -1776,9 +1758,13 @@ void Graphics::Release(bool clearGPUObjects, bool closeWindow)
     depthTextures_.Clear();
     depthTextures_.Clear();
     shaderPrograms_.Clear();
     shaderPrograms_.Clear();
     
     
-    // When the new context is initialized, it will have default state again
-    ResetCachedState();
-    ClearParameterSources();
+    if (impl_->context_)
+    {
+        MutexLock lock(GetStaticMutex());
+        
+        SDL_GL_DeleteContext(impl_->context_);
+        impl_->context_ = 0;
+    }
     
     
     if (closeWindow)
     if (closeWindow)
     {
     {
@@ -1790,6 +1776,24 @@ void Graphics::Release(bool clearGPUObjects, bool closeWindow)
     }
     }
 }
 }
 
 
+void Graphics::Restore()
+{
+    if (!impl_->window_)
+        return;
+    
+    // Ensure first that the context exists
+    if (!impl_->context_)
+        impl_->context_ = SDL_GL_CreateContext(impl_->window_);
+    if (!impl_->context_)
+        return;
+    
+    for (Vector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
+        (*i)->OnDeviceReset();
+    
+    ResetCachedState();
+    ClearParameterSources();
+}
+
 void Graphics::CleanupRenderSurface(RenderSurface* surface)
 void Graphics::CleanupRenderSurface(RenderSurface* surface)
 {
 {
     if (!surface)
     if (!surface)

+ 2 - 0
Engine/Graphics/OpenGL/OGLGraphics.h

@@ -330,6 +330,8 @@ public:
     void FreeScratchBuffer(void* buffer);
     void FreeScratchBuffer(void* buffer);
     /// Release/clear GPU objects and optionally close the window.
     /// Release/clear GPU objects and optionally close the window.
     void Release(bool clearGPUObjects, bool closeWindow);
     void Release(bool clearGPUObjects, bool closeWindow);
+    /// Restore GPU objects and reinitialize state. Requires an open window.
+    void Restore();
     /// Clean up a render surface from all FBOs.
     /// Clean up a render surface from all FBOs.
     void CleanupRenderSurface(RenderSurface* surface);
     void CleanupRenderSurface(RenderSurface* surface);
     
     

+ 5 - 0
Engine/Graphics/OpenGL/OGLIndexBuffer.cpp

@@ -309,6 +309,11 @@ bool IndexBuffer::Create()
         
         
         if (!object_)
         if (!object_)
             glGenBuffers(1, &object_);
             glGenBuffers(1, &object_);
+        if (!object_)
+        {
+            LOGERROR("Failed to create index buffer");
+            return false;
+        }
         
         
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object_);
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object_);
         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount_ * indexSize_, 0, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount_ * indexSize_, 0, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);

+ 5 - 0
Engine/Graphics/OpenGL/OGLVertexBuffer.cpp

@@ -385,6 +385,11 @@ bool VertexBuffer::Create()
     {
     {
         if (!object_)
         if (!object_)
             glGenBuffers(1, &object_);
             glGenBuffers(1, &object_);
+        if (!object_)
+        {
+            LOGERROR("Failed to create vertex buffer");
+            return false;
+        }
         
         
         glBindBuffer(GL_ARRAY_BUFFER, object_);
         glBindBuffer(GL_ARRAY_BUFFER, object_);
         glBufferData(GL_ARRAY_BUFFER, vertexCount_ * vertexSize_, 0, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
         glBufferData(GL_ARRAY_BUFFER, vertexCount_ * vertexSize_, 0, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);

+ 17 - 1
Engine/Input/Input.cpp

@@ -227,7 +227,7 @@ void Input::Update()
     {
     {
         IntVector2 mousePos = GetCursorPosition();
         IntVector2 mousePos = GetCursorPosition();
         mouseMove_ = mousePos - lastCursorPosition_;
         mouseMove_ = mousePos - lastCursorPosition_;
-
+        
         // Recenter the mouse cursor manually if it moved
         // Recenter the mouse cursor manually if it moved
         if (mouseMove_ != IntVector2::ZERO)
         if (mouseMove_ != IntVector2::ZERO)
         {
         {
@@ -847,6 +847,22 @@ void Input::HandleSDLEvent(void* sdlEvent)
             if (input)
             if (input)
                 input->GetSubsystem<Graphics>()->Close();
                 input->GetSubsystem<Graphics>()->Close();
         }
         }
+        #ifdef ANDROID
+        if (evt.window.event == SDL_WINDOWEVENT_SURFACE_LOST)
+        {
+            input = GetInputInstance(evt.window.windowID);
+            // Mark GPU objects lost
+            if (input)
+                input->graphics_->Release(false, false);
+        }
+        if (evt.window.event == SDL_WINDOWEVENT_SURFACE_CREATED)
+        {
+            input = GetInputInstance(evt.window.windowID);
+            // Restore GPU objects
+            if (input)
+                input->graphics_->Restore();
+        }
+        #endif
         break;
         break;
     }
     }
 }
 }

+ 5 - 1
ThirdParty/SDL/include/SDL_video.h

@@ -19,6 +19,8 @@
   3. This notice may not be removed or altered from any source distribution.
   3. This notice may not be removed or altered from any source distribution.
 */
 */
 
 
+// Modified by Lasse Öörni for Urho3D
+
 /**
 /**
  *  \file SDL_video.h
  *  \file SDL_video.h
  *  
  *  
@@ -150,8 +152,10 @@ typedef enum
     SDL_WINDOWEVENT_LEAVE,          /**< Window has lost mouse focus */
     SDL_WINDOWEVENT_LEAVE,          /**< Window has lost mouse focus */
     SDL_WINDOWEVENT_FOCUS_GAINED,   /**< Window has gained keyboard focus */
     SDL_WINDOWEVENT_FOCUS_GAINED,   /**< Window has gained keyboard focus */
     SDL_WINDOWEVENT_FOCUS_LOST,     /**< Window has lost keyboard focus */
     SDL_WINDOWEVENT_FOCUS_LOST,     /**< Window has lost keyboard focus */
-    SDL_WINDOWEVENT_CLOSE           /**< The window manager requests that the 
+    SDL_WINDOWEVENT_CLOSE,          /**< The window manager requests that the 
                                          window be closed */
                                          window be closed */
+    SDL_WINDOWEVENT_SURFACE_LOST,   /**< Android only: surface has been lost */
+    SDL_WINDOWEVENT_SURFACE_CREATED /**< Android only: surface has been restored after loss */
 } SDL_WindowEventID;
 } SDL_WindowEventID;
 
 
 /**
 /**

+ 17 - 0
ThirdParty/SDL/src/core/android/SDL_android.cpp

@@ -248,6 +248,23 @@ extern "C" void Java_org_libsdl_app_SDLActivity_nativeRunAudioThread(
     Android_RunAudioThread();
     Android_RunAudioThread();
 }
 }
 
 
+// Surface destroyed
+extern "C" void Java_org_libsdl_app_SDLActivity_onNativeSurfaceDestroyed(
+                                    JNIEnv* env, jclass cls)
+{
+    if (Android_Window) {
+        SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_SURFACE_LOST, 0, 0);
+    }
+}
+
+// Surface created
+extern "C" void Java_org_libsdl_app_SDLActivity_onNativeSurfaceCreated(
+                                    JNIEnv* env, jclass cls)
+{
+    if (Android_Window) {
+        SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_SURFACE_CREATED, 0, 0);
+    }
+}
 
 
 /*******************************************************************************
 /*******************************************************************************
              Functions called by SDL into Java
              Functions called by SDL into Java