Android OpenGL context loss handling.
This commit is contained in:
Родитель
35bec043ad
Коммит
8cc2a83e48
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче