Android OpenGL context loss handling.

This commit is contained in:
Lasse Öörni 2012-05-30 22:17:58 +00:00
Родитель 35bec043ad
Коммит 8cc2a83e48
8 изменённых файлов: 90 добавлений и 31 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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) Restore();
(*i)->OnDeviceReset();
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 if (impl_->context_)
ResetCachedState(); {
ClearParameterSources(); 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)

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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;
} }
} }

6
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;
/** /**

Просмотреть файл

@ -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