 +#define NACLVID_DRIVER_NAME "nacl"
 +
 +void SDL_NACL_SetInstance(PP_Instance instance, int width, int height) {
-+  gNaclPPInstance = pp::Module::Get()->InstanceForPPInstance(instance);
++  if (!gNaclPPInstance) {
++    gNaclPPInstance = pp::Module::Get()->InstanceForPPInstance(instance);
++    gNaclMainThreadRunner = new MainThreadRunner(gNaclPPInstance);
++  }
 +  gNaclVideoWidth = width;
 +  gNaclVideoHeight = height;
 +}

+    return;
+
+  assert(_this->hidden->image_data);
+  assert(_this->hidden->w == _this->hidden->ow);
+  assert(_this->hidden->h == _this->hidden->oh);
+
+  SDL_LockMutex(_this->hidden->flush_mutex);
+
+  // If we are flushing, wait.
+  // TODO(eugenis): this blocks the game thread. Should we just drop the frame
+  // instead, or store it in some kind of a side buffer?
+  while (_this->hidden->flush_pending)
+    SDL_CondWait(_this->hidden->flush_cond, _this->hidden->flush_mutex);
+
+  // data_ready may be true here if the previous frame is not flushed yet.
+  // No problem, just drop it.
+
+  // Copy the updated areas to the ImageData.
+  unsigned pitch = _this->hidden->w * _this->hidden->bpp / 8;
+  for (int i = 0; i < numrects; ++i) {
+    unsigned start_offset = rects[i].x * _this->hidden->bpp / 8 + rects[i].y * pitch;
+    unsigned char* src = (unsigned char*)_this->hidden->buffer + start_offset;
+    unsigned char* src_end = src + rects[i].h * pitch;
+    unsigned char* dst = (unsigned char*)_this->hidden->image_data->data() + start_offset;
+    unsigned line_size = rects[i].w * _this->hidden->bpp / 8;
+    while (src < src_end) {
+      SDL_memcpy(dst, src, line_size);
+      src += pitch;
+      dst += pitch;
+    }
+    _this->hidden->updated_rects.push_back(rects[i]);
+  }
+
+  // Clear alpha channel in the ImageData.
+  unsigned char* start = (unsigned char*)_this->hidden->image_data->data();

 
 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
 	/* Allow ourselves to be asynchronously cancelled */
diff -urN SDL-1.2.14/src/video/nacl/eventqueue.h SDL-1.2.14-nacl//src/video/nacl/eventqueue.h
--- SDL-1.2.14/src/video/nacl/eventqueue.h	1970-01-01 03:00:00.000000000 +0300
+++ SDL-1.2.14-nacl//src/video/nacl/eventqueue.h	2011-11-28 23:43:22.689635148 +0400
@@ -0,0 +1,43 @@
+#ifndef _SDL_nacl_eventqueue_h
+#define _SDL_nacl_eventqueue_h
+
+#include "SDL_mutex.h"
+
+#include <queue>
+#include <ppapi/c/pp_input_event.h>
+
+struct SDL_NACL_Event;
+
+class EventQueue {
+public:
+  EventQueue() {
+    mu_ = SDL_CreateMutex();
+  }
+
+  ~EventQueue() {
+    SDL_DestroyMutex(mu_);
+  }
+
+  SDL_NACL_Event* PopEvent() {
+    SDL_LockMutex(mu_);
+    SDL_NACL_Event* event = NULL;
+    if (!queue_.empty()) {
+      event = queue_.front();
+      queue_.pop();
+    }
+    SDL_UnlockMutex(mu_);
+    return event;
+  }
+
+   void PushEvent(SDL_NACL_Event* event) {
+    SDL_LockMutex(mu_);
+    queue_.push(event);
+    SDL_UnlockMutex(mu_);
+   } 
+
+private:
+  std::queue<SDL_NACL_Event*> queue_;
+  SDL_mutex* mu_;
+};
+
+#endif // _SDL_nacl_eventqueue_h
diff -urN SDL-1.2.14/src/video/nacl/MainThreadRunner.cc SDL-1.2.14-nacl//src/video/nacl/MainThreadRunner.cc
--- SDL-1.2.14/src/video/nacl/MainThreadRunner.cc	1970-01-01 03:00:00.000000000 +0300
+++ SDL-1.2.14-nacl//src/video/nacl/MainThreadRunner.cc	2011-11-28 23:43:34.019635132 +0400
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2011 The Native Client Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "MainThreadRunner.h"
+#include <alloca.h>
+#include <assert.h>
+#include <errno.h>
+
+// Only use pepper in nacl to allow unit testing.
+#ifdef __native_client__
+#  include <ppapi/c/pp_errors.h>
+#  include <ppapi/cpp/completion_callback.h>
+#  include <ppapi/cpp/module.h>
+#  define USE_PEPPER
+#endif
+
+// kWORK_POLL_TIMEOUT sets the time delay (in milliseconds) between checks
+// for available jobs.
+static const int kWorkPollTimeout = 10;
+
+// Stack space to allocate by default to the event handler
+// thread in the presence of an ancillary 'pseudo-thread'.
+// 640K of stack should be enough for anyone.
+static const int kDefaultPseudoThreadHeadroom = 640 * 1024;
+
+// If we're not using pepper, track main thread's id so
+// we can do something sensible.
+#ifndef USE_PEPPER
+static pthread_t main_thread_id_;
+#endif
+
+struct MainThreadRunner::JobEntry {
+  pp::Instance* pepper_instance;
+  MainThreadRunner* runner;
+  MainThreadJob* job;
+  pthread_mutex_t done_mutex;
+  pthread_cond_t done_cond;
+  bool is_done;
+  int32_t result;
+  bool pseudo_thread_job;
+};
+
+
+MainThreadRunner::MainThreadRunner(pp::Instance *instance) {
+#ifndef USE_PEPPER
+  // Record main thread if not using pepper.
+  main_thread_id_ = pthread_self();
+#endif
+
+  pepper_instance_ = instance;
+  pthread_mutex_init(&lock_, NULL);
+
+#ifdef USE_PEPPER
+  // Start work cycling if using pepper.
+  DoWork();
+#endif
+}
+
+MainThreadRunner::~MainThreadRunner() {
+  pthread_mutex_destroy(&lock_);
+}
+
+int32_t MainThreadRunner::RunJob(MainThreadJob* job) {
+  JobEntry entry;
+
+  // initialize the entry
+  entry.runner = this;
+  entry.pepper_instance = pepper_instance_;
+  entry.job = job;
+
+  bool in_main_thread = IsMainThread();
+  // Must be off main thread, or on a pseudothread.
+  assert(!in_main_thread || in_pseudo_thread_);
+
+  // Thread type specific initialization.
+  if (in_main_thread) {
+    entry.pseudo_thread_job = true;
+  } else {
+    entry.pseudo_thread_job = false;
+    // Init condition variable.
+    entry.is_done = false;
+    int ret = pthread_mutex_init(&entry.done_mutex, NULL);
+    assert(!ret);
+    ret = pthread_cond_init(&entry.done_cond, NULL);
+    assert(!ret);
+  }
+
+  // put the job on the queue
+  pthread_mutex_lock(&lock_);
+  job_queue_.push_back(&entry);
+  pthread_mutex_unlock(&lock_);
+
+  // Block differntly on the main thread.
+  if (entry.pseudo_thread_job) {
+    // block pseudothread until job is done
+    PseudoThreadBlock();
+  } else {
+    // wait on condition until the job is done
+    pthread_mutex_lock(&entry.done_mutex);
+    while (!entry.is_done) {
+      pthread_cond_wait(&entry.done_cond, &entry.done_mutex);
+    }
+    pthread_mutex_unlock(&entry.done_mutex);
+    pthread_mutex_destroy(&entry.done_mutex);
+    pthread_cond_destroy(&entry.done_cond);
+  }
+
+  // Cleanup.
+  delete job;
+  return entry.result;
+}
+
+void MainThreadRunner::ResultCompletion(void *arg, int32_t result) {
+  JobEntry* entry = reinterpret_cast<JobEntry*>(arg);
+#ifdef USE_PEPPER
+  MainThreadRunner* runner = entry->runner;
+#endif
+  entry->result = result;
+  // Signal differently depending on if the pseudothread is involved.
+  if (entry->pseudo_thread_job) {
+    PseudoThreadResume();
+  } else {
+    pthread_mutex_lock(&entry->done_mutex);
+    entry->is_done = true;
+    pthread_cond_signal(&entry->done_cond);
+    pthread_mutex_unlock(&entry->done_mutex);
+  }
+#ifdef USE_PEPPER
+  // Do more work now if in pepper.
+  DoWorkShim(runner, 0);
+#endif
+}
+
+void MainThreadRunner::DoWorkShim(void *p, int32_t unused) {
+  MainThreadRunner* mtr = static_cast<MainThreadRunner *>(p);
+  mtr->DoWork();
+}
+
+void MainThreadRunner::DoWork(void) {
+  pthread_mutex_lock(&lock_);
+  if (!job_queue_.empty()) {
+    JobEntry* entry = job_queue_.front();
+    job_queue_.pop_front();
+    // Release lock before doing work.
+    pthread_mutex_unlock(&lock_);
+    entry->job->Run(entry);
+    return;
+  }
+#ifdef USE_PEPPER
+  // Wake ourselves back up if we're using pepper.
+  pp::Module::Get()->core()->CallOnMainThread(kWorkPollTimeout,
+      pp::CompletionCallback(&DoWorkShim, this), PP_OK);
+#endif
+  pthread_mutex_unlock(&lock_);
+}
+
+pp::Instance *MainThreadRunner::ExtractPepperInstance(
+    MainThreadRunner::JobEntry *e) {
+  return e->pepper_instance;
+}
+
+void MainThreadRunner::PseudoThreadFork(void *(*func)(void *arg), void *arg) {
+  PseudoThreadHeadroomFork(kDefaultPseudoThreadHeadroom, func, arg);
+}
+
+void MainThreadRunner::PseudoThreadHeadroomFork(
+    int bytes_headroom, void *(*func)(void *arg), void *arg) {
+  // Must be run from the main thread.
+  assert(IsMainThread());
+  // Only one pseudothread can be forked.
+  assert(!forked_pseudo_thread_);
+  // Leave a gap of bytes_headroom on the stack between
+  alloca(bytes_headroom);
+  // Goto pseudothread, but remeber how to come back here.
+  if (!setjmp(main_thread_state_)) {
+    InnerPseudoThreadFork(func, arg);
+  }
+  in_pseudo_thread_ = false;
+}
+
+// Put things in another scope to keep above headroom,
+// even after thread ends.
+void MainThreadRunner::InnerPseudoThreadFork(
+    void *(func)(void *arg), void *arg) {
+  forked_pseudo_thread_ = true;
+  in_pseudo_thread_ = true;
+  func(arg);
+  forked_pseudo_thread_ = false;
+  in_pseudo_thread_ = false;
+  // Dead, keep kicking back to the main thread.
+  for (;;) {
+    longjmp(main_thread_state_, 1);
+  }
+}
+
+void MainThreadRunner::PseudoThreadBlock(void) {
+  // Must be run from the main thread.
+  assert(IsMainThread());
+  // Pseudothread must have been forked.
+  assert(forked_pseudo_thread_);
+  // Must be run only from the pseudothread.
+  assert(in_pseudo_thread_);
+  if (!setjmp(pseudo_thread_state_)) {
+    // Go back to the main thread after saving state.
+    longjmp(main_thread_state_, 1);
+  }
+  in_pseudo_thread_ = true;
+}
+
+void MainThreadRunner::PseudoThreadResume(void) {
+  // Must be run from the main thread.
+  assert(IsMainThread());
+  // Pseudothread must have been forked.
+  assert(forked_pseudo_thread_);
+  // Can only be run from the main thread.
+  assert(!in_pseudo_thread_);
+  if (!setjmp(main_thread_state_)) {
+    // Go back to the pseudo thread after saving state.
+    longjmp(pseudo_thread_state_, 1);
+  }
+  in_pseudo_thread_ = false;
+}
+
+bool MainThreadRunner::IsMainThread(void) {
+#ifdef USE_PEPPER
+  return pp::Module::Get()->core()->IsMainThread();
+#else
+  return pthread_equal(pthread_self(), main_thread_id_);
+#endif
+}
+
+bool MainThreadRunner::IsPseudoThread(void) {
+  return IsMainThread() && in_pseudo_thread_;
+}
+
+// Static variables in MainThreaadRunner.
+jmp_buf MainThreadRunner::main_thread_state_;
+jmp_buf MainThreadRunner::pseudo_thread_state_;
+bool MainThreadRunner::in_pseudo_thread_ = false;
+bool MainThreadRunner::forked_pseudo_thread_ = false;
diff -urN SDL-1.2.14/src/video/nacl/MainThreadRunner.h SDL-1.2.14-nacl//src/video/nacl/MainThreadRunner.h
--- SDL-1.2.14/src/video/nacl/MainThreadRunner.h	1970-01-01 03:00:00.000000000 +0300
+++ SDL-1.2.14-nacl//src/video/nacl/MainThreadRunner.h	2011-11-28 23:43:34.019635132 +0400
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2011 The Native Client Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef LIBRARIES_NACL_MOUNTS_BASE_MAINTHREADRUNNER_H_
+#define LIBRARIES_NACL_MOUNTS_BASE_MAINTHREADRUNNER_H_
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <setjmp.h>
+#include <list>
+
+// Keep pepper specifics out so we can unit test.
+namespace pp {
+  class Instance;
+};
+
+// MainThreadJob is a class that provides a method for running
+// a MainThreadRunner::JobEntry.
+class MainThreadJob;
+
+// MainThreadRunner executes MainThreadJobs asynchronously
+// on the main thread.
+class MainThreadRunner {
+ public:
+  explicit MainThreadRunner(pp::Instance *instance);
+  ~MainThreadRunner();
+
+  // RunJob() creates an entry for the job and submits
+  // that job for execution.
+  int32_t RunJob(MainThreadJob *job);
+
+  // ResultCompletion() is a function for putting result into arg, which
+  // is reinterpreted as a JobEntry pointer.  ResultCompletion()
+  // is intended to be used with pp::CompletionCallback()
+  static void ResultCompletion(void *arg, int32_t result);
+
+  // The JobEntry struct provides all of the information for
+  // a particular job.  It acts as an opaque handle to the job to and
+  // is used by ResultCompletion().
+  struct JobEntry;
+
+  static pp::Instance *ExtractPepperInstance(MainThreadRunner::JobEntry *e);
+
+  // You can have one 'pseudothread' on top of the main thread.
+  // This coroutine (setjmp) based thread can block on Run.
+  // You will have to take some amount of re-entrancy into account.
+  // Assumes 640K of stack is enough for anyone for event handling in the
+  // main thread.
+  static void PseudoThreadFork(void *(*func)(void *arg), void *arg);
+  // Same as above with selectable bytes of headroom.
+  static void PseudoThreadHeadroomFork(
+      int bytes_headroom, void *(*func)(void *arg), void *arg);
+
+  // Returns:
+  //   true - main thread or pseudothread.
+  //   false - other pthreads.
+  static bool IsMainThread(void);
+
+  // Returns true if on the psuedothread.
+  static bool IsPseudoThread(void);
+
+  // Use these directly only if you are interacting with PPAPI
+  // such that you can guarantee you'll resume because of an
+  // asynchronous event you issued.
+  // Block pseudothread until main thread yields.
+  static void PseudoThreadBlock(void);
+  // Yield main thread to pseudothread.
+  static void PseudoThreadResume(void);
+
+  // Do at least one main thread job.
+  // DO NOT use this with pepper (which sets up an event
+  // cycle to call this automatically).
+  // Use directly only for testing.
+  void DoWork(void);
+
+ private:
+  static void DoWorkShim(void *p, int32_t unused);
+
+  // Used to keep things above the headroom.
+  static void InnerPseudoThreadFork(void *(func)(void *arg), void *arg);
+
+  pthread_mutex_t lock_;
+  std::list<JobEntry*> job_queue_;
+  pp::Instance *pepper_instance_;
+
+  static jmp_buf pseudo_thread_state_;
+  static jmp_buf main_thread_state_;
+  static bool in_pseudo_thread_;
+  static bool forked_pseudo_thread_;
+};
+
+class MainThreadJob {
+ public:
+  virtual ~MainThreadJob() {}
+  virtual void Run(MainThreadRunner::JobEntry *entry) = 0;
+};
+
+// MainThreadRunner executes MainThreadJobs asynchronously
+
+#endif  // LIBRARIES_NACL_MOUNTS_BASE_MAINTHREADRUNNER_H_
diff -urN SDL-1.2.14/src/video/nacl/SDL_naclevents.cc SDL-1.2.14-nacl//src/video/nacl/SDL_naclevents.cc
--- SDL-1.2.14/src/video/nacl/SDL_naclevents.cc	1970-01-01 03:00:00.000000000 +0300
+++ SDL-1.2.14-nacl//src/video/nacl/SDL_naclevents.cc	2011-11-28 23:43:22.689635148 +0400
@@ -0,0 +1,196 @@
+#include "SDL_config.h"
+
