summaryrefslogtreecommitdiffstats
path: root/o3d/core
diff options
context:
space:
mode:
authorgman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-11 00:29:35 +0000
committergman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-11 00:29:35 +0000
commit6689dbbb7832c151d6d846b6ed55445a6c979f20 (patch)
tree3b570d0bd063a1e50b821d924d13f6beb8741ef4 /o3d/core
parentf68b7fa0fc9b002a9db4d499cc7e0c7c7636be8a (diff)
downloadchromium_src-6689dbbb7832c151d6d846b6ed55445a6c979f20.zip
chromium_src-6689dbbb7832c151d6d846b6ed55445a6c979f20.tar.gz
chromium_src-6689dbbb7832c151d6d846b6ed55445a6c979f20.tar.bz2
Add UpdateTexure2DRect to IMC
Also refactored IMC for to be more safe and easy to use. It still needs: *) structures/wrappers for message responces *) Some of the error checking could probably be moved out of the inidivdual message processing functions *) Need some constants or wrappers for the handles so a message isn't pulling things out of handles by magic numbers. Review URL: http://codereview.chromium.org/165266 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22987 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/core')
-rw-r--r--o3d/core/build.scons1
-rw-r--r--o3d/core/core.gyp3
-rw-r--r--o3d/core/cross/message_commands.cc50
-rw-r--r--o3d/core/cross/message_commands.h292
-rw-r--r--o3d/core/cross/message_commands_test.cc47
-rw-r--r--o3d/core/cross/message_queue.cc344
-rw-r--r--o3d/core/cross/message_queue.h129
-rw-r--r--o3d/core/cross/message_queue_test.cc483
-rw-r--r--o3d/core/cross/packing.h66
9 files changed, 983 insertions, 432 deletions
diff --git a/o3d/core/build.scons b/o3d/core/build.scons
index e155919..c332368 100644
--- a/o3d/core/build.scons
+++ b/o3d/core/build.scons
@@ -74,6 +74,7 @@ cross_inputs = [
'cross/matrix4_composition.cc',
'cross/matrix4_scale.cc',
'cross/matrix4_translation.cc',
+ 'cross/message_commands.cc',
'cross/message_queue.cc',
'cross/named_object.cc',
'cross/object_base.cc',
diff --git a/o3d/core/core.gyp b/o3d/core/core.gyp
index e0644a1..2cf7794 100644
--- a/o3d/core/core.gyp
+++ b/o3d/core/core.gyp
@@ -144,6 +144,8 @@
'cross/matrix4_scale.h',
'cross/matrix4_translation.cc',
'cross/matrix4_translation.h',
+ 'cross/message_commands.cc',
+ 'cross/message_commands.h',
'cross/message_queue.cc',
'cross/message_queue.h',
'cross/named_object.cc',
@@ -380,6 +382,7 @@
'cross/matrix4_composition_test.cc',
'cross/matrix4_scale_test.cc',
'cross/matrix4_translation_test.cc',
+ 'cross/message_commands_test.cc',
'cross/message_queue_test.cc',
'cross/object_base_test.cc',
'cross/pack_test.cc',
diff --git a/o3d/core/cross/message_commands.cc b/o3d/core/cross/message_commands.cc
new file mode 100644
index 0000000..631f518
--- /dev/null
+++ b/o3d/core/cross/message_commands.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file contains string descriptions of various IMC messages for O3D.
+
+#include "core/cross/precompile.h"
+#include "core/cross/message_commands.h"
+
+namespace o3d {
+
+const char* IMCMessage::GetMessageDescription(IMCMessage::MessageId id) {
+ const char* const message_descriptions[] = {
+ #define O3D_IMC_MESSAGE_OP(id, class_name) #id,
+ O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP)
+ #undef O3D_IMC_MESSAGE_OP
+ };
+ return message_descriptions[id];
+}
+
+} // namespace o3d
+
+
diff --git a/o3d/core/cross/message_commands.h b/o3d/core/cross/message_commands.h
new file mode 100644
index 0000000..bb14f9b
--- /dev/null
+++ b/o3d/core/cross/message_commands.h
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file contains the declarations of various IMC messages for O3D.
+
+#ifndef O3D_CORE_CROSS_MESSAGE_COMMANDS_H_
+#define O3D_CORE_CROSS_MESSAGE_COMMANDS_H_
+
+#include "core/cross/types.h"
+#include "core/cross/packing.h"
+
+namespace o3d {
+
+// Make sure the compiler does not add extra padding to any of the message
+// structures.
+O3D_PUSH_STRUCTURE_PACKING_1;
+
+// This macro is used to safely and convienently expand the list of possible IMC
+// messages in to various lists and never have them get out of sync. To add a
+// new message add a this list, the first argument is the enum Id, the second
+// argument is the name of the structure that describes the message. Once you've
+// added it to this list, create the structure below and then add a function in
+// message_queue.cc called ProcessMessageStructureName where
+// MessageStructureName is the name of your message structure.
+//
+// NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
+#define O3D_IMC_MESSAGE_LIST(OP) \
+ OP(INVALID_ID, MessageInvalidId) \
+ OP(HELLO, MessageHello) \
+ OP(ALLOCATE_SHARED_MEMORY, MessageAllocateSharedMemory) \
+ OP(UPDATE_TEXTURE2D, MessageUpdateTexture2D) \
+ OP(REGISTER_SHARED_MEMORY, MessageRegisterSharedMemory) \
+ OP(UNREGISTER_SHARED_MEMORY, MessageUnregisterSharedMemory) \
+ OP(UPDATE_TEXTURE2D_RECT, MessageUpdateTexture2DRect) \
+
+
+// The base of all IMCMessages
+struct IMCMessage {
+ enum MessageId {
+ #define O3D_IMC_MESSAGE_OP(id, class_name) id,
+ O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP)
+ #undef O3D_IMC_MESSAGE_OP
+
+ MAX_NUM_IDS,
+
+ ID_FORCE_DWORD = 0x7fffffff // Forces a 32-bit size enum
+ };
+
+ explicit IMCMessage(MessageId id) : message_id(id) {
+ }
+
+ // Returns a string by message ID.
+ static const char* GetMessageDescription(MessageId id);
+
+ int32 message_id;
+};
+
+// An invalid message. This is mostly a place holder for id 0.
+struct MessageInvalidId : public IMCMessage {
+ static const IMCMessage::MessageId kMessageId = INVALID_ID;
+
+ MessageInvalidId()
+ : IMCMessage(kMessageId) {
+ }
+};
+
+// The first message you send.
+struct MessageHello : public IMCMessage {
+ static const IMCMessage::MessageId kMessageId = HELLO;
+
+ MessageHello()
+ : IMCMessage(kMessageId) {
+ }
+};
+
+// A message to allocate shared memory
+struct MessageAllocateSharedMemory : public IMCMessage {
+ static const MessageId kMessageId = ALLOCATE_SHARED_MEMORY;
+ static const int32 kMaxSharedMemSize = 1024 * 1024 * 128; // 128MB
+
+ MessageAllocateSharedMemory()
+ : IMCMessage(kMessageId) {
+ }
+
+ // Parameters:
+ // in_mem_size: The number of bytes to allocate.
+ explicit MessageAllocateSharedMemory(int32 in_mem_size)
+ : IMCMessage(kMessageId),
+ mem_size(in_mem_size) {
+ }
+
+ // The amount of memory to allocate.
+ int32 mem_size;
+};
+
+// A message to register shared memory.
+struct MessageRegisterSharedMemory : public IMCMessage {
+ static const MessageId kMessageId = REGISTER_SHARED_MEMORY;
+ static const int32 kMaxSharedMemSize = 1024 * 1024 * 128; // 128MB
+
+ MessageRegisterSharedMemory()
+ : IMCMessage(kMessageId) {
+ }
+ explicit MessageRegisterSharedMemory(int32 in_mem_size)
+ : IMCMessage(kMessageId),
+ mem_size(in_mem_size) {
+ }
+
+ int32 mem_size;
+};
+
+// A message to unregister shared memory.
+struct MessageUnregisterSharedMemory : public IMCMessage {
+ static const MessageId kMessageId = UNREGISTER_SHARED_MEMORY;
+
+ MessageUnregisterSharedMemory()
+ : IMCMessage(kMessageId) {
+ }
+
+ // Parameters:
+ // in_buffer_id: The id of the buffer to unregister.
+ explicit MessageUnregisterSharedMemory(int32 in_buffer_id)
+ : IMCMessage(kMessageId),
+ buffer_id(in_buffer_id) {
+ }
+
+ int32 buffer_id;
+};
+
+// A message to update the entire contents of a 2D texture. The number
+// of bytes MUST equal the size of the entire texture to be updated including
+// all mips.
+struct MessageUpdateTexture2D : public IMCMessage {
+ static const MessageId kMessageId = UPDATE_TEXTURE2D;
+
+ MessageUpdateTexture2D()
+ : IMCMessage(kMessageId) {
+ }
+
+ // Parameters:
+ // in_texture_id: The id of the texture to set.
+ // in_level: The mip level of the texture to set.
+ // in_shared_memory_id: The id of the shared memory the contains the data
+ // to use to set the texture.
+ // in_offset: The offset inside the shared memory where the texture data
+ // starts.
+ // in_number_of_bytes: The number of bytes to get out of shared memory.
+ // NOTE: this number MUST match the size of the texture. For example for
+ // an ARGB texture it must be mip_width * mip_height * 4 * sizeof(uint8)
+ MessageUpdateTexture2D(Id in_texture_id,
+ int32 in_level,
+ int32 in_shared_memory_id,
+ int32 in_offset,
+ int32 in_number_of_bytes)
+ : IMCMessage(kMessageId),
+ texture_id(in_texture_id),
+ level(in_level),
+ shared_memory_id(in_shared_memory_id),
+ offset(in_offset),
+ number_of_bytes(in_number_of_bytes) {
+ }
+
+ // The id of the texture to set.
+ Id texture_id;
+
+ // The mip level of the texture to set.
+ int32 level;
+
+ // The id of the shared memory the contains the data to use to set the
+ // texture.
+ int32 shared_memory_id;
+
+ // The offset inside the shared memory where the texture data starts.
+ int32 offset;
+
+ // The number of bytes to get out of shared memory.
+ // NOTE: this number MUST match the size of the texture. For example for an
+ // ARGB texture it must be mip_width * mip_height * 4 * sizeof(uint8)
+ int32 number_of_bytes;
+};
+
+// A message to update a portion of a 2D texture. The number of bytes MUST equal
+// the size of the portion of the texture to be updated.
+struct MessageUpdateTexture2DRect : public IMCMessage {
+ static const MessageId kMessageId = UPDATE_TEXTURE2D_RECT;
+
+ MessageUpdateTexture2DRect()
+ : IMCMessage(kMessageId) {
+ }
+
+ // Parameters:
+ // in_texture_id: The id of the texture to set.
+ // in_level: The mip level of the texture to set.
+ // in_x: The left edge of the rectangle to update in the texture.
+ // in_y: The top edge of the rectangle to update in the texture.
+ // in_width: The width of the rectangle to update in the texture.
+ // in_height: The height of the rectangle to update in the texture.
+ // in_shared_memory_id: The id of the shared memory the contains the data to
+ // use to set the texture.
+ // in_offset: The offset inside the shared memory where the texture data
+ // starts.
+ // in_number_of_bytes: The number of bytes to get out of shared memory.
+ // NOTE: this number MUST match the size of the area in the texture to
+ // be updated. For example for an ARGB texture it must be
+ // width * height 4 * sizeof(uint8)
+ MessageUpdateTexture2DRect(Id in_texture_id,
+ int32 in_level,
+ int32 in_x,
+ int32 in_y,
+ int32 in_width,
+ int32 in_height,
+ int32 in_shared_memory_id,
+ int32 in_offset,
+ int32 in_number_of_bytes)
+ : IMCMessage(kMessageId),
+ texture_id(in_texture_id),
+ level(in_level),
+ x(in_x),
+ y(in_y),
+ width(in_width),
+ height(in_height),
+ shared_memory_id(in_shared_memory_id),
+ offset(in_offset),
+ number_of_bytes(in_number_of_bytes) {
+ }
+
+ // The id of the texture to set.
+ Id texture_id;
+
+ // The mip level of the texture to set.
+ int32 level;
+
+ // The left edge of the rectangle to update in the texture.
+ int32 x;
+
+ // The top edge of the rectangle to update in the texture.
+ int32 y;
+
+ // The width of the rectangle to update in the texture.
+ int32 width;
+
+ // The height of the rectangle to update in the texture.
+ int32 height;
+
+ // The id of the shared memory the contains the data to use to set the
+ // texture.
+ int32 shared_memory_id;
+
+ // The offset inside the shared memory where the texture data starts.
+ int32 offset;
+
+ // The number of bytes to get out of shared memory.
+ // NOTE: this number MUST match the size of the area in the texture to be
+ // updated. For example for an ARGB texture it must be
+ // width * height 4 * sizeof(uint8)
+ int32 number_of_bytes;
+};
+
+O3D_POP_STRUCTURE_PACKING;
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_MESSAGE_COMMANDS_H_
+
diff --git a/o3d/core/cross/message_commands_test.cc b/o3d/core/cross/message_commands_test.cc
new file mode 100644
index 0000000..93459a2
--- /dev/null
+++ b/o3d/core/cross/message_commands_test.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/cross/message_commands.h"
+#include "tests/common/win/testing_common.h"
+
+namespace o3d {
+
+class MessageCommandsTest : public testing::Test {
+};
+
+TEST_F(MessageCommandsTest, GetMessageDescription) {
+ EXPECT_STREQ(IMCMessage::GetMessageDescription(
+ IMCMessage::ALLOCATE_SHARED_MEMORY), "ALLOCATE_SHARED_MEMORY");
+};
+
+} // namespace o3d
+
+
diff --git a/o3d/core/cross/message_queue.cc b/o3d/core/cross/message_queue.cc
index 7e24767..9b6e6bf 100644
--- a/o3d/core/cross/message_queue.cc
+++ b/o3d/core/cross/message_queue.cc
@@ -44,6 +44,7 @@
#include "core/cross/bitmap.h"
#include "core/cross/texture.h"
#include "core/cross/error.h"
+#include "core/cross/pointer_utils.h"
#ifdef OS_WIN
#include "core/cross/core_metrics.h"
@@ -77,8 +78,8 @@ ConnectedClient::~ConnectedClient() {
// Unmap and close shared memory.
for (iter = shared_memory_array_.begin(); iter < shared_memory_array_.end();
++iter) {
- nacl::Unmap(iter->mapped_address_, iter->size_);
- nacl::Close(iter->shared_memory_handle_);
+ nacl::Unmap(iter->mapped_address, iter->size);
+ nacl::Close(iter->shared_memory_handle);
}
}
@@ -90,10 +91,10 @@ void ConnectedClient::RegisterSharedMemory(int32 buffer_id,
void *address,
int32 size) {
SharedMemoryInfo shared_mem;
- shared_mem.buffer_id_ = buffer_id;
- shared_mem.shared_memory_handle_ = handle;
- shared_mem.mapped_address_ = address;
- shared_mem.size_ = size;
+ shared_mem.buffer_id = buffer_id;
+ shared_mem.shared_memory_handle = handle;
+ shared_mem.mapped_address = address;
+ shared_mem.size = size;
shared_memory_array_.push_back(shared_mem);
}
@@ -104,9 +105,9 @@ bool ConnectedClient::UnregisterSharedMemory(int32 buffer_id) {
std::vector<SharedMemoryInfo>::iterator iter;
for (iter = shared_memory_array_.begin(); iter < shared_memory_array_.end();
++iter) {
- if (iter->buffer_id_ == buffer_id) {
- nacl::Unmap(iter->mapped_address_, iter->size_);
- nacl::Close(iter->shared_memory_handle_);
+ if (iter->buffer_id == buffer_id) {
+ nacl::Unmap(iter->mapped_address, iter->size);
+ nacl::Close(iter->shared_memory_handle);
shared_memory_array_.erase(iter);
return true;
}
@@ -121,7 +122,7 @@ const SharedMemoryInfo* ConnectedClient::GetSharedMemoryInfo(int32 id) const {
std::vector<SharedMemoryInfo>::const_iterator iter;
for (iter = shared_memory_array_.begin(); iter < shared_memory_array_.end();
++iter) {
- if (iter->buffer_id_ == id) {
+ if (iter->buffer_id == id) {
return &(*iter);
}
}
@@ -220,13 +221,13 @@ bool MessageQueue::CheckForNewMessages() {
// ReceiveMessageFromSocket also returns true if there are no
// messages in the queue in which case message_length will be equal
// to -1.
- MessageId message_id;
+ IMCMessage::MessageId message_id;
int message_length = 0;
if (ReceiveMessageFromSocket(server_socket_handle_,
&header,
&message_id,
&message_length)) {
- if (message_id == HELLO) {
+ if (message_id == IMCMessage::HELLO) {
ProcessHelloMessage(&header, handles);
#ifdef OS_WIN
metric_imc_hello_msg.Set(true);
@@ -276,9 +277,9 @@ bool MessageQueue::CheckForNewMessages() {
// return the ID in message_id.
bool MessageQueue::ReceiveMessageFromSocket(nacl::Handle socket,
nacl::MessageHeader* header,
- MessageId* message_id,
+ IMCMessage::MessageId* message_id,
int* length) {
- *message_id = INVALID_ID;
+ *message_id = IMCMessage::INVALID_ID;
// Check if there's a new message but don't block waiting for it.
int message_length = nacl::ReceiveDatagram(socket,
@@ -323,8 +324,10 @@ bool MessageQueue::ReceiveMessageFromSocket(nacl::Handle socket,
}
// Extract the ID of the message just received.
- MessageId id_found = *(reinterpret_cast<MessageId*>(header->iov[0].base));
- if (id_found <= INVALID_ID || id_found >= MAX_NUM_IDS) {
+ IMCMessage::MessageId id_found =
+ *(reinterpret_cast<IMCMessage::MessageId*>(header->iov[0].base));
+ if (id_found <= IMCMessage::INVALID_ID ||
+ id_found >= IMCMessage::MAX_NUM_IDS) {
LOG(ERROR) << "Unknown ID found in message :" << id_found;
}
*message_id = id_found;
@@ -339,36 +342,35 @@ bool MessageQueue::ReceiveMessageFromSocket(nacl::Handle socket,
bool MessageQueue::ProcessClientRequest(ConnectedClient* client,
int message_length,
- MessageId message_id,
+ IMCMessage::MessageId message_id,
nacl::MessageHeader* header,
nacl::Handle* handles) {
+ static size_t expected_message_lengths[] = {
+ #define O3D_IMC_MESSAGE_OP(id, class_name) sizeof(class_name),
+ O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP)
+ #undef O3D_IMC_MESSAGE_OP
+ };
+
+ if (message_id == IMCMessage::INVALID_ID ||
+ message_id >= arraysize(expected_message_lengths)) {
+ LOG(ERROR) << "Unrecognized message id " << message_id;
+ return false;
+ }
+
+ if (message_length != expected_message_lengths[message_id]) {
+ LOG(ERROR) << "Bad message length for "
+ << IMCMessage::GetMessageDescription(message_id);
+ return false;
+ }
+
switch (message_id) {
- case ALLOCATE_SHARED_MEMORY:
- return ProcessAllocateSharedMemory(client,
- message_length,
- message_id,
- header,
- handles);
- case UPDATE_TEXTURE2D:
- return ProcessUpdateTexture2D(client,
- message_length,
- message_id,
- header,
- handles);
- case REGISTER_SHARED_MEMORY:
- return ProcessRegisterSharedMemory(client,
- message_length,
- message_id,
- header,
- handles);
- case UNREGISTER_SHARED_MEMORY:
- return ProcessUnregisterSharedMemory(client,
- message_length,
- message_id,
- header,
- handles);
+ #define O3D_IMC_MESSAGE_OP(id, class_name) \
+ case IMCMessage::id: return Process ## class_name( \
+ client, message_length, header, handles, \
+ *static_cast<const class_name*>(header->iov[0].base));
+ O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP)
+ #undef O3D_IMC_MESSAGE_OP
default:
- LOG(ERROR) << "Unrecognized message id " << message_id;
return false;
}
@@ -434,34 +436,50 @@ bool MessageQueue::ProcessHelloMessage(nacl::MessageHeader *header,
return false;
}
+// All emums need a Process function.
+bool MessageQueue::ProcessMessageInvalidId(
+ ConnectedClient* client,
+ int message_length,
+ nacl::MessageHeader* header,
+ nacl::Handle* handles,
+ const MessageInvalidId& message) {
+ return false;
+}
+
+bool MessageQueue::ProcessMessageHello(
+ ConnectedClient* client,
+ int message_length,
+ nacl::MessageHeader* header,
+ nacl::Handle* handles,
+ const MessageHello& message) {
+ // Hello is handled special.
+ return false;
+}
// Processes a request to allocate a shared memory buffer on behalf of a
// connected client. Parses the arguments of the message to determine how
// much space is requested, it creates the shared memory buffer, maps it in
// the local address space and sends a message back to the client with the
// newly created memory handle.
-bool MessageQueue::ProcessAllocateSharedMemory(ConnectedClient* client,
- int message_length,
- MessageId message_id,
- nacl::MessageHeader* header,
- nacl::Handle* handles) {
- int32 mem_size = 0;
- int expected_message_length = sizeof(message_id) + sizeof(mem_size);
-
- if (message_length != expected_message_length ||
- header->iov_length != 1 ||
+bool MessageQueue::ProcessMessageAllocateSharedMemory(
+ ConnectedClient* client,
+ int message_length,
+ nacl::MessageHeader* header,
+ nacl::Handle* handles,
+ const MessageAllocateSharedMemory& message) {
+
+ if (header->iov_length != 1 ||
header->handle_count != 0) {
LOG(ERROR) << "Malformed message for ALLOCATE_SHARED_MEMORY";
return false;
}
- char* message_buffer = static_cast<char*>(header->iov[0].base);
- message_buffer += sizeof(message_id);
- mem_size = *(reinterpret_cast<int32*>(message_buffer));
- const int32 kMaxSharedMemSize = 1024 * 1024 * 100; // 100MB
- if (mem_size <= 0 || mem_size > kMaxSharedMemSize) {
+ int32 mem_size = message.mem_size;
+ if (mem_size <= 0 ||
+ mem_size > MessageAllocateSharedMemory::kMaxSharedMemSize) {
LOG(ERROR) << "Invalid mem size requested: " << mem_size
- << "(max size = " << kMaxSharedMemSize << ")";
+ << "(max size = "
+ << MessageAllocateSharedMemory::kMaxSharedMemSize << ")";
return false;
}
@@ -523,92 +541,163 @@ bool MessageQueue::ProcessAllocateSharedMemory(ConnectedClient* client,
// Texture object, the level to be modified and the number of bytes to copy.
// This is essentially asynchronous as the client will not receive a response
// back from the server
-bool MessageQueue::ProcessUpdateTexture2D(ConnectedClient* client,
- int message_length,
- MessageId message_id,
- nacl::MessageHeader* header,
- nacl::Handle* handles) {
- int32 offset = 0;
- Id texture_id = 0;
- int32 level = 0;
- int32 number_of_bytes = 0;
- int32 shared_memory_id = -1;
-
+bool MessageQueue::ProcessMessageUpdateTexture2D(
+ ConnectedClient* client,
+ int message_length,
+ nacl::MessageHeader* header,
+ nacl::Handle* handles,
+ const MessageUpdateTexture2D& message) {
// Check the length of the message to make sure it contains the size of
// the requested buffer.
- int expected_message_length = sizeof(message_id)+
- sizeof(texture_id)+
- sizeof(level)+
- sizeof(shared_memory_id)+
- sizeof(offset)+
- sizeof(number_of_bytes);
-
- if (message_length != expected_message_length ||
- header->iov_length != 1 ||
+ if (header->iov_length != 1 ||
header->handle_count != 0) {
LOG(ERROR) << "Malformed message for UPDATE_TEXTURE";
SendBooleanResponse(client->client_handle(), false);
return false;
}
- char* message_buffer = static_cast<char*>(header->iov[0].base);
- message_buffer += sizeof(message_id);
- texture_id = *(reinterpret_cast<Id*>(message_buffer));
- message_buffer += sizeof(texture_id);
- level = *(reinterpret_cast<int32*>(message_buffer));
- message_buffer += sizeof(level);
- shared_memory_id = *(reinterpret_cast<int*>(message_buffer));
- message_buffer += sizeof(shared_memory_id);
- offset = *(reinterpret_cast<int32*>(message_buffer));
- message_buffer += sizeof(offset);
- number_of_bytes = *(reinterpret_cast<int32*>(message_buffer));
- message_buffer += sizeof(number_of_bytes);
-
// Check that this client did actually allocate the shared memory
// corresponding to this handle.
const SharedMemoryInfo* info =
- client->GetSharedMemoryInfo(shared_memory_id);
+ client->GetSharedMemoryInfo(message.shared_memory_id);
+ if (info == NULL) {
+ O3D_ERROR(service_locator_)
+ << "shared memory id " << message.shared_memory_id << " not found";
+ SendBooleanResponse(client->client_handle(), false);
+ return false;
+ }
// Check that the Id passed in actually corresponds to a texture.
Texture2D* texture_object =
- object_manager_->GetById<Texture2D>(texture_id);
+ object_manager_->GetById<Texture2D>(message.texture_id);
if (texture_object == NULL) {
O3D_ERROR(service_locator_)
- << "Texture with id " << texture_id << " not found";
+ << "Texture with id " << message.texture_id << " not found";
SendBooleanResponse(client->client_handle(), false);
return false;
}
// Check that we will not be reading past the end of the allocated shared
// memory.
- if (offset + number_of_bytes > info->size_) {
+ if (message.offset + message.number_of_bytes > info->size) {
O3D_ERROR(service_locator_)
<< "Offset + texture size exceed allocated shared memory size ("
- << offset << " + " << number_of_bytes << " > " << info->size_;
+ << message.offset << " + " << message.number_of_bytes << " > "
+ << info->size;
SendBooleanResponse(client->client_handle(), false);
return false;
}
unsigned int mip_width =
- image::ComputeMipDimension(level, texture_object->width());
+ image::ComputeMipDimension(message.level, texture_object->width());
unsigned int mip_height =
- image::ComputeMipDimension(level, texture_object->height());
+ image::ComputeMipDimension(message.level, texture_object->height());
- if (static_cast<unsigned>(number_of_bytes) !=
+ if (static_cast<unsigned>(message.number_of_bytes) !=
image::ComputeMipChainSize(mip_width, mip_height,
texture_object->format(),
1)) {
O3D_ERROR(service_locator_)
<< "texture_size does not match size of texture level ("
- << offset << " + " << number_of_bytes << " > " << info->size_;
+ << message.offset << " + " << message.number_of_bytes << " > "
+ << info->size;
+ SendBooleanResponse(client->client_handle(), false);
+ return false;
+ }
+
+ void *target_address =
+ static_cast<char*>(info->mapped_address) + message.offset;
+ texture_object->SetRect(
+ message.level, 0, 0, mip_width, mip_height, target_address,
+ image::ComputePitch(texture_object->format(), mip_width));
+
+ SendBooleanResponse(client->client_handle(), true);
+ return true;
+}
+
+bool MessageQueue::ProcessMessageUpdateTexture2DRect(
+ ConnectedClient* client,
+ int message_length,
+ nacl::MessageHeader* header,
+ nacl::Handle* handles,
+ const MessageUpdateTexture2DRect& message) {
+ // Check the length of the message to make sure it contains the size of
+ // the requested buffer.
+ if (header->iov_length != 1 ||
+ header->handle_count != 0) {
+ LOG(ERROR) << "Malformed message for UPDATE_TEXTURE_RECT";
+ SendBooleanResponse(client->client_handle(), false);
+ return false;
+ }
+
+ // Check that this client did actually allocate the shared memory
+ // corresponding to this handle.
+ const SharedMemoryInfo* info =
+ client->GetSharedMemoryInfo(message.shared_memory_id);
+ if (info == NULL) {
+ O3D_ERROR(service_locator_)
+ << "shared memory id " << message.shared_memory_id << " not found";
+ SendBooleanResponse(client->client_handle(), false);
+ return false;
+ }
+
+ // Check that the Id passed in actually corresponds to a texture.
+ Texture2D* texture_object =
+ object_manager_->GetById<Texture2D>(message.texture_id);
+
+ if (texture_object == NULL) {
+ O3D_ERROR(service_locator_)
+ << "Texture with id " << message.texture_id << " not found";
+ SendBooleanResponse(client->client_handle(), false);
+ return false;
+ }
+
+ // Check that we will not be reading past the end of the allocated shared
+ // memory.
+ if (message.offset + message.number_of_bytes > info->size) {
+ O3D_ERROR(service_locator_)
+ << "Offset + texture size exceed allocated shared memory size ("
+ << message.offset << " + " << message.number_of_bytes << " > "
+ << info->size;
+ SendBooleanResponse(client->client_handle(), false);
+ return false;
+ }
+
+ unsigned int mip_width =
+ image::ComputeMipDimension(message.level, texture_object->width());
+ unsigned int mip_height =
+ image::ComputeMipDimension(message.level, texture_object->height());
+
+ if (message.x < 0 || message.width < 0 ||
+ message.y < 0 || message.height < 0 ||
+ message.x + message.width > mip_width ||
+ message.y + message.height > mip_height) {
+ O3D_ERROR(service_locator_)
+ << "rect out of range ("
+ << message.x << ", " << message.y << ", " << message.width
+ << message.height << ")";
SendBooleanResponse(client->client_handle(), false);
return false;
}
- void *target_address = static_cast<char*>(info->mapped_address_) + offset;
+ if (static_cast<unsigned>(message.number_of_bytes) !=
+ image::ComputeMipChainSize(message.width, message.height,
+ texture_object->format(),
+ 1)) {
+ O3D_ERROR(service_locator_)
+ << "number of bytes does not match size of texture rect ("
+ << message.offset << " + " << message.number_of_bytes << " > "
+ << info->size;
+ SendBooleanResponse(client->client_handle(), false);
+ return false;
+ }
+
+ void *target_address =
+ static_cast<char*>(info->mapped_address) + message.offset;
texture_object->SetRect(
- level, 0, 0, mip_width, mip_height, target_address,
+ message.level, message.x, message.y, message.width, message.height,
+ target_address,
image::ComputePitch(texture_object->format(), mip_width));
SendBooleanResponse(client->client_handle(), true);
@@ -621,28 +710,24 @@ bool MessageQueue::ProcessUpdateTexture2D(ConnectedClient* client,
// the shared memory buffer into the local address space and sends a
// message back to the client with the newly allocated shared memory
// ID.
-bool MessageQueue::ProcessRegisterSharedMemory(ConnectedClient* client,
- int message_length,
- MessageId message_id,
- nacl::MessageHeader* header,
- nacl::Handle* handles) {
- int32 mem_size = 0;
- int expected_message_length = sizeof(message_id) + sizeof(mem_size);
-
- if (message_length != expected_message_length ||
- header->iov_length != 1 ||
+bool MessageQueue::ProcessMessageRegisterSharedMemory(
+ ConnectedClient* client,
+ int message_length,
+ nacl::MessageHeader* header,
+ nacl::Handle* handles,
+ const MessageRegisterSharedMemory& message) {
+ if (header->iov_length != 1 ||
header->handle_count != 1) {
LOG(ERROR) << "Malformed message for REGISTER_SHARED_MEMORY";
return false;
}
- char* message_buffer = static_cast<char*>(header->iov[0].base);
- message_buffer += sizeof(message_id);
- mem_size = *(reinterpret_cast<int32*>(message_buffer));
- const int32 kMaxSharedMemSize = 1024 * 1024 * 100; // 100MB
- if (mem_size <= 0 || mem_size > kMaxSharedMemSize) {
+ int32 mem_size = message.mem_size;
+ if (mem_size <= 0 ||
+ mem_size > MessageRegisterSharedMemory::kMaxSharedMemSize) {
LOG(ERROR) << "Invalid mem size sent: " << mem_size
- << "(max size = " << kMaxSharedMemSize << ")";
+ << "(max size = "
+ << MessageRegisterSharedMemory::kMaxSharedMemSize << ")";
return false;
}
@@ -699,26 +784,19 @@ bool MessageQueue::ProcessRegisterSharedMemory(ConnectedClient* client,
// Processes a request to unregister a client-allocated shared memory
// buffer, referenced by ID.
-bool MessageQueue::ProcessUnregisterSharedMemory(ConnectedClient* client,
- int message_length,
- MessageId message_id,
- nacl::MessageHeader* header,
- nacl::Handle* handles) {
- int32 buffer_id = 0;
- int expected_message_length = sizeof(message_id) + sizeof(buffer_id);
-
- if (message_length != expected_message_length ||
- header->iov_length != 1 ||
+bool MessageQueue::ProcessMessageUnregisterSharedMemory(
+ ConnectedClient* client,
+ int message_length,
+ nacl::MessageHeader* header,
+ nacl::Handle* handles,
+ const MessageUnregisterSharedMemory& message) {
+ if (header->iov_length != 1 ||
header->handle_count != 0) {
LOG(ERROR) << "Malformed message for UNREGISTER_SHARED_MEMORY";
return false;
}
- char* message_buffer = static_cast<char*>(header->iov[0].base);
- message_buffer += sizeof(message_id);
- buffer_id = *(reinterpret_cast<int32*>(message_buffer));
-
- bool res = client->UnregisterSharedMemory(buffer_id);
+ bool res = client->UnregisterSharedMemory(message.buffer_id);
SendBooleanResponse(client->client_handle(), res);
return res;
}
diff --git a/o3d/core/cross/message_queue.h b/o3d/core/cross/message_queue.h
index 50e7f4d..7226064 100644
--- a/o3d/core/cross/message_queue.h
+++ b/o3d/core/cross/message_queue.h
@@ -40,6 +40,7 @@
#include <vector>
#include "native_client/src/shared/imc/nacl_imc.h"
#include "core/cross/types.h"
+#include "core/cross/message_commands.h"
namespace o3d {
@@ -48,17 +49,17 @@ class ObjectManager;
// Structure keeping information about shared memory regions created on the
// request of a client connection.
-typedef struct {
+struct SharedMemoryInfo {
// Unique (to the MessageQueue object that created it) id of the shared
// memory buffer.
- int buffer_id_;
+ int buffer_id;
// Handle to the shared memory.
- nacl::Handle shared_memory_handle_;
+ nacl::Handle shared_memory_handle;
// Address to which it maps in the local memory space.
- void* mapped_address_;
+ void* mapped_address;
// Size in bytes
- int32 size_;
-} SharedMemoryInfo;
+ int32 size;
+};
// The ConnectedClient class holds information about clients that have made
// contact with the this instance of the server.
@@ -97,8 +98,9 @@ class ConnectedClient {
nacl::Handle client_handle_;
std::vector<SharedMemoryInfo> shared_memory_array_;
-};
+ DISALLOW_COPY_AND_ASSIGN(ConnectedClient);
+};
// The MessageQueue class handles the communcation between external code and
// O3D. It provides methods for initializing the communcation channel
@@ -106,20 +108,6 @@ class ConnectedClient {
// the NativeClient Inter-Module Communication (IMC) library.
class MessageQueue {
public:
- enum MessageId {
- INVALID_ID = 0,
- HELLO, // Handshake between the client and the server
- ALLOCATE_SHARED_MEMORY, // Request to allocate a shared memory buffer
- UPDATE_TEXTURE2D, // Request to update a 2D texture bitmap
- REGISTER_SHARED_MEMORY, // Register a client-allocated shared memory
- // buffer, returning a shared memory ID
- UNREGISTER_SHARED_MEMORY, // Unregister a client-allocated shared
- // memory ID
- MAX_NUM_IDS,
-
- ID_FORCE_DWORD = 0x7fffffff // Forces a 32-bit size enum
- };
-
// Creates a MessageQueue that is able to receive messages and execute calls
// to the given Client object.
explicit MessageQueue(ServiceLocator* service_locator);
@@ -156,7 +144,7 @@ class MessageQueue {
// Client.
bool ProcessClientRequest(ConnectedClient* client,
int message_length,
- MessageId message_id,
+ IMCMessage::MessageId message_id,
nacl::MessageHeader* header,
nacl::Handle* handles);
@@ -170,86 +158,17 @@ class MessageQueue {
// true if the new client connected successfully.
bool ProcessHelloMessage(nacl::MessageHeader* header, nacl::Handle* handles);
- // Processes a request by a connected client to allocate a shared memory
- // buffer. The size of the requested buffer is determined from the data
- // passed in the message. Once the memory is allocated, a message containing
- // the shared memory handle is sent back to the client.
- // Parameters:
- // client - pointer to the ConnectedClient the request came from.
- // message_length - length of the received message in bytes.
- // message_id - id of the request received by the message
- // header - message header containing information about the received
- // message.
- // handles - the array of handles referenced by the header.
- // Returns:
- // true if the message is properly formed and is succesfully handled by the
- // Client.
- bool ProcessAllocateSharedMemory(ConnectedClient* client,
- int message_length,
- MessageId message_id,
- nacl::MessageHeader* header,
- nacl::Handle* handles);
-
- // Processes a request by a connected client to update the contents of the
- // bitmap corresponding to a Texture2D object.
- // Parameters:
- // client - pointer to the ConnectedClient the request came from.
- // message_length - length of the received message in bytes.
- // message_id - id of the request received by the message
- // header - message header containing information about the received
- // message.
- // handles - the array of handles referenced by the header.
- // Returns:
- // true if the message is properly formed and is succesfully handled by the
- // Client.
- bool ProcessUpdateTexture2D(ConnectedClient* client,
- int message_length,
- MessageId message_id,
- nacl::MessageHeader* header,
- nacl::Handle* handles);
-
- // Processes a request by a connected client to register a
- // client-allocated shared memory buffer with O3D. The size of the
- // buffer is determined from the data passed in the message. Once
- // the shared memory buffer has been mapped and registered, a
- // message containing the shared memory ID is sent back to the
- // client. This ID can be used to update the contents of a Texture2D
- // object.
- // Parameters:
- // client - pointer to the ConnectedClient the request came from.
- // message_length - length of the received message in bytes.
- // message_id - id of the request received by the message
- // header - message header containing information about the received
- // message.
- // handles - the array of handles referenced by the header.
- // Returns:
- // true if the message is properly formed and is succesfully handled by the
- // Client.
- bool ProcessRegisterSharedMemory(ConnectedClient* client,
- int message_length,
- MessageId message_id,
- nacl::MessageHeader* header,
- nacl::Handle* handles);
-
- // Processes a request by a connected client to unregister a shared
- // memory buffer previously registered with O3D. The shared memory
- // buffer is referenced by the ID returned from
- // RegisterSharedMemory.
- // Parameters:
- // client - pointer to the ConnectedClient the request came from.
- // message_length - length of the received message in bytes.
- // message_id - id of the request received by the message
- // header - message header containing information about the received
- // message.
- // handles - the array of handles referenced by the header.
- // Returns:
- // true if the message is properly formed and is succesfully handled by the
- // Client.
- bool ProcessUnregisterSharedMemory(ConnectedClient* client,
- int message_length,
- MessageId message_id,
- nacl::MessageHeader* header,
- nacl::Handle* handles);
+ // Declare all the message processing functions. For each type of message
+ // will declare a function called Process<MessageName>.
+ #define O3D_IMC_MESSAGE_OP(id, class_name) \
+ bool Process ## class_name( \
+ ConnectedClient* client, \
+ int message_length, \
+ nacl::MessageHeader* header, \
+ nacl::Handle* handles, \
+ const class_name& message);
+ O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP)
+ #undef O3D_IMC_MESSAGE_OP
// Sends a true of false (1 or 0) message using the given socket handle.
// Parameters:
@@ -271,11 +190,9 @@ class MessageQueue {
// false in every other case.
bool ReceiveMessageFromSocket(nacl::Handle socket,
nacl::MessageHeader* header,
- MessageId* message_id,
+ IMCMessage::MessageId* message_id,
int* message_length);
- private:
-
ServiceLocator* service_locator_;
ObjectManager* object_manager_;
@@ -296,6 +213,8 @@ class MessageQueue {
// us to create multiple instances of the MessageQueue, each with a unique
// address.
static int next_message_queue_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageQueue);
};
diff --git a/o3d/core/cross/message_queue_test.cc b/o3d/core/cross/message_queue_test.cc
index 5a0d30f..ac34ad8 100644
--- a/o3d/core/cross/message_queue_test.cc
+++ b/o3d/core/cross/message_queue_test.cc
@@ -49,6 +49,7 @@ using ::base::TimeDelta;
namespace o3d {
+namespace {
//----------------------------------------------------------------------
// These are helper classes for the little multithreaded test harness
// below.
@@ -207,128 +208,6 @@ class TestProvider {
};
//----------------------------------------------------------------------
-// This is the main class containing all of the other ones. It knows
-// how to run multiple concurrent PerThreadConnectedTests.
-class MessageQueueTest : public testing::Test {
- protected:
- MessageQueueTest()
- : object_manager_(g_service_locator),
- socket_handles_(NULL),
- num_socket_handles_(0) {}
-
- virtual void SetUp();
- virtual void TearDown();
-
- // This is the entry point for test cases that need to be run in one
- // or more threads.
- void RunTests(int num_threads,
- TimeDelta timeout,
- TestProvider* test_provider);
-
- Pack* pack() { return pack_; }
-
- private:
- ServiceDependency<ObjectManager> object_manager_;
- Pack *pack_;
- nacl::Handle* socket_handles_;
- int num_socket_handles_;
-
- // This can't be part of SetUp since it needs to be called from each
- // individual test.
- void ConfigureSockets(int number_of_clients);
-
- nacl::Handle GetSocketHandle(int i) {
- // We would use ASSERT_ here, but that doesn't seem to work from
- // within methods that have non-void return types.
- EXPECT_TRUE(socket_handles_ != NULL);
- EXPECT_LT(i, num_socket_handles_);
- return socket_handles_[i];
- }
-};
-
-void MessageQueueTest::SetUp() {
- pack_ = object_manager_->CreatePack();
- pack_->set_name("MessageQueueTest pack");
-}
-
-void MessageQueueTest::ConfigureSockets(int number_of_clients) {
- ASSERT_GT(number_of_clients, 0);
- num_socket_handles_ = number_of_clients;
- socket_handles_ = new nacl::Handle[num_socket_handles_];
- ASSERT_TRUE(socket_handles_ != NULL);
- for (int i = 0; i < num_socket_handles_; i++) {
- nacl::SocketAddress socket_address;
- ::base::snprintf(socket_address.path,
- sizeof(socket_address.path),
- "%s%d",
- "test-client",
- i);
- socket_handles_[i] = nacl::BoundSocket(&socket_address);
- ASSERT_NE(nacl::kInvalidHandle, socket_handles_[i]);
- }
-}
-
-void MessageQueueTest::TearDown() {
- if (socket_handles_ != NULL) {
- for (int i = 0; i < num_socket_handles_; i++) {
- nacl::Close(socket_handles_[i]);
- }
- delete[] socket_handles_;
- socket_handles_ = NULL;
- num_socket_handles_ = 0;
- }
-
- object_manager_->DestroyPack(pack_);
-}
-
-void MessageQueueTest::RunTests(int num_threads,
- TimeDelta timeout,
- TestProvider* provider) {
- MessageQueue* message_queue = new MessageQueue(g_service_locator);
- message_queue->Initialize();
-
- TimeSource* time_source = new WallClockTimeSource();
- TestWatchdog* watchdog = new TestWatchdog(num_threads,
- timeout,
- time_source);
- PerThreadConnectedTest** tests = new PerThreadConnectedTest*[num_threads];
- ASSERT_TRUE(tests != NULL);
- PlatformThreadHandle* thread_handles = new PlatformThreadHandle[num_threads];
- ASSERT_TRUE(thread_handles != NULL);
- ConfigureSockets(num_threads);
- for (int i = 0; i < num_threads; i++) {
- tests[i] = provider->CreateTest();
- ASSERT_TRUE(tests[i] != NULL);
- tests[i]->Configure(message_queue, GetSocketHandle(i), watchdog);
- }
- // Now that all tests are created, start them up
- for (int i = 0; i < num_threads; i++) {
- ASSERT_TRUE(PlatformThread::Create(0, tests[i], &thread_handles[i]));
- }
- // Wait for completion
- while (!watchdog->Done()) {
- ASSERT_TRUE(message_queue->CheckForNewMessages());
- watchdog->WaitBrieflyForSignal();
- }
- ASSERT_FALSE(watchdog->Expired());
- ASSERT_TRUE(watchdog->Succeeded());
- for (int i = 0; i < num_threads; i++) {
- PerThreadConnectedTest* test = tests[i];
- ASSERT_TRUE(test->Passed()) << test->FailureMessage();
- // Only join the thread and delete the test if it completed
- if (test->Completed()) {
- PlatformThread::Join(thread_handles[i]);
- delete test;
- }
- }
- delete[] thread_handles;
- delete[] tests;
- delete watchdog;
- delete time_source;
- delete message_queue;
-}
-
-//----------------------------------------------------------------------
// This is a helper class that handles connecting to the MessageQueue
// and issuing commands to it.
class TextureUpdateHelper {
@@ -351,6 +230,17 @@ class TextureUpdateHelper {
size_t offset,
size_t number_of_bytes);
+ // Makes a request to update a portion of a texture.
+ bool RequestTextureRectUpdate(unsigned int texture_id,
+ int level,
+ int x,
+ int y,
+ int width,
+ int height,
+ int shared_memory_id,
+ size_t offset,
+ size_t number_of_bytes);
+
// Registers a client-allocated shared memory segment with O3D,
// returning O3D's shared memory ID for later updating. Returns -1
// upon failure.
@@ -402,17 +292,11 @@ bool TextureUpdateHelper::ConnectToO3D(const char* o3d_address,
return false;
}
- char buffer[128];
- int message_size = 0;
- MessageQueue::MessageId *msg_id =
- reinterpret_cast<MessageQueue::MessageId*>(buffer);
- *msg_id = MessageQueue::HELLO;
- message_size += sizeof(*msg_id);
-
+ MessageHello msg;
nacl::MessageHeader header;
nacl::IOVec vec;
- vec.base = buffer;
- vec.length = message_size;
+ vec.base = &msg;
+ vec.length = sizeof(msg);
nacl::SocketAddress socket_address;
::base::snprintf(socket_address.path,
@@ -428,8 +312,8 @@ bool TextureUpdateHelper::ConnectToO3D(const char* o3d_address,
0,
&socket_address);
- EXPECT_EQ(message_size, result);
- if (result != message_size) {
+ EXPECT_EQ(sizeof(msg), static_cast<size_t>(result));
+ if (static_cast<size_t>(result) != sizeof(msg)) {
return false;
}
@@ -458,22 +342,12 @@ bool TextureUpdateHelper::RequestSharedMemory(size_t requested_size,
return false;
}
- MessageQueue::MessageId message_id = MessageQueue::ALLOCATE_SHARED_MEMORY;
-
+ MessageAllocateSharedMemory msg(requested_size);
nacl::MessageHeader header;
nacl::IOVec vec;
- char buffer[256];
- char *buffer_ptr = &buffer[0];
- // Message contains the ID and one argument (the size of the shared memory
- // buffer to be allocated).
- *(reinterpret_cast<MessageQueue::MessageId*>(buffer_ptr)) = message_id;
- buffer_ptr += sizeof(message_id);
- *(reinterpret_cast<size_t*>(buffer_ptr)) = requested_size;
- buffer_ptr += sizeof(requested_size);
-
- vec.base = buffer;
- vec.length = buffer_ptr - &buffer[0];
+ vec.base = &msg;
+ vec.length = sizeof(msg);
header.iov = &vec;
header.iov_length = 1;
@@ -541,37 +415,63 @@ bool TextureUpdateHelper::RequestTextureUpdate(unsigned int texture_id,
int shared_memory_id,
size_t offset,
size_t number_of_bytes) {
- MessageQueue::MessageId message_id = MessageQueue::UPDATE_TEXTURE2D;
+ MessageUpdateTexture2D msg(
+ texture_id, level, shared_memory_id, offset, number_of_bytes);
nacl::MessageHeader header;
nacl::IOVec vec;
- char buffer[256];
- char *buffer_ptr = &buffer[0];
-
- // Message contains the message ID and two arguments, the id of the Texture
- // object in O3D and the offset in the shared memory region where the
- // bitmap is stored.
- *(reinterpret_cast<MessageQueue::MessageId*>(buffer_ptr)) = message_id;
- buffer_ptr += sizeof(message_id);
- *(reinterpret_cast<unsigned int*>(buffer_ptr)) = texture_id;
- buffer_ptr += sizeof(texture_id);
- *(reinterpret_cast<int*>(buffer_ptr)) = level;
- buffer_ptr += sizeof(level);
- *(reinterpret_cast<int*>(buffer_ptr)) = shared_memory_id;
- buffer_ptr += sizeof(shared_memory_id);
- *(reinterpret_cast<size_t*>(buffer_ptr)) = offset;
- buffer_ptr += sizeof(offset);
- *(reinterpret_cast<size_t*>(buffer_ptr)) = number_of_bytes;
- buffer_ptr += sizeof(number_of_bytes);
-
- vec.base = buffer;
- vec.length = buffer_ptr - &buffer[0];
+
+ vec.base = &msg;
+ vec.length = sizeof(msg);
header.iov = &vec;
header.iov_length = 1;
header.handles = NULL;
header.handle_count = 0;
+ // Send message.
+ int result = nacl::SendDatagram(o3d_handle_, &header, 0);
+
+ EXPECT_EQ(vec.length, static_cast<unsigned>(result));
+
+ if (static_cast<unsigned>(result) != vec.length) {
+ return false;
+ }
+
+ // Wait for a response from the server. If the server returns true then
+ // the texture update was successfully procesed.
+ bool texture_updated = ReceiveBooleanResponse();
+
+ EXPECT_TRUE(texture_updated);
+
+ return texture_updated;
+}
+
+// Sends a message to O3D to update the a potion of the contents of a texture
+// using the data stored in shared memory.
+bool TextureUpdateHelper::RequestTextureRectUpdate(unsigned int texture_id,
+ int level,
+ int x,
+ int y,
+ int width,
+ int height,
+ int shared_memory_id,
+ size_t offset,
+ size_t number_of_bytes) {
+ MessageUpdateTexture2DRect msg(
+ texture_id, level, x, y, width, height,
+ shared_memory_id, offset, number_of_bytes);
+
+ nacl::MessageHeader header;
+ nacl::IOVec vec;
+
+ vec.base = &msg;
+ vec.length = sizeof(msg);
+
+ header.iov = &vec;
+ header.iov_length = 1;
+ header.handles = NULL;
+ header.handle_count = 0;
// Send message.
int result = nacl::SendDatagram(o3d_handle_, &header, 0);
@@ -600,22 +500,13 @@ int TextureUpdateHelper::RegisterSharedMemory(nacl::Handle shared_memory,
return false;
}
- MessageQueue::MessageId message_id = MessageQueue::REGISTER_SHARED_MEMORY;
+ MessageRegisterSharedMemory msg(static_cast<int32>(shared_memory_size));
nacl::MessageHeader header;
nacl::IOVec vec;
- char buffer[256];
- char *buffer_ptr = &buffer[0];
-
- // Message contains the ID and one argument (the size of the shared memory
- // buffer which has been allocated).
- *(reinterpret_cast<MessageQueue::MessageId*>(buffer_ptr)) = message_id;
- buffer_ptr += sizeof(message_id);
- *(reinterpret_cast<size_t*>(buffer_ptr)) = shared_memory_size;
- buffer_ptr += sizeof(shared_memory_size);
- vec.base = buffer;
- vec.length = buffer_ptr - &buffer[0];
+ vec.base = &msg;
+ vec.length = sizeof(msg);
header.iov = &vec;
header.iov_length = 1;
@@ -653,21 +544,12 @@ int TextureUpdateHelper::RegisterSharedMemory(nacl::Handle shared_memory,
// Unregisters a previously-registered client-allocated shared
// memory segment.
bool TextureUpdateHelper::UnregisterSharedMemory(int shared_memory_id) {
- MessageQueue::MessageId message_id = MessageQueue::UNREGISTER_SHARED_MEMORY;
+ MessageUnregisterSharedMemory msg(shared_memory_id);
nacl::MessageHeader header;
nacl::IOVec vec;
- char buffer[256];
- char *buffer_ptr = &buffer[0];
-
- // Message contains the message ID and the ID of the shared memory
- // segment to release
- *(reinterpret_cast<MessageQueue::MessageId*>(buffer_ptr)) = message_id;
- buffer_ptr += sizeof(message_id);
- *(reinterpret_cast<int*>(buffer_ptr)) = shared_memory_id;
- buffer_ptr += sizeof(shared_memory_id);
-
- vec.base = buffer;
- vec.length = buffer_ptr - buffer;
+
+ vec.base = &msg;
+ vec.length = sizeof(msg);
header.iov = &vec;
header.iov_length = 1;
header.handles = NULL;
@@ -682,6 +564,131 @@ bool TextureUpdateHelper::UnregisterSharedMemory(int shared_memory_id) {
return reply;
}
+
+} // anonymous namespace.
+
+//----------------------------------------------------------------------
+// This is the main class containing all of the other ones. It knows
+// how to run multiple concurrent PerThreadConnectedTests.
+class MessageQueueTest : public testing::Test {
+ protected:
+ MessageQueueTest()
+ : object_manager_(g_service_locator),
+ socket_handles_(NULL),
+ num_socket_handles_(0) {}
+
+ virtual void SetUp();
+ virtual void TearDown();
+
+ // This is the entry point for test cases that need to be run in one
+ // or more threads.
+ void RunTests(int num_threads,
+ TimeDelta timeout,
+ TestProvider* test_provider);
+
+ Pack* pack() { return pack_; }
+
+ private:
+ ServiceDependency<ObjectManager> object_manager_;
+ Pack *pack_;
+ nacl::Handle* socket_handles_;
+ int num_socket_handles_;
+
+ // This can't be part of SetUp since it needs to be called from each
+ // individual test.
+ void ConfigureSockets(int number_of_clients);
+
+ nacl::Handle GetSocketHandle(int i) {
+ // We would use ASSERT_ here, but that doesn't seem to work from
+ // within methods that have non-void return types.
+ EXPECT_TRUE(socket_handles_ != NULL);
+ EXPECT_LT(i, num_socket_handles_);
+ return socket_handles_[i];
+ }
+};
+
+void MessageQueueTest::SetUp() {
+ pack_ = object_manager_->CreatePack();
+ pack_->set_name("MessageQueueTest pack");
+}
+
+void MessageQueueTest::ConfigureSockets(int number_of_clients) {
+ ASSERT_GT(number_of_clients, 0);
+ num_socket_handles_ = number_of_clients;
+ socket_handles_ = new nacl::Handle[num_socket_handles_];
+ ASSERT_TRUE(socket_handles_ != NULL);
+ for (int i = 0; i < num_socket_handles_; i++) {
+ nacl::SocketAddress socket_address;
+ ::base::snprintf(socket_address.path,
+ sizeof(socket_address.path),
+ "%s%d",
+ "test-client",
+ i);
+ socket_handles_[i] = nacl::BoundSocket(&socket_address);
+ ASSERT_NE(nacl::kInvalidHandle, socket_handles_[i]);
+ }
+}
+
+void MessageQueueTest::TearDown() {
+ if (socket_handles_ != NULL) {
+ for (int i = 0; i < num_socket_handles_; i++) {
+ nacl::Close(socket_handles_[i]);
+ }
+ delete[] socket_handles_;
+ socket_handles_ = NULL;
+ num_socket_handles_ = 0;
+ }
+
+ object_manager_->DestroyPack(pack_);
+}
+
+void MessageQueueTest::RunTests(int num_threads,
+ TimeDelta timeout,
+ TestProvider* provider) {
+ MessageQueue* message_queue = new MessageQueue(g_service_locator);
+ message_queue->Initialize();
+
+ TimeSource* time_source = new WallClockTimeSource();
+ TestWatchdog* watchdog = new TestWatchdog(num_threads,
+ timeout,
+ time_source);
+ PerThreadConnectedTest** tests = new PerThreadConnectedTest*[num_threads];
+ ASSERT_TRUE(tests != NULL);
+ PlatformThreadHandle* thread_handles = new PlatformThreadHandle[num_threads];
+ ASSERT_TRUE(thread_handles != NULL);
+ ConfigureSockets(num_threads);
+ for (int i = 0; i < num_threads; i++) {
+ tests[i] = provider->CreateTest();
+ ASSERT_TRUE(tests[i] != NULL);
+ tests[i]->Configure(message_queue, GetSocketHandle(i), watchdog);
+ }
+ // Now that all tests are created, start them up
+ for (int i = 0; i < num_threads; i++) {
+ ASSERT_TRUE(PlatformThread::Create(0, tests[i], &thread_handles[i]));
+ }
+ // Wait for completion
+ while (!watchdog->Done()) {
+ ASSERT_TRUE(message_queue->CheckForNewMessages());
+ watchdog->WaitBrieflyForSignal();
+ }
+ ASSERT_FALSE(watchdog->Expired());
+ ASSERT_TRUE(watchdog->Succeeded());
+ for (int i = 0; i < num_threads; i++) {
+ PerThreadConnectedTest* test = tests[i];
+ ASSERT_TRUE(test->Passed()) << test->FailureMessage();
+ // Only join the thread and delete the test if it completed
+ if (test->Completed()) {
+ PlatformThread::Join(thread_handles[i]);
+ delete test;
+ }
+ }
+ delete[] thread_handles;
+ delete[] tests;
+ delete watchdog;
+ delete time_source;
+ delete message_queue;
+}
+
//----------------------------------------------------------------------
// Test cases follow.
@@ -810,7 +817,7 @@ TEST_F(MessageQueueTest, UpdateTexture2D) {
FAIL_TEST("Memory request failed");
}
- int texture_buffer_size = 128*128*4;
+ int texture_buffer_size = 128 * 128 * 4;
if (!helper.RequestTextureUpdate(texture_id_,
0,
@@ -848,6 +855,92 @@ TEST_F(MessageQueueTest, UpdateTexture2D) {
RunTests(1, TimeDelta::FromSeconds(1), &provider);
}
+// Tests a request to update a texture.
+TEST_F(MessageQueueTest, UpdateTexture2DRect) {
+ class UpdateTexture2DRectTest : public PerThreadConnectedTest {
+ private:
+ int texture_id_;
+
+ public:
+ explicit UpdateTexture2DRectTest(int texture_id) {
+ texture_id_ = texture_id;
+ }
+
+ void Run(MessageQueue* queue,
+ nacl::Handle socket_handle) {
+ String socket_addr = queue->GetSocketAddress();
+ TextureUpdateHelper helper;
+ if (!helper.ConnectToO3D(socket_addr.c_str(),
+ socket_handle)) {
+ FAIL_TEST("Failed to connect to O3D");
+ }
+
+ void *shared_mem_address = NULL;
+ int shared_mem_id = -1;
+ bool memory_ok = helper.RequestSharedMemory(65536,
+ &shared_mem_id,
+ &shared_mem_address);
+ if (shared_mem_id == -1) {
+ FAIL_TEST("Shared memory id was -1");
+ }
+
+ if (shared_mem_address == NULL) {
+ FAIL_TEST("Shared memory address was NULL");
+ }
+
+ if (!memory_ok) {
+ FAIL_TEST("Memory request failed");
+ }
+
+ const int kLevel = 0;
+ const int kX = 10;
+ const int kY = 11;
+ const int kWidth = 12;
+ const int kHeight = 13;
+ const int kTextureRectSize = kWidth * kHeight * 4;
+
+ if (!helper.RequestTextureRectUpdate(texture_id_,
+ kLevel,
+ kX,
+ kY,
+ kWidth,
+ kHeight,
+ shared_mem_id,
+ 0,
+ kTextureRectSize)) {
+ FAIL_TEST("RequestTextureRectUpdate failed");
+ }
+
+ Pass();
+ }
+ };
+
+ class Provider : public TestProvider {
+ private:
+ int texture_id_;
+
+ public:
+ explicit Provider(int texture_id) : texture_id_(texture_id) {}
+
+ virtual PerThreadConnectedTest* CreateTest() {
+ return new UpdateTexture2DRectTest(texture_id_);
+ }
+ };
+
+ Texture2D* texture = pack()->CreateTexture2D(128,
+ 128,
+ Texture::ARGB8,
+ 0,
+ false);
+
+ ASSERT_TRUE(texture != NULL);
+
+ Provider provider(texture->id());
+ RunTests(1, TimeDelta::FromSeconds(1), &provider);
+}
+
+namespace {
+
// This helper class is used for both single-threaded and concurrent
// shared memory registration / unregistration tests.
class SharedMemoryRegisterUnregisterTest : public PerThreadConnectedTest {
@@ -897,6 +990,8 @@ class SharedMemoryRegisterUnregisterTest : public PerThreadConnectedTest {
}
};
+} // anonymous namespace.
+
// Tests that a simple shared memory registration and unregistration
// pair appear to work.
TEST_F(MessageQueueTest, RegisterAndUnregisterSharedMemory) {
diff --git a/o3d/core/cross/packing.h b/o3d/core/cross/packing.h
new file mode 100644
index 0000000..674ef09
--- /dev/null
+++ b/o3d/core/cross/packing.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file defines Packing macros for the packing of structures.
+
+#ifndef O3D_UTILS_CROSS_PACKING_H_
+#define O3D_UTILS_CROSS_PACKING_H_
+
+#if defined(COMPILER_GCC)
+
+// NOTE: I tried building the string as in
+// #define O3D_SET_STRUCTURE_PACKING(p) _Pragma("pack(" #p ")")
+// but gcc doesn't like that. :-(
+#define O3D_SET_STRUCTURE_PACKING_1 _Pragma("pack(1)")
+#define O3D_SET_STRUCTURE_PACKING_2 _Pragma("pack(2)")
+#define O3D_SET_STRUCTURE_PACKING_4 _Pragma("pack(4)")
+#define O3D_PUSH_STRUCTURE_PACKING_1 _Pragma("pack(push, 1)")
+#define O3D_PUSH_STRUCTURE_PACKING_2 _Pragma("pack(push, 2)")
+#define O3D_PUSH_STRUCTURE_PACKING_4 _Pragma("pack(push, 4)")
+#define O3D_POP_STRUCTURE_PACKING _Pragma("pack(pop)")
+
+#elif defined(COMPILER_MSVC)
+
+#define O3D_SET_STRUCTURE_PACKING_1 __pragma(pack(1))
+#define O3D_SET_STRUCTURE_PACKING_2 __pragma(pack(2))
+#define O3D_SET_STRUCTURE_PACKING_4 __pragma(pack(4))
+#define O3D_PUSH_STRUCTURE_PACKING_1 __pragma(pack(push, 1))
+#define O3D_PUSH_STRUCTURE_PACKING_2 __pragma(pack(push, 2))
+#define O3D_PUSH_STRUCTURE_PACKING_4 __pragma(pack(push, 4))
+#define O3D_POP_STRUCTURE_PACKING __pragma(pack(pop))
+
+#else
+#error Need Packing Macros
+#endif
+
+#endif // O3D_UTILS_CROSS_PACKING_H_
+