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,
float y, float p);
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();
@ -453,8 +455,11 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
public void surfaceCreated(SurfaceHolder holder) {
Log.v("SDL", "surfaceCreated()");
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
SDLActivity.createEGLSurface();
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
@ -462,6 +467,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
Log.v("SDL", "surfaceDestroyed()");
SDLActivity.nativePause();
enableSensor(Sensor.TYPE_ACCELEROMETER, false);
SDLActivity.onNativeSurfaceDestroyed();
}
// 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_);
// Let GPU objects restore themselves
for (Vector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
(*i)->OnDeviceReset();
Restore();
CheckFeatureSupport();
if (multiSample > 1)
@ -377,7 +375,7 @@ bool Graphics::TakeScreenShot(Image& destImage)
bool Graphics::BeginFrame()
{
if (!IsInitialized())
if (!IsInitialized() || !impl_->context_)
return false;
// If we should be fullscreen, but are not currently active, do not render
@ -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)
{
if (!indexCount || !indexBuffer_)
if (!indexCount || !indexBuffer_ || !indexBuffer_->GetGPUObject())
return;
if (impl_->fboDirty_)
@ -608,7 +606,7 @@ bool Graphics::SetVertexBuffers(const Vector<VertexBuffer*>& buffers, const PODV
elementMasks_[i] = elementMask;
changed = true;
if (!buffer)
if (!buffer || !buffer->GetGPUObject())
continue;
glBindBuffer(GL_ARRAY_BUFFER, buffer->GetGPUObject());
@ -695,7 +693,7 @@ bool Graphics::SetVertexBuffers(const Vector<SharedPtr<VertexBuffer> >& buffers,
elementMasks_[i] = elementMask;
changed = true;
if (!buffer)
if (!buffer || !buffer->GetGPUObject())
continue;
glBindBuffer(GL_ARRAY_BUFFER, buffer->GetGPUObject());
@ -1744,29 +1742,13 @@ void Graphics::Release(bool clearGPUObjects, bool closeWindow)
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)
(*i)->Release();
gpuObjects_.Clear();
if (impl_->context_)
{
MutexLock lock(GetStaticMutex());
SDL_GL_DeleteContext(impl_->context_);
impl_->context_ = 0;
}
CleanupFramebuffers(true);
}
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
for (Vector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
(*i)->OnDeviceLost();
@ -1776,9 +1758,13 @@ void Graphics::Release(bool clearGPUObjects, bool closeWindow)
depthTextures_.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)
{
@ -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)
{
if (!surface)

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

@ -330,6 +330,8 @@ public:
void FreeScratchBuffer(void* buffer);
/// Release/clear GPU objects and optionally close the window.
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.
void CleanupRenderSurface(RenderSurface* surface);

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

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

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

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

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

@ -847,6 +847,22 @@ void Input::HandleSDLEvent(void* sdlEvent)
if (input)
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;
}
}

6
ThirdParty/SDL/include/SDL_video.h поставляемый
Просмотреть файл

@ -19,6 +19,8 @@
3. This notice may not be removed or altered from any source distribution.
*/
// Modified by Lasse Öörni for Urho3D
/**
* \file SDL_video.h
*
@ -150,8 +152,10 @@ typedef enum
SDL_WINDOWEVENT_LEAVE, /**< Window has lost mouse focus */
SDL_WINDOWEVENT_FOCUS_GAINED, /**< Window has gained 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 */
SDL_WINDOWEVENT_SURFACE_LOST, /**< Android only: surface has been lost */
SDL_WINDOWEVENT_SURFACE_CREATED /**< Android only: surface has been restored after loss */
} SDL_WindowEventID;
/**

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

@ -248,6 +248,23 @@ extern "C" void Java_org_libsdl_app_SDLActivity_nativeRunAudioThread(
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