summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/gamepad_resource.cc
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-10 07:06:39 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-10 07:06:39 +0000
commit00c0d0437c9f6f8896df580bcbeffd022d1cf878 (patch)
tree0177c166101ddd30916ee2eaf50d409d2e86ace2 /ppapi/proxy/gamepad_resource.cc
parent7b64f86e2c50c086dba2d3aba2b1a0d22208f072 (diff)
downloadchromium_src-00c0d0437c9f6f8896df580bcbeffd022d1cf878.zip
chromium_src-00c0d0437c9f6f8896df580bcbeffd022d1cf878.tar.gz
chromium_src-00c0d0437c9f6f8896df580bcbeffd022d1cf878.tar.bz2
Implement the gamepad API in the IPC proxy
This does some reworking of the gamepad system to make it possible to hook in (previously it assumed that it was only talking to renderers) and I did some cleanup. Gamepad files were renamed to match the classes, and I did a bunch of test infrastructure work. IMPORTANT BEHAVIOR CHANGE: This changes the Web gamepad API to report all gamepad data as soon as any of them are interacted with. This is what we need to do for Pepper anyway (since it gets all or none of the share memory) and I think makes more sense for most consumers anyway. I separated out the user gesture detection code into a place where it can be used in the browser process as well, and exposed functionality in the gamepad provider to be notified when a user gesture happens. The existing gamepad test was disabled and had bitrotted. This fixes it. Review URL: https://chromiumcodereview.appspot.com/10912062 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155676 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/proxy/gamepad_resource.cc')
-rw-r--r--ppapi/proxy/gamepad_resource.cc87
1 files changed, 72 insertions, 15 deletions
diff --git a/ppapi/proxy/gamepad_resource.cc b/ppapi/proxy/gamepad_resource.cc
index 21ee02d..446c11c 100644
--- a/ppapi/proxy/gamepad_resource.cc
+++ b/ppapi/proxy/gamepad_resource.cc
@@ -6,16 +6,47 @@
#include <string.h>
-#include "ppapi/c/ppb_gamepad.h"
+#include "base/threading/platform_thread.h"
#include "ppapi/proxy/dispatch_reply_message.h"
#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/ppb_gamepad_shared.h"
namespace ppapi {
namespace proxy {
+namespace {
+
+// This is the read logic from content/common/gamepad_seqlock.h
+base::subtle::Atomic32 ReadBegin(const base::subtle::Atomic32* sequence) {
+ base::subtle::Atomic32 version;
+ for (;;) {
+ version = base::subtle::NoBarrier_Load(sequence);
+
+ // If the counter is even, then the associated data might be in a
+ // consistent state, so we can try to read.
+ if ((version & 1) == 0)
+ break;
+
+ // Otherwise, the writer is in the middle of an update. Retry the read.
+ base::PlatformThread::YieldCurrentThread();
+ }
+ return version;
+}
+
+bool ReadRetry(const base::subtle::Atomic32* sequence,
+ base::subtle::Atomic32 version) {
+ // If the sequence number was updated then a read should be re-attempted.
+ // -- Load fence, read membarrier
+ return base::subtle::Release_Load(sequence) != version;
+}
+
+} // namespace
+
GamepadResource::GamepadResource(Connection connection, PP_Instance instance)
: PluginResource(connection, instance),
buffer_(NULL) {
+ memset(&last_read_, 0, sizeof(last_read_));
+
SendCreateToBrowser(PpapiHostMsg_Gamepad_Create());
CallBrowser(PpapiHostMsg_Gamepad_RequestMemory());
}
@@ -28,30 +59,56 @@ void GamepadResource::Sample(PP_GamepadsSampleData* data) {
// Browser hasn't sent back our shared memory, give the plugin gamepad
// data corresponding to "not connected".
memset(data, 0, sizeof(PP_GamepadsSampleData));
- } else {
- memcpy(data, buffer_, sizeof(PP_GamepadsSampleData));
+ return;
}
+
+ // ==========
+ // DANGER
+ // ==========
+ //
+ // This logic is duplicated in the renderer as well. If you change it, that
+ // also needs to be in sync. See gamepad_shared_memory_reader.cc.
+
+ // Only try to read this many times before failing to avoid waiting here
+ // very long in case of contention with the writer.
+ const int kMaximumContentionCount = 10;
+ int contention_count = -1;
+ base::subtle::Atomic32 version;
+ WebKitGamepads read_into;
+ do {
+ version = ReadBegin(&buffer_->sequence);
+ memcpy(&read_into, &buffer_->buffer, sizeof(read_into));
+ ++contention_count;
+ if (contention_count == kMaximumContentionCount)
+ break;
+ } while (ReadRetry(&buffer_->sequence, version));
+
+ // In the event of a read failure, just leave the last read data as-is (the
+ // hardware thread is taking unusally long).
+ if (contention_count < kMaximumContentionCount)
+ ConvertWebKitGamepadData(read_into, &last_read_);
+
+ memcpy(data, &last_read_, sizeof(PP_GamepadsSampleData));
}
void GamepadResource::OnReplyReceived(const ResourceMessageReplyParams& params,
const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(GamepadResource, msg)
- PPAPI_DISPATCH_RESOURCE_REPLY(PpapiPluginMsg_Gamepad_SendMemory,
- OnPluginMsgSendMemory)
+ PPAPI_DISPATCH_RESOURCE_REPLY_0(PpapiPluginMsg_Gamepad_SendMemory,
+ OnPluginMsgSendMemory)
IPC_END_MESSAGE_MAP()
}
void GamepadResource::OnPluginMsgSendMemory(
- const ResourceMessageReplyParams& params,
- base::SharedMemoryHandle shared_memory_handle) {
- /* TODO(brettw) implement this when we have shared gamepad code. It would be
- something like this:
- shared_memory_.reset(
- new base::SharedMemory(shared_memory_handle, true));
- CHECK(shared_memory_->Map(sizeof(GamepadHardwareBuffer)));
- void *memory = shared_memory_->memory();
- // Use the memory...
- */
+ const ResourceMessageReplyParams& params) {
+ // On failure, the handle will be null and the CHECK below will be tripped.
+ base::SharedMemoryHandle handle;
+ params.GetSharedMemoryHandleAtIndex(0, &handle);
+
+ shared_memory_.reset(new base::SharedMemory(handle, true));
+ CHECK(shared_memory_->Map(sizeof(ContentGamepadHardwareBuffer)));
+ buffer_ = static_cast<const ContentGamepadHardwareBuffer*>(
+ shared_memory_->memory());
}
} // namespace proxy