summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-03 23:27:43 +0000
committerapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-03 23:27:43 +0000
commit9a298ada39103abf74e423519a9ee8251bbe0555 (patch)
treefe6229f2fe75a3d844408d9051cc3fa90dfe7fa8 /gpu
parent49a518aabe67f9366bc23d0142493cb6508d662d (diff)
downloadchromium_src-9a298ada39103abf74e423519a9ee8251bbe0555.zip
chromium_src-9a298ada39103abf74e423519a9ee8251bbe0555.tar.gz
chromium_src-9a298ada39103abf74e423519a9ee8251bbe0555.tar.bz2
Added support for lost context recovery on the client side. None of our service side GL implementations actually report lost contexts (yet).
Added pglGetError to PGL library. pglSwapBuffers returns false on a lost context or other non-recoverable error and pglGetError reports PGL_CONTEXT_LOST. Updated demo plugins to reset their PGL contexts on context lost. Standalone plugins cannot currently recover from lost context because they don't use PGL. Added error code to NPDeviceContext3D for lost context. TEST=none BUG=none Review URL: http://codereview.chromium.org/566021 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38039 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r--gpu/command_buffer/client/gles2_demo.cc6
-rw-r--r--gpu/command_buffer/client/gles2_demo_c.c2
-rw-r--r--gpu/command_buffer/client/gles2_demo_c.h2
-rw-r--r--gpu/command_buffer/client/gles2_demo_cc.cc73
-rw-r--r--gpu/command_buffer/client/gles2_demo_cc.h3
-rw-r--r--gpu/command_buffer/client/gles2_lib.cc1
-rw-r--r--gpu/command_buffer/common/constants.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc2
-rw-r--r--gpu/demos/framework/plugin.cc55
-rw-r--r--gpu/demos/framework/plugin.h3
-rw-r--r--gpu/pgl/pgl.cc85
-rw-r--r--gpu/pgl/pgl.h18
12 files changed, 164 insertions, 87 deletions
diff --git a/gpu/command_buffer/client/gles2_demo.cc b/gpu/command_buffer/client/gles2_demo.cc
index 9b5977e..8992c2c 100644
--- a/gpu/command_buffer/client/gles2_demo.cc
+++ b/gpu/command_buffer/client/gles2_demo.cc
@@ -83,6 +83,8 @@ bool GLES2Demo::Setup(void* hwnd, int32 size) {
transfer_buffer.ptr,
transfer_buffer_id));
+ GLFromCPPInit();
+
return command_buffer.release() != NULL;
}
@@ -97,8 +99,8 @@ LRESULT CALLBACK WindowProc(
PostQuitMessage(0);
break;
case WM_PAINT: {
- GLFromCPPTestFunction();
- GLFromCTestFunction();
+ GLFromCPPDraw();
+ GLFromCDraw();
// TODO(gman): Not sure how SwapBuffer should be exposed.
gles2::GetGLContext()->SwapBuffers();
break;
diff --git a/gpu/command_buffer/client/gles2_demo_c.c b/gpu/command_buffer/client/gles2_demo_c.c
index abba8b7..aa83b57 100644
--- a/gpu/command_buffer/client/gles2_demo_c.c
+++ b/gpu/command_buffer/client/gles2_demo_c.c
@@ -8,7 +8,7 @@
#include <GLES2/gl2.h>
#include "gpu/command_buffer/client/gles2_demo_c.h"
-void GLFromCTestFunction() {
+void GLFromCDraw() {
// glClear(GL_COLOR_BUFFER_BIT);
}
diff --git a/gpu/command_buffer/client/gles2_demo_c.h b/gpu/command_buffer/client/gles2_demo_c.h
index 3ce07b2..d4d69e9 100644
--- a/gpu/command_buffer/client/gles2_demo_c.h
+++ b/gpu/command_buffer/client/gles2_demo_c.h
@@ -11,7 +11,7 @@
extern "C" {
#endif
-void GLFromCTestFunction();
+void GLFromCDraw();
#ifdef __cplusplus
}
diff --git a/gpu/command_buffer/client/gles2_demo_cc.cc b/gpu/command_buffer/client/gles2_demo_cc.cc
index 2544f42..c6beff6 100644
--- a/gpu/command_buffer/client/gles2_demo_cc.cc
+++ b/gpu/command_buffer/client/gles2_demo_cc.cc
@@ -130,15 +130,43 @@ void InitShaders() {
CheckGLError();
}
-#define PI 3.1415926535897932384626433832795f
+GLuint CreateCheckerboardTexture() {
+ static unsigned char pixels[] = {
+ 255, 255, 255,
+ 0, 0, 0,
+ 0, 0, 0,
+ 255, 255, 255,
+ };
+ GLuint texture;
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE,
+ pixels);
+ return texture;
+}
+
+} // anonymous namespace.
+
+void GLFromCPPInit() {
+ glClearColor(0.f, 0.f, .7f, 1.f);
+ g_texture = CreateCheckerboardTexture();
+ InitShaders();
+}
+
+void GLFromCPPDraw() {
+ const float kPi = 3.1415926535897932384626433832795f;
-void Draw() {
// TODO(kbr): base the angle on time rather than on ticks
g_angle = (g_angle + 1) % 360;
// Rotate about the Z axis
GLfloat rot_matrix[16];
- GLfloat cos_angle = cosf(static_cast<GLfloat>(g_angle) * PI / 180.0f);
- GLfloat sin_angle = sinf(static_cast<GLfloat>(g_angle) * PI / 180.0f);
+ GLfloat cos_angle = cosf(static_cast<GLfloat>(g_angle) * kPi / 180.0f);
+ GLfloat sin_angle = sinf(static_cast<GLfloat>(g_angle) * kPi / 180.0f);
// OpenGL matrices are column-major
rot_matrix[0] = cos_angle;
rot_matrix[1] = sin_angle;
@@ -188,40 +216,3 @@ void Draw() {
CheckGLError();
glFlush();
}
-
-GLuint CreateCheckerboardTexture() {
- static unsigned char pixels[] = {
- 255, 255, 255,
- 0, 0, 0,
- 0, 0, 0,
- 255, 255, 255,
- };
- GLuint texture;
- glGenTextures(1, &texture);
- glBindTexture(GL_TEXTURE_2D, texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE,
- pixels);
- return texture;
-}
-
-void Init() {
- glClearColor(0.f, 0.f, .7f, 1.f);
- g_texture = CreateCheckerboardTexture();
- InitShaders();
-}
-
-} // anonymous namespace.
-
-void GLFromCPPTestFunction() {
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
- Init();
- }
- Draw();
-}
diff --git a/gpu/command_buffer/client/gles2_demo_cc.h b/gpu/command_buffer/client/gles2_demo_cc.h
index ef074e0..158ba43 100644
--- a/gpu/command_buffer/client/gles2_demo_cc.h
+++ b/gpu/command_buffer/client/gles2_demo_cc.h
@@ -7,7 +7,8 @@
#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_DEMO_CC_H
#define GPU_COMMAND_BUFFER_CLIENT_GLES2_DEMO_CC_H
-void GLFromCPPTestFunction();
+void GLFromCPPInit();
+void GLFromCPPDraw();
#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_DEMO_CC_H
diff --git a/gpu/command_buffer/client/gles2_lib.cc b/gpu/command_buffer/client/gles2_lib.cc
index 003a4cc..5753715 100644
--- a/gpu/command_buffer/client/gles2_lib.cc
+++ b/gpu/command_buffer/client/gles2_lib.cc
@@ -16,6 +16,7 @@ void Initialize() {
void Terminate() {
gpu::ThreadLocalFree(g_gl_context_key);
+ g_gl_context_key = 0;
}
gpu::gles2::GLES2Implementation* GetGLContext() {
diff --git a/gpu/command_buffer/common/constants.h b/gpu/command_buffer/common/constants.h
index b208153..2359bea 100644
--- a/gpu/command_buffer/common/constants.h
+++ b/gpu/command_buffer/common/constants.h
@@ -20,6 +20,7 @@ namespace error {
kOutOfBounds,
kUnknownCommand,
kInvalidArguments,
+ kLostContext,
kGenericError
};
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index ddfc358..684e579 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1549,8 +1549,6 @@ void GLES2DecoderImpl::DoLinkProgram(GLuint program) {
}
};
-// NOTE: If you need to know the results of SwapBuffers (like losing
-// the context) then add a new command. Do NOT make SwapBuffers synchronous.
void GLES2DecoderImpl::DoSwapBuffers() {
#if defined(UNIT_TEST)
#elif defined(OS_WIN)
diff --git a/gpu/demos/framework/plugin.cc b/gpu/demos/framework/plugin.cc
index 153cd97..0514f81 100644
--- a/gpu/demos/framework/plugin.cc
+++ b/gpu/demos/framework/plugin.cc
@@ -7,12 +7,13 @@
#include "base/logging.h"
#include "gpu/demos/framework/demo_factory.h"
+using gpu::demos::Plugin;
+
namespace {
const int32 kCommandBufferSize = 1024 * 1024;
NPExtensions* g_extensions = NULL;
// Plugin class functions.
-using gpu::demos::Plugin;
NPObject* PluginAllocate(NPP npp, NPClass* the_class) {
Plugin* plugin = new Plugin(npp);
return plugin;
@@ -97,7 +98,7 @@ Plugin::~Plugin() {
demo_.reset();
pglMakeCurrent(NULL);
- pglDestroyContext(pgl_context_);
+ DestroyContext();
}
NPClass* Plugin::GetPluginClass() {
@@ -116,20 +117,10 @@ void Plugin::New(NPMIMEType pluginType,
}
void Plugin::SetWindow(const NPWindow& window) {
- if (!pgl_context_) {
- // Initialize a 3D context.
- NPDeviceContext3DConfig config;
- config.commandBufferSize = kCommandBufferSize;
- device3d_->initializeContext(npp_, &config, &context3d_);
-
- // Create a PGL context.
- pgl_context_ = pglCreateContext(npp_, device3d_, &context3d_);
+ demo_->InitWindowSize(window.width, window.height);
- // Initialize demo.
- pglMakeCurrent(pgl_context_);
- demo_->InitWindowSize(window.width, window.height);
- CHECK(demo_->InitGL());
- pglMakeCurrent(NULL);
+ if (!pgl_context_) {
+ CreateContext();
}
// Schedule the first call to Draw.
@@ -137,8 +128,12 @@ void Plugin::SetWindow(const NPWindow& window) {
}
void Plugin::Paint() {
- // Render some stuff.
- pglMakeCurrent(pgl_context_);
+ if (!pglMakeCurrent(pgl_context_) && pglGetError() == PGL_CONTEXT_LOST) {
+ DestroyContext();
+ CreateContext();
+ pglMakeCurrent(pgl_context_);
+ }
+
demo_->Draw();
pglSwapBuffers();
pglMakeCurrent(NULL);
@@ -147,5 +142,31 @@ void Plugin::Paint() {
g_browser->pluginthreadasynccall(npp_, PaintCallback, this);
}
+void Plugin::CreateContext() {
+ DCHECK(!pgl_context_);
+
+ // Initialize a 3D context.
+ NPDeviceContext3DConfig config;
+ config.commandBufferSize = kCommandBufferSize;
+ device3d_->initializeContext(npp_, &config, &context3d_);
+
+ // Create a PGL context.
+ pgl_context_ = pglCreateContext(npp_, device3d_, &context3d_);
+
+ // Initialize demo.
+ pglMakeCurrent(pgl_context_);
+ CHECK(demo_->InitGL());
+ pglMakeCurrent(NULL);
+}
+
+void Plugin::DestroyContext() {
+ DCHECK(pgl_context_);
+
+ pglDestroyContext(pgl_context_);
+ pgl_context_ = NULL;
+
+ device3d_->destroyContext(npp_, &context3d_);
+}
+
} // namespace demos
} // namespace gpu
diff --git a/gpu/demos/framework/plugin.h b/gpu/demos/framework/plugin.h
index 7832d3b..0f4b55e 100644
--- a/gpu/demos/framework/plugin.h
+++ b/gpu/demos/framework/plugin.h
@@ -31,6 +31,9 @@ class Plugin : public NPObject {
void Paint();
private:
+ void CreateContext();
+ void DestroyContext();
+
// This class object needs to be safely casted to NPObject* and cross
// c-c++ module boundaries. To accomplish that this class should not have
// any virtual member function.
diff --git a/gpu/pgl/pgl.cc b/gpu/pgl/pgl.cc
index 41903e1..68a074f 100644
--- a/gpu/pgl/pgl.cc
+++ b/gpu/pgl/pgl.cc
@@ -7,6 +7,7 @@
#include "gpu/command_buffer/client/gles2_cmd_helper.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "gpu/command_buffer/client/gles2_lib.h"
+#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/thread_local.h"
#include "gpu/pgl/command_buffer_pepper.h"
#include "gpu/pgl/pgl.h"
@@ -22,16 +23,19 @@ class PGLContextImpl {
~PGLContextImpl();
// Initlaize a PGL context with a transfer buffer of a particular size.
- bool Initialize(int32 transfer_buffer_size);
+ PGLBoolean Initialize(int32 transfer_buffer_size);
// Destroy all resources associated with the PGL context.
void Destroy();
// Make a PGL context current for the calling thread.
- static bool MakeCurrent(PGLContextImpl* pgl_context);
+ static PGLBoolean MakeCurrent(PGLContextImpl* pgl_context);
// Display all content rendered since last call to SwapBuffers.
- bool SwapBuffers();
+ PGLBoolean SwapBuffers();
+
+ // Get the current error code.
+ PGLInt GetError();
private:
PGLContextImpl(const PGLContextImpl&);
@@ -64,7 +68,7 @@ PGLContextImpl::~PGLContextImpl() {
Destroy();
}
-bool PGLContextImpl::Initialize(int32 transfer_buffer_size) {
+PGLBoolean PGLContextImpl::Initialize(int32 transfer_buffer_size) {
// Create and initialize the objects required to issue GLES2 calls.
command_buffer_ = new CommandBufferPepper(
npp_, device_, device_context_);
@@ -80,13 +84,13 @@ bool PGLContextImpl::Initialize(int32 transfer_buffer_size) {
transfer_buffer.size,
transfer_buffer.ptr,
transfer_buffer_id_);
- return true;
+ return PGL_TRUE;
}
}
// Tear everything down if initialization failed.
Destroy();
- return false;
+ return PGL_FALSE;
}
void PGLContextImpl::Destroy() {
@@ -105,22 +109,48 @@ void PGLContextImpl::Destroy() {
command_buffer_ = NULL;
}
-bool PGLContextImpl::MakeCurrent(PGLContextImpl* pgl_context) {
+PGLBoolean PGLContextImpl::MakeCurrent(PGLContextImpl* pgl_context) {
if (!g_pgl_context_key)
- return false;
+ return PGL_FALSE;
gpu::ThreadLocalSetValue(g_pgl_context_key, pgl_context);
- if (pgl_context)
+ if (pgl_context) {
gles2::SetGLContext(pgl_context->gles2_implementation_);
- else
+
+ // Don't request latest error status from service. Just use the locally
+ // cached information from the last flush.
+ // TODO(apatrick): I'm not sure if this should actually change the
+ // current context if it fails. For now it gets changed even if it fails
+ // becuase making GL calls with a NULL context crashes.
+ if (pgl_context->device_context_->error != NPDeviceContext3DError_NoError)
+ return PGL_FALSE;
+ }
+ else {
gles2::SetGLContext(NULL);
+ }
- return true;
+ return PGL_TRUE;
}
-bool PGLContextImpl::SwapBuffers() {
+PGLBoolean PGLContextImpl::SwapBuffers() {
+ // Don't request latest error status from service. Just use the locally cached
+ // information from the last flush.
+ if (device_context_->error != NPDeviceContext3DError_NoError)
+ return PGL_FALSE;
+
gles2_implementation_->SwapBuffers();
- return true;
+ return PGL_TRUE;
+}
+
+PGLInt PGLContextImpl::GetError() {
+ gpu::CommandBuffer::State state = command_buffer_->GetState();
+ if (state.error == gpu::error::kNoError) {
+ return PGL_SUCCESS;
+ } else {
+ // All command buffer errors are unrecoverable. The error is treated as a
+ // lost context: destroy the context and create another one.
+ return PGL_CONTEXT_LOST;
+ }
}
} // namespace anonymous
@@ -128,20 +158,22 @@ extern "C" {
PGLBoolean pglInitialize() {
if (g_pgl_context_key)
- return true;
+ return PGL_TRUE;
gles2::Initialize();
g_pgl_context_key = gpu::ThreadLocalAlloc();
- return true;
+ return PGL_TRUE;
}
PGLBoolean pglTerminate() {
if (!g_pgl_context_key)
- return true;
+ return PGL_TRUE;
gpu::ThreadLocalFree(g_pgl_context_key);
+ g_pgl_context_key = 0;
+
gles2::Terminate();
- return true;
+ return PGL_TRUE;
}
PGLContext pglCreateContext(NPP npp,
@@ -175,23 +207,34 @@ PGLBoolean pglSwapBuffers(void) {
PGLContextImpl* context = static_cast<PGLContextImpl*>(
pglGetCurrentContext());
if (!context)
- return false;
+ return PGL_FALSE;
return context->SwapBuffers();
}
PGLBoolean pglDestroyContext(PGLContext pgl_context) {
if (!g_pgl_context_key)
- return NULL;
+ return PGL_FALSE;
if (!pgl_context)
- return false;
+ return PGL_FALSE;
if (pgl_context == pglGetCurrentContext())
pglMakeCurrent(NULL);
delete static_cast<PGLContextImpl*>(pgl_context);
- return true;
+ return PGL_TRUE;
}
+PGLInt pglGetError() {
+ if (!g_pgl_context_key)
+ return PGL_NOT_INITIALIZED;
+
+ PGLContextImpl* context = static_cast<PGLContextImpl*>(
+ pglGetCurrentContext());
+ if (!context)
+ return PGL_BAD_CONTEXT;
+
+ return context->GetError();
+}
} // extern "C"
diff --git a/gpu/pgl/pgl.h b/gpu/pgl/pgl.h
index 3a7735e..ac67ec1 100644
--- a/gpu/pgl/pgl.h
+++ b/gpu/pgl/pgl.h
@@ -8,12 +8,25 @@
#include "npapi.h"
#include "npapi_extensions.h"
+#define PGL_TRUE 1
+#define PGL_FALSE 0
+
#ifdef __cplusplus
extern "C" {
#endif
typedef void* PGLContext;
-typedef bool PGLBoolean;
+typedef unsigned int PGLBoolean;
+typedef int32 PGLInt;
+
+// These are the same error codes as used by EGL.
+enum {
+ PGL_SUCCESS = 0x3000,
+ PGL_NOT_INITIALIZED = 0x3001,
+ PGL_BAD_CONTEXT = 0x3006,
+ PGL_BAD_PARAMETER = 0x300C,
+ PGL_CONTEXT_LOST = 0x300E
+};
// Initialize the PGL library. This must have completed before any other PGL
// functions are invoked.
@@ -40,6 +53,9 @@ PGLBoolean pglSwapBuffers(void);
// Destroy the given PGL context.
PGLBoolean pglDestroyContext(PGLContext pgl_context);
+// Return the current PGL error.
+PGLInt pglGetError();
+
#ifdef __cplusplus
} // extern "C"
#endif