summaryrefslogtreecommitdiffstats
path: root/o3d/gpu
diff options
context:
space:
mode:
authorapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-11 19:47:26 +0000
committerapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-11 19:47:26 +0000
commit0d85ea6e9786806964ec2a05a12dd2e0a05bdb0c (patch)
tree552a503dd6c198dcaaf88d7cf9fcecf545fd8b69 /o3d/gpu
parent7c9109b43243c43c427c337c7ac3c049fe77a5b9 (diff)
downloadchromium_src-0d85ea6e9786806964ec2a05a12dd2e0a05bdb0c.zip
chromium_src-0d85ea6e9786806964ec2a05a12dd2e0a05bdb0c.tar.gz
chromium_src-0d85ea6e9786806964ec2a05a12dd2e0a05bdb0c.tar.bz2
Recomitting 31676 with fix.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31692 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/gpu')
-rw-r--r--o3d/gpu/command_buffer/client/cmd_buffer_helper.cc197
-rw-r--r--o3d/gpu/command_buffer/client/cmd_buffer_helper.h212
-rw-r--r--o3d/gpu/command_buffer/client/cmd_buffer_helper_test.cc298
-rw-r--r--o3d/gpu/command_buffer/client/effect_helper.cc250
-rw-r--r--o3d/gpu/command_buffer/client/effect_helper.h156
-rw-r--r--o3d/gpu/command_buffer/client/fenced_allocator.cc214
-rw-r--r--o3d/gpu/command_buffer/client/fenced_allocator.h266
-rw-r--r--o3d/gpu/command_buffer/client/fenced_allocator_test.cc496
-rw-r--r--o3d/gpu/command_buffer/client/id_allocator.cc85
-rw-r--r--o3d/gpu/command_buffer/client/id_allocator.h78
-rw-r--r--o3d/gpu/command_buffer/client/id_allocator_test.cc112
-rw-r--r--o3d/gpu/command_buffer/client/o3d_cmd_helper.cc42
-rw-r--r--o3d/gpu/command_buffer/client/o3d_cmd_helper.h636
-rw-r--r--o3d/gpu/command_buffer/common/GLES2/gl2.h621
-rw-r--r--o3d/gpu/command_buffer/common/GLES2/gl2platform.h29
-rw-r--r--o3d/gpu/command_buffer/common/KHR/khrplatform.h269
-rw-r--r--o3d/gpu/command_buffer/common/bitfield_helpers.h68
-rw-r--r--o3d/gpu/command_buffer/common/bitfield_helpers_test.cc66
-rw-r--r--o3d/gpu/command_buffer/common/cmd_buffer_common.cc57
-rw-r--r--o3d/gpu/command_buffer/common/cmd_buffer_common.h247
-rw-r--r--o3d/gpu/command_buffer/common/constants.h71
-rw-r--r--o3d/gpu/command_buffer/common/gapi_interface.h833
-rw-r--r--o3d/gpu/command_buffer/common/logging.h67
-rw-r--r--o3d/gpu/command_buffer/common/o3d_cmd_format.cc57
-rw-r--r--o3d/gpu/command_buffer/common/o3d_cmd_format.h3155
-rw-r--r--o3d/gpu/command_buffer/common/resource.cc120
-rw-r--r--o3d/gpu/command_buffer/common/resource.h229
-rw-r--r--o3d/gpu/command_buffer/common/types.h60
-rw-r--r--o3d/gpu/command_buffer/service/big_test_main.cc124
-rw-r--r--o3d/gpu/command_buffer/service/cmd_buffer_engine.h70
-rw-r--r--o3d/gpu/command_buffer/service/cmd_parser.cc112
-rw-r--r--o3d/gpu/command_buffer/service/cmd_parser.h115
-rw-r--r--o3d/gpu/command_buffer/service/cmd_parser_test.cc316
-rw-r--r--o3d/gpu/command_buffer/service/common_decoder.cc122
-rw-r--r--o3d/gpu/command_buffer/service/common_decoder.h107
-rw-r--r--o3d/gpu/command_buffer/service/d3d9_utils.h145
-rw-r--r--o3d/gpu/command_buffer/service/effect_d3d9.cc679
-rw-r--r--o3d/gpu/command_buffer/service/effect_d3d9.h139
-rw-r--r--o3d/gpu/command_buffer/service/effect_gl.cc852
-rw-r--r--o3d/gpu/command_buffer/service/effect_gl.h162
-rw-r--r--o3d/gpu/command_buffer/service/effect_utils.cc69
-rw-r--r--o3d/gpu/command_buffer/service/effect_utils.h54
-rw-r--r--o3d/gpu/command_buffer/service/effect_utils_test.cc87
-rw-r--r--o3d/gpu/command_buffer/service/gapi_d3d9.cc393
-rw-r--r--o3d/gpu/command_buffer/service/gapi_d3d9.h508
-rw-r--r--o3d/gpu/command_buffer/service/gapi_decoder.cc940
-rw-r--r--o3d/gpu/command_buffer/service/gapi_decoder.h81
-rw-r--r--o3d/gpu/command_buffer/service/gapi_gl.cc420
-rw-r--r--o3d/gpu/command_buffer/service/gapi_gl.h465
-rw-r--r--o3d/gpu/command_buffer/service/geometry_d3d9.cc439
-rw-r--r--o3d/gpu/command_buffer/service/geometry_d3d9.h126
-rw-r--r--o3d/gpu/command_buffer/service/geometry_gl.cc554
-rw-r--r--o3d/gpu/command_buffer/service/geometry_gl.h144
-rw-r--r--o3d/gpu/command_buffer/service/gl_utils.h60
-rw-r--r--o3d/gpu/command_buffer/service/mocks.h108
-rw-r--r--o3d/gpu/command_buffer/service/precompile.cc33
-rw-r--r--o3d/gpu/command_buffer/service/precompile.h50
-rw-r--r--o3d/gpu/command_buffer/service/render_surface_d3d9.cc230
-rw-r--r--o3d/gpu/command_buffer/service/render_surface_d3d9.h161
-rw-r--r--o3d/gpu/command_buffer/service/render_surface_gl.cc262
-rw-r--r--o3d/gpu/command_buffer/service/render_surface_gl.h117
-rw-r--r--o3d/gpu/command_buffer/service/resource.cc101
-rw-r--r--o3d/gpu/command_buffer/service/resource.h268
-rw-r--r--o3d/gpu/command_buffer/service/resource_test.cc127
-rw-r--r--o3d/gpu/command_buffer/service/sampler_d3d9.cc199
-rw-r--r--o3d/gpu/command_buffer/service/sampler_d3d9.h85
-rw-r--r--o3d/gpu/command_buffer/service/sampler_gl.cc238
-rw-r--r--o3d/gpu/command_buffer/service/sampler_gl.h87
-rw-r--r--o3d/gpu/command_buffer/service/states_d3d9.cc355
-rw-r--r--o3d/gpu/command_buffer/service/states_gl.cc346
-rw-r--r--o3d/gpu/command_buffer/service/texture_d3d9.cc731
-rw-r--r--o3d/gpu/command_buffer/service/texture_d3d9.h282
-rw-r--r--o3d/gpu/command_buffer/service/texture_gl.cc767
-rw-r--r--o3d/gpu/command_buffer/service/texture_gl.h284
-rw-r--r--o3d/gpu/command_buffer/service/texture_utils.cc105
-rw-r--r--o3d/gpu/command_buffer/service/texture_utils.h156
-rw-r--r--o3d/gpu/command_buffer/service/x_utils.cc92
-rw-r--r--o3d/gpu/command_buffer/service/x_utils.h76
-rw-r--r--o3d/gpu/gpu.gyp351
-rw-r--r--o3d/gpu/gpu_plugin/command_buffer.cc143
-rw-r--r--o3d/gpu/gpu_plugin/command_buffer.h130
-rw-r--r--o3d/gpu/gpu_plugin/command_buffer_mock.h42
-rw-r--r--o3d/gpu/gpu_plugin/command_buffer_unittest.cc182
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin.cc136
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin.h30
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin_object.cc117
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin_object.h132
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin_object_factory.cc27
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin_object_factory.h26
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin_object_factory_unittest.cc39
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin_object_unittest.cc346
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin_object_win.cc62
-rw-r--r--o3d/gpu/gpu_plugin/gpu_plugin_unittest.cc305
-rw-r--r--o3d/gpu/gpu_plugin/gpu_processor.cc80
-rw-r--r--o3d/gpu/gpu_plugin/gpu_processor.h119
-rw-r--r--o3d/gpu/gpu_plugin/gpu_processor_mock.h41
-rw-r--r--o3d/gpu/gpu_plugin/gpu_processor_unittest.cc309
-rw-r--r--o3d/gpu/gpu_plugin/gpu_processor_win.cc85
-rw-r--r--o3d/gpu/np_utils/default_np_object.h84
-rw-r--r--o3d/gpu/np_utils/dispatched_np_object_unittest.cc403
-rw-r--r--o3d/gpu/np_utils/dynamic_np_object.cc59
-rw-r--r--o3d/gpu/np_utils/dynamic_np_object.h35
-rw-r--r--o3d/gpu/np_utils/dynamic_np_object_unittest.cc83
-rw-r--r--o3d/gpu/np_utils/np_browser.cc128
-rw-r--r--o3d/gpu/np_utils/np_browser.h95
-rw-r--r--o3d/gpu/np_utils/np_browser_mock.h50
-rw-r--r--o3d/gpu/np_utils/np_browser_stub.cc125
-rw-r--r--o3d/gpu/np_utils/np_browser_stub.h84
-rw-r--r--o3d/gpu/np_utils/np_class.h125
-rw-r--r--o3d/gpu/np_utils/np_class_unittest.cc143
-rw-r--r--o3d/gpu/np_utils/np_dispatcher.cc86
-rw-r--r--o3d/gpu/np_utils/np_dispatcher.h222
-rw-r--r--o3d/gpu/np_utils/np_dispatcher_specializations.h85
-rw-r--r--o3d/gpu/np_utils/np_headers.h16
-rw-r--r--o3d/gpu/np_utils/np_object_mock.h36
-rw-r--r--o3d/gpu/np_utils/np_object_pointer.h119
-rw-r--r--o3d/gpu/np_utils/np_object_pointer_unittest.cc220
-rw-r--r--o3d/gpu/np_utils/np_plugin_object.h50
-rw-r--r--o3d/gpu/np_utils/np_plugin_object_factory.cc30
-rw-r--r--o3d/gpu/np_utils/np_plugin_object_factory.h37
-rw-r--r--o3d/gpu/np_utils/np_plugin_object_factory_mock.h23
-rw-r--r--o3d/gpu/np_utils/np_plugin_object_mock.h26
-rw-r--r--o3d/gpu/np_utils/np_utils.cc170
-rw-r--r--o3d/gpu/np_utils/np_utils.h271
-rw-r--r--o3d/gpu/np_utils/np_utils_unittest.cc424
-rw-r--r--o3d/gpu/np_utils/webkit_browser.h117
126 files changed, 27582 insertions, 0 deletions
diff --git a/o3d/gpu/command_buffer/client/cmd_buffer_helper.cc b/o3d/gpu/command_buffer/client/cmd_buffer_helper.cc
new file mode 100644
index 0000000..e6a49d1
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/cmd_buffer_helper.cc
@@ -0,0 +1,197 @@
+/*
+ * 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 implementation of the command buffer helper class.
+
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/np_utils/np_utils.h"
+
+namespace command_buffer {
+
+using gpu_plugin::CommandBuffer;
+using gpu_plugin::NPBrowser;
+using gpu_plugin::NPInvoke;
+using gpu_plugin::NPObjectPointer;
+
+CommandBufferHelper::CommandBufferHelper(
+ NPP npp,
+ const NPObjectPointer<CommandBuffer>& command_buffer)
+ : npp_(npp),
+ command_buffer_(command_buffer),
+ entries_(NULL),
+ entry_count_(0),
+ token_(0),
+ last_token_read_(-1),
+ get_(0),
+ put_(0) {
+}
+
+bool CommandBufferHelper::Initialize() {
+ ring_buffer_ = command_buffer_->GetRingBuffer();
+ if (!ring_buffer_)
+ return false;
+
+ // Map the ring buffer into this process.
+ if (!ring_buffer_->Map(ring_buffer_->max_size()))
+ return false;
+
+ entries_ = static_cast<CommandBufferEntry*>(ring_buffer_->memory());
+ entry_count_ = command_buffer_->GetSize();
+ get_ = command_buffer_->GetGetOffset();
+ put_ = command_buffer_->GetPutOffset();
+ last_token_read_ = command_buffer_->GetToken();
+
+ return true;
+}
+
+CommandBufferHelper::~CommandBufferHelper() {
+}
+
+bool CommandBufferHelper::Flush() {
+ get_ = command_buffer_->SyncOffsets(put_);
+ return !command_buffer_->GetErrorStatus();
+}
+
+// Calls Flush() and then waits until the buffer is empty. Break early if the
+// error is set.
+bool CommandBufferHelper::Finish() {
+ do {
+ // Do not loop forever if the flush fails, meaning the command buffer reader
+ // has shutdown).
+ if (!Flush())
+ return false;
+ } while (put_ != get_);
+
+ return true;
+}
+
+// Inserts a new token into the command stream. It uses an increasing value
+// scheme so that we don't lose tokens (a token has passed if the current token
+// value is higher than that token). Calls Finish() if the token value wraps,
+// which will be rare.
+int32 CommandBufferHelper::InsertToken() {
+ // Increment token as 31-bit integer. Negative values are used to signal an
+ // error.
+ token_ = (token_ + 1) & 0x7FFFFFFF;
+ CommandBufferEntry args;
+ args.value_uint32 = token_;
+ const uint32 kSetToken = 1; // TODO(gman): add a common set of commands.
+ AddCommand(kSetToken, 1, &args);
+ if (token_ == 0) {
+ // we wrapped
+ Finish();
+ last_token_read_ = command_buffer_->GetToken();
+ DCHECK_EQ(token_, last_token_read_);
+ }
+ return token_;
+}
+
+// Waits until the current token value is greater or equal to the value passed
+// in argument.
+void CommandBufferHelper::WaitForToken(int32 token) {
+ // Return immediately if corresponding InsertToken failed.
+ if (token < 0)
+ return;
+ if (last_token_read_ >= token) return; // fast path.
+ if (token > token_) return; // we wrapped
+ Flush();
+ last_token_read_ = command_buffer_->GetToken();
+ while (last_token_read_ < token) {
+ if (get_ == put_) {
+ LOG(FATAL) << "Empty command buffer while waiting on a token.";
+ return;
+ }
+ // Do not loop forever if the flush fails, meaning the command buffer reader
+ // has shutdown.
+ if (!Flush())
+ return;
+ last_token_read_ = command_buffer_->GetToken();
+ }
+}
+
+// Waits for available entries, basically waiting until get >= put + count + 1.
+// It actually waits for contiguous entries, so it may need to wrap the buffer
+// around, adding noops. Thus this function may change the value of put_.
+// The function will return early if an error occurs, in which case the
+// available space may not be available.
+void CommandBufferHelper::WaitForAvailableEntries(int32 count) {
+ CHECK(count < entry_count_);
+ if (put_ + count > entry_count_) {
+ // There's not enough room between the current put and the end of the
+ // buffer, so we need to wrap. We will add noops all the way to the end,
+ // but we need to make sure get wraps first, actually that get is 1 or
+ // more (since put will wrap to 0 after we add the noops).
+ DCHECK_LE(1, put_);
+ Flush();
+ while (get_ > put_ || get_ == 0) {
+ // Do not loop forever if the flush fails, meaning the command buffer
+ // reader has shutdown.
+ if (!Flush())
+ return;
+ }
+ // Add the noops. By convention, a noop is a command 0 with no args.
+ // TODO(apatrick): A noop can have a size. It would be better to add a
+ // single noop with a variable size. Watch out for size limit on
+ // individual commands.
+ CommandHeader header;
+ header.size = 1;
+ header.command = 0;
+ while (put_ < entry_count_) {
+ entries_[put_++].value_header = header;
+ }
+ put_ = 0;
+ }
+ // If we have enough room, return immediatly.
+ if (count <= AvailableEntries()) return;
+ // Otherwise flush, and wait until we do have enough room.
+ Flush();
+ while (AvailableEntries() < count) {
+ // Do not loop forever if the flush fails, meaning the command buffer reader
+ // has shutdown.
+ if (!Flush())
+ return;
+ }
+}
+
+CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) {
+ WaitForAvailableEntries(entries);
+ CommandBufferEntry* space = &entries_[put_];
+ put_ += entries;
+ return space;
+}
+
+parse_error::ParseError CommandBufferHelper::GetParseError() {
+ int32 parse_error = command_buffer_->ResetParseError();
+ return static_cast<parse_error::ParseError>(parse_error);
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/client/cmd_buffer_helper.h b/o3d/gpu/command_buffer/client/cmd_buffer_helper.h
new file mode 100644
index 0000000..d63a53e
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/cmd_buffer_helper.h
@@ -0,0 +1,212 @@
+/*
+ * 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 command buffer helper class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_
+
+#include "gpu/command_buffer/common/logging.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/gpu_plugin/command_buffer.h"
+#include "gpu/np_utils/np_object_pointer.h"
+
+namespace command_buffer {
+
+// Command buffer helper class. This class simplifies ring buffer management:
+// it will allocate the buffer, give it to the buffer interface, and let the
+// user add commands to it, while taking care of the synchronization (put and
+// get). It also provides a way to ensure commands have been executed, through
+// the token mechanism:
+//
+// helper.AddCommand(...);
+// helper.AddCommand(...);
+// int32 token = helper.InsertToken();
+// helper.AddCommand(...);
+// helper.AddCommand(...);
+// [...]
+//
+// helper.WaitForToken(token); // this doesn't return until the first two
+// // commands have been executed.
+class CommandBufferHelper {
+ public:
+ CommandBufferHelper(
+ NPP npp,
+ const gpu_plugin::NPObjectPointer<gpu_plugin::CommandBuffer>&
+ command_buffer);
+ virtual ~CommandBufferHelper();
+
+ bool Initialize();
+
+ // Flushes the commands, setting the put pointer to let the buffer interface
+ // know that new commands have been added. After a flush returns, the command
+ // buffer service is aware of all pending commands and it is guaranteed to
+ // have made some progress in processing them. Returns whether the flush was
+ // successful. The flush will fail if the command buffer service has
+ // disconnected.
+ bool Flush();
+
+ // Waits until all the commands have been executed. Returns whether it
+ // was successful. The function will fail if the command buffer service has
+ // disconnected.
+ bool Finish();
+
+ // Waits until a given number of available entries are available.
+ // Parameters:
+ // count: number of entries needed. This value must be at most
+ // the size of the buffer minus one.
+ void WaitForAvailableEntries(int32 count);
+
+ // Adds a command data to the command buffer. This may wait until sufficient
+ // space is available.
+ // Parameters:
+ // entries: The command entries to add.
+ // count: The number of entries.
+ void AddCommandData(const CommandBufferEntry* entries, int32 count) {
+ WaitForAvailableEntries(count);
+ for (; count > 0; --count) {
+ entries_[put_++] = *entries++;
+ }
+ DCHECK_LE(put_, entry_count_);
+ if (put_ == entry_count_) put_ = 0;
+ }
+
+ // A typed version of AddCommandData.
+ template <typename T>
+ void AddTypedCmdData(const T& cmd) {
+ AddCommandData(reinterpret_cast<const CommandBufferEntry*>(&cmd),
+ ComputeNumEntries(sizeof(cmd)));
+ }
+
+ // Adds a command to the command buffer. This may wait until sufficient space
+ // is available.
+ // Parameters:
+ // command: the command index.
+ // arg_count: the number of arguments for the command.
+ // args: the arguments for the command (these are copied before the
+ // function returns).
+ void AddCommand(int32 command,
+ int32 arg_count,
+ const CommandBufferEntry *args) {
+ CommandHeader header;
+ header.size = arg_count + 1;
+ header.command = command;
+ WaitForAvailableEntries(header.size);
+ entries_[put_++].value_header = header;
+ for (int i = 0; i < arg_count; ++i) {
+ entries_[put_++] = args[i];
+ }
+ DCHECK_LE(put_, entry_count_);
+ if (put_ == entry_count_) put_ = 0;
+ }
+
+ // Inserts a new token into the command buffer. This token either has a value
+ // different from previously inserted tokens, or ensures that previously
+ // inserted tokens with that value have already passed through the command
+ // stream.
+ // Returns:
+ // the value of the new token or -1 if the command buffer reader has
+ // shutdown.
+ int32 InsertToken();
+
+ // Waits until the token of a particular value has passed through the command
+ // stream (i.e. commands inserted before that token have been executed).
+ // NOTE: This will call Flush if it needs to block.
+ // Parameters:
+ // the value of the token to wait for.
+ void WaitForToken(int32 token);
+
+ // Waits for a certain amount of space to be available. Returns address
+ // of space.
+ CommandBufferEntry* GetSpace(uint32 entries);
+
+ // Typed version of GetSpace. Gets enough room for the given type and returns
+ // a reference to it.
+ template <typename T>
+ T& GetCmdSpace() {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
+ uint32 space_needed = ComputeNumEntries(sizeof(T));
+ void* data = GetSpace(space_needed);
+ return *reinterpret_cast<T*>(data);
+ }
+
+ // Typed version of GetSpace for immediate commands.
+ template <typename T>
+ T& GetImmediateCmdSpace(size_t space) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ uint32 space_needed = ComputeNumEntries(sizeof(T) + space);
+ void* data = GetSpace(space_needed);
+ return *reinterpret_cast<T*>(data);
+ }
+
+ parse_error::ParseError GetParseError();
+
+ // Common Commands
+ void Noop(uint32 skip_count) {
+ cmd::Noop& cmd = GetImmediateCmdSpace<cmd::Noop>(
+ skip_count * sizeof(CommandBufferEntry));
+ cmd.Init(skip_count);
+ }
+
+ void SetToken(uint32 token) {
+ cmd::SetToken& cmd = GetCmdSpace<cmd::SetToken>();
+ cmd.Init(token);
+ }
+
+
+ private:
+ // Waits until get changes, updating the value of get_.
+ void WaitForGetChange();
+
+ // Returns the number of available entries (they may not be contiguous).
+ int32 AvailableEntries() {
+ return (get_ - put_ - 1 + entry_count_) % entry_count_;
+ }
+
+ NPP npp_;
+ gpu_plugin::NPObjectPointer<gpu_plugin::CommandBuffer> command_buffer_;
+ ::base::SharedMemory* ring_buffer_;
+ CommandBufferEntry *entries_;
+ int32 entry_count_;
+ int32 token_;
+ int32 last_token_read_;
+ int32 get_;
+ int32 put_;
+
+ friend class CommandBufferHelperTest;
+ DISALLOW_COPY_AND_ASSIGN(CommandBufferHelper);
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_
diff --git a/o3d/gpu/command_buffer/client/cmd_buffer_helper_test.cc b/o3d/gpu/command_buffer/client/cmd_buffer_helper_test.cc
new file mode 100644
index 0000000..b2f5bde
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/cmd_buffer_helper_test.cc
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+
+// Tests for the Command Buffer Helper.
+
+#include "tests/common/win/testing_common.h"
+#include "base/message_loop.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/gpu_plugin/command_buffer.h"
+#include "gpu/gpu_plugin/gpu_processor.h"
+#include "gpu/np_utils/np_object_pointer.h"
+
+namespace command_buffer {
+
+using gpu_plugin::CommandBuffer;
+using gpu_plugin::GPUProcessor;
+using gpu_plugin::NPCreateObject;
+using gpu_plugin::NPObjectPointer;
+using testing::Return;
+using testing::Mock;
+using testing::Truly;
+using testing::Sequence;
+using testing::DoAll;
+using testing::Invoke;
+using testing::_;
+
+const int32 kNumCommandEntries = 10;
+const int32 kCommandBufferSizeBytes = kNumCommandEntries * sizeof(int32);
+
+// Test fixture for CommandBufferHelper test - Creates a CommandBufferHelper,
+// using a CommandBufferEngine with a mock AsyncAPIInterface for its interface
+// (calling it directly, not through the RPC mechanism).
+class CommandBufferHelperTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ api_mock_.reset(new AsyncAPIMock);
+ // ignore noops in the mock - we don't want to inspect the internals of the
+ // helper.
+ EXPECT_CALL(*api_mock_, DoCommand(0, 0, _))
+ .WillRepeatedly(Return(parse_error::kParseNoError));
+
+ ::base::SharedMemory* ring_buffer = new ::base::SharedMemory;
+ ring_buffer->Create(std::wstring(), false, false, kCommandBufferSizeBytes);
+ ring_buffer->Map(1024);
+
+ command_buffer_ = NPCreateObject<CommandBuffer>(NULL);
+ command_buffer_->Initialize(ring_buffer);
+
+ parser_ = new command_buffer::CommandParser(ring_buffer->memory(),
+ kCommandBufferSizeBytes,
+ 0,
+ kCommandBufferSizeBytes,
+ 0,
+ api_mock_.get());
+
+ scoped_refptr<GPUProcessor> gpu_processor(new GPUProcessor(
+ NULL, command_buffer_.Get(), NULL, NULL, parser_, 1));
+ command_buffer_->SetPutOffsetChangeCallback(NewCallback(
+ gpu_processor.get(), &GPUProcessor::ProcessCommands));
+
+ api_mock_->set_engine(gpu_processor.get());
+
+ helper_.reset(new CommandBufferHelper(NULL, command_buffer_));
+ helper_->Initialize();
+ }
+
+ virtual void TearDown() {
+ // If the GPUProcessor posts any tasks, this forces them to run.
+ MessageLoop::current()->RunAllPending();
+ helper_.release();
+ }
+
+ // Adds a command to the buffer through the helper, while adding it as an
+ // expected call on the API mock.
+ void AddCommandWithExpect(parse_error::ParseError _return,
+ unsigned int command,
+ unsigned int arg_count,
+ CommandBufferEntry *args) {
+ helper_->AddCommand(command, arg_count, args);
+ EXPECT_CALL(*api_mock_, DoCommand(command, arg_count,
+ Truly(AsyncAPIMock::IsArgs(arg_count, args))))
+ .InSequence(sequence_)
+ .WillOnce(Return(_return));
+ }
+
+ // Checks that the buffer from put to put+size is free in the parser.
+ void CheckFreeSpace(CommandBufferOffset put, unsigned int size) {
+ CommandBufferOffset parser_put = parser_->put();
+ CommandBufferOffset parser_get = parser_->get();
+ CommandBufferOffset limit = put + size;
+ if (parser_get > parser_put) {
+ // "busy" buffer wraps, so "free" buffer is between put (inclusive) and
+ // get (exclusive).
+ EXPECT_LE(parser_put, put);
+ EXPECT_GT(parser_get, limit);
+ } else {
+ // "busy" buffer does not wrap, so the "free" buffer is the top side (from
+ // put to the limit) and the bottom side (from 0 to get).
+ if (put >= parser_put) {
+ // we're on the top side, check we are below the limit.
+ EXPECT_GE(kNumCommandEntries, limit);
+ } else {
+ // we're on the bottom side, check we are below get.
+ EXPECT_GT(parser_get, limit);
+ }
+ }
+ }
+
+ CommandBufferOffset get_helper_put() { return helper_->put_; }
+
+ scoped_ptr<AsyncAPIMock> api_mock_;
+ NPObjectPointer<CommandBuffer> command_buffer_;
+ command_buffer::CommandParser* parser_;
+ scoped_ptr<CommandBufferHelper> helper_;
+ Sequence sequence_;
+};
+
+// Checks that commands in the buffer are properly executed, and that the
+// status/error stay valid.
+TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
+ // Check initial state of the engine - it should have been configured by the
+ // helper.
+ EXPECT_TRUE(parser_ != NULL);
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+ EXPECT_EQ(parse_error::kParseNoError, command_buffer_->ResetParseError());
+ EXPECT_EQ(0u, command_buffer_->GetGetOffset());
+
+ // Add 3 commands through the helper
+ AddCommandWithExpect(parse_error::kParseNoError, 1, 0, NULL);
+
+ CommandBufferEntry args1[2];
+ args1[0].value_uint32 = 3;
+ args1[1].value_float = 4.f;
+ AddCommandWithExpect(parse_error::kParseNoError, 2, 2, args1);
+
+ CommandBufferEntry args2[2];
+ args2[0].value_uint32 = 5;
+ args2[1].value_float = 6.f;
+ AddCommandWithExpect(parse_error::kParseNoError, 3, 2, args2);
+
+ helper_->Flush();
+ // Check that the engine has work to do now.
+ EXPECT_FALSE(parser_->IsEmpty());
+
+ // Wait until it's done.
+ helper_->Finish();
+ // Check that the engine has no more work to do.
+ EXPECT_TRUE(parser_->IsEmpty());
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+ EXPECT_EQ(parse_error::kParseNoError, command_buffer_->ResetParseError());
+}
+
+// Checks that commands in the buffer are properly executed when wrapping the
+// buffer, and that the status/error stay valid.
+TEST_F(CommandBufferHelperTest, TestCommandWrapping) {
+ // Add 5 commands of size 3 through the helper to make sure we do wrap.
+ CommandBufferEntry args1[2];
+ args1[0].value_uint32 = 3;
+ args1[1].value_float = 4.f;
+
+ for (unsigned int i = 0; i < 5; ++i) {
+ AddCommandWithExpect(parse_error::kParseNoError, i + 1, 2, args1);
+ }
+
+ helper_->Finish();
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+ EXPECT_EQ(parse_error::kParseNoError, command_buffer_->ResetParseError());
+}
+
+
+// Checks that commands in the buffer are properly executed, even if they
+// generate a recoverable error. Check that the error status is properly set,
+// and reset when queried.
+TEST_F(CommandBufferHelperTest, TestRecoverableError) {
+ CommandBufferEntry args[2];
+ args[0].value_uint32 = 3;
+ args[1].value_float = 4.f;
+
+ // Create a command buffer with 3 commands, 2 of them generating errors
+ AddCommandWithExpect(parse_error::kParseNoError, 1, 2, args);
+ AddCommandWithExpect(parse_error::kParseUnknownCommand, 2, 2, args);
+ AddCommandWithExpect(parse_error::kParseInvalidArguments, 3, 2,
+ args);
+
+ helper_->Finish();
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check that the error status was set to the first error.
+ EXPECT_EQ(parse_error::kParseUnknownCommand,
+ command_buffer_->ResetParseError());
+ // Check that the error status was reset after the query.
+ EXPECT_EQ(parse_error::kParseNoError, command_buffer_->ResetParseError());
+}
+
+// Checks that asking for available entries work, and that the parser
+// effectively won't use that space.
+TEST_F(CommandBufferHelperTest, TestAvailableEntries) {
+ CommandBufferEntry args[2];
+ args[0].value_uint32 = 3;
+ args[1].value_float = 4.f;
+
+ // Add 2 commands through the helper - 8 entries
+ AddCommandWithExpect(parse_error::kParseNoError, 1, 0, NULL);
+ AddCommandWithExpect(parse_error::kParseNoError, 2, 0, NULL);
+ AddCommandWithExpect(parse_error::kParseNoError, 3, 2, args);
+ AddCommandWithExpect(parse_error::kParseNoError, 4, 2, args);
+
+ // Ask for 5 entries.
+ helper_->WaitForAvailableEntries(5);
+
+ CommandBufferOffset put = get_helper_put();
+ CheckFreeSpace(put, 5);
+
+ // Add more commands.
+ AddCommandWithExpect(parse_error::kParseNoError, 5, 2, args);
+
+ // Wait until everything is done done.
+ helper_->Finish();
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+ EXPECT_EQ(parse_error::kParseNoError, command_buffer_->ResetParseError());
+}
+
+// Checks that the InsertToken/WaitForToken work.
+TEST_F(CommandBufferHelperTest, TestToken) {
+ CommandBufferEntry args[2];
+ args[0].value_uint32 = 3;
+ args[1].value_float = 4.f;
+
+ // Add a first command.
+ AddCommandWithExpect(parse_error::kParseNoError, 3, 2, args);
+ // keep track of the buffer position.
+ CommandBufferOffset command1_put = get_helper_put();
+ int32 token = helper_->InsertToken();
+
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
+ Return(parse_error::kParseNoError)));
+ // Add another command.
+ AddCommandWithExpect(parse_error::kParseNoError, 4, 2, args);
+ helper_->WaitForToken(token);
+ // check that the get pointer is beyond the first command.
+ EXPECT_LE(command1_put, command_buffer_->GetGetOffset());
+ helper_->Finish();
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+ EXPECT_EQ(parse_error::kParseNoError, command_buffer_->ResetParseError());
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/client/effect_helper.cc b/o3d/gpu/command_buffer/client/effect_helper.cc
new file mode 100644
index 0000000..f3daaae
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/effect_helper.cc
@@ -0,0 +1,250 @@
+/*
+ * 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 implements the EffectHelper class.
+
+#include "gpu/command_buffer/common/o3d_cmd_format.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/client/effect_helper.h"
+#include "gpu/command_buffer/client/fenced_allocator.h"
+#include "gpu/command_buffer/client/id_allocator.h"
+
+// TODO: write a unit test.
+
+namespace command_buffer {
+
+bool EffectHelper::CreateEffectParameters(ResourceId effect_id,
+ std::vector<EffectParamDesc> *descs) {
+ using effect_param::Desc;
+ DCHECK_NE(effect_id, kInvalidResource);
+ DCHECK(descs);
+ descs->clear();
+
+ // Get the param count.
+ Uint32 *retval = shm_allocator_->AllocTyped<Uint32>(1);
+ helper_->GetParamCount(effect_id, sizeof(*retval),
+ shm_id_, shm_allocator_->GetOffset(retval));
+ // Finish has to be called to get the result.
+ helper_->Finish();
+
+ // We could have failed if the effect_id is invalid.
+ if (helper_->GetParseError() != parse_error::kParseNoError) {
+ shm_allocator_->Free(retval);
+ return false;
+ }
+ unsigned int param_count = *retval;
+
+ shm_allocator_->Free(retval);
+ unsigned int max_buffer_size = shm_allocator_->GetLargestFreeOrPendingSize();
+ if (max_buffer_size < sizeof(Desc)) { // NOLINT
+ // Not enough memory to get at least 1 param desc.
+ return false;
+ }
+ descs->resize(param_count);
+ for (unsigned int i = 0; i < param_count; ++i) {
+ EffectParamDesc *desc = &((*descs)[i]);
+ desc->id = param_id_allocator_->AllocateID();
+ helper_->CreateParam(desc->id, effect_id, i);
+ }
+
+ // Read param descriptions in batches. We use as much shared memory as
+ // possible so that we only call Finish as little as possible.
+ unsigned int max_param_per_batch =
+ std::min(static_cast<unsigned>(param_count),
+ static_cast<unsigned>(max_buffer_size / sizeof(Desc))); // NOLINT
+ Desc *raw_descs = shm_allocator_->AllocTyped<Desc>(max_param_per_batch);
+ DCHECK(raw_descs);
+ for (unsigned int i = 0; i < param_count; i += max_param_per_batch) {
+ unsigned int count = std::min(param_count - i, max_param_per_batch);
+ for (unsigned int j = 0 ; j < count; ++j) {
+ EffectParamDesc *desc = &((*descs)[i + j]);
+ Desc *raw_desc = raw_descs + j;
+ helper_->GetParamDesc(desc->id, sizeof(*raw_desc),
+ shm_id_,
+ shm_allocator_->GetOffset(raw_desc));
+ }
+ // Finish to get the results.
+ helper_->Finish();
+ DCHECK_EQ(helper_->GetParseError(), parse_error::kParseNoError);
+ for (unsigned int j = 0 ; j < count; ++j) {
+ EffectParamDesc *desc = &((*descs)[i + j]);
+ Desc *raw_desc = raw_descs + j;
+ desc->data_type = raw_desc->data_type;
+ desc->data_size = raw_desc->data_size;
+ desc->num_elements = raw_desc->num_elements;
+ desc->cmd_desc_size = raw_desc->size;
+ }
+ }
+ shm_allocator_->Free(raw_descs);
+ return true;
+}
+
+bool EffectHelper::GetParamStrings(EffectParamDesc *desc) {
+ using effect_param::Desc;
+ DCHECK(desc);
+ DCHECK_NE(desc->id, kInvalidResource);
+ // desc may not have come directly from CreateEffectParameters, so it may be
+ // less than the minimum required size.
+ unsigned int size = std::max(static_cast<unsigned>(desc->cmd_desc_size),
+ static_cast<unsigned>(sizeof(Desc))); // NOLINT
+ Desc *raw_desc = static_cast<Desc *>(shm_allocator_->Alloc(size));
+ if (!raw_desc) {
+ // Not enough memory to get the param desc.
+ return false;
+ }
+ helper_->GetParamDesc(desc->id, size,
+ shm_id_,
+ shm_allocator_->GetOffset(raw_desc));
+
+ // Finish to get the results.
+ helper_->Finish();
+
+ // We could have failed if the param ID is invalid.
+ if (helper_->GetParseError() != parse_error::kParseNoError) {
+ shm_allocator_->Free(raw_desc);
+ return false;
+ }
+
+ if (raw_desc->size > size) {
+ // We had not allocated enough memory the first time (e.g. if the
+ // EffectParamDesc didn't come from CreateEffectParameters, so the user had
+ // no way of knowing what size was needed for the strings), so re-allocate
+ // and try again.
+ size = raw_desc->size;
+ desc->cmd_desc_size = size;
+ shm_allocator_->Free(raw_desc);
+ raw_desc = static_cast<Desc *>(shm_allocator_->Alloc(size));
+ if (!raw_desc) {
+ // Not enough memory to get the param desc.
+ return false;
+ }
+ helper_->GetParamDesc(desc->id, size,
+ shm_id_,
+ shm_allocator_->GetOffset(raw_desc));
+ // Finish to get the results.
+ helper_->Finish();
+ DCHECK_EQ(helper_->GetParseError(), parse_error::kParseNoError);
+ DCHECK_EQ(raw_desc->size, size);
+ }
+
+ const char *raw_desc_string = reinterpret_cast<char *>(raw_desc);
+ if (raw_desc->name_offset) {
+ DCHECK_LE(raw_desc->name_offset + raw_desc->name_size, raw_desc->size);
+ DCHECK_GT(raw_desc->name_size, 0U);
+ DCHECK_EQ(raw_desc_string[raw_desc->name_offset + raw_desc->name_size - 1],
+ 0);
+ desc->name = String(raw_desc_string + raw_desc->name_offset,
+ raw_desc->name_size - 1);
+ } else {
+ desc->name.clear();
+ }
+ if (raw_desc->semantic_offset) {
+ DCHECK_LE(raw_desc->semantic_offset + raw_desc->semantic_size,
+ raw_desc->size);
+ DCHECK_GT(raw_desc->semantic_size, 0U);
+ DCHECK_EQ(raw_desc_string[raw_desc->semantic_offset +
+ raw_desc->semantic_size - 1],
+ 0);
+ desc->semantic = String(raw_desc_string + raw_desc->semantic_offset,
+ raw_desc->semantic_size - 1);
+ } else {
+ desc->semantic.clear();
+ }
+ shm_allocator_->Free(raw_desc);
+ return true;
+}
+
+void EffectHelper::DestroyEffectParameters(
+ const std::vector<EffectParamDesc> &descs) {
+ for (unsigned int i = 0; i < descs.size(); ++i) {
+ const EffectParamDesc &desc = descs[i];
+ helper_->DestroyParam(desc.id);
+ param_id_allocator_->FreeID(desc.id);
+ }
+}
+
+bool EffectHelper::GetEffectStreams(ResourceId effect_id,
+ std::vector<EffectStreamDesc> *descs) {
+ using effect_stream::Desc;
+ DCHECK_NE(effect_id, kInvalidResource);
+
+ // Get the param count.
+ Uint32 *retval = shm_allocator_->AllocTyped<Uint32>(1);
+ helper_->GetStreamCount(effect_id, sizeof(*retval),
+ shm_id_,
+ shm_allocator_->GetOffset(retval));
+ // Finish has to be called to get the result.
+ helper_->Finish();
+
+ // We could have failed if the effect_id is invalid.
+ if (helper_->GetParseError() != parse_error::kParseNoError) {
+ shm_allocator_->Free(retval);
+ return false;
+ }
+ unsigned int stream_count = *retval;
+ shm_allocator_->Free(retval);
+ unsigned int max_buffer_size = shm_allocator_->GetLargestFreeOrPendingSize();
+ if (max_buffer_size < sizeof(Desc)) { // NOLINT
+ // Not enough memory to get at least 1 stream desc.
+ return false;
+ }
+ descs->resize(stream_count);
+
+ // Read stream descriptions in batches. We use as much shared memory as
+ // possible so that we only call Finish as little as possible.
+ unsigned int max_stream_per_batch =
+ std::min(static_cast<unsigned>(stream_count),
+ static_cast<unsigned>(max_buffer_size / sizeof(Desc))); // NOLINT
+ Desc *raw_descs = shm_allocator_->AllocTyped<Desc>(max_stream_per_batch);
+ DCHECK(raw_descs);
+ for (unsigned int i = 0; i < stream_count; i += max_stream_per_batch) {
+ unsigned int count = std::min(stream_count - i, max_stream_per_batch);
+ for (unsigned int j = 0 ; j < count; ++j) {
+ Desc *raw_desc = raw_descs + j;
+ helper_->GetStreamDesc(effect_id, i + j, sizeof(*raw_desc),
+ shm_id_,
+ shm_allocator_->GetOffset(raw_desc));
+ }
+ // Finish to get the results.
+ helper_->Finish();
+ DCHECK_EQ(helper_->GetParseError(), parse_error::kParseNoError);
+ for (unsigned int j = 0 ; j < count; ++j) {
+ EffectStreamDesc *desc = &((*descs)[i + j]);
+ Desc *raw_desc = raw_descs + j;
+ desc->semantic = static_cast<vertex_struct::Semantic>(raw_desc->semantic);
+ desc->semantic_index = raw_desc->semantic_index;
+ }
+ }
+ shm_allocator_->Free(raw_descs);
+ return true;
+}
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/client/effect_helper.h b/o3d/gpu/command_buffer/client/effect_helper.h
new file mode 100644
index 0000000..dc11b24
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/effect_helper.h
@@ -0,0 +1,156 @@
+/*
+ * 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 the EffectHelper class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CROSS_EFFECT_HELPER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CROSS_EFFECT_HELPER_H_
+
+#include <vector>
+#include "gpu/command_buffer/common/resource.h"
+#include "gpu/command_buffer/client/o3d_cmd_helper.h"
+
+namespace command_buffer {
+
+class FencedAllocatorWrapper;
+class IdAllocator;
+class CommandBufferHelper;
+
+// A helper class to find parameters in an effect.
+class EffectHelper {
+ public:
+ // A more usable version of effect_param::Desc
+ struct EffectParamDesc {
+ ResourceId id; // The resource ID for the param.
+ String name; // The name of the param.
+ String semantic; // The semantic of the param.
+ effect_param::DataType data_type; // The data type of a param.
+ unsigned int data_size; // The size of the data for a param.
+ int num_elements; // The number of array entries if the
+ // parameter is an array, 0 otherwise.
+ unsigned int cmd_desc_size; // The size of the effect_param::Desc
+ // structure (counting strings) for a
+ // param.
+ };
+ struct EffectStreamDesc {
+ vertex_struct::Semantic semantic; // The semantic enum type.
+ unsigned int semantic_index;
+ };
+
+ EffectHelper(O3DCmdHelper *helper,
+ FencedAllocatorWrapper *shm_allocator,
+ unsigned int shm_id,
+ IdAllocator *param_id_allocator)
+ : helper_(helper),
+ shm_allocator_(shm_allocator),
+ shm_id_(shm_id),
+ param_id_allocator_(param_id_allocator) {
+ DCHECK(helper);
+ DCHECK(shm_allocator);
+ DCHECK(param_id_allocator);
+ }
+
+ // Creates all the parameters in an effect and gets their descriptions. The
+ // strings will not be retrieved, so name and semantic will be empty. The
+ // cmd_desc_size field will be set to the proper size to be able to get the
+ // strings with a single command within GetParamStrings, so it should be left
+ // alone.
+ //
+ // The ResourceIDs will be allocated in the param_id_allocator.
+ // Temporary buffers will be allocated in the shm_allocator, but they will be
+ // freed before the function returns (possibly pending a token). At least
+ // sizeof(effect_param::Desc) must be available for this function to succeed.
+ // This function will call Finish(), hence will block.
+ //
+ // Parameters:
+ // effect_id: the ResourceId of the effect.
+ // descs: A pointer to a vector containing the returned descriptions.
+ // The pointed vector will be cleared.
+ // Returns:
+ // true if successful. Reasons for failure are:
+ // - invalid effect_id,
+ // - not enough memory in the shm_allocator_.
+ bool CreateEffectParameters(ResourceId effect_id,
+ std::vector<EffectParamDesc> *descs);
+
+ // Gets the strings for a desc. This will fill in the values for the name and
+ // semantic fields.
+ // Temporary buffers will be allocated in the shm_allocator, but they will be
+ // freed before the function returns (possibly pending a token). At least
+ // desc.cmd_desc_size (as returned by CreateEffectParameters) must be
+ // available for this function to succeed.
+ // This function will call Finish(), hence will block.
+ //
+ // Parameters:
+ // desc: a pointer to the description for a parameter. The id field should
+ // be set to the ResourceId of the parameter.
+ // Returns:
+ // true if successful. Reasons for failure are:
+ // - invalid parameter ResourceId,
+ // - not enough memory in the shm_allocator_.
+ bool GetParamStrings(EffectParamDesc *desc);
+
+ // Destroys all parameter resources referenced by the descriptions. The
+ // ResourceId will be freed from the param_id_allocator.
+ // Parameters:
+ // descs: the vector of descriptions containing the ResourceIDs of the
+ // parameters to destroy.
+ void DestroyEffectParameters(const std::vector<EffectParamDesc> &descs);
+
+ // Gets all the input stream semantics and semantic indices in an
+ // array. These will be retrieved as many as possible at a time. At least
+ // sizeof(effect_param::Desc) must be available for this function to succeed.
+ // This function will call Finish(), hence will block.
+ //
+ // Parameters:
+ // effect_id: the ResourceId of the effect.
+ // descs: A pointer to a vector containing the returned descriptions.
+ // The pointed vector will be cleared.
+ // Returns:
+ // true if successful. Reasons for failure are:
+ // - invalid effect_id,
+ // - not enough memory in the shm_allocator_.
+ bool GetEffectStreams(ResourceId effect_id,
+ std::vector<EffectStreamDesc> *descs);
+
+ private:
+ O3DCmdHelper *helper_;
+ FencedAllocatorWrapper *shm_allocator_;
+ unsigned int shm_id_;
+ IdAllocator *param_id_allocator_;
+
+ DISALLOW_COPY_AND_ASSIGN(EffectHelper);
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_CROSS_EFFECT_HELPER_H_
diff --git a/o3d/gpu/command_buffer/client/fenced_allocator.cc b/o3d/gpu/command_buffer/client/fenced_allocator.cc
new file mode 100644
index 0000000..810feb5
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/fenced_allocator.cc
@@ -0,0 +1,214 @@
+/*
+ * 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 implementation of the FencedAllocator class.
+
+#include "gpu/command_buffer/client/fenced_allocator.h"
+#include <algorithm>
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+
+namespace command_buffer {
+
+#ifndef COMPILER_MSVC
+const FencedAllocator::Offset FencedAllocator::kInvalidOffset;
+#endif
+
+FencedAllocator::~FencedAllocator() {
+ // Free blocks pending tokens.
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ if (blocks_[i].state == FREE_PENDING_TOKEN) {
+ i = WaitForTokenAndFreeBlock(i);
+ }
+ }
+ DCHECK_EQ(blocks_.size(), 1u);
+ DCHECK_EQ(blocks_[0].state, FREE);
+}
+
+// Looks for a non-allocated block that is big enough. Search in the FREE
+// blocks first (for direct usage), first-fit, then in the FREE_PENDING_TOKEN
+// blocks, waiting for them. The current implementation isn't smart about
+// optimizing what to wait for, just looks inside the block in order (first-fit
+// as well).
+FencedAllocator::Offset FencedAllocator::Alloc(unsigned int size) {
+ // Similarly to malloc, an allocation of 0 allocates at least 1 byte, to
+ // return different pointers every time.
+ if (size == 0) size = 1;
+
+ // Try first to allocate in a free block.
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ Block &block = blocks_[i];
+ if (block.state == FREE && block.size >= size) {
+ return AllocInBlock(i, size);
+ }
+ }
+
+ // No free block is available. Look for blocks pending tokens, and wait for
+ // them to be re-usable.
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ if (blocks_[i].state != FREE_PENDING_TOKEN)
+ continue;
+ i = WaitForTokenAndFreeBlock(i);
+ if (blocks_[i].size >= size)
+ return AllocInBlock(i, size);
+ }
+ return kInvalidOffset;
+}
+
+// Looks for the corresponding block, mark it FREE, and collapse it if
+// necessary.
+void FencedAllocator::Free(FencedAllocator::Offset offset) {
+ BlockIndex index = GetBlockByOffset(offset);
+ DCHECK_NE(blocks_[index].state, FREE);
+ blocks_[index].state = FREE;
+ CollapseFreeBlock(index);
+}
+
+// Looks for the corresponding block, mark it FREE_PENDING_TOKEN.
+void FencedAllocator::FreePendingToken(FencedAllocator::Offset offset,
+ unsigned int token) {
+ BlockIndex index = GetBlockByOffset(offset);
+ Block &block = blocks_[index];
+ block.state = FREE_PENDING_TOKEN;
+ block.token = token;
+}
+
+// Gets the max of the size of the blocks marked as free.
+unsigned int FencedAllocator::GetLargestFreeSize() {
+ unsigned int max_size = 0;
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ Block &block = blocks_[i];
+ if (block.state == FREE)
+ max_size = std::max(max_size, block.size);
+ }
+ return max_size;
+}
+
+// Gets the size of the largest segment of blocks that are either FREE or
+// FREE_PENDING_TOKEN.
+unsigned int FencedAllocator::GetLargestFreeOrPendingSize() {
+ unsigned int max_size = 0;
+ unsigned int current_size = 0;
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ Block &block = blocks_[i];
+ if (block.state == IN_USE) {
+ max_size = std::max(max_size, current_size);
+ current_size = 0;
+ } else {
+ DCHECK(block.state == FREE || block.state == FREE_PENDING_TOKEN);
+ current_size += block.size;
+ }
+ }
+ return std::max(max_size, current_size);
+}
+
+// Makes sure that:
+// - there is at least one block.
+// - there are no contiguous FREE blocks (they should have been collapsed).
+// - the successive offsets match the block sizes, and they are in order.
+bool FencedAllocator::CheckConsistency() {
+ if (blocks_.size() < 1) return false;
+ for (unsigned int i = 0; i < blocks_.size() - 1; ++i) {
+ Block &current = blocks_[i];
+ Block &next = blocks_[i + 1];
+ // This test is NOT included in the next one, because offset is unsigned.
+ if (next.offset <= current.offset)
+ return false;
+ if (next.offset != current.offset + current.size)
+ return false;
+ if (current.state == FREE && next.state == FREE)
+ return false;
+ }
+ return true;
+}
+
+// Collapse the block to the next one, then to the previous one. Provided the
+// structure is consistent, those are the only blocks eligible for collapse.
+FencedAllocator::BlockIndex FencedAllocator::CollapseFreeBlock(
+ BlockIndex index) {
+ if (index + 1 < blocks_.size()) {
+ Block &next = blocks_[index + 1];
+ if (next.state == FREE) {
+ blocks_[index].size += next.size;
+ blocks_.erase(blocks_.begin() + index + 1);
+ }
+ }
+ if (index > 0) {
+ Block &prev = blocks_[index - 1];
+ if (prev.state == FREE) {
+ prev.size += blocks_[index].size;
+ blocks_.erase(blocks_.begin() + index);
+ --index;
+ }
+ }
+ return index;
+}
+
+// Waits for the block's token, then mark the block as free, then collapse it.
+FencedAllocator::BlockIndex FencedAllocator::WaitForTokenAndFreeBlock(
+ BlockIndex index) {
+ Block &block = blocks_[index];
+ DCHECK_EQ(block.state, FREE_PENDING_TOKEN);
+ helper_->WaitForToken(block.token);
+ block.state = FREE;
+ return CollapseFreeBlock(index);
+}
+
+// If the block is exactly the requested size, simply mark it IN_USE, otherwise
+// split it and mark the first one (of the requested size) IN_USE.
+FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index,
+ unsigned int size) {
+ Block &block = blocks_[index];
+ DCHECK_GE(block.size, size);
+ DCHECK_EQ(block.state, FREE);
+ Offset offset = block.offset;
+ if (block.size == size) {
+ block.state = IN_USE;
+ return offset;
+ }
+ Block newblock = { FREE, offset + size, block.size - size, kUnusedToken};
+ block.state = IN_USE;
+ block.size = size;
+ // this is the last thing being done because it may invalidate block;
+ blocks_.insert(blocks_.begin() + index + 1, newblock);
+ return offset;
+}
+
+// The blocks are in offset order, so we can do a binary search.
+FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) {
+ Block templ = { IN_USE, offset, 0, kUnusedToken };
+ Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(),
+ templ, OffsetCmp());
+ DCHECK(it != blocks_.end() && it->offset == offset);
+ return it-blocks_.begin();
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/client/fenced_allocator.h b/o3d/gpu/command_buffer/client/fenced_allocator.h
new file mode 100644
index 0000000..72bba33
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/fenced_allocator.h
@@ -0,0 +1,266 @@
+/*
+ * 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 definition of the FencedAllocator class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CROSS_FENCED_ALLOCATOR_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CROSS_FENCED_ALLOCATOR_H_
+
+#include <vector>
+#include "base/basictypes.h"
+#include "gpu/command_buffer/common/logging.h"
+
+namespace command_buffer {
+class CommandBufferHelper;
+
+// FencedAllocator provides a mechanism to manage allocations within a fixed
+// block of memory (storing the book-keeping externally). Furthermore this
+// class allows to free data "pending" the passage of a command buffer token,
+// that is, the memory won't be reused until the command buffer has processed
+// that token.
+//
+// NOTE: Although this class is intended to be used in the command buffer
+// environment which is multi-process, this class isn't "thread safe", because
+// it isn't meant to be shared across modules. It is thread-compatible though
+// (see http://www.corp.google.com/eng/doc/cpp_primer.html#thread_safety).
+class FencedAllocator {
+ public:
+ typedef unsigned int Offset;
+ // Invalid offset, returned by Alloc in case of failure.
+ static const Offset kInvalidOffset = 0xffffffffU;
+
+ // Creates a FencedAllocator. Note that the size of the buffer is passed, but
+ // not its base address: everything is handled as offsets into the buffer.
+ FencedAllocator(unsigned int size,
+ CommandBufferHelper *helper)
+ : helper_(helper) {
+ Block block = { FREE, 0, size, kUnusedToken };
+ blocks_.push_back(block);
+ }
+
+ ~FencedAllocator();
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ //
+ // Parameters:
+ // size: the size of the memory block to allocate.
+ //
+ // Returns:
+ // the offset of the allocated memory block, or kInvalidOffset if out of
+ // memory.
+ Offset Alloc(unsigned int size);
+
+ // Frees a block of memory.
+ //
+ // Parameters:
+ // offset: the offset of the memory block to free.
+ void Free(Offset offset);
+
+ // Frees a block of memory, pending the passage of a token. That memory won't
+ // be re-allocated until the token has passed through the command stream.
+ //
+ // Parameters:
+ // offset: the offset of the memory block to free.
+ // token: the token value to wait for before re-using the memory.
+ void FreePendingToken(Offset offset, unsigned int token);
+
+ // Gets the size of the largest free block that is available without waiting.
+ unsigned int GetLargestFreeSize();
+
+ // Gets the size of the largest free block that can be allocated if the
+ // caller can wait. Allocating a block of this size will succeed, but may
+ // block.
+ unsigned int GetLargestFreeOrPendingSize();
+
+ // Checks for consistency inside the book-keeping structures. Used for
+ // testing.
+ bool CheckConsistency();
+
+ private:
+ // Status of a block of memory, for book-keeping.
+ enum State {
+ IN_USE,
+ FREE,
+ FREE_PENDING_TOKEN
+ };
+
+ // Book-keeping sturcture that describes a block of memory.
+ struct Block {
+ State state;
+ Offset offset;
+ unsigned int size;
+ unsigned int token; // token to wait for in the FREE_PENDING_TOKEN case.
+ };
+
+ // Comparison functor for memory block sorting.
+ class OffsetCmp {
+ public:
+ bool operator() (const Block &left, const Block &right) {
+ return left.offset < right.offset;
+ }
+ };
+
+ typedef std::vector<Block> Container;
+ typedef unsigned int BlockIndex;
+
+ static const unsigned int kUnusedToken = 0;
+
+ // Gets the index of a memory block, given its offset.
+ BlockIndex GetBlockByOffset(Offset offset);
+
+ // Collapse a free block with its neighbours if they are free. Returns the
+ // index of the collapsed block.
+ // NOTE: this will invalidate block indices.
+ BlockIndex CollapseFreeBlock(BlockIndex index);
+
+ // Waits for a FREE_PENDING_TOKEN block to be usable, and free it. Returns
+ // the new index of that block (since it may have been collapsed).
+ // NOTE: this will invalidate block indices.
+ BlockIndex WaitForTokenAndFreeBlock(BlockIndex index);
+
+ // Allocates a block of memory inside a given block, splitting it in two
+ // (unless that block is of the exact requested size).
+ // NOTE: this will invalidate block indices.
+ // Returns the offset of the allocated block (NOTE: this is different from
+ // the other functions that return a block index).
+ Offset AllocInBlock(BlockIndex index, unsigned int size);
+
+ command_buffer::CommandBufferHelper *helper_;
+ Container blocks_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocator);
+};
+
+// This class functions just like FencedAllocator, but its API uses pointers
+// instead of offsets.
+class FencedAllocatorWrapper {
+ public:
+ FencedAllocatorWrapper(unsigned int size,
+ CommandBufferHelper *helper,
+ void *base)
+ : allocator_(size, helper),
+ base_(base) { }
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ //
+ // Parameters:
+ // size: the size of the memory block to allocate.
+ //
+ // Returns:
+ // the pointer to the allocated memory block, or NULL if out of
+ // memory.
+ void *Alloc(unsigned int size) {
+ FencedAllocator::Offset offset = allocator_.Alloc(size);
+ return GetPointer(offset);
+ }
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ // This is a type-safe version of Alloc, returning a typed pointer.
+ //
+ // Parameters:
+ // count: the number of elements to allocate.
+ //
+ // Returns:
+ // the pointer to the allocated memory block, or NULL if out of
+ // memory.
+ template <typename T> T *AllocTyped(unsigned int count) {
+ return static_cast<T *>(Alloc(count * sizeof(T)));
+ }
+
+ // Frees a block of memory.
+ //
+ // Parameters:
+ // pointer: the pointer to the memory block to free.
+ void Free(void *pointer) {
+ DCHECK(pointer);
+ allocator_.Free(GetOffset(pointer));
+ }
+
+ // Frees a block of memory, pending the passage of a token. That memory won't
+ // be re-allocated until the token has passed through the command stream.
+ //
+ // Parameters:
+ // pointer: the pointer to the memory block to free.
+ // token: the token value to wait for before re-using the memory.
+ void FreePendingToken(void *pointer, unsigned int token) {
+ DCHECK(pointer);
+ allocator_.FreePendingToken(GetOffset(pointer), token);
+ }
+
+ // Gets a pointer to a memory block given the base memory and the offset.
+ // It translates FencedAllocator::kInvalidOffset to NULL.
+ void *GetPointer(FencedAllocator::Offset offset) {
+ return (offset == FencedAllocator::kInvalidOffset) ?
+ NULL : static_cast<char *>(base_) + offset;
+ }
+
+ // Gets the offset to a memory block given the base memory and the address.
+ // It translates NULL to FencedAllocator::kInvalidOffset.
+ FencedAllocator::Offset GetOffset(void *pointer) {
+ return pointer ? static_cast<char *>(pointer) - static_cast<char *>(base_) :
+ FencedAllocator::kInvalidOffset;
+ }
+
+ // Gets the size of the largest free block that is available without waiting.
+ unsigned int GetLargestFreeSize() {
+ return allocator_.GetLargestFreeSize();
+ }
+
+ // Gets the size of the largest free block that can be allocated if the
+ // caller can wait.
+ unsigned int GetLargestFreeOrPendingSize() {
+ return allocator_.GetLargestFreeOrPendingSize();
+ }
+
+ // Checks for consistency inside the book-keeping structures. Used for
+ // testing.
+ bool CheckConsistency() {
+ return allocator_.CheckConsistency();
+ }
+
+ FencedAllocator &allocator() { return allocator_; }
+
+ private:
+ FencedAllocator allocator_;
+ void *base_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocatorWrapper);
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_CROSS_FENCED_ALLOCATOR_H_
diff --git a/o3d/gpu/command_buffer/client/fenced_allocator_test.cc b/o3d/gpu/command_buffer/client/fenced_allocator_test.cc
new file mode 100644
index 0000000..ce76542
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/fenced_allocator_test.cc
@@ -0,0 +1,496 @@
+/*
+ * 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 tests for the FencedAllocator class.
+
+#include "tests/common/win/testing_common.h"
+#include "base/message_loop.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/client/fenced_allocator.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/gpu_plugin/command_buffer.h"
+#include "gpu/gpu_plugin/gpu_processor.h"
+#include "gpu/np_utils/np_object_pointer.h"
+
+namespace command_buffer {
+
+using gpu_plugin::CommandBuffer;
+using gpu_plugin::GPUProcessor;
+using gpu_plugin::NPCreateObject;
+using gpu_plugin::NPObjectPointer;
+using testing::Return;
+using testing::Mock;
+using testing::Truly;
+using testing::Sequence;
+using testing::DoAll;
+using testing::Invoke;
+using testing::_;
+
+class BaseFencedAllocatorTest : public testing::Test {
+ protected:
+ static const unsigned int kBufferSize = 1024;
+
+ virtual void SetUp() {
+ api_mock_.reset(new AsyncAPIMock);
+ // ignore noops in the mock - we don't want to inspect the internals of the
+ // helper.
+ EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, 0, _))
+ .WillRepeatedly(Return(parse_error::kParseNoError));
+ // Forward the SetToken calls to the engine
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillRepeatedly(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
+ Return(parse_error::kParseNoError)));
+
+ ::base::SharedMemory* ring_buffer = new ::base::SharedMemory;
+ ring_buffer->Create(std::wstring(), false, false, 1024);
+ ring_buffer->Map(1024);
+
+ command_buffer_ = NPCreateObject<CommandBuffer>(NULL);
+ command_buffer_->Initialize(ring_buffer);
+
+ parser_ = new command_buffer::CommandParser(ring_buffer->memory(),
+ kBufferSize,
+ 0,
+ kBufferSize,
+ 0,
+ api_mock_.get());
+
+ scoped_refptr<GPUProcessor> gpu_processor(new GPUProcessor(
+ NULL, command_buffer_.Get(), NULL, NULL, parser_, INT_MAX));
+ command_buffer_->SetPutOffsetChangeCallback(NewCallback(
+ gpu_processor.get(), &GPUProcessor::ProcessCommands));
+
+ api_mock_->set_engine(gpu_processor.get());
+
+ helper_.reset(new CommandBufferHelper(NULL, command_buffer_));
+ helper_->Initialize();
+ }
+
+ virtual void TearDown() {
+ helper_.release();
+ }
+
+ scoped_ptr<AsyncAPIMock> api_mock_;
+ NPObjectPointer<CommandBuffer> command_buffer_;
+ command_buffer::CommandParser* parser_;
+ scoped_ptr<CommandBufferHelper> helper_;
+};
+
+#ifndef COMPILER_MSVC
+const unsigned int BaseFencedAllocatorTest::kBufferSize;
+#endif
+
+// Test fixture for FencedAllocator test - Creates a FencedAllocator, using a
+// CommandBufferHelper with a mock AsyncAPIInterface for its interface (calling
+// it directly, not through the RPC mechanism), making sure Noops are ignored
+// and SetToken are properly forwarded to the engine.
+class FencedAllocatorTest : public BaseFencedAllocatorTest {
+ protected:
+ virtual void SetUp() {
+ BaseFencedAllocatorTest::SetUp();
+ allocator_.reset(new FencedAllocator(kBufferSize, helper_.get()));
+ }
+
+ virtual void TearDown() {
+ // If the GPUProcessor posts any tasks, this forces them to run.
+ MessageLoop::current()->RunAllPending();
+
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ allocator_.release();
+
+ BaseFencedAllocatorTest::TearDown();
+ }
+
+ scoped_ptr<FencedAllocator> allocator_;
+};
+
+// Checks basic alloc and free.
+TEST_F(FencedAllocatorTest, TestBasic) {
+ allocator_->CheckConsistency();
+
+ const unsigned int kSize = 16;
+ FencedAllocator::Offset offset = allocator_->Alloc(kSize);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offset);
+ EXPECT_GE(kBufferSize, offset+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ allocator_->Free(offset);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+}
+
+// Checks out-of-memory condition.
+TEST_F(FencedAllocatorTest, TestOutOfMemory) {
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ // Allocate several buffers to fill in the memory.
+ FencedAllocator::Offset offsets[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ offsets[i] = allocator_->Alloc(kSize);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[i]);
+ EXPECT_GE(kBufferSize, offsets[i]+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+
+ // This allocation should fail.
+ FencedAllocator::Offset offset_failed = allocator_->Alloc(kSize);
+ EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free one successful allocation, reallocate with half the size
+ allocator_->Free(offsets[0]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ offsets[0] = allocator_->Alloc(kSize/2);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[0]);
+ EXPECT_GE(kBufferSize, offsets[0]+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // This allocation should fail as well.
+ offset_failed = allocator_->Alloc(kSize);
+ EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free up everything.
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ allocator_->Free(offsets[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+}
+
+// Checks the free-pending-token mechanism.
+TEST_F(FencedAllocatorTest, TestFreePendingToken) {
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ // Allocate several buffers to fill in the memory.
+ FencedAllocator::Offset offsets[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ offsets[i] = allocator_->Alloc(kSize);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[i]);
+ EXPECT_GE(kBufferSize, offsets[i]+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+
+ // This allocation should fail.
+ FencedAllocator::Offset offset_failed = allocator_->Alloc(kSize);
+ EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free one successful allocation, pending fence.
+ int32 token = helper_.get()->InsertToken();
+ allocator_->FreePendingToken(offsets[0], token);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // The way we hooked up the helper and engine, it won't process commands
+ // until it has to wait for something. Which means the token shouldn't have
+ // passed yet at this point.
+ EXPECT_GT(token, command_buffer_->GetToken());
+
+ // This allocation will need to reclaim the space freed above, so that should
+ // process the commands until the token is passed.
+ offsets[0] = allocator_->Alloc(kSize);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[0]);
+ EXPECT_GE(kBufferSize, offsets[0]+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ // Check that the token has indeed passed.
+ EXPECT_LE(token, command_buffer_->GetToken());
+
+ // Free up everything.
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ allocator_->Free(offsets[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+}
+
+// Tests GetLargestFreeSize
+TEST_F(FencedAllocatorTest, TestGetLargestFreeSize) {
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSize());
+
+ FencedAllocator::Offset offset = allocator_->Alloc(kBufferSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ EXPECT_EQ(0u, allocator_->GetLargestFreeSize());
+ allocator_->Free(offset);
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSize());
+
+ const unsigned int kSize = 16;
+ offset = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ // The following checks that the buffer is allocated "smartly" - which is
+ // dependent on the implementation. But both first-fit or best-fit would
+ // ensure that.
+ EXPECT_EQ(kBufferSize - kSize, allocator_->GetLargestFreeSize());
+
+ // Allocate 2 more buffers (now 3), and then free the first two. This is to
+ // ensure a hole. Note that this is dependent on the first-fit current
+ // implementation.
+ FencedAllocator::Offset offset1 = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset1);
+ FencedAllocator::Offset offset2 = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset2);
+ allocator_->Free(offset);
+ allocator_->Free(offset1);
+ EXPECT_EQ(kBufferSize - 3 * kSize, allocator_->GetLargestFreeSize());
+
+ offset = allocator_->Alloc(kBufferSize - 3 * kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ EXPECT_EQ(2 * kSize, allocator_->GetLargestFreeSize());
+
+ offset1 = allocator_->Alloc(2 * kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset1);
+ EXPECT_EQ(0u, allocator_->GetLargestFreeSize());
+
+ allocator_->Free(offset);
+ allocator_->Free(offset1);
+ allocator_->Free(offset2);
+}
+
+// Tests GetLargestFreeOrPendingSize
+TEST_F(FencedAllocatorTest, TestGetLargestFreeOrPendingSize) {
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+
+ FencedAllocator::Offset offset = allocator_->Alloc(kBufferSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ EXPECT_EQ(0u, allocator_->GetLargestFreeOrPendingSize());
+ allocator_->Free(offset);
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+
+ const unsigned int kSize = 16;
+ offset = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ // The following checks that the buffer is allocates "smartly" - which is
+ // dependent on the implementation. But both first-fit or best-fit would
+ // ensure that.
+ EXPECT_EQ(kBufferSize - kSize, allocator_->GetLargestFreeOrPendingSize());
+
+ // Allocate 2 more buffers (now 3), and then free the first two. This is to
+ // ensure a hole. Note that this is dependent on the first-fit current
+ // implementation.
+ FencedAllocator::Offset offset1 = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset1);
+ FencedAllocator::Offset offset2 = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset2);
+ allocator_->Free(offset);
+ allocator_->Free(offset1);
+ EXPECT_EQ(kBufferSize - 3 * kSize,
+ allocator_->GetLargestFreeOrPendingSize());
+
+ // Free the last one, pending a token.
+ int32 token = helper_.get()->InsertToken();
+ allocator_->FreePendingToken(offset2, token);
+
+ // Now all the buffers have been freed...
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+ // .. but one is still waiting for the token.
+ EXPECT_EQ(kBufferSize - 3 * kSize,
+ allocator_->GetLargestFreeSize());
+
+ // The way we hooked up the helper and engine, it won't process commands
+ // until it has to wait for something. Which means the token shouldn't have
+ // passed yet at this point.
+ EXPECT_GT(token, command_buffer_->GetToken());
+ // This allocation will need to reclaim the space freed above, so that should
+ // process the commands until the token is passed, but it will succeed.
+ offset = allocator_->Alloc(kBufferSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ // Check that the token has indeed passed.
+ EXPECT_LE(token, command_buffer_->GetToken());
+ allocator_->Free(offset);
+
+ // Everything now has been freed...
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+ // ... for real.
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSize());
+}
+
+// Test fixture for FencedAllocatorWrapper test - Creates a
+// FencedAllocatorWrapper, using a CommandBufferHelper with a mock
+// AsyncAPIInterface for its interface (calling it directly, not through the
+// RPC mechanism), making sure Noops are ignored and SetToken are properly
+// forwarded to the engine.
+class FencedAllocatorWrapperTest : public BaseFencedAllocatorTest {
+ protected:
+ virtual void SetUp() {
+ BaseFencedAllocatorTest::SetUp();
+
+ // Though allocating this buffer isn't strictly necessary, it makes
+ // allocations point to valid addresses, so they could be used for
+ // something.
+ buffer_.reset(new char[kBufferSize]);
+ allocator_.reset(new FencedAllocatorWrapper(kBufferSize, helper_.get(),
+ buffer_.get()));
+ }
+
+ virtual void TearDown() {
+ // If the GPUProcessor posts any tasks, this forces them to run.
+ MessageLoop::current()->RunAllPending();
+
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ allocator_.release();
+ buffer_.release();
+
+ BaseFencedAllocatorTest::TearDown();
+ }
+
+ scoped_ptr<FencedAllocatorWrapper> allocator_;
+ scoped_array<char> buffer_;
+};
+
+// Checks basic alloc and free.
+TEST_F(FencedAllocatorWrapperTest, TestBasic) {
+ allocator_->CheckConsistency();
+
+ const unsigned int kSize = 16;
+ void *pointer = allocator_->Alloc(kSize);
+ ASSERT_TRUE(pointer);
+ EXPECT_LE(buffer_.get(), static_cast<char *>(pointer));
+ EXPECT_GE(kBufferSize, static_cast<char *>(pointer) - buffer_.get() + kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ allocator_->Free(pointer);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ char *pointer_char = allocator_->AllocTyped<char>(kSize);
+ ASSERT_TRUE(pointer_char);
+ EXPECT_LE(buffer_.get(), pointer_char);
+ EXPECT_GE(buffer_.get() + kBufferSize, pointer_char + kSize);
+ allocator_->Free(pointer_char);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ unsigned int *pointer_uint = allocator_->AllocTyped<unsigned int>(kSize);
+ ASSERT_TRUE(pointer_uint);
+ EXPECT_LE(buffer_.get(), reinterpret_cast<char *>(pointer_uint));
+ EXPECT_GE(buffer_.get() + kBufferSize,
+ reinterpret_cast<char *>(pointer_uint + kSize));
+
+ // Check that it did allocate kSize * sizeof(unsigned int). We can't tell
+ // directly, except from the remaining size.
+ EXPECT_EQ(kBufferSize - kSize * sizeof(*pointer_uint),
+ allocator_->GetLargestFreeSize());
+ allocator_->Free(pointer_uint);
+}
+
+// Checks out-of-memory condition.
+TEST_F(FencedAllocatorWrapperTest, TestOutOfMemory) {
+ allocator_->CheckConsistency();
+
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ // Allocate several buffers to fill in the memory.
+ void *pointers[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ pointers[i] = allocator_->Alloc(kSize);
+ EXPECT_TRUE(pointers[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+
+ // This allocation should fail.
+ void *pointer_failed = allocator_->Alloc(kSize);
+ EXPECT_FALSE(pointer_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free one successful allocation, reallocate with half the size
+ allocator_->Free(pointers[0]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ pointers[0] = allocator_->Alloc(kSize/2);
+ EXPECT_TRUE(pointers[0]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // This allocation should fail as well.
+ pointer_failed = allocator_->Alloc(kSize);
+ EXPECT_FALSE(pointer_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free up everything.
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ allocator_->Free(pointers[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+}
+
+// Checks the free-pending-token mechanism.
+TEST_F(FencedAllocatorWrapperTest, TestFreePendingToken) {
+ allocator_->CheckConsistency();
+
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ // Allocate several buffers to fill in the memory.
+ void *pointers[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ pointers[i] = allocator_->Alloc(kSize);
+ EXPECT_TRUE(pointers[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+
+ // This allocation should fail.
+ void *pointer_failed = allocator_->Alloc(kSize);
+ EXPECT_FALSE(pointer_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free one successful allocation, pending fence.
+ int32 token = helper_.get()->InsertToken();
+ allocator_->FreePendingToken(pointers[0], token);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // The way we hooked up the helper and engine, it won't process commands
+ // until it has to wait for something. Which means the token shouldn't have
+ // passed yet at this point.
+ EXPECT_GT(token, command_buffer_->GetToken());
+
+ // This allocation will need to reclaim the space freed above, so that should
+ // process the commands until the token is passed.
+ pointers[0] = allocator_->Alloc(kSize);
+ EXPECT_TRUE(pointers[0]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ // Check that the token has indeed passed.
+ EXPECT_LE(token, command_buffer_->GetToken());
+
+ // Free up everything.
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ allocator_->Free(pointers[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/client/id_allocator.cc b/o3d/gpu/command_buffer/client/id_allocator.cc
new file mode 100644
index 0000000..49104e5
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/id_allocator.cc
@@ -0,0 +1,85 @@
+/*
+ * 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 implementation of IdAllocator.
+
+#include "gpu/command_buffer/client/id_allocator.h"
+
+namespace command_buffer {
+
+IdAllocator::IdAllocator() : bitmap_(1) { bitmap_[0] = 0; }
+
+static const unsigned int kBitsPerUint32 = sizeof(Uint32) * 8; // NOLINT
+
+// Looks for the first non-full entry, and return the first free bit in that
+// entry. If all the entries are full, it will return the first bit of an entry
+// that would be appended, but doesn't actually append that entry to the vector.
+unsigned int IdAllocator::FindFirstFree() const {
+ size_t size = bitmap_.size();
+ for (unsigned int i = 0; i < size; ++i) {
+ Uint32 value = bitmap_[i];
+ if (value != 0xffffffffU) {
+ for (unsigned int j = 0; j < kBitsPerUint32; ++j) {
+ if (!(value & (1 << j))) return i * kBitsPerUint32 + j;
+ }
+ DLOG(FATAL) << "Code should not reach here.";
+ }
+ }
+ return size*kBitsPerUint32;
+}
+
+// Sets the correct bit in the proper entry, resizing the vector if needed.
+void IdAllocator::SetBit(unsigned int bit, bool value) {
+ size_t size = bitmap_.size();
+ if (bit >= size * kBitsPerUint32) {
+ size_t newsize = bit / kBitsPerUint32 + 1;
+ bitmap_.resize(newsize);
+ for (size_t i = size; i < newsize; ++i) bitmap_[i] = 0;
+ }
+ Uint32 mask = 1U << (bit % kBitsPerUint32);
+ if (value) {
+ bitmap_[bit / kBitsPerUint32] |= mask;
+ } else {
+ bitmap_[bit / kBitsPerUint32] &= ~mask;
+ }
+}
+
+// Gets the bit from the proper entry. This doesn't resize the vector, just
+// returns false if the bit is beyond the last entry.
+bool IdAllocator::GetBit(unsigned int bit) const {
+ size_t size = bitmap_.size();
+ if (bit / kBitsPerUint32 >= size) return false;
+ Uint32 mask = 1U << (bit % kBitsPerUint32);
+ return (bitmap_[bit / kBitsPerUint32] & mask) != 0;
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/client/id_allocator.h b/o3d/gpu/command_buffer/client/id_allocator.h
new file mode 100644
index 0000000..b2b14b9
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/id_allocator.h
@@ -0,0 +1,78 @@
+/*
+ * 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 definition of the IdAllocator class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CROSS_ID_ALLOCATOR_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CROSS_ID_ALLOCATOR_H_
+
+#include <vector>
+#include "base/basictypes.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/command_buffer/common/resource.h"
+
+namespace command_buffer {
+
+// A class to manage the allocation of resource IDs. It uses a bitfield stored
+// into a vector of unsigned ints.
+class IdAllocator {
+ public:
+ IdAllocator();
+
+ // Allocates a new resource ID.
+ command_buffer::ResourceId AllocateID() {
+ unsigned int bit = FindFirstFree();
+ SetBit(bit, true);
+ return bit;
+ }
+
+ // Frees a resource ID.
+ void FreeID(command_buffer::ResourceId id) {
+ SetBit(id, false);
+ }
+
+ // Checks whether or not a resource ID is in use.
+ bool InUse(command_buffer::ResourceId id) {
+ return GetBit(id);
+ }
+ private:
+ void SetBit(unsigned int bit, bool value);
+ bool GetBit(unsigned int bit) const;
+ unsigned int FindFirstFree() const;
+
+ std::vector<Uint32> bitmap_;
+ DISALLOW_COPY_AND_ASSIGN(IdAllocator);
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_CROSS_ID_ALLOCATOR_H_
diff --git a/o3d/gpu/command_buffer/client/id_allocator_test.cc b/o3d/gpu/command_buffer/client/id_allocator_test.cc
new file mode 100644
index 0000000..10c7809
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/id_allocator_test.cc
@@ -0,0 +1,112 @@
+/*
+ * 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 has the unit tests for the IdAllocator class.
+
+#include "tests/common/win/testing_common.h"
+#include "gpu/command_buffer/client/id_allocator.h"
+
+namespace command_buffer {
+
+using command_buffer::ResourceId;
+
+class IdAllocatorTest : public testing::Test {
+ protected:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ IdAllocator* id_allocator() { return &id_allocator_; }
+
+ private:
+ IdAllocator id_allocator_;
+};
+
+// Checks basic functionality: AllocateID, FreeID, InUse.
+TEST_F(IdAllocatorTest, TestBasic) {
+ IdAllocator *allocator = id_allocator();
+ // Check that resource 0 is not in use
+ EXPECT_FALSE(allocator->InUse(0));
+
+ // Allocate an ID, check that it's in use.
+ ResourceId id1 = allocator->AllocateID();
+ EXPECT_TRUE(allocator->InUse(id1));
+
+ // Allocate another ID, check that it's in use, and different from the first
+ // one.
+ ResourceId id2 = allocator->AllocateID();
+ EXPECT_TRUE(allocator->InUse(id2));
+ EXPECT_NE(id1, id2);
+
+ // Free one of the IDs, check that it's not in use any more.
+ allocator->FreeID(id1);
+ EXPECT_FALSE(allocator->InUse(id1));
+
+ // Frees the other ID, check that it's not in use any more.
+ allocator->FreeID(id2);
+ EXPECT_FALSE(allocator->InUse(id2));
+}
+
+// Checks that the resource IDs are allocated conservatively, and re-used after
+// being freed.
+TEST_F(IdAllocatorTest, TestAdvanced) {
+ IdAllocator *allocator = id_allocator();
+
+ // Allocate a significant number of resources.
+ const unsigned int kNumResources = 100;
+ ResourceId ids[kNumResources];
+ for (unsigned int i = 0; i < kNumResources; ++i) {
+ ids[i] = allocator->AllocateID();
+ EXPECT_TRUE(allocator->InUse(ids[i]));
+ }
+
+ // Check that the allocation is conservative with resource IDs, that is that
+ // the resource IDs don't go over kNumResources - so that the service doesn't
+ // have to allocate too many internal structures when the resources are used.
+ for (unsigned int i = 0; i < kNumResources; ++i) {
+ EXPECT_GT(kNumResources, ids[i]);
+ }
+
+ // Check that the next resources are still free.
+ for (unsigned int i = 0; i < kNumResources; ++i) {
+ EXPECT_FALSE(allocator->InUse(kNumResources + i));
+ }
+
+ // Check that a new allocation re-uses the resource we just freed.
+ ResourceId id1 = ids[kNumResources / 2];
+ allocator->FreeID(id1);
+ EXPECT_FALSE(allocator->InUse(id1));
+ ResourceId id2 = allocator->AllocateID();
+ EXPECT_TRUE(allocator->InUse(id2));
+ EXPECT_EQ(id1, id2);
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/client/o3d_cmd_helper.cc b/o3d/gpu/command_buffer/client/o3d_cmd_helper.cc
new file mode 100644
index 0000000..85c6a27
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/o3d_cmd_helper.cc
@@ -0,0 +1,42 @@
+/*
+ * 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 implementation of the o3d buffer helper class.
+
+#include "gpu/command_buffer/client/o3d_cmd_helper.h"
+
+namespace command_buffer {
+
+// Currently this is a place holder.
+
+} // namespace command_buffer
+
diff --git a/o3d/gpu/command_buffer/client/o3d_cmd_helper.h b/o3d/gpu/command_buffer/client/o3d_cmd_helper.h
new file mode 100644
index 0000000..0dbbff4
--- /dev/null
+++ b/o3d/gpu/command_buffer/client/o3d_cmd_helper.h
@@ -0,0 +1,636 @@
+/*
+ * 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 o3d command buffer helper class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CROSS_O3D_CMD_HELPER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CROSS_O3D_CMD_HELPER_H_
+
+#include "gpu/command_buffer/common/logging.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/common/o3d_cmd_format.h"
+#include "gpu/np_utils/np_object_pointer.h"
+
+namespace command_buffer {
+
+// A helper for O3D command buffers.
+class O3DCmdHelper : public CommandBufferHelper {
+ public:
+ O3DCmdHelper(
+ NPP npp,
+ const gpu_plugin::NPObjectPointer<gpu_plugin::CommandBuffer>&
+ command_buffer)
+ : CommandBufferHelper(npp, command_buffer) {
+ }
+ virtual ~O3DCmdHelper() {
+ }
+
+ // ------------------ Individual commands ----------------------
+
+ void BeginFrame() {
+ o3d::BeginFrame& cmd = GetCmdSpace<o3d::BeginFrame>();
+ cmd.Init();
+ }
+
+
+ void EndFrame() {
+ o3d::EndFrame& cmd = GetCmdSpace<o3d::EndFrame>();
+ cmd.Init();
+ }
+
+ void Clear(
+ uint32 buffers,
+ float red, float green, float blue, float alpha,
+ float depth, uint32 stencil) {
+ o3d::Clear& cmd = GetCmdSpace<o3d::Clear>();
+ cmd.Init(buffers, red, green, blue, alpha, depth, stencil);
+ }
+
+ void SetViewport(
+ uint32 left,
+ uint32 top,
+ uint32 width,
+ uint32 height,
+ float z_min,
+ float z_max) {
+ o3d::SetViewport& cmd = GetCmdSpace<o3d::SetViewport>();
+ cmd.Init(left, top, width, height, z_min, z_max);
+ }
+
+ void CreateVertexBuffer(
+ ResourceId vertex_buffer_id, uint32 size, vertex_buffer::Flags flags) {
+ o3d::CreateVertexBuffer& cmd = GetCmdSpace<o3d::CreateVertexBuffer>();
+ cmd.Init(vertex_buffer_id, size, flags);
+ }
+
+ void DestroyVertexBuffer(ResourceId vertex_buffer_id) {
+ o3d::DestroyVertexBuffer& cmd = GetCmdSpace<o3d::DestroyVertexBuffer>();
+ cmd.Init(vertex_buffer_id);
+ }
+
+ void SetVertexBufferDataImmediate(
+ ResourceId vertex_buffer_id, uint32 offset,
+ const void* data, uint32 size) {
+ o3d::SetVertexBufferDataImmediate& cmd =
+ GetImmediateCmdSpace<o3d::SetVertexBufferDataImmediate>(size);
+ cmd.Init(vertex_buffer_id, offset, data, size);
+ }
+
+ void SetVertexBufferData(
+ ResourceId vertex_buffer_id, uint32 offset, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::SetVertexBufferData& cmd =
+ GetCmdSpace<o3d::SetVertexBufferData>();
+ cmd.Init(vertex_buffer_id, offset, size,
+ shared_memory_id, shared_memory_offset);
+ }
+
+ void GetVertexBufferData(
+ ResourceId vertex_buffer_id, uint32 offset, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::GetVertexBufferData& cmd =
+ GetCmdSpace<o3d::GetVertexBufferData>();
+ cmd.Init(vertex_buffer_id, offset, size,
+ shared_memory_id, shared_memory_offset);
+ }
+
+ void CreateIndexBuffer(
+ ResourceId index_buffer_id, uint32 size, index_buffer::Flags flags) {
+ o3d::CreateIndexBuffer& cmd =
+ GetCmdSpace<o3d::CreateIndexBuffer>();
+ cmd.Init(index_buffer_id, size, flags);
+ }
+
+ void DestroyIndexBuffer(ResourceId index_buffer_id) {
+ o3d::DestroyIndexBuffer& cmd = GetCmdSpace<o3d::DestroyIndexBuffer>();
+ cmd.Init(index_buffer_id);
+ }
+
+ void SetIndexBufferDataImmediate(
+ ResourceId index_buffer_id, uint32 offset,
+ const void* data, uint32 size) {
+ o3d::SetIndexBufferDataImmediate& cmd =
+ GetImmediateCmdSpace<o3d::SetIndexBufferDataImmediate>(size);
+ cmd.Init(index_buffer_id, offset, data, size);
+ }
+
+ void SetIndexBufferData(
+ ResourceId index_buffer_id, uint32 offset, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::SetIndexBufferData& cmd = GetCmdSpace<o3d::SetIndexBufferData>();
+ cmd.Init(index_buffer_id, offset, size,
+ shared_memory_id, shared_memory_offset);
+ }
+
+ void GetIndexBufferData(
+ ResourceId index_buffer_id, uint32 offset, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::GetIndexBufferData& cmd = GetCmdSpace<o3d::GetIndexBufferData>();
+ cmd.Init(index_buffer_id, offset, size,
+ shared_memory_id, shared_memory_offset);
+ }
+
+ void CreateVertexStruct(ResourceId vertex_struct_id, uint32 input_count) {
+ o3d::CreateVertexStruct& cmd = GetCmdSpace<o3d::CreateVertexStruct>();
+ cmd.Init(vertex_struct_id, input_count);
+ }
+
+ void DestroyVertexStruct(ResourceId vertex_struct_id) {
+ o3d::DestroyVertexStruct& cmd = GetCmdSpace<o3d::DestroyVertexStruct>();
+ cmd.Init(vertex_struct_id);
+ }
+
+ void SetVertexInput(
+ ResourceId vertex_struct_id,
+ uint32 input_index,
+ ResourceId vertex_buffer_id,
+ uint32 offset,
+ vertex_struct::Semantic semantic,
+ uint32 semantic_index,
+ vertex_struct::Type type,
+ uint32 stride) {
+ o3d::SetVertexInput& cmd = GetCmdSpace<o3d::SetVertexInput>();
+ cmd.Init(
+ vertex_struct_id,
+ input_index,
+ vertex_buffer_id,
+ offset,
+ semantic,
+ semantic_index,
+ type,
+ stride);
+ }
+
+ void SetVertexStruct(ResourceId vertex_struct_id) {
+ o3d::SetVertexStruct& cmd = GetCmdSpace<o3d::SetVertexStruct>();
+ cmd.Init(vertex_struct_id);
+ }
+
+ void Draw(o3d::PrimitiveType primitive_type, uint32 first, uint32 count) {
+ o3d::Draw& cmd = GetCmdSpace<o3d::Draw>();
+ cmd.Init(primitive_type, first, count);
+ }
+
+ void DrawIndexed(
+ o3d::PrimitiveType primitive_type,
+ ResourceId index_buffer_id,
+ uint32 first,
+ uint32 count,
+ uint32 min_index,
+ uint32 max_index) {
+ o3d::DrawIndexed& cmd = GetCmdSpace<o3d::DrawIndexed>();
+ cmd.Init(
+ primitive_type,
+ index_buffer_id,
+ first,
+ count,
+ min_index,
+ max_index);
+ }
+
+ void CreateEffect(
+ ResourceId effect_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::CreateEffect& cmd = GetCmdSpace<o3d::CreateEffect>();
+ cmd.Init(effect_id, size, shared_memory_id, shared_memory_offset);
+ }
+
+ void CreateEffectImmediate(
+ ResourceId effect_id, uint32 size, const void* data) {
+ o3d::CreateEffectImmediate& cmd =
+ GetImmediateCmdSpace<o3d::CreateEffectImmediate>(size);
+ cmd.Init(effect_id, size, data);
+ }
+
+ void DestroyEffect(ResourceId effect_id) {
+ o3d::DestroyEffect& cmd = GetCmdSpace<o3d::DestroyEffect>();
+ cmd.Init(effect_id);
+ }
+
+ void SetEffect(ResourceId effect_id) {
+ o3d::SetEffect& cmd = GetCmdSpace<o3d::SetEffect>();
+ cmd.Init(effect_id);
+ }
+
+ void GetParamCount(
+ ResourceId effect_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::GetParamCount& cmd = GetCmdSpace<o3d::GetParamCount>();
+ cmd.Init(effect_id, size, shared_memory_id, shared_memory_offset);
+ }
+
+ void CreateParam(ResourceId param_id, ResourceId effect_id, uint32 index) {
+ o3d::CreateParam& cmd = GetCmdSpace<o3d::CreateParam>();
+ cmd.Init(param_id, effect_id, index);
+ }
+
+ void CreateParamByName(
+ ResourceId param_id, ResourceId effect_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::CreateParamByName& cmd = GetCmdSpace<o3d::CreateParamByName>();
+ cmd.Init(param_id, effect_id, size, shared_memory_id, shared_memory_offset);
+ }
+
+ void CreateParamByNameImmediate(
+ ResourceId param_id, ResourceId effect_id,
+ uint32 size, const void* data) {
+ o3d::CreateParamByNameImmediate& cmd =
+ GetImmediateCmdSpace<o3d::CreateParamByNameImmediate>(size);
+ cmd.Init(param_id, effect_id, size, data);
+ }
+
+ void DestroyParam(ResourceId param_id) {
+ o3d::DestroyParam& cmd = GetCmdSpace<o3d::DestroyParam>();
+ cmd.Init(param_id);
+ }
+
+ void SetParamData(
+ ResourceId param_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::SetParamData& cmd = GetCmdSpace<o3d::SetParamData>();
+ cmd.Init(param_id, size, shared_memory_id, shared_memory_offset);
+ }
+
+ void SetParamDataImmediate(
+ ResourceId param_id, uint32 size, const void* data) {
+ o3d::SetParamDataImmediate& cmd =
+ GetImmediateCmdSpace<o3d::SetParamDataImmediate>(size);
+ cmd.Init(param_id, size, data);
+ }
+
+ void GetParamDesc(
+ ResourceId param_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::GetParamDesc& cmd = GetCmdSpace<o3d::GetParamDesc>();
+ cmd.Init(param_id, size, shared_memory_id, shared_memory_offset);
+ }
+
+ void GetStreamCount(
+ ResourceId effect_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::GetStreamCount& cmd = GetCmdSpace<o3d::GetStreamCount>();
+ cmd.Init(effect_id, size, shared_memory_id, shared_memory_offset);
+ }
+
+ void GetStreamDesc(
+ ResourceId effect_id, uint32 index, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ o3d::GetStreamDesc& cmd = GetCmdSpace<o3d::GetStreamDesc>();
+ cmd.Init(effect_id, index, size, shared_memory_id, shared_memory_offset);
+ }
+
+ void DestroyTexture(ResourceId texture_id) {
+ o3d::DestroyTexture& cmd = GetCmdSpace<o3d::DestroyTexture>();
+ cmd.Init(texture_id);
+ }
+
+ void CreateTexture2d(
+ ResourceId texture_id,
+ uint32 width, uint32 height,
+ uint32 levels, texture::Format format,
+ bool enable_render_surfaces) {
+ o3d::CreateTexture2d& cmd = GetCmdSpace<o3d::CreateTexture2d>();
+ cmd.Init(texture_id,
+ width, height, levels, format,
+ enable_render_surfaces);
+ }
+
+ void CreateTexture3d(
+ ResourceId texture_id,
+ uint32 width, uint32 height, uint32 depth,
+ uint32 levels, texture::Format format,
+ bool enable_render_surfaces) {
+ o3d::CreateTexture3d& cmd = GetCmdSpace<o3d::CreateTexture3d>();
+ cmd.Init(texture_id,
+ width, height, depth,
+ levels, format,
+ enable_render_surfaces);
+ }
+
+ void CreateTextureCube(
+ ResourceId texture_id,
+ uint32 edge_length, uint32 levels, texture::Format format,
+ bool enable_render_surfaces) {
+ o3d::CreateTextureCube& cmd = GetCmdSpace<o3d::CreateTextureCube>();
+ cmd.Init(texture_id,
+ edge_length, levels, format,
+ enable_render_surfaces);
+ }
+
+ void SetTextureData(
+ ResourceId texture_id,
+ uint32 x,
+ uint32 y,
+ uint32 z,
+ uint32 width,
+ uint32 height,
+ uint32 depth,
+ uint32 level,
+ texture::Face face,
+ uint32 row_pitch,
+ uint32 slice_pitch,
+ uint32 size,
+ uint32 shared_memory_id,
+ uint32 shared_memory_offset) {
+ o3d::SetTextureData& cmd = GetCmdSpace<o3d::SetTextureData>();
+ cmd.Init(
+ texture_id,
+ x,
+ y,
+ z,
+ width,
+ height,
+ depth,
+ level,
+ face,
+ row_pitch,
+ slice_pitch,
+ size,
+ shared_memory_id,
+ shared_memory_offset);
+ }
+
+ void SetTextureDataImmediate(
+ ResourceId texture_id,
+ uint32 x,
+ uint32 y,
+ uint32 z,
+ uint32 width,
+ uint32 height,
+ uint32 depth,
+ uint32 level,
+ texture::Face face,
+ uint32 row_pitch,
+ uint32 slice_pitch,
+ uint32 size,
+ const void* data) {
+ o3d::SetTextureDataImmediate& cmd =
+ GetImmediateCmdSpace<o3d::SetTextureDataImmediate>(size);
+ cmd.Init(
+ texture_id,
+ x,
+ y,
+ z,
+ width,
+ height,
+ depth,
+ level,
+ face,
+ row_pitch,
+ slice_pitch,
+ size,
+ data);
+ }
+
+ void GetTextureData(
+ ResourceId texture_id,
+ uint32 x,
+ uint32 y,
+ uint32 z,
+ uint32 width,
+ uint32 height,
+ uint32 depth,
+ uint32 level,
+ texture::Face face,
+ uint32 row_pitch,
+ uint32 slice_pitch,
+ uint32 size,
+ uint32 shared_memory_id,
+ uint32 shared_memory_offset) {
+ o3d::GetTextureData& cmd = GetCmdSpace<o3d::GetTextureData>();
+ cmd.Init(
+ texture_id,
+ x,
+ y,
+ z,
+ width,
+ height,
+ depth,
+ level,
+ face,
+ row_pitch,
+ slice_pitch,
+ size,
+ shared_memory_id,
+ shared_memory_offset);
+ }
+
+ void CreateSampler(ResourceId sampler_id) {
+ o3d::CreateSampler& cmd = GetCmdSpace<o3d::CreateSampler>();
+ cmd.Init(sampler_id);
+ }
+
+ void DestroySampler(ResourceId sampler_id) {
+ o3d::DestroySampler& cmd = GetCmdSpace<o3d::DestroySampler>();
+ cmd.Init(sampler_id);
+ }
+
+ void SetSamplerStates(
+ ResourceId sampler_id,
+ sampler::AddressingMode address_u_value,
+ sampler::AddressingMode address_v_value,
+ sampler::AddressingMode address_w_value,
+ sampler::FilteringMode mag_filter_value,
+ sampler::FilteringMode min_filter_value,
+ sampler::FilteringMode mip_filter_value,
+ uint8 max_anisotropy) {
+ o3d::SetSamplerStates& cmd = GetCmdSpace<o3d::SetSamplerStates>();
+ cmd.Init(
+ sampler_id,
+ address_u_value,
+ address_v_value,
+ address_w_value,
+ mag_filter_value,
+ min_filter_value,
+ mip_filter_value,
+ max_anisotropy);
+ }
+
+ void SetSamplerBorderColor(
+ ResourceId sampler_id,
+ float red, float green, float blue, float alpha) {
+ o3d::SetSamplerBorderColor& cmd =
+ GetCmdSpace<o3d::SetSamplerBorderColor>();
+ cmd.Init(sampler_id, red, green, blue, alpha);
+ }
+
+ void SetSamplerTexture(ResourceId sampler_id, ResourceId texture_id) {
+ o3d::SetSamplerTexture& cmd = GetCmdSpace<o3d::SetSamplerTexture>();
+ cmd.Init(sampler_id, texture_id);
+ }
+
+ void SetScissor(
+ uint32 x,
+ uint32 y,
+ uint32 width,
+ uint32 height,
+ bool enable) {
+ o3d::SetScissor& cmd = GetCmdSpace<o3d::SetScissor>();
+ cmd.Init(
+ x,
+ y,
+ width,
+ height,
+ enable);
+ }
+
+ void SetPolygonOffset(float slope_factor, float units) {
+ o3d::SetPolygonOffset& cmd = GetCmdSpace<o3d::SetPolygonOffset>();
+ cmd.Init(slope_factor, units);
+ }
+
+ void SetPointLineRaster(
+ bool line_smooth_enable, bool point_sprite_enable, float point_size) {
+ o3d::SetPointLineRaster& cmd = GetCmdSpace<o3d::SetPointLineRaster>();
+ cmd.Init(line_smooth_enable, point_sprite_enable, point_size);
+ }
+
+ void SetPolygonRaster(o3d::PolygonMode fill_mode,
+ o3d::FaceCullMode cull_mode) {
+ o3d::SetPolygonRaster& cmd = GetCmdSpace<o3d::SetPolygonRaster>();
+ cmd.Init(fill_mode, cull_mode);
+ }
+
+ void SetAlphaTest(o3d::Comparison func, bool enable, float value) {
+ o3d::SetAlphaTest& cmd = GetCmdSpace<o3d::SetAlphaTest>();
+ cmd.Init(func, enable, value);
+ }
+
+ void SetDepthTest(o3d::Comparison func, bool write_enable, bool enable) {
+ o3d::SetDepthTest& cmd = GetCmdSpace<o3d::SetDepthTest>();
+ cmd.Init(func, write_enable, enable);
+ }
+
+ void SetStencilTest(
+ uint8 write_mask,
+ uint8 compare_mask,
+ uint8 reference_value,
+ bool separate_ccw,
+ bool enable,
+ o3d::Comparison cw_func,
+ o3d::StencilOp cw_pass_op,
+ o3d::StencilOp cw_fail_op,
+ o3d::StencilOp cw_z_fail_op,
+ o3d::Comparison ccw_func,
+ o3d::StencilOp ccw_pass_op,
+ o3d::StencilOp ccw_fail_op,
+ o3d::StencilOp ccw_z_fail_op) {
+ o3d::SetStencilTest& cmd = GetCmdSpace<o3d::SetStencilTest>();
+ cmd.Init(
+ write_mask,
+ compare_mask,
+ reference_value,
+ separate_ccw,
+ enable,
+ cw_func,
+ cw_pass_op,
+ cw_fail_op,
+ cw_z_fail_op,
+ ccw_func,
+ ccw_pass_op,
+ ccw_fail_op,
+ ccw_z_fail_op);
+ }
+
+ void SetColorWrite(uint8 mask, bool dither_enable) {
+ o3d::SetColorWrite& cmd = GetCmdSpace<o3d::SetColorWrite>();
+ cmd.Init(mask, dither_enable);
+ }
+
+ void SetBlending(
+ o3d::BlendFunc color_src_func,
+ o3d::BlendFunc color_dst_func,
+ o3d::BlendEq color_eq,
+ o3d::BlendFunc alpha_src_func,
+ o3d::BlendFunc alpha_dst_func,
+ o3d::BlendEq alpha_eq,
+ bool separate_alpha,
+ bool enable) {
+ o3d::SetBlending& cmd = GetCmdSpace<o3d::SetBlending>();
+ cmd.Init(
+ color_src_func,
+ color_dst_func,
+ color_eq,
+ alpha_src_func,
+ alpha_dst_func,
+ alpha_eq,
+ separate_alpha,
+ enable);
+ }
+
+ void SetBlendingColor(float red, float green, float blue, float alpha) {
+ o3d::SetBlendingColor& cmd = GetCmdSpace<o3d::SetBlendingColor>();
+ cmd.Init(red, green, blue, alpha);
+ }
+
+ void CreateRenderSurface(
+ ResourceId render_surface_id, ResourceId texture_id,
+ uint32 width, uint32 height,
+ uint32 level, uint32 side) {
+ o3d::CreateRenderSurface& cmd = GetCmdSpace<o3d::CreateRenderSurface>();
+ cmd.Init(render_surface_id, texture_id, width, height, level, side);
+ }
+
+ void DestroyRenderSurface(ResourceId render_surface_id) {
+ o3d::DestroyRenderSurface& cmd =
+ GetCmdSpace<o3d::DestroyRenderSurface>();
+ cmd.Init(render_surface_id);
+ }
+
+ void CreateDepthSurface(
+ ResourceId depth_surface_id, uint32 width, uint32 height) {
+ o3d::CreateDepthSurface& cmd = GetCmdSpace<o3d::CreateDepthSurface>();
+ cmd.Init(depth_surface_id, width, height);
+ }
+
+ void DestroyDepthSurface(ResourceId depth_surface_id) {
+ o3d::DestroyDepthSurface& cmd = GetCmdSpace<o3d::DestroyDepthSurface>();
+ cmd.Init(depth_surface_id);
+ }
+
+ void SetRenderSurface(
+ ResourceId render_surface_id, ResourceId depth_surface_id) {
+ o3d::SetRenderSurface& cmd = GetCmdSpace<o3d::SetRenderSurface>();
+ cmd.Init(render_surface_id, depth_surface_id);
+ }
+
+ void SetBackSurfaces() {
+ o3d::SetBackSurfaces& cmd = GetCmdSpace<o3d::SetBackSurfaces>();
+ cmd.Init();
+ }
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_CROSS_O3D_CMD_HELPER_H_
+
diff --git a/o3d/gpu/command_buffer/common/GLES2/gl2.h b/o3d/gpu/command_buffer/common/GLES2/gl2.h
new file mode 100644
index 0000000..94c643b
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/GLES2/gl2.h
@@ -0,0 +1,621 @@
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 8784 $ on $Date:: 2009-09-02 09:49:17 -0700 #$ */
+
+#include <GLES2/gl2platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+typedef void GLvoid;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const char* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const char* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, char* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const char* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const char** string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
+
diff --git a/o3d/gpu/command_buffer/common/GLES2/gl2platform.h b/o3d/gpu/command_buffer/common/GLES2/gl2platform.h
new file mode 100644
index 0000000..3e9036c
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/GLES2/gl2platform.h
@@ -0,0 +1,29 @@
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
+ * Last modified on 2008/12/19
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_APICALL
+#define GL_APICALL KHRONOS_APICALL
+#endif
+
+#define GL_APIENTRY KHRONOS_APIENTRY
+
+#endif /* __gl2platform_h_ */
diff --git a/o3d/gpu/command_buffer/common/KHR/khrplatform.h b/o3d/gpu/command_buffer/common/KHR/khrplatform.h
new file mode 100644
index 0000000..8341f71b
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/KHR/khrplatform.h
@@ -0,0 +1,269 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * $Revision: 7820 $ on $Date: 2009-04-03 13:46:26 -0700 (Fri, 03 Apr 2009) $
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by sending them to the public Khronos Bugzilla
+ * (http://khronos.org/bugzilla) by filing a bug against product
+ * "Khronos (general)" component "Registry".
+ *
+ * A predefined template which fills in some of the bug fields can be
+ * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+ * must create a Bugzilla login first.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ * http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ * #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ * khronos_int8_t signed 8 bit
+ * khronos_uint8_t unsigned 8 bit
+ * khronos_int16_t signed 16 bit
+ * khronos_uint16_t unsigned 16 bit
+ * khronos_int32_t signed 32 bit
+ * khronos_uint32_t unsigned 32 bit
+ * khronos_int64_t signed 64 bit
+ * khronos_uint64_t unsigned 64 bit
+ * khronos_intptr_t signed same number of bits as a pointer
+ * khronos_uintptr_t unsigned same number of bits as a pointer
+ * khronos_ssize_t signed size
+ * khronos_usize_t unsigned size
+ * khronos_float_t signed 32 bit floating point
+ * khronos_time_ns_t unsigned 64 bit time in nanoseconds
+ * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ * nanoseconds
+ * khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ * khronos_boolean_enum_t enumerated boolean type. This should
+ * only be used as a base type when a client API's boolean type is
+ * an enum. Client APIs which use an integer or other type for
+ * booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ * KHRONOS_APICALL
+ * KHRONOS_APIENTRY
+ * KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ * int arg1,
+ * int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
+# define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+# define KHRONOS_APICALL IMPORT_C
+#else
+# define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+ /* Win32 but not WinCE */
+# define KHRONOS_APIENTRY __stdcall
+#else
+# define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32 khronos_int32_t;
+typedef unsigned __int32 khronos_uint32_t;
+typedef __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int khronos_int64_t;
+typedef unsigned long int khronos_uint64_t;
+#else
+typedef long long int khronos_int64_t;
+typedef unsigned long long int khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64 0
+#define KHRONOS_SUPPORT_FLOAT 0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef float khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time. Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted). The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years. Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t khronos_utime_nanoseconds_t;
+typedef khronos_int64_t khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true. Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+ KHRONOS_FALSE = 0,
+ KHRONOS_TRUE = 1,
+ KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
diff --git a/o3d/gpu/command_buffer/common/bitfield_helpers.h b/o3d/gpu/command_buffer/common/bitfield_helpers.h
new file mode 100644
index 0000000..b74374d
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/bitfield_helpers.h
@@ -0,0 +1,68 @@
+/*
+ * 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 a helper template class used to access bit fields in
+// unsigned int_ts.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_CROSS_BITFIELD_HELPERS_H_
+#define GPU_COMMAND_BUFFER_COMMON_CROSS_BITFIELD_HELPERS_H_
+
+namespace command_buffer {
+
+// Bitfield template class, used to access bit fields in unsigned int_ts.
+template<int shift, int length> class BitField {
+ public:
+ static const unsigned int kShift = shift;
+ static const unsigned int kLength = length;
+ // the following is really (1<<length)-1 but also work for length == 32
+ // without compiler warning.
+ static const unsigned int kMask = 1U + ((1U << (length-1)) - 1U) * 2U;
+
+ // Gets the value contained in this field.
+ static unsigned int Get(unsigned int container) {
+ return (container >> kShift) & kMask;
+ }
+
+ // Makes a value that can be or-ed into this field.
+ static unsigned int MakeValue(unsigned int value) {
+ return (value & kMask) << kShift;
+ }
+
+ // Changes the value of this field.
+ static void Set(unsigned int *container, unsigned int field_value) {
+ *container = (*container & ~(kMask << kShift)) | MakeValue(field_value);
+ }
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_COMMON_CROSS_BITFIELD_HELPERS_H_
diff --git a/o3d/gpu/command_buffer/common/bitfield_helpers_test.cc b/o3d/gpu/command_buffer/common/bitfield_helpers_test.cc
new file mode 100644
index 0000000..60014d2
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/bitfield_helpers_test.cc
@@ -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.
+ */
+
+
+// Tests for the bitfield helper class.
+
+#include "gtest/gtest.h"
+#include "gpu/command_buffer/common/bitfield_helpers.h"
+
+namespace command_buffer {
+
+// Tests that BitField<>::Get returns the right bits.
+TEST(BitFieldTest, TestGet) {
+ unsigned int value = 0x12345678u;
+ EXPECT_EQ(0x8u, (BitField<0, 4>::Get(value)));
+ EXPECT_EQ(0x45u, (BitField<12, 8>::Get(value)));
+ EXPECT_EQ(0x12345678u, (BitField<0, 32>::Get(value)));
+}
+
+// Tests that BitField<>::MakeValue generates the right bits.
+TEST(BitFieldTest, TestMakeValue) {
+ EXPECT_EQ(0x00000003u, (BitField<0, 4>::MakeValue(0x3)));
+ EXPECT_EQ(0x00023000u, (BitField<12, 8>::MakeValue(0x123)));
+ EXPECT_EQ(0x87654321u, (BitField<0, 32>::MakeValue(0x87654321)));
+}
+
+// Tests that BitField<>::Set modifies the right bits.
+TEST(BitFieldTest, TestSet) {
+ unsigned int value = 0x12345678u;
+ BitField<0, 4>::Set(&value, 0x9);
+ EXPECT_EQ(0x12345679u, value);
+ BitField<12, 8>::Set(&value, 0x123);
+ EXPECT_EQ(0x12323679u, value);
+ BitField<0, 32>::Set(&value, 0x87654321);
+ EXPECT_EQ(0x87654321u, value);
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/common/cmd_buffer_common.cc b/o3d/gpu/command_buffer/common/cmd_buffer_common.cc
new file mode 100644
index 0000000..e9172eb
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/cmd_buffer_common.cc
@@ -0,0 +1,57 @@
+/*
+ * 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 binary format definition of the command buffer and
+// command buffer commands.
+
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+
+namespace command_buffer {
+namespace cmd {
+
+const char* GetCommandName(CommandId command_id) {
+ static const char* const names[] = {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) # name,
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+ };
+
+ int id = static_cast<int>(command_id);
+ return (id >= 0 && id < kNumCommands) ? names[id] : "*unknown-command*";
+}
+
+} // namespace cmd
+} // namespace command_buffer
+
+
diff --git a/o3d/gpu/command_buffer/common/cmd_buffer_common.h b/o3d/gpu/command_buffer/common/cmd_buffer_common.h
new file mode 100644
index 0000000..0e44f86
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/cmd_buffer_common.h
@@ -0,0 +1,247 @@
+/*
+ * 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 common parts of command buffer formats.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_COMMON_H_
+#define GPU_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_COMMON_H_
+
+#include "base/basictypes.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/command_buffer/common/bitfield_helpers.h"
+#include "gpu/command_buffer/common/logging.h"
+
+namespace command_buffer {
+
+namespace cmd {
+ enum ArgFlags {
+ kFixed = 0x0,
+ kAtLeastN = 0x1,
+ };
+} // namespace cmd
+
+// Computes the number of command buffer entries needed for a certain size. In
+// other words it rounds up to a multiple of entries.
+inline uint32 ComputeNumEntries(size_t size_in_bytes) {
+ return static_cast<uint32>(
+ (size_in_bytes + sizeof(uint32) - 1) / sizeof(uint32)); // NOLINT
+}
+
+// Rounds up to a multiple of entries in bytes.
+inline size_t RoundSizeToMultipleOfEntries(size_t size_in_bytes) {
+ return ComputeNumEntries(size_in_bytes) * sizeof(uint32); // NOLINT
+}
+
+// Struct that defines the command header in the command buffer.
+struct CommandHeader {
+ Uint32 size:8;
+ Uint32 command:24;
+
+ void Init(uint32 _command, uint32 _size) {
+ DCHECK_LT(_size, 256u);
+ command = _command;
+ size = _size;
+ }
+
+ // Sets the header based on the passed in command. Can not be used for
+ // variable sized commands like immediate commands or Noop.
+ template <typename T>
+ void SetCmd() {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
+ Init(T::kCmdId, ComputeNumEntries(sizeof(T))); // NOLINT
+ }
+
+ // Sets the header by a size in bytes.
+ template <typename T>
+ void SetCmdBySize(uint32 size_in_bytes) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ Init(T::kCmdId, ComputeNumEntries(sizeof(T) + size_in_bytes)); // NOLINT
+ }
+};
+
+COMPILE_ASSERT(sizeof(CommandHeader) == 4, Sizeof_CommandHeader_is_not_4);
+
+// Union that defines possible command buffer entries.
+union CommandBufferEntry {
+ CommandHeader value_header;
+ Uint32 value_uint32;
+ Int32 value_int32;
+ float value_float;
+};
+
+COMPILE_ASSERT(sizeof(CommandBufferEntry) == 4,
+ Sizeof_CommandBufferEntry_is_not_4);
+
+
+// Make sure the compiler does not add extra padding to any of the command
+// structures.
+#pragma pack(push, 1)
+
+// Gets the address of memory just after a structure in a typesafe way. This is
+// used for IMMEDIATE commands to get the address of the place to put the data.
+// Immediate command put their data direclty in the command buffer.
+// Parameters:
+// cmd: Address of command.
+template <typename T>
+void* ImmediateDataAddress(T* cmd) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ return reinterpret_cast<char*>(cmd) + sizeof(*cmd);
+}
+
+// Gets the address of the place to put the next command in a typesafe way.
+// This can only be used for fixed sized commands.
+template <typename T>
+// Parameters:
+// cmd: Address of command.
+void* NextCmdAddress(void* cmd) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
+ return reinterpret_cast<char*>(cmd) + sizeof(T);
+}
+
+// Gets the address of the place to put the next command in a typesafe way.
+// This can only be used for variable sized command like IMMEDIATE commands.
+// Parameters:
+// cmd: Address of command.
+// size_of_data_in_bytes: Size of the data for the command.
+template <typename T>
+void* NextImmediateCmdAddress(void* cmd, uint32 size_of_data_in_bytes) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ return reinterpret_cast<char*>(cmd) + sizeof(T) + // NOLINT
+ RoundSizeToMultipleOfEntries(size_of_data_in_bytes);
+}
+
+struct SharedMemory {
+ void Init(uint32 _id, uint32 _offset) {
+ id = _id;
+ offset = _offset;
+ }
+
+ uint32 id;
+ uint32 offset;
+};
+
+COMPILE_ASSERT(offsetof(SharedMemory, id) == 0,
+ Offsetof_SharedMemory_id_not_0);
+COMPILE_ASSERT(offsetof(SharedMemory, offset) == 4,
+ Offsetof_SharedMemory_offset_not_4);
+
+
+namespace cmd {
+
+// This macro is used to safely and convienently expand the list of commnad
+// buffer commands in to various lists and never have them get out of sync. To
+// add a new command, add it this list, create the corresponding structure below
+// and then add a function in gapi_decoder.cc called Handle_COMMAND_NAME where
+// COMMAND_NAME is the name of your command structure.
+//
+// NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
+#define COMMON_COMMAND_BUFFER_CMDS(OP) \
+ OP(Noop) /* 0 */ \
+ OP(SetToken) /* 1 */ \
+
+// Common commands.
+enum CommandId {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name,
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+
+ kNumCommands,
+ kLastCommonId = 1023, // reserve 1024 spaces for common commands.
+};
+
+COMPILE_ASSERT(kNumCommands - 1 <= kLastCommonId, Too_many_common_commands);
+
+const char* GetCommandName(CommandId id);
+
+struct Noop {
+ typedef Noop ValueType;
+ static const CommandId kCmdId = kNoop;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ void SetHeader(uint32 skip_count) {
+ header.Init(kCmdId, skip_count + 1);
+ }
+
+ void Init(uint32 skip_count) {
+ SetHeader(skip_count);
+ }
+
+ static void* Set(void* cmd, uint32 skip_count) {
+ static_cast<ValueType*>(cmd)->Init(skip_count);
+ return NextImmediateCmdAddress<ValueType>(
+ cmd, skip_count * sizeof(CommandBufferEntry)); // NOLINT
+ }
+
+ CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(Noop) == 4, Sizeof_Noop_is_not_4);
+COMPILE_ASSERT(offsetof(Noop, header) == 0, Offsetof_Noop_header_not_0);
+
+struct SetToken {
+ typedef SetToken ValueType;
+ static const CommandId kCmdId = kSetToken;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _token) {
+ SetHeader();
+ token = _token;
+ }
+ static void* Set(void* cmd, uint32 token) {
+ static_cast<ValueType*>(cmd)->Init(token);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 token;
+};
+
+COMPILE_ASSERT(sizeof(SetToken) == 8, Sizeof_SetToken_is_not_8);
+COMPILE_ASSERT(offsetof(SetToken, header) == 0,
+ Offsetof_SetToken_header_not_0);
+COMPILE_ASSERT(offsetof(SetToken, token) == 4,
+ Offsetof_SetToken_token_not_4);
+
+} // namespace cmd
+
+#pragma pack(pop)
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_COMMON_H_
+
diff --git a/o3d/gpu/command_buffer/common/constants.h b/o3d/gpu/command_buffer/common/constants.h
new file mode 100644
index 0000000..ee874cd
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/constants.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+
+#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_CONSTANTS_H_
+#define O3D_COMMAND_BUFFER_COMMON_CROSS_CONSTANTS_H_
+
+#include "base/basictypes.h"
+
+namespace command_buffer {
+
+typedef int32 CommandBufferOffset;
+const CommandBufferOffset kInvalidCommandBufferOffset = -1;
+
+// Status of the command buffer service. It does not process commands
+// (meaning: get will not change) unless in kParsing state.
+namespace parser_status {
+ enum ParserStatus {
+ kNotConnected, // The service is not connected - initial state.
+ kNoBuffer, // The service is connected but no buffer was set.
+ kParsing, // The service is connected, and parsing commands from the
+ // buffer.
+ kParseError, // Parsing stopped because a parse error was found.
+ };
+}
+
+namespace parse_error {
+ enum ParseError {
+ kParseNoError,
+ kParseInvalidSize,
+ kParseOutOfBounds,
+ kParseUnknownCommand,
+ kParseInvalidArguments,
+ };
+}
+
+// Invalid shared memory Id, returned by RegisterSharedMemory in case of
+// failure.
+const int32 kInvalidSharedMemoryId = -1;
+
+} // namespace command_buffer
+
+#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_CONSTANTS_H_
diff --git a/o3d/gpu/command_buffer/common/gapi_interface.h b/o3d/gpu/command_buffer/common/gapi_interface.h
new file mode 100644
index 0000000..a032f0e
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/gapi_interface.h
@@ -0,0 +1,833 @@
+/*
+ * 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 interface class for the low-level graphics API
+// (GAPI).
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_CROSS_GAPI_INTERFACE_H_
+#define GPU_COMMAND_BUFFER_COMMON_CROSS_GAPI_INTERFACE_H_
+
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/resource.h"
+#include "gpu/command_buffer/common/o3d_cmd_format.h"
+
+namespace command_buffer {
+namespace o3d {
+
+// RBGA color definition.
+struct RGBA {
+ float red;
+ float green;
+ float blue;
+ float alpha;
+};
+
+// This class defines the low-level graphics API, as a pure interface class.
+class GAPIInterface {
+ public:
+ typedef parse_error::ParseError ParseError;
+
+ GAPIInterface() {}
+ virtual ~GAPIInterface() {}
+
+ // Initializes the graphics context.
+ // Returns:
+ // true if successful.
+ virtual bool Initialize() = 0;
+
+ // Destroys the graphics context.
+ virtual void Destroy() = 0;
+
+ // Starts a frame. Rendering should occur between BeginFrame and EndFrame.
+ virtual void BeginFrame() = 0;
+
+ // Ends the frame, and bring the back buffer to front. Rendering should occur
+ // between BeginFrame and EndFrame.
+ virtual void EndFrame() = 0;
+
+ // Clear buffers, filling them with a constant value.
+ // Parameters:
+ // buffers: which buffers to clear. Can be a combination (bitwise or) of
+ // values from ClearBuffer.
+ // color: the RGBA color to clear the color target with.
+ // depth: the depth to clear the depth buffer with.
+ // stencil: the stencil value to clear the stencil buffer with.
+ virtual void Clear(unsigned int buffers,
+ const RGBA &color,
+ float depth,
+ unsigned int stencil) = 0;
+
+ // Creates a vertex buffer.
+ // Parameters:
+ // id: the resource ID for the new vertex buffer.
+ // size: the size of the vertex buffer, in bytes.
+ // flags: the vertex buffer flags, as a combination of vertex_buffer::Flags
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateVertexBuffer(ResourceId id,
+ unsigned int size,
+ unsigned int flags) = 0;
+
+ // Destroys a vertex buffer.
+ // Parameters:
+ // id: the resource ID of the vertex buffer.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid vertex buffer
+ // ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DestroyVertexBuffer(ResourceId id) = 0;
+
+ // Sets data into a vertex buffer.
+ // Parameters:
+ // id: the resource ID of the vertex buffer.
+ // offset: the offset into the vertex buffer where to place the data.
+ // size: the size of the data.
+ // data: the source data.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments were
+ // passed: invalid resource ID, or offset or size out of range.
+ // parse_error::kParseNoError otherwise.
+ virtual ParseError SetVertexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data) = 0;
+
+ // Gets data from a vertex buffer.
+ // Parameters:
+ // id: the resource ID of the vertex buffer.
+ // offset: the offset into the vertex buffer where to get the data.
+ // size: the size of the data.
+ // data: the destination buffer.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments were
+ // passed: invalid resource ID, or offset or size out of range.
+ // parse_error::kParseNoError otherwise.
+ virtual ParseError GetVertexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data) = 0;
+
+ // Creates an index buffer.
+ // Parameters:
+ // id: the resource ID for the new index buffer.
+ // size: the size of the index buffer, in bytes.
+ // flags: the index buffer flags, as a combination of index_buffer::Flags.
+ // Note that indices are 16 bits unless the index_buffer::INDEX_32BIT
+ // flag is specified.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateIndexBuffer(ResourceId id,
+ unsigned int size,
+ unsigned int flags) = 0;
+
+ // Destroys an index buffer.
+ // Parameters:
+ // id: the resource ID of the index buffer.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid index buffer
+ // ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DestroyIndexBuffer(ResourceId id) = 0;
+
+ // Sets data into an index buffer.
+ // Parameters:
+ // id: the resource ID of the index buffer.
+ // offset: the offset into the index buffer where to place the data.
+ // size: the size of the data.
+ // data: the source data.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments were
+ // passed: invalid resource ID, or offset or size out of range.
+ // parse_error::kParseNoError otherwise.
+ virtual ParseError SetIndexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data) = 0;
+
+ // Gets data from an index buffer.
+ // Parameters:
+ // id: the resource ID of the index buffer.
+ // offset: the offset into the index buffer where to get the data.
+ // size: the size of the data.
+ // data: the destination buffer.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments were
+ // passed: invalid resource ID, or offset or size out of range.
+ // parse_error::kParseNoError otherwise.
+ virtual ParseError GetIndexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data) = 0;
+
+ // Creates a vertex struct. A vertex struct describes the input vertex
+ // attribute streams.
+ // Parameters:
+ // id: the resource ID of the vertex struct.
+ // input_count: the number of input vertex attributes.
+ // returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateVertexStruct(ResourceId id,
+ unsigned int input_count) = 0;
+
+ // Destroys a vertex struct.
+ // Parameters:
+ // id: the resource ID of the vertex struct.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid vertex struct
+ // ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DestroyVertexStruct(ResourceId id) = 0;
+
+ // Sets an input into a vertex struct.
+ // Parameters:
+ // vertex_struct_id: the resource ID of the vertex struct.
+ // input_index: the index of the input being set.
+ // vertex_buffer_id: the resource ID of the vertex buffer containing the
+ // data.
+ // offset: the offset into the vertex buffer of the input data, in bytes.
+ // stride: the stride of the input data, in bytes.
+ // type: the type of the input data.
+ // semantic: the semantic of the input.
+ // semantic_index: the semantic index of the input.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError SetVertexInput(ResourceId vertex_struct_id,
+ unsigned int input_index,
+ ResourceId vertex_buffer_id,
+ unsigned int offset,
+ unsigned int stride,
+ vertex_struct::Type type,
+ vertex_struct::Semantic semantic,
+ unsigned int semantic_index) = 0;
+
+ // Sets the current vertex struct for drawing.
+ // Parameters:
+ // id: the resource ID of the vertex struct.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed (invalid vertex struct), parse_error::kParseNoError
+ // otherwise.
+ virtual ParseError SetVertexStruct(ResourceId id) = 0;
+
+ // Draws primitives, using the current vertex struct and the current effect.
+ // Parameters:
+ // primitive_type: the type of primitive to draw.
+ // first: the index of the first vertex.
+ // count: the number of primitives to draw.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError Draw(PrimitiveType primitive_type,
+ unsigned int first,
+ unsigned int count) = 0;
+
+ // Draws primitives, using the current vertex struct and the current effect,
+ // as well as an index buffer.
+ // Parameters:
+ // primitive_type: the type of primitive to draw.
+ // index_buffer_id: the resource ID of the index buffer.
+ // first: the index into the index buffer of the first index to draw.
+ // count: the number of primitives to draw.
+ // min_index: the lowest index being drawn.
+ // max_index: the highest index being drawn.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DrawIndexed(PrimitiveType primitive_type,
+ ResourceId index_buffer_id,
+ unsigned int first,
+ unsigned int count,
+ unsigned int min_index,
+ unsigned int max_index) = 0;
+
+ // Creates an effect, from source code.
+ // Parameters:
+ // id: the resource ID of the effect.
+ // size: the size of data.
+ // data: the source code for the effect.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed or the effect failed to compile,
+ // parse_error::kParseNoError otherwise.
+ virtual ParseError CreateEffect(ResourceId id,
+ unsigned int size,
+ const void *data) = 0;
+
+ // Destroys an effect.
+ // Parameters:
+ // id: the resource ID of the effect.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid effect ID
+ // was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DestroyEffect(ResourceId id) = 0;
+
+ // Sets the active effect for drawing.
+ // Parameters:
+ // id: the resource ID of the effect.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError SetEffect(ResourceId id) = 0;
+
+ // Gets the number of parameters in an effect, returning it in a memory
+ // buffer as a Uint32.
+ // Parameters:
+ // id: the resource ID of the effect.
+ // size: the size of the data buffer. Must be at least 4 (the size of the
+ // Uint32).
+ // data: the buffer receiving the data.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError GetParamCount(ResourceId id,
+ unsigned int size,
+ void *data) = 0;
+
+ // Creates an effect parameter by index.
+ // Parameters:
+ // param_id: the resource ID of the parameter being created.
+ // effect_id: the resource ID of the effect containing the parameter.
+ // data_type: the data type for the parameter. Must match the data type in
+ // the effect source.
+ // index: the index of the parameter.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, such as invalid effect ID, unmatching data type or invalid
+ // index, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateParam(ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int index) = 0;
+
+ // Creates an effect parameter by name.
+ // Parameters:
+ // param_id: the resource ID of the parameter being created.
+ // effect_id: the resource ID of the effect containing the parameter.
+ // data_type: the data type for the parameter. Must match the data type in
+ // the effect source.
+ // size: the size of the parameter name.
+ // name: the parameter name, as an array of char. Doesn't have to be
+ // nul-terminated (though nul will terminate the string).
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, such as invalid effect ID, unmatching data type or no parameter
+ // was found with this name, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateParamByName(ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int size,
+ const void *name) = 0;
+
+ // Destroys an effect parameter.
+ // Parameters:
+ // id: the resource ID of the parameter.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid parameter ID
+ // was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DestroyParam(ResourceId id) = 0;
+
+ // Sets the effect parameter data.
+ // Parameters:
+ // id: the resource ID of the parameter.
+ // size: the size of the data. Must be at least the size of the parameter
+ // as described by its type.
+ // data: the parameter data.
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, such as invalid parameter ID, or unmatching data size,
+ // parse_error::kParseNoError otherwise.
+ virtual ParseError SetParamData(ResourceId id,
+ unsigned int size,
+ const void *data) = 0;
+
+ // Gets the parameter description, storing it into a memory buffer. The
+ // parameter is described by a effect_param::Desc structure. The size must be
+ // at least the size of that structure. The name and semantic fields are only
+ // filled if the character strings fit into the memory buffer. In any case,
+ // the size field (in the effect_param::Desc) is filled with the size needed
+ // to fill in the structure, the name and the semantic (if any). Thus to get
+ // the complete information, GetParamDesc can be called twice, once to get
+ // the size, and, after allocating a big enough buffer, again to fill in the
+ // complete information including the text strings.
+ // Parameters:
+ // id: the resource ID of the parameter.
+ // size: the size of the memory buffer that wil receive the parameter
+ // description. Must be at least sizeof(effect_param::Desc).
+ // data: the memory buffer.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, such as invalid parameter ID, or unsufficient data size,
+ // parse_error::kParseNoError otherwise. Note that
+ // parse_error::kParseNoError will be returned if the structure
+ // itself fits, not necessarily the names. To make sure all the information
+ // is available, the caller should compare the returned size member of the
+ // effect_param::Desc structure to the size parameter passed in.
+ virtual ParseError GetParamDesc(ResourceId id,
+ unsigned int size,
+ void *data) = 0;
+
+ // Gets the number of input streams for an effect, returning it in a memory
+ // buffer as a Uint32.
+ // Parameters:
+ // id: the resource ID of the effect.
+ // size: the size of the data buffer. Must be at least 4 (the size of the
+ // Uint32).
+ // data: the buffer receiving the data.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError GetStreamCount(ResourceId id,
+ unsigned int size,
+ void *data) = 0;
+
+ // Gets the stream semantics, storing them in the data buffer. The stream
+ // is described by an effect_stream::Desc structure which contains a
+ // semantic type and a semantic index.
+ // Parameters:
+ // id: the resource ID of the effect.
+ // index: which stream semantic to get
+ // size: the size of the data buffer. Must be at least 8 (the size of two
+ // Uint32).
+ // data: the buffer receiving the data.
+ virtual ParseError GetStreamDesc(ResourceId id,
+ unsigned int index,
+ unsigned int size,
+ void *data) = 0;
+
+ // Creates a 2D texture resource.
+ // Parameters:
+ // id: the resource ID of the texture.
+ // width: the texture width. Must be positive.
+ // height: the texture height. Must be positive.
+ // levels: the number of mipmap levels in the texture, or 0 to use the
+ // maximum.
+ // format: the format of the texels in the texture.
+ // flags: the texture flags, as a combination of texture::Flags.
+ // enable_render_surfaces: bool for whether to enable render surfaces
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateTexture2D(ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) = 0;
+
+ // Creates a 3D texture resource.
+ // Parameters:
+ // id: the resource ID of the texture.
+ // width: the texture width. Must be positive.
+ // height: the texture height. Must be positive.
+ // depth: the texture depth. Must be positive.
+ // levels: the number of mipmap levels in the texture, or 0 to use the
+ // maximum.
+ // format: the format of the pixels in the texture.
+ // flags: the texture flags, as a combination of texture::Flags.
+ // enable_render_surfaces: bool for whether to enable render surfaces
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateTexture3D(ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) = 0;
+
+ // Creates a cube map texture resource.
+ // Parameters:
+ // id: the resource ID of the texture.
+ // side: the texture side length. Must be positive.
+ // levels: the number of mipmap levels in the texture, or 0 to use the
+ // maximum.
+ // format: the format of the pixels in the texture.
+ // flags: the texture flags, as a combination of texture::Flags.
+ // enable_render_surfaces: bool for whether to enable render surfaces
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateTextureCube(ResourceId id,
+ unsigned int side,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) = 0;
+
+ // Sets texel data into a texture resource. This is a common function for
+ // each of the texture types, but some restrictions exist based on the
+ // texture type. The specified rectangle or volume of data, defined by x, y,
+ // width, height and possibly z and depth must fit into the selected mimmap
+ // level. Data is encoded by rows of 2D blocks, whose size depends on the
+ // texel format, usually 1x1 texel, but can be 4x4 for DXT* formats. See
+ // texture::GetBytesPerBlock, texture::GetBlockSizeX and
+ // texture::GetBlockSizeY.
+ // Parameters:
+ // id: the resource ID of the texture.
+ // x: the x position of the texel corresponding to the first byte of data.
+ // y: the y position of the texel corresponding to the first byte of data.
+ // z: the z position of the texel corresponding to the first byte of data.
+ // Must be 0 for non-3D textures.
+ // width: the width of the data rectangle/volume.
+ // height: the height of the data rectangle/volume.
+ // depth: the depth of the data volume. Must be 1 for non-3D textures.
+ // level: the mipmap level to put the data into.
+ // face: which face of the cube to put the data into. Is ignored for
+ // non-cube map textures.
+ // row_pitch: the number of bytes between two consecutive rows of blocks,
+ // in the source data.
+ // slice_pitch: the number of bytes between two consecutive slices of
+ // blocks, in the source data. Is ignored for non-3D textures.
+ // size: the size of the data.
+ // data: the texel data.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, for example invalid size, or out-of-bounds rectangle/volume,
+ // parse_error::kParseNoError otherwise.
+ virtual ParseError SetTextureData(ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) = 0;
+
+ // Gets texel data from a texture resource. This is a common function for
+ // each of the texture types, but some restrictions exist based on the
+ // texture type. The specified rectangle or volume of data, defined by x, y,
+ // width, height and possibly z and depth must fit into the selected mimmap
+ // level. Data is encoded by rows of 2D blocks, whose size depends on the
+ // texel format, usually 1x1 texel, but can be 4x4 for DXT* formats. See
+ // texture::GetBytesPerBlock, texture::GetBlockSizeX and
+ // texture::GetBlockSizeY.
+ // Parameters:
+ // id: the resource ID of the texture.
+ // x: the x position of the texel corresponding to the first byte of data.
+ // y: the y position of the texel corresponding to the first byte of data.
+ // z: the z position of the texel corresponding to the first byte of data.
+ // Must be 0 for non-3D textures.
+ // width: the width of the data rectangle/volume.
+ // height: the height of the data rectangle/volume.
+ // depth: the depth of the data volume. Must be 1 for non-3D textures.
+ // level: the mipmap level to put the data into.
+ // face: which face of the cube to put the data into. Is ignored for
+ // non-cube map textures.
+ // row_pitch: the number of bytes between two consecutive rows of blocks,
+ // in the destination buffer.
+ // slice_pitch: the number of bytes between two consecutive slices of
+ // blocks, in the destination buffer. Is ignored for non-3D textures.
+ // size: the size of the data.
+ // data: the destination buffer.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, for example invalid size, or out-of-bounds rectangle/volume,
+ // parse_error::kParseNoError otherwise.
+ virtual ParseError GetTextureData(ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) = 0;
+
+ // Destroys a texture resource.
+ // Parameters:
+ // id: the resource ID of the texture.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid texture
+ // resource ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DestroyTexture(ResourceId id) = 0;
+
+ // Creates a sampler resource.
+ // Parameters:
+ // id: the resource ID of the sampler.
+ // Returns:
+ // parse_error::kParseNoError.
+ virtual ParseError CreateSampler(ResourceId id) = 0;
+
+ // Destroys a sampler resource.
+ // Parameters:
+ // id: the resource ID of the sampler.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid sampler
+ // resource ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DestroySampler(ResourceId id) = 0;
+
+ // Sets the states in a sampler resource.
+ // Parameters:
+ // id: the resource ID of the sampler.
+ // addressing_u: the addressing mode for the U coordinate.
+ // addressing_v: the addressing mode for the V coordinate.
+ // addressing_w: the addressing mode for the W coordinate.
+ // mag_filter: the filtering mode when magnifying textures.
+ // min_filter: the filtering mode when minifying textures.
+ // mip_filter: the filtering mode for mip-map interpolation textures.
+ // max_anisotropy: the maximum anisotropy.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid sampler
+ // resource ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError SetSamplerStates(ResourceId id,
+ sampler::AddressingMode addressing_u,
+ sampler::AddressingMode addressing_v,
+ sampler::AddressingMode addressing_w,
+ sampler::FilteringMode mag_filter,
+ sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter,
+ unsigned int max_anisotropy) = 0;
+
+ // Sets the color of border pixels.
+ // Parameters:
+ // id: the resource ID of the sampler.
+ // color: the border color.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid sampler
+ // resource ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError SetSamplerBorderColor(ResourceId id,
+ const RGBA &color) = 0;
+
+ // Sets the texture resource used by a sampler resource.
+ // Parameters:
+ // id: the resource ID of the sampler.
+ // texture_id: the resource id of the texture.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid sampler
+ // resource ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError SetSamplerTexture(ResourceId id,
+ ResourceId texture_id) = 0;
+
+ // Sets the viewport, and depth range.
+ // Parameters:
+ // x, y: upper left corner of the viewport.
+ // width, height: dimensions of the viewport.
+ // z_min, z_max: depth range.
+ virtual void SetViewport(unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height,
+ float z_min,
+ float z_max) = 0;
+
+ // Sets the scissor test enable flag and rectangle.
+ // Parameters:
+ // enable: whether or not scissor test is enabled.
+ // x, y: upper left corner of the scissor rectangle.
+ // width, height: dimensions of the scissor rectangle.
+ virtual void SetScissor(bool enable,
+ unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height) = 0;
+
+ // Sets the point and line rasterization state.
+ // Parameters:
+ // line_smooth: Whether or not line anti-aliasing is enabled.
+ // point_sprite: Whether or not point sprites are enabled.
+ // point_size: The point size.
+ virtual void SetPointLineRaster(bool line_smooth,
+ bool point_sprite,
+ float point_size) = 0;
+
+ // Sets the polygon rasterization state.
+ // Parameters:
+ // fill_mode: The polygon filling mode.
+ // cull_mode: The polygon face culling mode.
+ virtual void SetPolygonRaster(PolygonMode fill_mode,
+ FaceCullMode cull_mode) = 0;
+
+ // Sets the polygon offset state. Polygon offset is enabled if slope_factor
+ // or units is not 0.
+ // The applied offset (in window coordinates) is:
+ // o = max_slope * slope_factor + r * units
+ // Where max_slope is the maximum slope of the polygon (in window
+ // coordinates again), and r is the minimum resolvable z unit.
+ // Parameters:
+ // slope_factor: slope factor for the offset.
+ // units: constant factor for the offset.
+ virtual void SetPolygonOffset(float slope_factor, float units) = 0;
+
+ // Sets the alpha test states.
+ // Parameters:
+ // enable: alpha test enable state.
+ // reference: reference value for comparison.
+ // comp: alpha comparison function.
+ virtual void SetAlphaTest(bool enable,
+ float reference,
+ Comparison comp) = 0;
+
+ // Sets the depth test states.
+ // Note: if the depth test is disabled, z values are not written to the z
+ // buffer (i.e enable/kAlways is different from disable/*).
+ // Parameters:
+ // enable: depth test enable state.
+ // write_enable: depth write enable state.
+ // comp: depth comparison function.
+ virtual void SetDepthTest(bool enable,
+ bool write_enable,
+ Comparison comp) = 0;
+
+ // Sets the stencil test states.
+ // Parameters:
+ // enable: stencil test enable state.
+ // separate_ccw: whether or not counter-clockwise faces use separate
+ // functions/operations (2-sided stencil).
+ // write_mask: stencil write mask.
+ // compare_mask: stencil compare mask.
+ // ref: stencil reference value.
+ // func_ops: stencil test function and operations for both clockwise and
+ // counter-clockwise faces. This is a bitfield following the following
+ // description (little-endian addressing):
+ // bits 0 - 11: clockwise functions/operations
+ // bits 12 - 15: must be 0.
+ // bits 16 - 28: counter-clockwise functions/operations
+ // bits 29 - 32: must be 0.
+ virtual void SetStencilTest(bool enable,
+ bool separate_ccw,
+ unsigned int write_mask,
+ unsigned int compare_mask,
+ unsigned int ref,
+ Uint32 func_ops) = 0;
+
+ // Sets the color write paramters.
+ // Parameters:
+ // red: enable red write.
+ // green: enable green write.
+ // blue: enable blue write.
+ // alpha: enable alpha write.
+ // dither: enable dithering.
+ virtual void SetColorWrite(bool red,
+ bool green,
+ bool blue,
+ bool alpha,
+ bool dither) = 0;
+
+ // Sets the blending mode.
+ // Parameters:
+ // enable: whether or not to enable blending.
+ // separate_alpha: whether or not alpha uses separate Equation/Functions
+ // (if false, it uses the color ones).
+ // color_eq: the equation for blending of color values.
+ // color_src_func: the source function for blending of color values.
+ // color_dst_func: the destination function for blending of color values.
+ // alpha_eq: the equation for blending of alpha values.
+ // alpha_src_func: the source function for blending of alpha values.
+ // alpha_dst_func: the destination function for blending of alpha values.
+ virtual void SetBlending(bool enable,
+ bool separate_alpha,
+ BlendEq color_eq,
+ BlendFunc color_src_func,
+ BlendFunc color_dst_func,
+ BlendEq alpha_eq,
+ BlendFunc alpha_src_func,
+ BlendFunc alpha_dst_func) = 0;
+
+ // Sets the blending color.
+ virtual void SetBlendingColor(const RGBA &color) = 0;
+
+ // Creates a render surface resource.
+ // Parameters:
+ // id: the resource ID of the render surface.
+ // width: the texture width. Must be positive.
+ // height: the texture height. Must be positive.
+ // texture_id: the resource id of the texture.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateRenderSurface(ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int mip_level,
+ unsigned int side,
+ ResourceId texture_id) = 0;
+
+ // Destroys a render surface resource.
+ // Parameters:
+ // id: the resource ID of the render surface.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid render
+ // surface
+ // resource ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DestroyRenderSurface(ResourceId id) = 0;
+
+ // Creates a depth stencil surface resource.
+ // Parameters:
+ // id: the resource ID of the depth stencil surface.
+ // width: the texture width. Must be positive.
+ // height: the texture height. Must be positive.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError CreateDepthSurface(ResourceId id,
+ unsigned int width,
+ unsigned int height) = 0;
+
+ // Destroys a depth stencil surface resource.
+ // Parameters:
+ // id: the resource ID of the depth stencil surface.
+ // Returns:
+ // parse_error::kParseInvalidArguments if an invalid render
+ // surface
+ // resource ID was passed, parse_error::kParseNoError otherwise.
+ virtual ParseError DestroyDepthSurface(ResourceId id) = 0;
+
+ // Switches the render surface and depth stencil surface to those
+ // corresponding to the passed in IDs.
+ // Parameters:
+ // render_surface_id: the resource ID of the render surface.
+ // depth_stencil_id: the resource ID of the render depth stencil surface.
+ // Returns:
+ // parse_error::kParseInvalidArguments if invalid arguments are
+ // passed, parse_error::kParseNoError otherwise.
+ virtual ParseError SetRenderSurface(ResourceId render_surface_id,
+ ResourceId depth_stencil_id) = 0;
+
+ // Switch the render surface and depth stencil surface back to the main
+ // surfaces stored in the render
+ virtual void SetBackSurfaces() = 0;
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_COMMON_CROSS_GAPI_INTERFACE_H_
diff --git a/o3d/gpu/command_buffer/common/logging.h b/o3d/gpu/command_buffer/common/logging.h
new file mode 100644
index 0000000..a9bbad8
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/logging.h
@@ -0,0 +1,67 @@
+/*
+ * 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 abstracts differences in logging between NaCl and host
+// environment.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_CROSS_LOGGING_H_
+#define GPU_COMMAND_BUFFER_COMMON_CROSS_LOGGING_H_
+
+#ifndef __native_client__
+#include "base/logging.h"
+#else
+#include <sstream>
+
+// TODO: implement logging through nacl's debug service runtime if
+// available.
+#define CHECK(X) do {} while (0)
+#define CHECK_EQ(X, Y) do {} while (0)
+#define CHECK_NE(X, Y) do {} while (0)
+#define CHECK_GT(X, Y) do {} while (0)
+#define CHECK_GE(X, Y) do {} while (0)
+#define CHECK_LT(X, Y) do {} while (0)
+#define CHECK_LE(X, Y) do {} while (0)
+
+#define DCHECK(X) do {} while (0)
+#define DCHECK_EQ(X, Y) do {} while (0)
+#define DCHECK_NE(X, Y) do {} while (0)
+#define DCHECK_GT(X, Y) do {} while (0)
+#define DCHECK_GE(X, Y) do {} while (0)
+#define DCHECK_LT(X, Y) do {} while (0)
+#define DCHECK_LE(X, Y) do {} while (0)
+
+#define LOG(LEVEL) if (0) std::ostringstream()
+#define DLOG(LEVEL) if (0) std::ostringstream()
+
+#endif
+
+#endif // GPU_COMMAND_BUFFER_COMMON_CROSS_LOGGING_H_
diff --git a/o3d/gpu/command_buffer/common/o3d_cmd_format.cc b/o3d/gpu/command_buffer/common/o3d_cmd_format.cc
new file mode 100644
index 0000000..c70dde7
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/o3d_cmd_format.cc
@@ -0,0 +1,57 @@
+/*
+ * 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 binary format definition of the command buffer and
+// command buffer commands.
+
+#include "gpu/command_buffer/common/o3d_cmd_format.h"
+
+namespace command_buffer {
+namespace o3d {
+
+const char* GetCommandName(CommandId command_id) {
+ static const char* const names[] = {
+ #define O3D_COMMAND_BUFFER_CMD_OP(name) # name,
+
+ O3D_COMMAND_BUFFER_CMDS(O3D_COMMAND_BUFFER_CMD_OP)
+
+ #undef O3D_COMMAND_BUFFER_CMD_OP
+ };
+
+ int id = static_cast<int>(command_id);
+ return (id > kStartPoint && id < kNumCommands) ?
+ names[id - kStartPoint - 1] : "*unknown-command*";
+}
+
+} // namespace o3d
+} // namespace command_buffer
+
diff --git a/o3d/gpu/command_buffer/common/o3d_cmd_format.h b/o3d/gpu/command_buffer/common/o3d_cmd_format.h
new file mode 100644
index 0000000..86503f4
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/o3d_cmd_format.h
@@ -0,0 +1,3155 @@
+/*
+ * 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 binary format definition of the command buffer and
+// command buffer commands.
+// It is recommended you use the CommandBufferHelper object to create commands
+// but if you want to go lower level you can use the structures here to help.
+//
+// A few ways to use them:
+//
+// Fill out a structure in place:
+//
+// cmd::SetViewport::Set(ptrToSomeSharedMemory,
+// left, right, width, height, z_min, z_max);
+//
+// Fill out consecutive commands:
+//
+// Note that each cmd::XXX::Set function returns a pointer to the place
+// the next command should go.
+//
+// void* dest = ptrToSomeSharedMemory;
+// dest = cmd::SetViewport::Set(dest, left, right, width, height, min, max);
+// dest = cmd::Clear::Set(dest, buffers, r, g, b, a, depth, stencil);
+// dest = cmd::Draw::Set(dest, primitive_type, first, count);
+//
+// NOTE: The types in this file must be POD types. That means they can not have
+// constructors, destructors, virtual functions or inheritance and they can only
+// use other POD types or intrinsics as members.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_FORMAT_H_
+#define GPU_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_FORMAT_H_
+
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/command_buffer/common/resource.h"
+
+namespace command_buffer {
+namespace o3d {
+
+// This macro is used to safely and convienently expand the list of commnad
+// buffer commands in to various lists and never have them get out of sync. To
+// add a new command, add it this list, create the corresponding structure below
+// and then add a function in gapi_decoder.cc called Handle_COMMAND_NAME where
+// COMMAND_NAME is the name of your command structure.
+//
+// NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
+#define O3D_COMMAND_BUFFER_CMDS(OP) \
+ OP(BeginFrame) /* 1024 */ \
+ OP(EndFrame) /* 1025 */ \
+ OP(Clear) /* 1026 */ \
+ OP(CreateVertexBuffer) /* 1027 */ \
+ OP(DestroyVertexBuffer) /* 1028 */ \
+ OP(SetVertexBufferData) /* 1029 */ \
+ OP(SetVertexBufferDataImmediate) /* 1030 */ \
+ OP(GetVertexBufferData) /* 1031 */ \
+ OP(CreateIndexBuffer) /* 1032 */ \
+ OP(DestroyIndexBuffer) /* 1033 */ \
+ OP(SetIndexBufferData) /* 1034 */ \
+ OP(SetIndexBufferDataImmediate) /* 1035 */ \
+ OP(GetIndexBufferData) /* 1036 */ \
+ OP(CreateVertexStruct) /* 1037 */ \
+ OP(DestroyVertexStruct) /* 1038 */ \
+ OP(SetVertexInput) /* 1039 */ \
+ OP(SetVertexStruct) /* 1040 */ \
+ OP(Draw) /* 1041 */ \
+ OP(DrawIndexed) /* 1042 */ \
+ OP(CreateEffect) /* 1043 */ \
+ OP(CreateEffectImmediate) /* 1044 */ \
+ OP(DestroyEffect) /* 1045 */ \
+ OP(SetEffect) /* 1046 */ \
+ OP(GetParamCount) /* 1047 */ \
+ OP(CreateParam) /* 1048 */ \
+ OP(CreateParamByName) /* 1049 */ \
+ OP(CreateParamByNameImmediate) /* 1050 */ \
+ OP(DestroyParam) /* 1051 */ \
+ OP(SetParamData) /* 1052 */ \
+ OP(SetParamDataImmediate) /* 1053 */ \
+ OP(GetParamDesc) /* 1054 */ \
+ OP(GetStreamCount) /* 1055 */ \
+ OP(GetStreamDesc) /* 1056 */ \
+ OP(DestroyTexture) /* 1057 */ \
+ OP(CreateTexture2d) /* 1058 */ \
+ OP(CreateTexture3d) /* 1059 */ \
+ OP(CreateTextureCube) /* 1060 */ \
+ OP(SetTextureData) /* 1061 */ \
+ OP(SetTextureDataImmediate) /* 1062 */ \
+ OP(GetTextureData) /* 1063 */ \
+ OP(CreateSampler) /* 1064 */ \
+ OP(DestroySampler) /* 1065 */ \
+ OP(SetSamplerStates) /* 1066 */ \
+ OP(SetSamplerBorderColor) /* 1067 */ \
+ OP(SetSamplerTexture) /* 1068 */ \
+ OP(SetViewport) /* 1069 */ \
+ OP(SetScissor) /* 1070 */ \
+ OP(SetPointLineRaster) /* 1071 */ \
+ OP(SetPolygonRaster) /* 1072 */ \
+ OP(SetPolygonOffset) /* 1073 */ \
+ OP(SetAlphaTest) /* 1074 */ \
+ OP(SetDepthTest) /* 1075 */ \
+ OP(SetStencilTest) /* 1076 */ \
+ OP(SetBlending) /* 1077 */ \
+ OP(SetBlendingColor) /* 1078 */ \
+ OP(SetColorWrite) /* 1079 */ \
+ OP(CreateRenderSurface) /* 1080 */ \
+ OP(DestroyRenderSurface) /* 1081 */ \
+ OP(CreateDepthSurface) /* 1082 */ \
+ OP(DestroyDepthSurface) /* 1083 */ \
+ OP(SetRenderSurface) /* 1084 */ \
+ OP(SetBackSurfaces) /* 1085 */ \
+
+
+// GAPI commands.
+enum CommandId {
+ kStartPoint = cmd::kLastCommonId, // All O3D commands start after this.
+ #define GPU_COMMAND_BUFFER_CMD_OP(name) k ## name,
+
+ O3D_COMMAND_BUFFER_CMDS(GPU_COMMAND_BUFFER_CMD_OP)
+
+ #undef GPU_COMMAND_BUFFER_CMD_OP
+
+ kNumCommands,
+};
+
+// Bit definitions for buffers to clear.
+enum ClearBuffer {
+ kColor = 0x1,
+ kDepth = 0x2,
+ kStencil = 0x4,
+ kAllBuffers = kColor | kDepth | kStencil
+};
+
+// Polygon mode for SetPolygonRaster
+enum PolygonMode {
+ kPolygonModePoints,
+ kPolygonModeLines,
+ kPolygonModeFill,
+ kNumPolygonMode
+};
+
+// Face culling mode for SetPolygonRaster
+enum FaceCullMode {
+ kCullNone,
+ kCullCW,
+ kCullCCW,
+ kNumFaceCullMode
+};
+
+// Primitive type for Draw and DrawIndexed.
+enum PrimitiveType {
+ kPoints,
+ kLines,
+ kLineStrips,
+ kTriangles,
+ kTriangleStrips,
+ kTriangleFans,
+ kMaxPrimitiveType
+};
+
+// Comparison function for alpha or depth test
+enum Comparison {
+ kNever,
+ kLess,
+ kEqual,
+ kLEqual,
+ kGreater,
+ kNotEqual,
+ kGEqual,
+ kAlways,
+ kNumComparison
+};
+
+// Stencil operation
+enum StencilOp {
+ kKeep,
+ kZero,
+ kReplace,
+ kIncNoWrap,
+ kDecNoWrap,
+ kInvert,
+ kIncWrap,
+ kDecWrap,
+ kNumStencilOp
+};
+
+// Blend Equation
+enum BlendEq {
+ kBlendEqAdd,
+ kBlendEqSub,
+ kBlendEqRevSub,
+ kBlendEqMin,
+ kBlendEqMax,
+ kNumBlendEq
+};
+
+// Blend Funtion
+enum BlendFunc {
+ kBlendFuncZero,
+ kBlendFuncOne,
+ kBlendFuncSrcColor,
+ kBlendFuncInvSrcColor,
+ kBlendFuncSrcAlpha,
+ kBlendFuncInvSrcAlpha,
+ kBlendFuncDstAlpha,
+ kBlendFuncInvDstAlpha,
+ kBlendFuncDstColor,
+ kBlendFuncInvDstColor,
+ kBlendFuncSrcAlphaSaturate,
+ kBlendFuncBlendColor,
+ kBlendFuncInvBlendColor,
+ kNumBlendFunc
+};
+
+const char* GetCommandName(CommandId id);
+
+// Make sure the compiler does not add extra padding to any of the command
+// structures.
+#pragma pack(push, 1)
+
+struct BeginFrame {
+ typedef BeginFrame ValueType;
+ static const CommandId kCmdId = kBeginFrame;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init() {
+ SetHeader();
+ }
+ static void* Set(void* cmd) {
+ static_cast<ValueType*>(cmd)->Init();
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(BeginFrame) == 4, Sizeof_BeginFrame_is_not_4);
+COMPILE_ASSERT(offsetof(BeginFrame, header) == 0,
+ OffsetOf_BeginFrame_header_not_0);
+
+struct EndFrame {
+ typedef EndFrame ValueType;
+ static const CommandId kCmdId = kEndFrame;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init() {
+ SetHeader();
+ }
+ static void* Set(void* cmd) {
+ static_cast<ValueType*>(cmd)->Init();
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(EndFrame) == 4, Sizeof_EndFrame_is_not_4);
+COMPILE_ASSERT(offsetof(EndFrame, header) == 0,
+ OffsetOf_EndFrame_header_not_0);
+
+struct Clear {
+ typedef Clear ValueType;
+ static const CommandId kCmdId = kClear;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _buffers, float _red, float _green, float _blue,
+ float _alpha, float _depth, uint32 _stencil) {
+ SetHeader();
+ buffers = _buffers;
+ red = _red;
+ green = _green;
+ blue = _blue;
+ alpha = _alpha;
+ depth = _depth;
+ stencil = _stencil;
+ }
+
+ static void* Set(void* cmd, uint32 buffers,
+ float red, float green, float blue, float alpha,
+ float depth,
+ uint32 stencil) {
+ static_cast<ValueType*>(cmd)->Init(
+ buffers, red, green, blue, alpha, depth, stencil);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 buffers;
+ float red;
+ float green;
+ float blue;
+ float alpha;
+ float depth;
+ uint32 stencil;
+};
+
+COMPILE_ASSERT(sizeof(Clear) == 32, Sizeof_Clear_is_not_32);
+COMPILE_ASSERT(offsetof(Clear, header) == 0,
+ OffsetOf_Clear_header_not_0);
+COMPILE_ASSERT(offsetof(Clear, buffers) == 4,
+ OffsetOf_Clear_buffers_not_4);
+COMPILE_ASSERT(offsetof(Clear, red) == 8,
+ OffsetOf_Clear_red_not_8);
+COMPILE_ASSERT(offsetof(Clear, green) == 12,
+ OffsetOf_Clear_green_not_12);
+COMPILE_ASSERT(offsetof(Clear, blue) == 16,
+ OffsetOf_Clear_blue_not_16);
+COMPILE_ASSERT(offsetof(Clear, alpha) == 20,
+ OffsetOf_Clear_alpha_not_20);
+COMPILE_ASSERT(offsetof(Clear, depth) == 24,
+ OffsetOf_Clear_depth_not_24);
+COMPILE_ASSERT(offsetof(Clear, stencil) == 28,
+ OffsetOf_Clear_stencil_not_28);
+
+struct SetViewport {
+ typedef SetViewport ValueType;
+ static const CommandId kCmdId = kSetViewport;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ uint32 _left,
+ uint32 _top,
+ uint32 _width,
+ uint32 _height,
+ float _z_min,
+ float _z_max) {
+ SetHeader();
+ left = _left;
+ top = _top;
+ width = _width;
+ height = _height;
+ z_min = _z_min;
+ z_max = _z_max;
+ }
+
+ static void* Set(void* cmd,
+ uint32 left,
+ uint32 top,
+ uint32 width,
+ uint32 height,
+ float z_min,
+ float z_max) {
+ static_cast<ValueType*>(cmd)->Init(
+ left,
+ top,
+ width,
+ height,
+ z_min,
+ z_max);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 left;
+ uint32 top;
+ uint32 width;
+ uint32 height;
+ float z_min;
+ float z_max;
+};
+
+COMPILE_ASSERT(sizeof(SetViewport) == 28, Sizeof_SetViewport_is_not_28);
+COMPILE_ASSERT(offsetof(SetViewport, header) == 0,
+ OffsetOf_SetViewport_header_not_0);
+COMPILE_ASSERT(offsetof(SetViewport, left) == 4,
+ OffsetOf_SetViewport_left_not_4);
+COMPILE_ASSERT(offsetof(SetViewport, top) == 8,
+ OffsetOf_SetViewport_top_not_8);
+COMPILE_ASSERT(offsetof(SetViewport, width) == 12,
+ OffsetOf_SetViewport_width_not_12);
+COMPILE_ASSERT(offsetof(SetViewport, height) == 16,
+ OffsetOf_SetViewport_height_not_16);
+COMPILE_ASSERT(offsetof(SetViewport, z_min) == 20,
+ OffsetOf_SetViewport_z_min_not_20);
+COMPILE_ASSERT(offsetof(SetViewport, z_max) == 24,
+ OffsetOf_SetViewport_z_max_not_24);
+
+struct CreateVertexBuffer {
+ typedef CreateVertexBuffer ValueType;
+ static const CommandId kCmdId = kCreateVertexBuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _vertex_buffer_id, uint32 _size,
+ vertex_buffer::Flags _flags) {
+ SetHeader();
+ vertex_buffer_id = _vertex_buffer_id;
+ size = _size;
+ flags = static_cast<uint32>(_flags);
+ }
+
+ static void* Set(void* cmd, ResourceId vertex_buffer_id,
+ uint32 size, vertex_buffer::Flags flags) {
+ static_cast<ValueType*>(cmd)->Init(vertex_buffer_id, size, flags);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId vertex_buffer_id;
+ uint32 size;
+ uint32 flags;
+};
+
+COMPILE_ASSERT(sizeof(CreateVertexBuffer) == 16,
+ Sizeof_CreateVertexBuffer_is_not_16);
+COMPILE_ASSERT(offsetof(CreateVertexBuffer, header) == 0,
+ OffsetOf_CreateVertexBuffer_header_not_0);
+COMPILE_ASSERT(offsetof(CreateVertexBuffer, vertex_buffer_id) == 4,
+ OffsetOf_CreateVertexBuffer_vertex_buffer_id_not_4);
+COMPILE_ASSERT(offsetof(CreateVertexBuffer, size) == 8,
+ OffsetOf_CreateVertexBuffer_size_not_8);
+COMPILE_ASSERT(offsetof(CreateVertexBuffer, flags) == 12,
+ OffsetOf_CreateVertexBuffer_flags_not_12);
+
+struct DestroyVertexBuffer {
+ typedef DestroyVertexBuffer ValueType;
+ static const CommandId kCmdId = kDestroyVertexBuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _vertex_buffer_id) {
+ SetHeader();
+ vertex_buffer_id = _vertex_buffer_id;
+ }
+
+ static void* Set(void* cmd, ResourceId vertex_buffer_id) {
+ static_cast<ValueType*>(cmd)->Init(vertex_buffer_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId vertex_buffer_id;
+};
+
+COMPILE_ASSERT(sizeof(DestroyVertexBuffer) == 8,
+ Sizeof_DestroyVertexBuffer_is_not_8);
+COMPILE_ASSERT(offsetof(DestroyVertexBuffer, header) == 0,
+ OffsetOf_DestroyVertexBuffer_header_not_0);
+COMPILE_ASSERT(offsetof(DestroyVertexBuffer, vertex_buffer_id) == 4,
+ OffsetOf_DestroyVertexBuffer_vertex_buffer_id_not_4);
+
+struct SetVertexBufferDataImmediate {
+ typedef SetVertexBufferDataImmediate ValueType;
+ static const CommandId kCmdId = kSetVertexBufferDataImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ void SetHeader(uint32 size) {
+ header.SetCmdBySize<ValueType>(size);
+ }
+
+ void Init(ResourceId _vertex_buffer_id, uint32 _offset,
+ const void* data, uint32 size) {
+ SetHeader(size);
+ vertex_buffer_id = _vertex_buffer_id;
+ offset = _offset;
+ memcpy(ImmediateDataAddress(this), data, size);
+ }
+
+ static void* Set(void* cmd, ResourceId vertex_buffer_id, uint32 offset,
+ const void* data, uint32 size) {
+ static_cast<ValueType*>(cmd)->Init(vertex_buffer_id, offset, data, size);
+ return NextImmediateCmdAddress<ValueType>(cmd, size);
+ }
+
+ CommandHeader header;
+ ResourceId vertex_buffer_id;
+ uint32 offset;
+};
+
+COMPILE_ASSERT(sizeof(SetVertexBufferDataImmediate) == 12,
+ Sizeof_SetVertexBufferDataImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(SetVertexBufferDataImmediate, header) == 0,
+ OffsetOf_SetVertexBufferDataImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(SetVertexBufferDataImmediate, vertex_buffer_id) == 4,
+ OffsetOf_SetVertexBufferDataImmediate_vertex_buffer_id_not_4);
+COMPILE_ASSERT(offsetof(SetVertexBufferDataImmediate, offset) == 8,
+ OffsetOf_SetVertexBufferDataImmediate_offset_not_8);
+
+struct SetVertexBufferData {
+ typedef SetVertexBufferData ValueType;
+ static const CommandId kCmdId = kSetVertexBufferData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _vertex_buffer_id, uint32 _offset, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ vertex_buffer_id = _vertex_buffer_id;
+ offset = _offset;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId vertex_buffer_id,
+ uint32 offset, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(vertex_buffer_id, offset, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId vertex_buffer_id;
+ uint32 offset;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(SetVertexBufferData) == 24,
+ Sizeof_SetVertexBufferData_is_not_24);
+COMPILE_ASSERT(offsetof(SetVertexBufferData, header) == 0,
+ OffsetOf_SetVertexBufferData_header_not_0);
+COMPILE_ASSERT(offsetof(SetVertexBufferData, vertex_buffer_id) == 4,
+ OffsetOf_SetVertexBufferData_vertex_buffer_id_not_4);
+COMPILE_ASSERT(offsetof(SetVertexBufferData, offset) == 8,
+ OffsetOf_SetVertexBufferData_offset_not_8);
+COMPILE_ASSERT(offsetof(SetVertexBufferData, size) == 12,
+ OffsetOf_SetVertexBufferData_size_not_12);
+COMPILE_ASSERT(offsetof(SetVertexBufferData, shared_memory) == 16,
+ OffsetOf_SetVertexBufferData_shared_memory_not_16);
+
+struct GetVertexBufferData {
+ typedef GetVertexBufferData ValueType;
+ static const CommandId kCmdId = kGetVertexBufferData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _vertex_buffer_id, uint32 _offset, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ vertex_buffer_id = _vertex_buffer_id;
+ offset = _offset;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId vertex_buffer_id,
+ uint32 offset, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(vertex_buffer_id, offset, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId vertex_buffer_id;
+ uint32 offset;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(GetVertexBufferData) == 24,
+ Sizeof_GetVertexBufferData_is_not_24);
+COMPILE_ASSERT(offsetof(GetVertexBufferData, header) == 0,
+ OffsetOf_GetVertexBufferData_header_not_0);
+COMPILE_ASSERT(offsetof(GetVertexBufferData, vertex_buffer_id) == 4,
+ OffsetOf_GetVertexBufferData_vertex_buffer_id_not_4);
+COMPILE_ASSERT(offsetof(GetVertexBufferData, offset) == 8,
+ OffsetOf_GetVertexBufferData_offset_not_8);
+COMPILE_ASSERT(offsetof(GetVertexBufferData, size) == 12,
+ OffsetOf_GetVertexBufferData_size_not_12);
+COMPILE_ASSERT(offsetof(GetVertexBufferData, shared_memory) == 16,
+ OffsetOf_GetVertexBufferData_shared_memory_not_16);
+
+struct CreateIndexBuffer {
+ typedef CreateIndexBuffer ValueType;
+ static const CommandId kCmdId = kCreateIndexBuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _index_buffer_id, uint32 _size,
+ index_buffer::Flags _flags) {
+ SetHeader();
+ index_buffer_id = _index_buffer_id;
+ size = _size;
+ flags = static_cast<uint32>(_flags);
+ }
+
+ static void* Set(void* cmd, ResourceId index_buffer_id,
+ uint32 size, index_buffer::Flags flags) {
+ static_cast<ValueType*>(cmd)->Init(index_buffer_id, size, flags);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId index_buffer_id;
+ uint32 size;
+ uint32 flags;
+};
+
+COMPILE_ASSERT(sizeof(CreateIndexBuffer) == 16,
+ Sizeof_CreateIndexBuffer_is_not_16);
+COMPILE_ASSERT(offsetof(CreateIndexBuffer, header) == 0,
+ OffsetOf_CreateIndexBuffer_header_not_0);
+COMPILE_ASSERT(offsetof(CreateIndexBuffer, index_buffer_id) == 4,
+ OffsetOf_CreateIndexBuffer_index_buffer_id_not_4);
+COMPILE_ASSERT(offsetof(CreateIndexBuffer, size) == 8,
+ OffsetOf_CreateIndexBuffer_size_not_8);
+COMPILE_ASSERT(offsetof(CreateIndexBuffer, flags) == 12,
+ OffsetOf_CreateIndexBuffer_flags_not_12);
+
+struct DestroyIndexBuffer {
+ typedef DestroyIndexBuffer ValueType;
+ static const CommandId kCmdId = kDestroyIndexBuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _index_buffer_id) {
+ SetHeader();
+ index_buffer_id = _index_buffer_id;
+ }
+
+ static void* Set(void* cmd, ResourceId index_buffer_id) {
+ static_cast<ValueType*>(cmd)->Init(index_buffer_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId index_buffer_id;
+};
+
+COMPILE_ASSERT(sizeof(DestroyIndexBuffer) == 8,
+ Sizeof_DestroyIndexBuffer_is_not_8);
+COMPILE_ASSERT(offsetof(DestroyIndexBuffer, header) == 0,
+ OffsetOf_DestroyIndexBuffer_header_not_0);
+COMPILE_ASSERT(offsetof(DestroyIndexBuffer, index_buffer_id) == 4,
+ OffsetOf_DestroyIndexBuffer_index_buffer_id_not_4);
+
+struct SetIndexBufferDataImmediate {
+ typedef SetIndexBufferDataImmediate ValueType;
+ static const CommandId kCmdId = kSetIndexBufferDataImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ void SetHeader(uint32 size) {
+ header.SetCmdBySize<ValueType>(size);
+ }
+
+ void Init(ResourceId _index_buffer_id, uint32 _offset,
+ const void* data, uint32 size) {
+ SetHeader(size);
+ index_buffer_id = _index_buffer_id;
+ offset = _offset;
+ memcpy(ImmediateDataAddress(this), data, size);
+ }
+
+ static void* Set(void* cmd, ResourceId index_buffer_id, uint32 offset,
+ const void* data, uint32 size) {
+ static_cast<ValueType*>(cmd)->Init(index_buffer_id, offset, data, size);
+ return NextImmediateCmdAddress<ValueType>(cmd, size);
+ }
+
+ CommandHeader header;
+ ResourceId index_buffer_id;
+ uint32 offset;
+};
+
+COMPILE_ASSERT(sizeof(SetIndexBufferDataImmediate) == 12,
+ Sizeof_SetIndexBufferDataImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(SetIndexBufferDataImmediate, header) == 0,
+ OffsetOf_SetIndexBufferDataImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(SetIndexBufferDataImmediate, index_buffer_id) == 4,
+ OffsetOf_SetIndexBufferDataImmediate_index_buffer_id_not_4);
+COMPILE_ASSERT(offsetof(SetIndexBufferDataImmediate, offset) == 8,
+ OffsetOf_SetIndexBufferDataImmediate_offset_not_8);
+
+struct SetIndexBufferData {
+ typedef SetIndexBufferData ValueType;
+ static const CommandId kCmdId = kSetIndexBufferData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _index_buffer_id, uint32 _offset, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ index_buffer_id = _index_buffer_id;
+ offset = _offset;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd,
+ ResourceId index_buffer_id, uint32 offset, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(index_buffer_id, offset, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId index_buffer_id;
+ uint32 offset;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(SetIndexBufferData) == 24,
+ Sizeof_SetIndexBufferData_is_not_24);
+COMPILE_ASSERT(offsetof(SetIndexBufferData, header) == 0,
+ OffsetOf_SetIndexBufferData_header_not_0);
+COMPILE_ASSERT(offsetof(SetIndexBufferData, index_buffer_id) == 4,
+ OffsetOf_SetIndexBufferData_index_buffer_id_not_4);
+COMPILE_ASSERT(offsetof(SetIndexBufferData, offset) == 8,
+ OffsetOf_SetIndexBufferData_offset_not_8);
+COMPILE_ASSERT(offsetof(SetIndexBufferData, size) == 12,
+ OffsetOf_SetIndexBufferData_size_not_12);
+COMPILE_ASSERT(offsetof(SetIndexBufferData, shared_memory) == 16,
+ OffsetOf_SetIndexBufferData_shared_memory_not_16);
+
+struct GetIndexBufferData {
+ typedef GetIndexBufferData ValueType;
+ static const CommandId kCmdId = kGetIndexBufferData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _index_buffer_id, uint32 _offset, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ index_buffer_id = _index_buffer_id;
+ offset = _offset;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId index_buffer_id,
+ uint32 offset, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(index_buffer_id, offset, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId index_buffer_id;
+ uint32 offset;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(GetIndexBufferData) == 24,
+ Sizeof_GetIndexBufferData_is_not_24);
+COMPILE_ASSERT(offsetof(GetIndexBufferData, header) == 0,
+ OffsetOf_GetIndexBufferData_header_not_0);
+COMPILE_ASSERT(offsetof(GetIndexBufferData, index_buffer_id) == 4,
+ OffsetOf_GetIndexBufferData_index_buffer_id_not_4);
+COMPILE_ASSERT(offsetof(GetIndexBufferData, offset) == 8,
+ OffsetOf_GetIndexBufferData_offset_not_8);
+COMPILE_ASSERT(offsetof(GetIndexBufferData, size) == 12,
+ OffsetOf_GetIndexBufferData_size_not_12);
+COMPILE_ASSERT(offsetof(GetIndexBufferData, shared_memory) == 16,
+ OffsetOf_GetIndexBufferData_shared_memory_not_16);
+
+struct CreateVertexStruct {
+ typedef CreateVertexStruct ValueType;
+ static const CommandId kCmdId = kCreateVertexStruct;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _vertex_struct_id, uint32 _input_count) {
+ SetHeader();
+ vertex_struct_id = _vertex_struct_id;
+ input_count = _input_count;
+ }
+
+ static void* Set(void* cmd, ResourceId vertex_struct_id, uint32 input_count) {
+ static_cast<ValueType*>(cmd)->Init(vertex_struct_id, input_count);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId vertex_struct_id;
+ uint32 input_count;
+};
+
+COMPILE_ASSERT(sizeof(CreateVertexStruct) == 12,
+ Sizeof_CreateVertexStruct_is_not_12);
+COMPILE_ASSERT(offsetof(CreateVertexStruct, header) == 0,
+ OffsetOf_CreateVertexStruct_header_not_0);
+COMPILE_ASSERT(offsetof(CreateVertexStruct, vertex_struct_id) == 4,
+ OffsetOf_CreateVertexStruct_vertex_struct_id_not_4);
+COMPILE_ASSERT(offsetof(CreateVertexStruct, input_count) == 8,
+ OffsetOf_CreateVertexStruct_input_count_not_8);
+
+struct DestroyVertexStruct {
+ typedef DestroyVertexStruct ValueType;
+ static const CommandId kCmdId = kDestroyVertexStruct;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _vertex_struct_id) {
+ SetHeader();
+ vertex_struct_id = _vertex_struct_id;
+ }
+
+ static void* Set(void* cmd, ResourceId vertex_struct_id) {
+ static_cast<ValueType*>(cmd)->Init(vertex_struct_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId vertex_struct_id;
+};
+
+COMPILE_ASSERT(sizeof(DestroyVertexStruct) == 8,
+ Sizeof_DestroyVertexStruct_is_not_8);
+COMPILE_ASSERT(offsetof(DestroyVertexStruct, header) == 0,
+ OffsetOf_DestroyVertexStruct_header_not_0);
+COMPILE_ASSERT(offsetof(DestroyVertexStruct, vertex_struct_id) == 4,
+ OffsetOf_DestroyVertexStruct_vertex_struct_id_not_4);
+
+struct SetVertexInput {
+ typedef SetVertexInput ValueType;
+ static const CommandId kCmdId = kSetVertexInput;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // type_stride_semantic field.
+ typedef BitField<0, 4> SemanticIndex;
+ typedef BitField<4, 4> Semantic;
+ typedef BitField<8, 8> Type;
+ typedef BitField<16, 16> Stride;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _vertex_struct_id,
+ uint32 _input_index,
+ ResourceId _vertex_buffer_id,
+ uint32 _offset,
+ vertex_struct::Semantic _semantic,
+ uint32 _semantic_index,
+ vertex_struct::Type _type,
+ uint32 _stride) {
+ SetHeader();
+ vertex_struct_id = _vertex_struct_id;
+ input_index = _input_index;
+ vertex_buffer_id = _vertex_buffer_id;
+ offset = _offset;
+ type_stride_semantic =
+ Semantic::MakeValue(_semantic) |
+ SemanticIndex::MakeValue(_semantic_index) |
+ Type::MakeValue(_type) |
+ Stride::MakeValue(_stride);
+ }
+
+ static void* Set(
+ void* cmd,
+ ResourceId vertex_struct_id,
+ uint32 input_index,
+ ResourceId vertex_buffer_id,
+ uint32 offset,
+ vertex_struct::Semantic semantic,
+ uint32 semantic_index,
+ vertex_struct::Type type,
+ uint32 stride) {
+ static_cast<ValueType*>(cmd)->Init(
+ vertex_struct_id,
+ input_index,
+ vertex_buffer_id,
+ offset,
+ semantic,
+ semantic_index,
+ type,
+ stride);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId vertex_struct_id;
+ uint32 input_index;
+ ResourceId vertex_buffer_id;
+ uint32 offset;
+ uint32 type_stride_semantic;
+};
+
+COMPILE_ASSERT(sizeof(SetVertexInput) == 24,
+ Sizeof_SetVertexInput_is_not_24);
+COMPILE_ASSERT(offsetof(SetVertexInput, header) == 0,
+ OffsetOf_SetVertexInput_header_not_0);
+COMPILE_ASSERT(offsetof(SetVertexInput, vertex_struct_id) == 4,
+ OffsetOf_SetVertexInput_vertex_struct_id_not_4);
+COMPILE_ASSERT(offsetof(SetVertexInput, input_index) == 8,
+ OffsetOf_SetVertexInput_input_index_not_8);
+COMPILE_ASSERT(offsetof(SetVertexInput, vertex_buffer_id) == 12,
+ OffsetOf_SetVertexInput_vertex_buffer_id_not_12);
+COMPILE_ASSERT(offsetof(SetVertexInput, offset) == 16,
+ OffsetOf_SetVertexInput_offset_not_16);
+COMPILE_ASSERT(offsetof(SetVertexInput, type_stride_semantic) == 20,
+ OffsetOf_SetVertexInput_type_stride_semantic_not_20);
+
+struct SetVertexStruct {
+ typedef SetVertexStruct ValueType;
+ static const CommandId kCmdId = kSetVertexStruct;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _vertex_struct_id) {
+ SetHeader();
+ vertex_struct_id = _vertex_struct_id;
+ }
+
+ static void* Set(void* cmd, ResourceId vertex_struct_id) {
+ static_cast<ValueType*>(cmd)->Init(vertex_struct_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId vertex_struct_id;
+};
+
+COMPILE_ASSERT(sizeof(SetVertexStruct) == 8,
+ Sizeof_SetVertexStruct_is_not_8);
+COMPILE_ASSERT(offsetof(SetVertexStruct, header) == 0,
+ OffsetOf_SetVertexStruct_header_not_0);
+COMPILE_ASSERT(offsetof(SetVertexStruct, vertex_struct_id) == 4,
+ OffsetOf_SetVertexStruct_vertex_struct_id_not_4);
+
+struct Draw {
+ typedef Draw ValueType;
+ static const CommandId kCmdId = kDraw;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(PrimitiveType _primitive_type, uint32 _first, uint32 _count) {
+ SetHeader();
+ primitive_type = _primitive_type;
+ first = _first;
+ count = _count;
+ }
+
+ static void* Set(void* cmd, PrimitiveType primitive_type, uint32 first,
+ uint32 count) {
+ static_cast<ValueType*>(cmd)->Init(primitive_type, first, count);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 primitive_type;
+ uint32 first;
+ uint32 count;
+};
+
+COMPILE_ASSERT(sizeof(Draw) == 16, Sizeof_DRAW_is_not_16);
+COMPILE_ASSERT(offsetof(Draw, header) == 0,
+ OffsetOf_Draw_header_not_0);
+COMPILE_ASSERT(offsetof(Draw, primitive_type) == 4,
+ OffsetOf_Draw_primitive_type_not_4);
+COMPILE_ASSERT(offsetof(Draw, first) == 8,
+ OffsetOf_Draw_first_not_8);
+COMPILE_ASSERT(offsetof(Draw, count) == 12,
+ OffsetOf_Draw_count_not_12);
+
+struct DrawIndexed {
+ typedef DrawIndexed ValueType;
+ static const CommandId kCmdId = kDrawIndexed;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ PrimitiveType _primitive_type,
+ ResourceId _index_buffer_id,
+ uint32 _first,
+ uint32 _count,
+ uint32 _min_index,
+ uint32 _max_index) {
+ SetHeader();
+ primitive_type = _primitive_type;
+ index_buffer_id = _index_buffer_id;
+ first = _first;
+ count = _count;
+ min_index = _min_index;
+ max_index = _max_index;
+ }
+
+ static void* Set(void* cmd,
+ PrimitiveType primitive_type,
+ ResourceId index_buffer_id,
+ uint32 first,
+ uint32 count,
+ uint32 min_index,
+ uint32 max_index) {
+ static_cast<ValueType*>(cmd)->Init(
+ primitive_type,
+ index_buffer_id,
+ first,
+ count,
+ min_index,
+ max_index);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 primitive_type;
+ ResourceId index_buffer_id;
+ uint32 first;
+ uint32 count;
+ uint32 min_index;
+ uint32 max_index;
+};
+
+COMPILE_ASSERT(sizeof(DrawIndexed) == 28, Sizeof_DrawIndexed_is_not_28);
+COMPILE_ASSERT(offsetof(DrawIndexed, header) == 0,
+ OffsetOf_DrawIndexed_header_not_0);
+COMPILE_ASSERT(offsetof(DrawIndexed, primitive_type) == 4,
+ OffsetOf_DrawIndexed_primitive_type_not_4);
+COMPILE_ASSERT(offsetof(DrawIndexed, index_buffer_id) == 8,
+ OffsetOf_DrawIndexed_index_buffer_id_not_8);
+COMPILE_ASSERT(offsetof(DrawIndexed, first) == 12,
+ OffsetOf_DrawIndexed_first_not_12);
+COMPILE_ASSERT(offsetof(DrawIndexed, count) == 16,
+ OffsetOf_DrawIndexed_count_not_16);
+COMPILE_ASSERT(offsetof(DrawIndexed, min_index) == 20,
+ OffsetOf_DrawIndexed_min_index_not_20);
+COMPILE_ASSERT(offsetof(DrawIndexed, max_index) == 24,
+ OffsetOf_DrawIndexed_max_index_not_24);
+
+struct CreateEffect {
+ typedef CreateEffect ValueType;
+ static const CommandId kCmdId = kCreateEffect;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _effect_id, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ effect_id = _effect_id;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId effect_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(effect_id, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId effect_id;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(CreateEffect) == 20, Sizeof_CreateEffect_is_not_20);
+COMPILE_ASSERT(offsetof(CreateEffect, header) == 0,
+ OffsetOf_CreateEffect_header_not_0);
+COMPILE_ASSERT(offsetof(CreateEffect, effect_id) == 4,
+ OffsetOf_CreateEffect_effect_id_not_4);
+COMPILE_ASSERT(offsetof(CreateEffect, size) == 8,
+ OffsetOf_CreateEffect_size_not_8);
+COMPILE_ASSERT(offsetof(CreateEffect, shared_memory) == 12,
+ OffsetOf_CreateEffect_shared_memory_not_12);
+
+struct CreateEffectImmediate {
+ typedef CreateEffectImmediate ValueType;
+ static const CommandId kCmdId = kCreateEffectImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ void SetHeader(uint32 size) {
+ header.SetCmdBySize<ValueType>(size);
+ }
+
+ void Init(ResourceId _effect_id, uint32 _size, const void* data) {
+ SetHeader(_size);
+ effect_id = _effect_id;
+ size = _size;
+ }
+
+ static void* Set(void* cmd,
+ ResourceId effect_id, uint32 size, const void* data) {
+ static_cast<ValueType*>(cmd)->Init(effect_id, size, data);
+ return NextImmediateCmdAddress<ValueType>(cmd, size);
+ }
+
+ CommandHeader header;
+ ResourceId effect_id;
+ uint32 size;
+};
+
+COMPILE_ASSERT(sizeof(CreateEffectImmediate) == 12,
+ Sizeof_CreateEffectImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(CreateEffectImmediate, header) == 0,
+ OffsetOf_CreateEffectImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(CreateEffectImmediate, effect_id) == 4,
+ OffsetOf_CreateEffectImmediate_effect_id_not_4);
+COMPILE_ASSERT(offsetof(CreateEffectImmediate, size) == 8,
+ OffsetOf_CreateEffectImmediate_size_not_8);
+
+struct DestroyEffect {
+ typedef DestroyEffect ValueType;
+ static const CommandId kCmdId = kDestroyEffect;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _effect_id) {
+ SetHeader();
+ effect_id = _effect_id;
+ }
+
+ static void* Set(void* cmd, ResourceId effect_id) {
+ static_cast<ValueType*>(cmd)->Init(effect_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId effect_id;
+};
+
+COMPILE_ASSERT(sizeof(DestroyEffect) == 8, Sizeof_DestroyEffect_is_not_8);
+COMPILE_ASSERT(offsetof(DestroyEffect, header) == 0,
+ OffsetOf_DestroyEffect_header_not_0);
+COMPILE_ASSERT(offsetof(DestroyEffect, effect_id) == 4,
+ OffsetOf_DestroyEffect_effect_id_not_4);
+
+struct SetEffect {
+ typedef SetEffect ValueType;
+ static const CommandId kCmdId = kSetEffect;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _effect_id) {
+ SetHeader();
+ effect_id = _effect_id;
+ }
+
+ static void* Set(void* cmd, ResourceId effect_id) {
+ static_cast<ValueType*>(cmd)->Init(effect_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId effect_id;
+};
+
+COMPILE_ASSERT(sizeof(SetEffect) == 8, Sizeof_SetEffect_is_not_8);
+COMPILE_ASSERT(offsetof(SetEffect, header) == 0,
+ OffsetOf_SetEffect_header_not_0);
+COMPILE_ASSERT(offsetof(SetEffect, effect_id) == 4,
+ OffsetOf_SetEffect_effect_id_not_4);
+
+struct GetParamCount {
+ typedef GetParamCount ValueType;
+ static const CommandId kCmdId = kGetParamCount;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _effect_id, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ effect_id = _effect_id;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId effect_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(effect_id, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId effect_id;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(GetParamCount) == 20, Sizeof_GetParamCount_is_not_20);
+COMPILE_ASSERT(offsetof(GetParamCount, header) == 0,
+ OffsetOf_GetParamCount_header_not_0);
+COMPILE_ASSERT(offsetof(GetParamCount, effect_id) == 4,
+ OffsetOf_GetParamCount_effect_id_not_4);
+COMPILE_ASSERT(offsetof(GetParamCount, size) == 8,
+ OffsetOf_GetParamCount_size_not_8);
+COMPILE_ASSERT(offsetof(GetParamCount, shared_memory) == 12,
+ OffsetOf_GetParamCount_shared_memory_not_12);
+
+struct CreateParam {
+ typedef CreateParam ValueType;
+ static const CommandId kCmdId = kCreateParam;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _param_id, ResourceId _effect_id, uint32 _index) {
+ SetHeader();
+ param_id = _param_id;
+ effect_id = _effect_id;
+ index = _index;
+ }
+
+ static void* Set(void* cmd,
+ ResourceId param_id, ResourceId effect_id, uint32 index) {
+ static_cast<ValueType*>(cmd)->Init(param_id, effect_id, index);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId param_id;
+ ResourceId effect_id;
+ uint32 index;
+};
+
+COMPILE_ASSERT(sizeof(CreateParam) == 16, Sizeof_CreateParam_is_not_16);
+COMPILE_ASSERT(offsetof(CreateParam, header) == 0,
+ OffsetOf_CreateParam_header_not_0);
+COMPILE_ASSERT(offsetof(CreateParam, param_id) == 4,
+ OffsetOf_CreateParam_param_id_not_4);
+COMPILE_ASSERT(offsetof(CreateParam, effect_id) == 8,
+ OffsetOf_CreateParam_effect_id_not_8);
+COMPILE_ASSERT(offsetof(CreateParam, index) == 12,
+ OffsetOf_CreateParam_index_not_12);
+
+struct CreateParamByName {
+ typedef CreateParamByName ValueType;
+ static const CommandId kCmdId = kCreateParamByName;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _param_id, ResourceId _effect_id, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ param_id = _param_id;
+ effect_id = _effect_id;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId param_id, ResourceId effect_id,
+ uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(param_id, effect_id, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId param_id;
+ ResourceId effect_id;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(CreateParamByName) == 24,
+ Sizeof_CreateParamByName_is_not_24);
+COMPILE_ASSERT(offsetof(CreateParamByName, header) == 0,
+ OffsetOf_CreateParamByName_header_not_0);
+COMPILE_ASSERT(offsetof(CreateParamByName, param_id) == 4,
+ OffsetOf_CreateParamByName_param_id_not_4);
+COMPILE_ASSERT(offsetof(CreateParamByName, effect_id) == 8,
+ OffsetOf_CreateParamByName_effect_id_not_8);
+COMPILE_ASSERT(offsetof(CreateParamByName, size) == 12,
+ OffsetOf_CreateParamByName_size_not_12);
+COMPILE_ASSERT(offsetof(CreateParamByName, shared_memory) == 16,
+ OffsetOf_CreateParamByName_shared_memory_not_16);
+
+struct CreateParamByNameImmediate {
+ typedef CreateParamByNameImmediate ValueType;
+ static const CommandId kCmdId = kCreateParamByNameImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ void SetHeader(uint32 size) {
+ header.SetCmdBySize<ValueType>(size);
+ }
+
+ void Init(ResourceId _param_id, ResourceId _effect_id, uint32 _size,
+ const void* data) {
+ SetHeader(_size);
+ param_id = _param_id;
+ effect_id = _effect_id;
+ size = _size;
+ memcpy(ImmediateDataAddress(this), data, _size);
+ }
+
+ static void* Set(void* cmd, ResourceId param_id, ResourceId effect_id,
+ uint32 size, const void* data) {
+ static_cast<ValueType*>(cmd)->Init(param_id, effect_id, size, data);
+ return NextImmediateCmdAddress<ValueType>(cmd, size);
+ }
+
+ CommandHeader header;
+ ResourceId param_id;
+ ResourceId effect_id;
+ uint32 size;
+};
+
+COMPILE_ASSERT(sizeof(CreateParamByNameImmediate) == 16,
+ Sizeof_CreateParamByNameImmediate_is_not_16);
+COMPILE_ASSERT(offsetof(CreateParamByNameImmediate, header) == 0,
+ OffsetOf_CreateParamByNameImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(CreateParamByNameImmediate, param_id) == 4,
+ OffsetOf_CreateParamByNameImmediate_param_id_not_4);
+COMPILE_ASSERT(offsetof(CreateParamByNameImmediate, effect_id) == 8,
+ OffsetOf_CreateParamByNameImmediate_effect_id_not_8);
+COMPILE_ASSERT(offsetof(CreateParamByNameImmediate, size) == 12,
+ OffsetOf_CreateParamByNameImmediate_size_not_12);
+
+struct DestroyParam {
+ typedef DestroyParam ValueType;
+ static const CommandId kCmdId = kDestroyParam;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _param_id) {
+ SetHeader();
+ param_id = _param_id;
+ }
+
+ static void* Set(void* cmd, ResourceId param_id) {
+ static_cast<ValueType*>(cmd)->Init(param_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId param_id;
+};
+
+COMPILE_ASSERT(sizeof(DestroyParam) == 8, Sizeof_DestroyParam_is_not_8);
+COMPILE_ASSERT(offsetof(DestroyParam, header) == 0,
+ OffsetOf_DestroyParam_header_not_0);
+COMPILE_ASSERT(offsetof(DestroyParam, param_id) == 4,
+ OffsetOf_DestroyParam_param_id_not_4);
+
+struct SetParamData {
+ typedef SetParamData ValueType;
+ static const CommandId kCmdId = kSetParamData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _param_id, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ param_id = _param_id;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId param_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(param_id, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId param_id;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(SetParamData) == 20, Sizeof_SetParamData_is_not_20);
+COMPILE_ASSERT(offsetof(SetParamData, header) == 0,
+ OffsetOf_SetParamData_header_not_0);
+COMPILE_ASSERT(offsetof(SetParamData, param_id) == 4,
+ OffsetOf_SetParamData_param_id_not_4);
+COMPILE_ASSERT(offsetof(SetParamData, size) == 8,
+ OffsetOf_SetParamData_size_not_8);
+COMPILE_ASSERT(offsetof(SetParamData, shared_memory) == 12,
+ OffsetOf_SetParamData_shared_memory_not_12);
+
+struct SetParamDataImmediate {
+ typedef SetParamDataImmediate ValueType;
+ static const CommandId kCmdId = kSetParamDataImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ void SetHeader(uint32 size) {
+ header.SetCmdBySize<ValueType>(size);
+ }
+
+ void Init(ResourceId _param_id, uint32 _size, const void* data) {
+ SetHeader(_size);
+ param_id = _param_id;
+ size = _size;
+ memcpy(ImmediateDataAddress(this), data, _size);
+ }
+
+ static void* Set(void* cmd, ResourceId param_id,
+ uint32 size, const void* data) {
+ static_cast<ValueType*>(cmd)->Init(param_id, size, data);
+ return NextImmediateCmdAddress<ValueType>(cmd, size);
+ }
+
+ CommandHeader header;
+ ResourceId param_id;
+ uint32 size;
+};
+
+COMPILE_ASSERT(sizeof(SetParamDataImmediate) == 12,
+ Sizeof_SetParamDataImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(SetParamDataImmediate, header) == 0,
+ OffsetOf_SetParamDataImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(SetParamDataImmediate, param_id) == 4,
+ OffsetOf_SetParamDataImmediate_param_id_not_4);
+COMPILE_ASSERT(offsetof(SetParamDataImmediate, size) == 8,
+ OffsetOf_SetParamDataImmediate_size_not_8);
+
+struct GetParamDesc {
+ typedef GetParamDesc ValueType;
+ static const CommandId kCmdId = kGetParamDesc;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _param_id, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ param_id = _param_id;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId param_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(param_id, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId param_id;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(GetParamDesc) == 20, Sizeof_GetParamDesc_is_not_20);
+COMPILE_ASSERT(offsetof(GetParamDesc, header) == 0,
+ OffsetOf_GetParamDesc_header_not_0);
+COMPILE_ASSERT(offsetof(GetParamDesc, param_id) == 4,
+ OffsetOf_GetParamDesc_id_not_4);
+COMPILE_ASSERT(offsetof(GetParamDesc, size) == 8,
+ OffsetOf_GetParamDesc_size_not_8);
+COMPILE_ASSERT(offsetof(GetParamDesc, shared_memory) == 12,
+ OffsetOf_GetParamDesc_shared_memory_not_12);
+
+struct GetStreamCount {
+ typedef GetStreamCount ValueType;
+ static const CommandId kCmdId = kGetStreamCount;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _effect_id, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ effect_id = _effect_id;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId effect_id, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(effect_id, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId effect_id;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(GetStreamCount) == 20,
+ Sizeof_GetStreamCount_is_not_20);
+COMPILE_ASSERT(offsetof(GetStreamCount, header) == 0,
+ OffsetOf_GetStreamCount_header_not_0);
+COMPILE_ASSERT(offsetof(GetStreamCount, effect_id) == 4,
+ OffsetOf_GetStreamCount_effect_id_not_4);
+COMPILE_ASSERT(offsetof(GetStreamCount, size) == 8,
+ OffsetOf_GetStreamCount_size_not_8);
+COMPILE_ASSERT(offsetof(GetStreamCount, shared_memory) == 12,
+ OffsetOf_GetStreamCount_shared_memory_not_12);
+
+struct GetStreamDesc {
+ typedef GetStreamDesc ValueType;
+ static const CommandId kCmdId = kGetStreamDesc;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _effect_id, uint32 _index, uint32 _size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ SetHeader();
+ effect_id = _effect_id;
+ index = _index;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(void* cmd, ResourceId effect_id, uint32 index, uint32 size,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(effect_id, index, size,
+ shared_memory_id, shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId effect_id;
+ uint32 index;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(GetStreamDesc) == 24, Sizeof_GetStreamDesc_is_not_24);
+COMPILE_ASSERT(offsetof(GetStreamDesc, header) == 0,
+ OffsetOf_GetStreamDesc_header_not_0);
+COMPILE_ASSERT(offsetof(GetStreamDesc, effect_id) ==4 ,
+ OffsetOf_GetStreamDesc_effect_id_not_4);
+COMPILE_ASSERT(offsetof(GetStreamDesc, index) == 8,
+ OffsetOf_GetStreamDesc_index_not_8);
+COMPILE_ASSERT(offsetof(GetStreamDesc, size) == 12,
+ OffsetOf_GetStreamDesc_size_not_12);
+COMPILE_ASSERT(offsetof(GetStreamDesc, shared_memory) == 16,
+ OffsetOf_GetStreamDesc_shared_memory_not_16);
+
+struct DestroyTexture {
+ typedef DestroyTexture ValueType;
+ static const CommandId kCmdId = kDestroyTexture;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _texture_id) {
+ SetHeader();
+ texture_id = _texture_id;
+ }
+
+ static void* Set(void* cmd, ResourceId texture_id) {
+ static_cast<ValueType*>(cmd)->Init(texture_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId texture_id;
+};
+
+COMPILE_ASSERT(sizeof(DestroyTexture) == 8, Sizeof_DestroyTexture_is_not_8);
+COMPILE_ASSERT(offsetof(DestroyTexture, header) == 0,
+ OffsetOf_DestroyTexture_header_not_0);
+COMPILE_ASSERT(offsetof(DestroyTexture, texture_id) == 4,
+ OffsetOf_DestroyTexture_texture_id_not_4);
+
+struct CreateTexture2d {
+ typedef CreateTexture2d ValueType;
+ static const CommandId kCmdId = kCreateTexture2d;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 1
+ typedef BitField<0, 16> Width;
+ typedef BitField<16, 16> Height;
+ // argument 2
+ typedef BitField<0, 4> Levels;
+ typedef BitField<4, 4> Unused;
+ typedef BitField<8, 8> Format;
+ typedef BitField<16, 16> Flags;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _texture_id,
+ uint32 _width, uint32 _height, uint32 _levels,
+ texture::Format _format,
+ bool _enable_render_surfaces) {
+ SetHeader();
+ texture_id = _texture_id;
+ width_height = Width::MakeValue(_width) | Height::MakeValue(_height);
+ levels_format_flags =
+ Levels::MakeValue(_levels) |
+ Format::MakeValue(_format) |
+ Flags::MakeValue(_enable_render_surfaces ? 1 : 0);
+ }
+
+ static void* Set(void* cmd, ResourceId texture_id,
+ uint32 width, uint32 height, uint32 levels,
+ texture::Format format,
+ bool enable_render_surfaces) {
+ static_cast<ValueType*>(cmd)->Init(texture_id,
+ width, height, levels, format,
+ enable_render_surfaces);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ ResourceId texture_id;
+ uint32 width_height;
+ uint32 levels_format_flags;
+};
+
+COMPILE_ASSERT(sizeof(CreateTexture2d) == 16,
+ Sizeof_CreateTexture2d_is_not_16);
+COMPILE_ASSERT(offsetof(CreateTexture2d, header) == 0,
+ OffsetOf_CreateTexture2d_header_not_0);
+COMPILE_ASSERT(offsetof(CreateTexture2d, texture_id) == 4,
+ OffsetOf_CreateTexture2d_texture_id_not_4);
+COMPILE_ASSERT(offsetof(CreateTexture2d, width_height) == 8,
+ OffsetOf_CreateTexture2d_width_height_not_8);
+COMPILE_ASSERT(offsetof(CreateTexture2d, levels_format_flags) == 12,
+ OffsetOf_CreateTexture2d_levels_format_flags_not_12);
+
+struct CreateTexture3d {
+ typedef CreateTexture3d ValueType;
+ static const CommandId kCmdId = kCreateTexture3d;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 1
+ typedef BitField<0, 16> Width;
+ typedef BitField<16, 16> Height;
+ // argument 2
+ typedef BitField<0, 16> Depth;
+ typedef BitField<16, 16> Unused1;
+ // argument 3
+ typedef BitField<0, 4> Levels;
+ typedef BitField<4, 4> Unused2;
+ typedef BitField<8, 8> Format;
+ typedef BitField<16, 16> Flags;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _texture_id,
+ uint32 _width, uint32 _height, uint32 _depth,
+ uint32 _levels, texture::Format _format,
+ bool _enable_render_surfaces) {
+ SetHeader();
+ texture_id = _texture_id;
+ width_height = Width::MakeValue(_width) | Height::MakeValue(_height);
+ depth_unused = Depth::MakeValue(_depth);
+ levels_format_flags =
+ Levels::MakeValue(_levels) |
+ Format::MakeValue(_format) |
+ Flags::MakeValue(_enable_render_surfaces ? 1 : 0);
+ }
+
+ static void* Set(void* cmd, ResourceId texture_id,
+ uint32 width, uint32 height, uint32 depth,
+ uint32 levels, texture::Format format,
+ bool enable_render_surfaces) {
+ static_cast<ValueType*>(cmd)->Init(texture_id,
+ width, height, depth,
+ levels, format,
+ enable_render_surfaces);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ ResourceId texture_id;
+ uint32 width_height;
+ uint32 depth_unused;
+ uint32 levels_format_flags;
+};
+
+COMPILE_ASSERT(sizeof(CreateTexture3d) == 20,
+ Sizeof_CreateTexture3d_is_not_20);
+COMPILE_ASSERT(offsetof(CreateTexture3d, header) == 0,
+ OffsetOf_CreateTexture3d_header_not_0);
+COMPILE_ASSERT(offsetof(CreateTexture3d, texture_id) == 4,
+ OffsetOf_CreateTexture3d_texture_id_not_4);
+COMPILE_ASSERT(offsetof(CreateTexture3d, width_height) == 8,
+ OffsetOf_CreateTexture3d_width_height_not_8);
+COMPILE_ASSERT(offsetof(CreateTexture3d, depth_unused) == 12,
+ OffsetOf_CreateTexture3d_depth_unused_not_12);
+COMPILE_ASSERT(offsetof(CreateTexture3d, levels_format_flags) == 16,
+ OffsetOf_CreateTexture3d_levels_format_flags_not_16);
+
+struct CreateTextureCube {
+ typedef CreateTextureCube ValueType;
+ static const CommandId kCmdId = kCreateTextureCube;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 1
+ typedef BitField<0, 16> Side;
+ typedef BitField<16, 16> Unused1;
+ // argument 2
+ typedef BitField<0, 4> Levels;
+ typedef BitField<4, 4> Unused2;
+ typedef BitField<8, 8> Format;
+ typedef BitField<16, 16> Flags;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _texture_id,
+ uint32 _edge_length, uint32 _levels, texture::Format _format,
+ bool _enable_render_surfaces) {
+ SetHeader();
+ texture_id = _texture_id;
+ edge_length = _edge_length;
+ levels_format_flags =
+ Levels::MakeValue(_levels) |
+ Format::MakeValue(_format) |
+ Flags::MakeValue(_enable_render_surfaces ? 1 : 0);
+ }
+
+ static void* Set(void* cmd, ResourceId texture_id,
+ uint32 edge_length, uint32 levels, texture::Format format,
+ bool enable_render_surfaces) {
+ static_cast<ValueType*>(cmd)->Init(texture_id,
+ edge_length, levels, format,
+ enable_render_surfaces);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ ResourceId texture_id;
+ uint32 edge_length;
+ uint32 levels_format_flags;
+};
+
+COMPILE_ASSERT(sizeof(CreateTextureCube) == 16,
+ Sizeof_CreateTextureCube_is_not_16);
+COMPILE_ASSERT(offsetof(CreateTextureCube, header) == 0,
+ OffsetOf_CreateTextureCube_header_not_0);
+COMPILE_ASSERT(offsetof(CreateTextureCube, texture_id) == 4,
+ OffsetOf_CreateTextureCube_texture_id_not_4);
+COMPILE_ASSERT(offsetof(CreateTextureCube, edge_length) == 8,
+ OffsetOf_CreateTextureCube_edge_length_not_8);
+COMPILE_ASSERT(offsetof(CreateTextureCube, levels_format_flags) == 12,
+ OffsetOf_CreateTextureCube_levels_format_flags_not_12);
+
+struct SetTextureData {
+ typedef SetTextureData ValueType;
+ static const CommandId kCmdId = kSetTextureData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 1
+ typedef BitField<0, 16> X;
+ typedef BitField<16, 16> Y;
+ // argument 2
+ typedef BitField<0, 16> Width;
+ typedef BitField<16, 16> Height;
+ // argument 3
+ typedef BitField<0, 16> Z;
+ typedef BitField<16, 16> Depth;
+ // argument 4
+ typedef BitField<0, 4> Level;
+ typedef BitField<4, 3> Face;
+ typedef BitField<7, 25> Unused;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ ResourceId _texture_id,
+ uint32 _x,
+ uint32 _y,
+ uint32 _z,
+ uint32 _width,
+ uint32 _height,
+ uint32 _depth,
+ uint32 _level,
+ texture::Face _face,
+ uint32 _row_pitch,
+ uint32 _slice_pitch,
+ uint32 _size,
+ uint32 shared_memory_id,
+ uint32 shared_memory_offset) {
+ SetHeader();
+ texture_id = _texture_id;
+ x_y = X::MakeValue(_x) | Y::MakeValue(_y);
+ width_height = Width::MakeValue(_width) | Height::MakeValue(_height);
+ z_depth = Z::MakeValue(_z) | Depth::MakeValue(_depth);
+ level_face = Level::MakeValue(_level) | Face::MakeValue(_face);
+ row_pitch = _row_pitch;
+ slice_pitch = _slice_pitch;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(
+ void* cmd,
+ ResourceId texture_id,
+ uint32 x,
+ uint32 y,
+ uint32 z,
+ uint32 width,
+ uint32 height,
+ uint32 depth,
+ uint32 level,
+ texture::Face face,
+ uint32 row_pitch,
+ uint32 slice_pitch,
+ uint32 size,
+ uint32 shared_memory_id,
+ uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(
+ texture_id,
+ x,
+ y,
+ z,
+ width,
+ height,
+ depth,
+ level,
+ face,
+ row_pitch,
+ slice_pitch,
+ size,
+ shared_memory_id,
+ shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ ResourceId texture_id;
+ uint32 x_y;
+ uint32 width_height;
+ uint32 z_depth;
+ uint32 level_face;
+ uint32 row_pitch;
+ uint32 slice_pitch;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(SetTextureData) == 44,
+ Sizeof_SetTextureData_is_not_44);
+COMPILE_ASSERT(offsetof(SetTextureData, header) == 0,
+ OffsetOf_SetTextureData_header_not_0);
+COMPILE_ASSERT(offsetof(SetTextureData, texture_id) == 4,
+ OffsetOf_SetTextureData_texture_id_not_4);
+COMPILE_ASSERT(offsetof(SetTextureData, x_y) == 8,
+ OffsetOf_SetTextureData_x_y_not_8);
+COMPILE_ASSERT(offsetof(SetTextureData, width_height) == 12,
+ OffsetOf_SetTextureData_width_height_not_12);
+COMPILE_ASSERT(offsetof(SetTextureData, z_depth) == 16,
+ OffsetOf_SetTextureData_z_depth_not_16);
+COMPILE_ASSERT(offsetof(SetTextureData, level_face) == 20,
+ OffsetOf_SetTextureData_level_face_not_20);
+COMPILE_ASSERT(offsetof(SetTextureData, row_pitch) == 24,
+ OffsetOf_SetTextureData_row_pitch_not_24);
+COMPILE_ASSERT(offsetof(SetTextureData, slice_pitch) == 28,
+ OffsetOf_SetTextureData_slice_pitch_not_28);
+COMPILE_ASSERT(offsetof(SetTextureData, size) == 32,
+ OffsetOf_SetTextureData_size_not_32);
+COMPILE_ASSERT(offsetof(SetTextureData, shared_memory) == 36,
+ OffsetOf_SetTextureData_shared_memory_not_36);
+
+struct SetTextureDataImmediate {
+ typedef SetTextureDataImmediate ValueType;
+ static const CommandId kCmdId = kSetTextureDataImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ // argument 1
+ typedef BitField<0, 16> X;
+ typedef BitField<16, 16> Y;
+ // argument 2
+ typedef BitField<0, 16> Width;
+ typedef BitField<16, 16> Height;
+ // argument 3
+ typedef BitField<0, 16> Z;
+ typedef BitField<16, 16> Depth;
+ // argument 4
+ typedef BitField<0, 4> Level;
+ typedef BitField<4, 3> Face;
+ typedef BitField<7, 25> Unused;
+
+ void SetHeader(uint32 size) {
+ header.SetCmdBySize<ValueType>(size);
+ }
+
+ void Init(
+ ResourceId _texture_id,
+ uint32 _x,
+ uint32 _y,
+ uint32 _z,
+ uint32 _width,
+ uint32 _height,
+ uint32 _depth,
+ uint32 _level,
+ texture::Face _face,
+ uint32 _row_pitch,
+ uint32 _slice_pitch,
+ uint32 _size,
+ const void* data) {
+ SetHeader(_size);
+ texture_id = _texture_id;
+ x_y = X::MakeValue(_x) | Y::MakeValue(_y);
+ width_height = Width::MakeValue(_width) | Height::MakeValue(_height);
+ z_depth = Z::MakeValue(_z) | Depth::MakeValue(_depth);
+ level_face = Level::MakeValue(_level) | Face::MakeValue(_face);
+ row_pitch = _row_pitch;
+ slice_pitch = _slice_pitch;
+ size = _size;
+ memcpy(ImmediateDataAddress(this), data, _size);
+ }
+
+ static void* Set(
+ void* cmd,
+ ResourceId texture_id,
+ uint32 x,
+ uint32 y,
+ uint32 z,
+ uint32 width,
+ uint32 height,
+ uint32 depth,
+ uint32 level,
+ texture::Face face,
+ uint32 row_pitch,
+ uint32 slice_pitch,
+ uint32 size,
+ const void* data) {
+ static_cast<ValueType*>(cmd)->Init(
+ texture_id,
+ x,
+ y,
+ z,
+ width,
+ height,
+ depth,
+ level,
+ face,
+ row_pitch,
+ slice_pitch,
+ size,
+ data);
+ return NextImmediateCmdAddress<ValueType>(cmd, size);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ ResourceId texture_id;
+ uint32 x_y;
+ uint32 width_height;
+ uint32 z_depth;
+ uint32 level_face;
+ uint32 row_pitch;
+ uint32 slice_pitch;
+ uint32 size;
+};
+
+COMPILE_ASSERT(sizeof(SetTextureDataImmediate) == 36,
+ Sizeof_SetTextureDataImmediate_is_not_36);
+COMPILE_ASSERT(offsetof(SetTextureDataImmediate, header) == 0,
+ OffsetOf_SetTextureDataImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(SetTextureDataImmediate, texture_id) == 4,
+ OffsetOf_SetTextureDataImmediate_texture_id_not_4);
+COMPILE_ASSERT(offsetof(SetTextureDataImmediate, x_y) == 8,
+ OffsetOf_SetTextureDataImmediate_x_y_not_8);
+COMPILE_ASSERT(offsetof(SetTextureDataImmediate, width_height) == 12,
+ OffsetOf_SetTextureDataImmediate_width_height_not_12);
+COMPILE_ASSERT(offsetof(SetTextureDataImmediate, z_depth) == 16,
+ OffsetOf_SetTextureDataImmediate_z_depth_not_16);
+COMPILE_ASSERT(offsetof(SetTextureDataImmediate, level_face) == 20,
+ OffsetOf_SetTextureDataImmediate_level_face_not_20);
+COMPILE_ASSERT(offsetof(SetTextureDataImmediate, row_pitch) == 24,
+ OffsetOf_SetTextureDataImmediate_row_pitch_not_24);
+COMPILE_ASSERT(offsetof(SetTextureDataImmediate, slice_pitch) == 28,
+ OffsetOf_SetTextureDataImmediate_slice_pitch_not_28);
+COMPILE_ASSERT(offsetof(SetTextureDataImmediate, size) == 32,
+ OffsetOf_SetTextureDataImmediate_size_not_32);
+
+struct GetTextureData {
+ typedef GetTextureData ValueType;
+ static const CommandId kCmdId = kGetTextureData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 1
+ typedef BitField<0, 16> X;
+ typedef BitField<16, 16> Y;
+ // argument 2
+ typedef BitField<0, 16> Width;
+ typedef BitField<16, 16> Height;
+ // argument 3
+ typedef BitField<0, 16> Z;
+ typedef BitField<16, 16> Depth;
+ // argument 4
+ typedef BitField<0, 4> Level;
+ typedef BitField<4, 3> Face;
+ typedef BitField<7, 25> Unused;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ ResourceId _texture_id,
+ uint32 _x,
+ uint32 _y,
+ uint32 _z,
+ uint32 _width,
+ uint32 _height,
+ uint32 _depth,
+ uint32 _level,
+ texture::Face _face,
+ uint32 _row_pitch,
+ uint32 _slice_pitch,
+ uint32 _size,
+ uint32 shared_memory_id,
+ uint32 shared_memory_offset) {
+ SetHeader();
+ texture_id = _texture_id;
+ x_y = X::MakeValue(_x) | Y::MakeValue(_y);
+ width_height = Width::MakeValue(_width) | Height::MakeValue(_height);
+ z_depth = Z::MakeValue(_z) | Depth::MakeValue(_depth);
+ level_face = Level::MakeValue(_level) | Face::MakeValue(_face);
+ row_pitch = _row_pitch;
+ slice_pitch = _slice_pitch;
+ size = _size;
+ shared_memory.Init(shared_memory_id, shared_memory_offset);
+ }
+
+ static void* Set(
+ void* cmd,
+ ResourceId texture_id,
+ uint32 x,
+ uint32 y,
+ uint32 z,
+ uint32 width,
+ uint32 height,
+ uint32 depth,
+ uint32 level,
+ texture::Face face,
+ uint32 row_pitch,
+ uint32 slice_pitch,
+ uint32 size,
+ uint32 shared_memory_id,
+ uint32 shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(
+ texture_id,
+ x,
+ y,
+ z,
+ width,
+ height,
+ depth,
+ level,
+ face,
+ row_pitch,
+ slice_pitch,
+ size,
+ shared_memory_id,
+ shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ ResourceId texture_id;
+ uint32 x_y;
+ uint32 width_height;
+ uint32 z_depth;
+ uint32 level_face;
+ uint32 row_pitch;
+ uint32 slice_pitch;
+ uint32 size;
+ SharedMemory shared_memory;
+};
+
+COMPILE_ASSERT(sizeof(GetTextureData) == 44,
+ Sizeof_GetTextureData_is_not_44);
+COMPILE_ASSERT(offsetof(GetTextureData, header) == 0,
+ OffsetOf_GetTextureData_header_not_0);
+COMPILE_ASSERT(offsetof(GetTextureData, texture_id) == 4,
+ OffsetOf_GetTextureData_texture_id_not_4);
+COMPILE_ASSERT(offsetof(GetTextureData, x_y) == 8,
+ OffsetOf_GetTextureData_x_y_not_8);
+COMPILE_ASSERT(offsetof(GetTextureData, width_height) == 12,
+ OffsetOf_GetTextureData_width_height_not_12);
+COMPILE_ASSERT(offsetof(GetTextureData, z_depth) == 16,
+ OffsetOf_GetTextureData_z_depth_not_16);
+COMPILE_ASSERT(offsetof(GetTextureData, level_face) == 20,
+ OffsetOf_GetTextureData_level_face_not_20);
+COMPILE_ASSERT(offsetof(GetTextureData, row_pitch) == 24,
+ OffsetOf_GetTextureData_row_pitch_not_24);
+COMPILE_ASSERT(offsetof(GetTextureData, slice_pitch) == 28,
+ OffsetOf_GetTextureData_slice_pitch_not_28);
+COMPILE_ASSERT(offsetof(GetTextureData, size) == 32,
+ OffsetOf_GetTextureData_size_not_32);
+COMPILE_ASSERT(offsetof(GetTextureData, shared_memory) == 36,
+ OffsetOf_GetTextureData_shared_memory_not_36);
+
+struct CreateSampler {
+ typedef CreateSampler ValueType;
+ static const CommandId kCmdId = kCreateSampler;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _sampler_id) {
+ SetHeader();
+ sampler_id = _sampler_id;
+ }
+
+ static void* Set(void* cmd, ResourceId sampler_id) {
+ static_cast<ValueType*>(cmd)->Init(sampler_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId sampler_id;
+};
+
+COMPILE_ASSERT(sizeof(CreateSampler) == 8, Sizeof_CreateSampler_is_not_8);
+COMPILE_ASSERT(offsetof(CreateSampler, header) == 0,
+ OffsetOf_CreateSampler_header_not_0);
+COMPILE_ASSERT(offsetof(CreateSampler, sampler_id) == 4,
+ OffsetOf_CreateSampler_sampler_id_not_4);
+
+struct DestroySampler {
+ typedef DestroySampler ValueType;
+ static const CommandId kCmdId = kDestroySampler;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _sampler_id) {
+ SetHeader();
+ sampler_id = _sampler_id;
+ }
+
+ static void* Set(void* cmd, ResourceId sampler_id) {
+ static_cast<ValueType*>(cmd)->Init(sampler_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId sampler_id;
+};
+
+COMPILE_ASSERT(sizeof(DestroySampler) == 8, Sizeof_DestroySampler_is_not_8);
+COMPILE_ASSERT(offsetof(DestroySampler, header) == 0,
+ OffsetOf_DestroySampler_header_not_0);
+COMPILE_ASSERT(offsetof(DestroySampler, sampler_id) == 4,
+ OffsetOf_DestroySampler_sampler_id_not_4);
+
+struct SetSamplerStates {
+ typedef SetSamplerStates ValueType;
+ static const CommandId kCmdId = kSetSamplerStates;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 2
+ typedef BitField<0, 3> AddressingU;
+ typedef BitField<3, 3> AddressingV;
+ typedef BitField<6, 3> AddressingW;
+ typedef BitField<9, 3> MagFilter;
+ typedef BitField<12, 3> MinFilter;
+ typedef BitField<15, 3> MipFilter;
+ typedef BitField<18, 6> Unused;
+ typedef BitField<24, 8> MaxAnisotropy;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ ResourceId _sampler_id,
+ sampler::AddressingMode _address_u_value,
+ sampler::AddressingMode _address_v_value,
+ sampler::AddressingMode _address_w_value,
+ sampler::FilteringMode _mag_filter_value,
+ sampler::FilteringMode _min_filter_value,
+ sampler::FilteringMode _mip_filter_value,
+ uint8 _max_anisotropy) {
+ SetHeader();
+ sampler_id = _sampler_id;
+ sampler_states =
+ AddressingU::MakeValue(_address_u_value) |
+ AddressingV::MakeValue(_address_v_value) |
+ AddressingW::MakeValue(_address_w_value) |
+ MagFilter::MakeValue(_mag_filter_value) |
+ MinFilter::MakeValue(_min_filter_value) |
+ MipFilter::MakeValue(_mip_filter_value) |
+ MaxAnisotropy::MakeValue(_max_anisotropy);
+ }
+
+ static void* Set(void* cmd,
+ ResourceId sampler_id,
+ sampler::AddressingMode address_u_value,
+ sampler::AddressingMode address_v_value,
+ sampler::AddressingMode address_w_value,
+ sampler::FilteringMode mag_filter_value,
+ sampler::FilteringMode min_filter_value,
+ sampler::FilteringMode mip_filter_value,
+ uint8 max_anisotropy) {
+ static_cast<ValueType*>(cmd)->Init(
+ sampler_id,
+ address_u_value,
+ address_v_value,
+ address_w_value,
+ mag_filter_value,
+ min_filter_value,
+ mip_filter_value,
+ max_anisotropy);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ ResourceId sampler_id;
+ uint32 sampler_states;
+};
+
+COMPILE_ASSERT(sizeof(SetSamplerStates) == 12,
+ Sizeof_SetSamplerStates_is_not_12);
+COMPILE_ASSERT(offsetof(SetSamplerStates, header) == 0,
+ OffsetOf_SetSamplerStates_header_not_0);
+COMPILE_ASSERT(offsetof(SetSamplerStates, sampler_id) == 4,
+ OffsetOf_SetSamplerStates_sampler_id_not_4);
+COMPILE_ASSERT(offsetof(SetSamplerStates, sampler_states) == 8,
+ OffsetOf_SetSamplerStates_sampler_states_not_8);
+
+struct SetSamplerBorderColor {
+ typedef SetSamplerBorderColor ValueType;
+ static const CommandId kCmdId = kSetSamplerBorderColor;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _sampler_id,
+ float _red, float _green, float _blue, float _alpha) {
+ SetHeader();
+ sampler_id = _sampler_id;
+ red = _red;
+ green = _green;
+ blue = _blue;
+ alpha = _alpha;
+ }
+
+ static void* Set(void* cmd, ResourceId sampler_id,
+ float red, float green, float blue, float alpha) {
+ static_cast<ValueType*>(cmd)->Init(sampler_id, red, green, blue, alpha);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId sampler_id;
+ float red;
+ float blue;
+ float green;
+ float alpha;
+};
+
+COMPILE_ASSERT(sizeof(SetSamplerBorderColor) == 24,
+ Sizeof_SetSamplerBorderColor_is_not_24);
+COMPILE_ASSERT(offsetof(SetSamplerBorderColor, header) == 0,
+ OffsetOf_SetSamplerBorderColor_header_not_0);
+COMPILE_ASSERT(offsetof(SetSamplerBorderColor, sampler_id) == 4,
+ OffsetOf_SetSamplerBorderColor_sampler_id_not_4);
+COMPILE_ASSERT(offsetof(SetSamplerBorderColor, red) == 8,
+ OffsetOf_SetSamplerBorderColor_red_not_8);
+COMPILE_ASSERT(offsetof(SetSamplerBorderColor, blue) == 12,
+ OffsetOf_SetSamplerBorderColor_blue_not_12);
+COMPILE_ASSERT(offsetof(SetSamplerBorderColor, green) == 16,
+ OffsetOf_SetSamplerBorderColor_green_not_16);
+COMPILE_ASSERT(offsetof(SetSamplerBorderColor, alpha) == 20,
+ OffsetOf_SetSamplerBorderColor_alpha_not_20);
+
+struct SetSamplerTexture {
+ typedef SetSamplerTexture ValueType;
+ static const CommandId kCmdId = kSetSamplerTexture;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _sampler_id, ResourceId _texture_id) {
+ SetHeader();
+ sampler_id = _sampler_id;
+ texture_id = _texture_id;
+ }
+
+ static void* Set(void* cmd, ResourceId sampler_id, ResourceId texture_id) {
+ static_cast<ValueType*>(cmd)->Init(sampler_id, texture_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId sampler_id;
+ ResourceId texture_id;
+};
+
+COMPILE_ASSERT(sizeof(SetSamplerTexture) == 12,
+ Sizeof_SetSamplerTexture_is_not_12);
+COMPILE_ASSERT(offsetof(SetSamplerTexture, header) == 0,
+ OffsetOf_SetSamplerTexture_header_not_0);
+COMPILE_ASSERT(offsetof(SetSamplerTexture, sampler_id) == 4,
+ OffsetOf_SetSamplerTexture_sampler_id_not_4);
+COMPILE_ASSERT(offsetof(SetSamplerTexture, texture_id) == 8,
+ OffsetOf_SetSamplerTexture_texture_id_not_8);
+
+struct SetScissor {
+ typedef SetScissor ValueType;
+ static const CommandId kCmdId = kSetScissor;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 0
+ typedef BitField<0, 15> X;
+ typedef BitField<15, 1> Unused;
+ typedef BitField<16, 15> Y;
+ typedef BitField<31, 1> Enable;
+ // argument 1
+ typedef BitField<0, 16> Width;
+ typedef BitField<16, 16> Height;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _x,
+ uint32 _y,
+ uint32 _width,
+ uint32 _height,
+ bool _enable) {
+ SetHeader();
+ x_y_enable =
+ X::MakeValue(_x) |
+ Y::MakeValue(_y) |
+ Enable::MakeValue(_enable ? 1 : 0);
+ width_height = Width::MakeValue(_width) | Height::MakeValue(_height);
+ }
+
+ static void* Set(
+ void* cmd,
+ uint32 x,
+ uint32 y,
+ uint32 width,
+ uint32 height,
+ bool enable) {
+ static_cast<ValueType*>(cmd)->Init(
+ x,
+ y,
+ width,
+ height,
+ enable);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ uint32 x_y_enable;
+ uint32 width_height;
+};
+
+COMPILE_ASSERT(sizeof(SetScissor) == 12, Sizeof_SetScissor_is_not_12);
+COMPILE_ASSERT(offsetof(SetScissor, header) == 0,
+ OffsetOf_SetScissor_header_not_0);
+COMPILE_ASSERT(offsetof(SetScissor, x_y_enable) == 4,
+ OffsetOf_SetScissor_x_y_enable_not_4);
+COMPILE_ASSERT(offsetof(SetScissor, width_height) == 8,
+ OffsetOf_SetScissor_width_height_not_8);
+
+struct SetPolygonOffset {
+ typedef SetPolygonOffset ValueType;
+ static const CommandId kCmdId = kSetPolygonOffset;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(float _slope_factor, float _units) {
+ SetHeader();
+ slope_factor = _slope_factor;
+ units = _units;
+ }
+
+ static void* Set(void* cmd, float slope_factor, float units) {
+ static_cast<ValueType*>(cmd)->Init(slope_factor, units);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ float slope_factor;
+ float units;
+};
+
+COMPILE_ASSERT(sizeof(SetPolygonOffset) == 12,
+ Sizeof_SetPolygonOffset_is_not_12);
+COMPILE_ASSERT(offsetof(SetPolygonOffset, header) == 0,
+ OffsetOf_SetPolygonOffset_header_not_0);
+COMPILE_ASSERT(offsetof(SetPolygonOffset, slope_factor) == 4,
+ OffsetOf_SetPolygonOffset_slope_factor_not_4);
+COMPILE_ASSERT(offsetof(SetPolygonOffset, units) == 8,
+ OffsetOf_SetPolygonOffset_units_not_8);
+
+struct SetPointLineRaster {
+ typedef SetPointLineRaster ValueType;
+ static const CommandId kCmdId = kSetPointLineRaster;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 0
+ typedef BitField<0, 1> LineSmoothEnable;
+ typedef BitField<1, 1> PointSpriteEnable;
+ typedef BitField<2, 30> Unused;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(bool _line_smooth_enable, bool _point_sprite_enable,
+ float _point_size) {
+ SetHeader();
+ enables =
+ LineSmoothEnable::MakeValue(_line_smooth_enable ? 1 : 0) |
+ PointSpriteEnable::MakeValue(_point_sprite_enable ? 1 : 0);
+ point_size = _point_size;
+ }
+
+ static void* Set(void* cmd, bool line_smooth_enable, bool point_sprite_enable,
+ float point_size) {
+ static_cast<ValueType*>(cmd)->Init(line_smooth_enable, point_sprite_enable,
+ point_size);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ uint32 enables;
+ float point_size;
+};
+
+COMPILE_ASSERT(sizeof(SetPointLineRaster) == 12,
+ Sizeof_SetPointLineRaster_is_not_12);
+COMPILE_ASSERT(offsetof(SetPointLineRaster, header) == 0,
+ OffsetOf_SetPointLineRaster_header_not_0);
+COMPILE_ASSERT(offsetof(SetPointLineRaster, enables) == 4,
+ OffsetOf_SetPointLineRaster_enables_not_4);
+COMPILE_ASSERT(offsetof(SetPointLineRaster, point_size) == 8,
+ OffsetOf_SetPointLineRaster_point_size_not_8);
+
+struct SetPolygonRaster {
+ typedef SetPolygonRaster ValueType;
+ static const CommandId kCmdId = kSetPolygonRaster;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 0
+ typedef BitField<0, 2> FillMode;
+ typedef BitField<2, 2> CullMode;
+ typedef BitField<4, 28> Unused;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(PolygonMode _fill_mode, FaceCullMode _cull_mode) {
+ SetHeader();
+ fill_cull = FillMode::MakeValue(_fill_mode) |
+ CullMode::MakeValue(_cull_mode);
+ }
+
+ static void* Set(void* cmd, PolygonMode fill_mode, FaceCullMode cull_mode) {
+ static_cast<ValueType*>(cmd)->Init(fill_mode, cull_mode);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ uint32 fill_cull;
+};
+
+COMPILE_ASSERT(sizeof(SetPolygonRaster) == 8,
+ Sizeof_SetPolygonRaster_is_not_8);
+COMPILE_ASSERT(offsetof(SetPolygonRaster, header) == 0,
+ OffsetOf_SetPolygonRaster_header_not_0);
+COMPILE_ASSERT(offsetof(SetPolygonRaster, fill_cull) == 4,
+ OffsetOf_SetPolygonRaster_fill_cull_not_4);
+
+struct SetAlphaTest {
+ typedef SetAlphaTest ValueType;
+ static const CommandId kCmdId = kSetAlphaTest;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 0
+ typedef BitField<0, 3> Func;
+ typedef BitField<3, 28> Unused;
+ typedef BitField<31, 1> Enable;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(Comparison _func, bool _enable, float _value) {
+ SetHeader();
+ func_enable = Func::MakeValue(_func) | Enable::MakeValue(_enable ? 1 : 0);
+ value = _value;
+ }
+
+ static void* Set(void* cmd, Comparison func, bool enable, float value) {
+ static_cast<ValueType*>(cmd)->Init(func, enable, value);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ uint32 func_enable;
+ float value;
+};
+
+COMPILE_ASSERT(sizeof(SetAlphaTest) == 12, Sizeof_SetAlphaTest_is_not_12);
+COMPILE_ASSERT(offsetof(SetAlphaTest, header) == 0,
+ OffsetOf_SetAlphaTest_header_not_0);
+COMPILE_ASSERT(offsetof(SetAlphaTest, func_enable) == 4,
+ OffsetOf_SetAlphaTest_func_enable_not_4);
+COMPILE_ASSERT(offsetof(SetAlphaTest, value) == 8,
+ OffsetOf_SetAlphaTest_value_not_8);
+
+struct SetDepthTest {
+ typedef SetDepthTest ValueType;
+ static const CommandId kCmdId = kSetDepthTest;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 0
+ typedef BitField<0, 3> Func;
+ typedef BitField<3, 27> Unused;
+ typedef BitField<30, 1> WriteEnable;
+ typedef BitField<31, 1> Enable;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(Comparison _func, bool _write_enable, bool _enable) {
+ SetHeader();
+ func_enable =
+ Func::MakeValue(_func) |
+ WriteEnable::MakeValue(_write_enable ? 1 : 0) |
+ Enable::MakeValue(_enable ? 1 : 0);
+ }
+
+ static void* Set(void* cmd,
+ Comparison func, bool write_enable, bool enable) {
+ static_cast<ValueType*>(cmd)->Init(func, write_enable, enable);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ uint32 func_enable;
+};
+
+COMPILE_ASSERT(sizeof(SetDepthTest) == 8, Sizeof_SetDepthTest_is_not_8);
+COMPILE_ASSERT(offsetof(SetDepthTest, header) == 0,
+ OffsetOf_SetDepthTest_header_not_0);
+COMPILE_ASSERT(offsetof(SetDepthTest, func_enable) == 4,
+ OffsetOf_SetDepthTest_func_enable_not_4);
+
+struct SetStencilTest {
+ typedef SetStencilTest ValueType;
+ static const CommandId kCmdId = kSetStencilTest;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 0
+ typedef BitField<0, 8> WriteMask;
+ typedef BitField<8, 8> CompareMask;
+ typedef BitField<16, 8> ReferenceValue;
+ typedef BitField<24, 6> Unused0;
+ typedef BitField<30, 1> SeparateCCW;
+ typedef BitField<31, 1> Enable;
+ // argument 1
+ typedef BitField<0, 3> CWFunc;
+ typedef BitField<3, 3> CWPassOp;
+ typedef BitField<6, 3> CWFailOp;
+ typedef BitField<9, 3> CWZFailOp;
+ typedef BitField<12, 4> Unused1;
+ typedef BitField<16, 3> CCWFunc;
+ typedef BitField<19, 3> CCWPassOp;
+ typedef BitField<22, 3> CCWFailOp;
+ typedef BitField<25, 3> CCWZFailOp;
+ typedef BitField<28, 4> Unused2;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint8 _write_mask,
+ uint8 _compare_mask,
+ uint8 _reference_value,
+ bool _separate_ccw,
+ bool _enable,
+ Comparison _cw_func,
+ StencilOp _cw_pass_op,
+ StencilOp _cw_fail_op,
+ StencilOp _cw_z_fail_op,
+ Comparison _ccw_func,
+ StencilOp _ccw_pass_op,
+ StencilOp _ccw_fail_op,
+ StencilOp _ccw_z_fail_op) {
+ SetHeader();
+ stencil_args0 =
+ WriteMask::MakeValue(_write_mask) |
+ CompareMask::MakeValue(_compare_mask) |
+ ReferenceValue::MakeValue(_reference_value) |
+ SeparateCCW::MakeValue(_separate_ccw ? 1 : 0) |
+ Enable::MakeValue(_enable ? 1 : 0);
+ stencil_args1 =
+ CWFunc::MakeValue(_cw_func) |
+ CWPassOp::MakeValue(_cw_pass_op) |
+ CWFailOp::MakeValue(_cw_fail_op) |
+ CWZFailOp::MakeValue(_cw_z_fail_op) |
+ CCWFunc::MakeValue(_ccw_func) |
+ CCWPassOp::MakeValue(_ccw_pass_op) |
+ CCWFailOp::MakeValue(_ccw_fail_op) |
+ CCWZFailOp::MakeValue(_ccw_z_fail_op);
+ }
+
+ static void* Set(
+ void* cmd,
+ uint8 write_mask,
+ uint8 compare_mask,
+ uint8 reference_value,
+ bool separate_ccw,
+ bool enable,
+ Comparison cw_func,
+ StencilOp cw_pass_op,
+ StencilOp cw_fail_op,
+ StencilOp cw_z_fail_op,
+ Comparison ccw_func,
+ StencilOp ccw_pass_op,
+ StencilOp ccw_fail_op,
+ StencilOp ccw_z_fail_op) {
+ static_cast<ValueType*>(cmd)->Init(
+ write_mask,
+ compare_mask,
+ reference_value,
+ separate_ccw,
+ enable,
+ cw_func,
+ cw_pass_op,
+ cw_fail_op,
+ cw_z_fail_op,
+ ccw_func,
+ ccw_pass_op,
+ ccw_fail_op,
+ ccw_z_fail_op);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ uint32 stencil_args0;
+ uint32 stencil_args1;
+};
+
+COMPILE_ASSERT(sizeof(SetStencilTest) == 12,
+ Sizeof_SetStencilTest_is_not_12);
+COMPILE_ASSERT(offsetof(SetStencilTest, header) == 0,
+ OffsetOf_SetStencilTest_header_not_0);
+COMPILE_ASSERT(offsetof(SetStencilTest, stencil_args0) == 4,
+ OffsetOf_SetStencilTest_stencil_args0_not_4);
+COMPILE_ASSERT(offsetof(SetStencilTest, stencil_args1) == 8,
+ OffsetOf_SetStencilTest_stencil_args1_not_8);
+
+struct SetColorWrite {
+ typedef SetColorWrite ValueType;
+ static const CommandId kCmdId = kSetColorWrite;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 0
+ typedef BitField<0, 1> RedMask;
+ typedef BitField<1, 1> GreenMask;
+ typedef BitField<2, 1> BlueMask;
+ typedef BitField<3, 1> AlphaMask;
+ typedef BitField<0, 4> AllColorsMask; // alias for RGBA
+ typedef BitField<4, 27> Unused;
+ typedef BitField<31, 1> DitherEnable;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint8 _mask, bool _dither_enable) {
+ SetHeader();
+ flags =
+ RedMask::MakeValue((_mask | 0x01) != 0 ? 1 : 0) |
+ GreenMask::MakeValue((_mask | 0x02) != 0 ? 1 : 0) |
+ BlueMask::MakeValue((_mask | 0x02) != 0 ? 1 : 0) |
+ AlphaMask::MakeValue((_mask | 0x02) != 0 ? 1 : 0) |
+ DitherEnable::MakeValue(_dither_enable ? 1 : 0);
+ }
+
+ static void* Set(void* cmd, uint8 mask, bool dither_enable) {
+ static_cast<ValueType*>(cmd)->Init(mask, dither_enable);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 flags;
+};
+
+COMPILE_ASSERT(sizeof(SetColorWrite) == 8, Sizeof_SetColorWrite_is_not_8);
+COMPILE_ASSERT(offsetof(SetColorWrite, header) == 0,
+ OffsetOf_SetColorWrite_header_not_0);
+COMPILE_ASSERT(offsetof(SetColorWrite, flags) == 4,
+ OffsetOf_SetColorWrite_flags_not_4);
+
+struct SetBlending {
+ typedef SetBlending ValueType;
+ static const CommandId kCmdId = kSetBlending;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 0
+ typedef BitField<0, 4> ColorSrcFunc;
+ typedef BitField<4, 4> ColorDstFunc;
+ typedef BitField<8, 3> ColorEq;
+ typedef BitField<11, 5> Unused0;
+ typedef BitField<16, 4> AlphaSrcFunc;
+ typedef BitField<20, 4> AlphaDstFunc;
+ typedef BitField<24, 3> AlphaEq;
+ typedef BitField<27, 3> Unused1;
+ typedef BitField<30, 1> SeparateAlpha;
+ typedef BitField<31, 1> Enable;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ BlendFunc _color_src_func,
+ BlendFunc _color_dst_func,
+ BlendEq _color_eq,
+ BlendFunc _alpha_src_func,
+ BlendFunc _alpha_dst_func,
+ BlendEq _alpha_eq,
+ bool _separate_alpha,
+ bool _enable) {
+ SetHeader();
+ blend_settings =
+ ColorSrcFunc::MakeValue(_color_src_func) |
+ ColorDstFunc::MakeValue(_color_dst_func) |
+ ColorEq::MakeValue(_color_eq) |
+ AlphaSrcFunc::MakeValue(_alpha_src_func) |
+ AlphaDstFunc::MakeValue(_alpha_dst_func) |
+ AlphaEq::MakeValue(_alpha_eq) |
+ SeparateAlpha::MakeValue(_separate_alpha ? 1 : 0) |
+ Enable::MakeValue(_enable ? 1 : 0);
+ }
+
+ static void* Set(
+ void* cmd,
+ BlendFunc color_src_func,
+ BlendFunc color_dst_func,
+ BlendEq color_eq,
+ BlendFunc alpha_src_func,
+ BlendFunc alpha_dst_func,
+ BlendEq alpha_eq,
+ bool separate_alpha,
+ bool enable) {
+ static_cast<ValueType*>(cmd)->Init(
+ color_src_func,
+ color_dst_func,
+ color_eq,
+ alpha_src_func,
+ alpha_dst_func,
+ alpha_eq,
+ separate_alpha,
+ enable);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ uint32 blend_settings;
+};
+
+COMPILE_ASSERT(sizeof(SetBlending) == 8, Sizeof_SetBlending_is_not_8);
+COMPILE_ASSERT(offsetof(SetBlending, header) == 0,
+ OffsetOf_SetBlending_header_not_0);
+COMPILE_ASSERT(offsetof(SetBlending, blend_settings) == 4,
+ OffsetOf_SetBlending_blend_settings_not_4);
+
+struct SetBlendingColor {
+ typedef SetBlendingColor ValueType;
+ static const CommandId kCmdId = kSetBlendingColor;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(float _red, float _green, float _blue, float _alpha) {
+ SetHeader();
+ red = _red;
+ green = _green;
+ blue = _blue;
+ alpha = _alpha;
+ }
+
+ static void* Set(void* cmd,
+ float red, float green, float blue, float alpha) {
+ static_cast<ValueType*>(cmd)->Init(red, green, blue, alpha);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ float red;
+ float blue;
+ float green;
+ float alpha;
+};
+
+COMPILE_ASSERT(sizeof(SetBlendingColor) == 20,
+ Sizeof_SetBlendingColor_is_not_20);
+COMPILE_ASSERT(offsetof(SetBlendingColor, header) == 0,
+ OffsetOf_SetBlendingColor_header_not_0);
+COMPILE_ASSERT(offsetof(SetBlendingColor, red) == 4,
+ OffsetOf_SetBlendingColor_red_not_4);
+COMPILE_ASSERT(offsetof(SetBlendingColor, blue) == 8,
+ OffsetOf_SetBlendingColor_blue_not_8);
+COMPILE_ASSERT(offsetof(SetBlendingColor, green) == 12,
+ OffsetOf_SetBlendingColor_green_not_12);
+COMPILE_ASSERT(offsetof(SetBlendingColor, alpha) == 16,
+ OffsetOf_SetBlendingColor_alpha_not_16);
+
+struct CreateRenderSurface {
+ typedef CreateRenderSurface ValueType;
+ static const CommandId kCmdId = kCreateRenderSurface;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 1
+ typedef BitField<0, 16> Width;
+ typedef BitField<16, 16> Height;
+ // argument 2 may refer to side or depth
+ typedef BitField<0, 16> Levels;
+ typedef BitField<16, 16> Side;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _render_surface_id,
+ ResourceId _texture_id, uint32 _width, uint32 _height,
+ uint32 _level, uint32 _side) {
+ SetHeader();
+ render_surface_id = _render_surface_id;
+ // TODO(gman): Why does this need a width and height. It's inherited from
+ // the texture isn't it?
+ width_height = Width::MakeValue(_width) | Height::MakeValue(_height);
+ levels_side = Levels::MakeValue(_level) | Side::MakeValue(_side);
+ texture_id = _texture_id;
+ }
+
+ static void* Set(void* cmd,
+ ResourceId render_surface_id, ResourceId texture_id,
+ uint32 width, uint32 height,
+ uint32 level, uint32 side) {
+ static_cast<ValueType*>(cmd)->Init(render_surface_id, texture_id,
+ width, height,
+ level, side);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ ResourceId render_surface_id;
+ uint32 width_height;
+ uint32 levels_side;
+ ResourceId texture_id;
+};
+
+COMPILE_ASSERT(sizeof(CreateRenderSurface) == 20,
+ Sizeof_CreateRenderSurface_is_not_20);
+COMPILE_ASSERT(offsetof(CreateRenderSurface, header) == 0,
+ OffsetOf_CreateRenderSurface_header_not_0);
+COMPILE_ASSERT(offsetof(CreateRenderSurface, render_surface_id) == 4,
+ OffsetOf_CreateRenderSurface_render_surface_id_not_4);
+COMPILE_ASSERT(offsetof(CreateRenderSurface, width_height) == 8,
+ OffsetOf_CreateRenderSurface_width_height_not_8);
+COMPILE_ASSERT(offsetof(CreateRenderSurface, levels_side) == 12,
+ OffsetOf_CreateRenderSurface_levels_side_not_12);
+COMPILE_ASSERT(offsetof(CreateRenderSurface, texture_id) == 16,
+ OffsetOf_CreateRenderSurface_texture_id_not_16);
+
+struct DestroyRenderSurface {
+ typedef DestroyRenderSurface ValueType;
+ static const CommandId kCmdId = kDestroyRenderSurface;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _render_surface_id) {
+ SetHeader();
+ render_surface_id = _render_surface_id;
+ }
+
+ static void* Set(void* cmd, ResourceId render_surface_id) {
+ static_cast<ValueType*>(cmd)->Init(render_surface_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId render_surface_id;
+};
+
+COMPILE_ASSERT(sizeof(DestroyRenderSurface) == 8,
+ Sizeof_DestroyRenderSurface_is_not_8);
+COMPILE_ASSERT(offsetof(DestroyRenderSurface, header) == 0,
+ OffsetOf_DestroyRenderSurface_header_not_0);
+COMPILE_ASSERT(offsetof(DestroyRenderSurface, render_surface_id) == 4,
+ OffsetOf_DestroyRenderSurface_render_surface_id_not_4);
+
+struct CreateDepthSurface {
+ typedef CreateDepthSurface ValueType;
+ static const CommandId kCmdId = kCreateDepthSurface;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ // argument 1
+ typedef BitField<0, 16> Width;
+ typedef BitField<16, 16> Height;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _depth_surface_id, uint32 _width, uint32 _height) {
+ SetHeader();
+ depth_surface_id = _depth_surface_id;
+ width_height = Width::MakeValue(_width) | Height::MakeValue(_height);
+ }
+
+ static void* Set(void* cmd, ResourceId depth_surface_id,
+ uint32 width, uint32 height) {
+ static_cast<ValueType*>(cmd)->Init(depth_surface_id, width, height);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ // TODO(gman): fix this to not use obfusticated fields.
+ CommandHeader header;
+ ResourceId depth_surface_id;
+ uint32 width_height;
+};
+
+COMPILE_ASSERT(sizeof(CreateDepthSurface) == 12,
+ Sizeof_CreateDepthSurface_is_not_12);
+COMPILE_ASSERT(offsetof(CreateDepthSurface, header) == 0,
+ OffsetOf_CreateDepthSurface_header_not_0);
+COMPILE_ASSERT(offsetof(CreateDepthSurface, depth_surface_id) == 4,
+ OffsetOf_CreateDepthSurface_depth_surface_id_not_4);
+COMPILE_ASSERT(offsetof(CreateDepthSurface, width_height) == 8,
+ OffsetOf_CreateDepthSurface_width_height_not_8);
+
+struct DestroyDepthSurface {
+ typedef DestroyDepthSurface ValueType;
+ static const CommandId kCmdId = kDestroyDepthSurface;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _depth_surface_id) {
+ SetHeader();
+ depth_surface_id = _depth_surface_id;
+ }
+
+ static void* Set(void* cmd, ResourceId depth_surface_id) {
+ static_cast<ValueType*>(cmd)->Init(depth_surface_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId depth_surface_id;
+};
+
+COMPILE_ASSERT(sizeof(DestroyDepthSurface) == 8,
+ Sizeof_DestroyDepthSurface_is_not_8);
+COMPILE_ASSERT(offsetof(DestroyDepthSurface, header) == 0,
+ OffsetOf_DestroyDepthSurface_header_not_0);
+COMPILE_ASSERT(offsetof(DestroyDepthSurface, depth_surface_id) == 4,
+ OffsetOf_DestroyDepthdepth_surface_id_not_4);
+
+struct SetRenderSurface {
+ typedef SetRenderSurface ValueType;
+ static const CommandId kCmdId = kSetRenderSurface;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(ResourceId _render_surface_id, ResourceId _depth_surface_id) {
+ SetHeader();
+ render_surface_id = _render_surface_id;
+ depth_surface_id = _depth_surface_id;
+ }
+
+ static void* Set(void* cmd,
+ ResourceId render_surface_id, ResourceId depth_surface_id) {
+ static_cast<ValueType*>(cmd)->Init(render_surface_id, depth_surface_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ ResourceId render_surface_id;
+ ResourceId depth_surface_id;
+};
+
+COMPILE_ASSERT(sizeof(SetRenderSurface) == 12,
+ Sizeof_SetRenderSurface_is_not_12);
+COMPILE_ASSERT(offsetof(SetRenderSurface, header) == 0,
+ OffsetOf_SetRenderSurface_header_not_0);
+COMPILE_ASSERT(offsetof(SetRenderSurface, render_surface_id) == 4,
+ OffsetOf_SetRenderSurface_render_surface_id_not_4);
+COMPILE_ASSERT(offsetof(SetRenderSurface, depth_surface_id) == 8,
+ OffsetOf_SetRenderSurface_depth_surface_id_not_8);
+
+struct SetBackSurfaces {
+ typedef SetBackSurfaces ValueType;
+ static const CommandId kCmdId = kSetBackSurfaces;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init() {
+ SetHeader();
+ }
+
+ static void* Set(void* cmd) {
+ static_cast<ValueType*>(cmd)->Init();
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(SetBackSurfaces) == 4,
+ Sizeof_SetBackSurfaces_is_not_4);
+COMPILE_ASSERT(offsetof(SetBackSurfaces, header) == 0,
+ OffsetOf_SetBackSurfaces_header_not_0);
+
+#pragma pack(pop)
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_FORMAT_H_
diff --git a/o3d/gpu/command_buffer/common/resource.cc b/o3d/gpu/command_buffer/common/resource.cc
new file mode 100644
index 0000000..f3b75ec
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/resource.cc
@@ -0,0 +1,120 @@
+/*
+ * 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 implementation of the helper functions for resources.
+
+#include "gpu/command_buffer/common/resource.h"
+
+namespace command_buffer {
+
+namespace texture {
+
+// Gets the number of bytes per block for a given format.
+unsigned int GetBytesPerBlock(Format format) {
+ switch (format) {
+ case kXRGB8:
+ case kARGB8:
+ case kR32F:
+ return 4;
+ case kABGR16F:
+ return 8;
+ case kABGR32F:
+ return 16;
+ case kDXT1:
+ return 8;
+ default:
+ // TODO(petersont): Add DXT3/5 support.
+ LOG(FATAL) << "Invalid format";
+ return 1;
+ }
+}
+
+// Gets the width of a block for a given format.
+unsigned int GetBlockSizeX(Format format) {
+ switch (format) {
+ case kXRGB8:
+ case kARGB8:
+ case kABGR16F:
+ case kR32F:
+ case kABGR32F:
+ return 1;
+ case kDXT1:
+ return 4;
+ default:
+ // TODO(petersont): Add DXT3/5 support.
+ LOG(FATAL) << "Invalid format";
+ return 1;
+ }
+}
+
+// Gets the height of a block for a given format.
+unsigned int GetBlockSizeY(Format format) {
+ // NOTE: currently only supported formats use square blocks.
+ return GetBlockSizeX(format);
+}
+
+} // namespace texture
+
+namespace effect_param {
+
+// Gets the size of the data of a given parameter type.
+unsigned int GetDataSize(DataType type) {
+ switch (type) {
+ case kUnknown:
+ return 0;
+ case kFloat1:
+ return sizeof(float); // NOLINT
+ case kFloat2:
+ return sizeof(float) * 2; // NOLINT
+ case kFloat3:
+ return sizeof(float) * 3; // NOLINT
+ case kFloat4:
+ return sizeof(float) * 4; // NOLINT
+ case kMatrix4:
+ return sizeof(float) * 16; // NOLINT
+ case kInt:
+ return sizeof(int); // NOLINT
+ case kBool:
+ return sizeof(bool); // NOLINT
+ case kSampler:
+ return sizeof(ResourceId); // NOLINT
+ case kTexture:
+ return sizeof(ResourceId); // NOLINT
+ default:
+ LOG(FATAL) << "Invalid type.";
+ return 0;
+ }
+}
+
+} // namespace effect_param
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/common/resource.h b/o3d/gpu/command_buffer/common/resource.h
new file mode 100644
index 0000000..01de6a1
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/resource.h
@@ -0,0 +1,229 @@
+/*
+ * 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 definitions for resource flags, enums, and helper
+// functions.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_CROSS_RESOURCE_H_
+#define GPU_COMMAND_BUFFER_COMMON_CROSS_RESOURCE_H_
+
+#include <algorithm>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/command_buffer/common/logging.h"
+
+namespace command_buffer {
+
+// A resource ID, key to the resource maps.
+typedef uint32 ResourceId;
+// Invalid resource ID.
+static const ResourceId kInvalidResource = 0xffffffffU;
+
+namespace vertex_buffer {
+// Vertex buffer flags.
+enum Flags {
+ kNone = 0x00,
+ kDynamic = 0x01, // This vertex buffer is dynamic and is expected to have
+ // its data updated often.
+};
+} // namespace vertex_buffer
+
+namespace index_buffer {
+// Index buffer flags.
+enum Flags {
+ kNone = 0x00,
+ kDynamic = 0x01, // This index buffer is dynamic and is expected to have
+ // its data updated often.
+ kIndex32Bit = 0x02, // Indices contained in this index buffer are 32 bits
+ // (unsigned int) instead of 16 bit (unsigned short).
+};
+} // namespace index_buffer
+
+namespace vertex_struct {
+// Semantics for input data.
+enum Semantic {
+ kUnknownSemantic = -1,
+ kPosition = 0,
+ kNormal,
+ kColor,
+ kTexCoord,
+ kNumSemantics
+};
+
+// Input data types.
+enum Type {
+ kFloat1,
+ kFloat2,
+ kFloat3,
+ kFloat4,
+ kUChar4N,
+ kNumTypes
+};
+} // namespace vertex_struct
+
+namespace effect_param {
+enum DataType {
+ kUnknown, // A parameter exists in the effect, but the type is not
+ // representable (e.g. MATRIX3x4).
+ kFloat1,
+ kFloat2,
+ kFloat3,
+ kFloat4,
+ kMatrix4,
+ kInt,
+ kBool,
+ kSampler,
+ kTexture,
+ kNumTypes,
+ kMake32Bit = 0x7fffffff,
+};
+COMPILE_ASSERT(sizeof(DataType) == 4, DataType_should_be_32_bits);
+
+// Gets the size of the data of a particular type.
+unsigned int GetDataSize(DataType type);
+
+// Structure describing a parameter, filled in by the
+// GAPIInterface::GetParamDesc call.
+struct Desc {
+ Uint32 size; // the total memory size needed for the complete
+ // description.
+ Uint32 name_offset; // the offset of the parameter name, relative to
+ // the beginning of the structure. May be 0 if the
+ // name doesn't fit into the memory buffer.
+ Uint32 name_size; // the size of the parameter name, including the
+ // terminating nul character. Will always be set
+ // even if the name doesn't fit into the buffer.
+ Uint32 semantic_offset; // the offset of the parameter semantic, relative
+ // to the beginning of the structure. May be 0 if
+ // the semantic doesn't fit into the memory
+ // buffer.
+ Uint32 semantic_size; // the size of the parameter semantic, including
+ // the terminating nul character. Will always be
+ // set even if the semantic doesn't fit into the
+ // buffer.
+ Uint32 num_elements; // the number of entries if the parameter is an array
+ // 0 otherwise.
+ DataType data_type; // the data type of the parameter.
+ Uint32 data_size; // the size of the parameter data, in bytes.
+};
+} // namespace effect_param
+
+namespace effect_stream {
+struct Desc {
+ Desc()
+ : semantic(vertex_struct::kUnknownSemantic),
+ semantic_index(0) {}
+ Desc(Uint32 semantic, Uint32 semantic_index)
+ : semantic(semantic),
+ semantic_index(semantic_index) {}
+ Uint32 semantic; // the semantic type
+ Uint32 semantic_index;
+};
+} // namespace effect_stream
+
+namespace texture {
+// Texture flags.
+enum Flags {
+ kNone = 0x00,
+ kDynamic = 0x01, // This texture is dynamic and is expected to have
+ // its data updated often.
+};
+
+// Texel formats.
+enum Format {
+ kUnknown,
+ kXRGB8,
+ kARGB8,
+ kABGR16F,
+ kR32F,
+ kABGR32F,
+ kDXT1
+};
+
+// Texture type.
+enum Type {
+ kTexture2d,
+ kTexture3d,
+ kTextureCube,
+};
+
+// Cube map face.
+enum Face {
+ kFacePositiveX,
+ kFaceNegativeX,
+ kFacePositiveY,
+ kFaceNegativeY,
+ kFacePositiveZ,
+ kFaceNegativeZ,
+ kFaceNone = kFacePositiveX, // For non-cube maps.
+};
+
+// Gets the number of bytes per block for a given texture format. For most
+// texture formats, a block is 1x1 texels, but DXT* formats have 4x4 blocks.
+unsigned int GetBytesPerBlock(Format format);
+// Gets the x dimension of a texel block for a given texture format. For most
+// texture formats, a block is 1x1 texels, but DXT* formats have 4x4 blocks.
+unsigned int GetBlockSizeX(Format format);
+// Gets the y dimension of a texel block for a given texture format. For most
+// texture formats, a block is 1x1 texels, but DXT* formats have 4x4 blocks.
+unsigned int GetBlockSizeY(Format format);
+// Gets the dimension of a mipmap level given the dimension of the base
+// level. Every mipmap level is half the size of the previous level, rounding
+// down.
+inline unsigned int GetMipMapDimension(unsigned int base,
+ unsigned int level) {
+ DCHECK_GT(base, 0U);
+ return std::max(1U, base >> level);
+}
+} // namespace texture
+
+namespace sampler {
+enum AddressingMode {
+ kWrap,
+ kMirrorRepeat,
+ kClampToEdge,
+ kClampToBorder,
+ kNumAddressingMode
+};
+
+enum FilteringMode {
+ kNone,
+ kPoint,
+ kLinear,
+ kNumFilteringMode
+};
+} // namespace sampler
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_COMMON_CROSS_RESOURCE_H_
diff --git a/o3d/gpu/command_buffer/common/types.h b/o3d/gpu/command_buffer/common/types.h
new file mode 100644
index 0000000..daa01cb
--- /dev/null
+++ b/o3d/gpu/command_buffer/common/types.h
@@ -0,0 +1,60 @@
+/*
+ * 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 cross-platform basic type definitions
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_CROSS_TYPES_H_
+#define GPU_COMMAND_BUFFER_COMMON_CROSS_TYPES_H_
+
+#include <build/build_config.h>
+#if !defined(COMPILER_MSVC)
+#include <stdint.h>
+#endif
+#include <string>
+
+namespace command_buffer {
+#if defined(COMPILER_MSVC)
+typedef short Int16;
+typedef unsigned short Uint16;
+typedef int Int32;
+typedef unsigned int Uint32;
+#else
+typedef int16_t Int16;
+typedef uint16_t Uint16;
+typedef int32_t Int32;
+typedef uint32_t Uint32;
+#endif
+
+typedef std::string String;
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_COMMON_CROSS_TYPES_H_
diff --git a/o3d/gpu/command_buffer/service/big_test_main.cc b/o3d/gpu/command_buffer/service/big_test_main.cc
new file mode 100644
index 0000000..cda7d0e
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/big_test_main.cc
@@ -0,0 +1,124 @@
+/*
+ * 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 entry to the big test program, for linux.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/cross/big_test_helpers.h"
+#include "gpu/command_buffer/service/cross/gl/gapi_gl.h"
+#include "gpu/command_buffer/service/linux/x_utils.h"
+
+namespace command_buffer {
+
+String *g_program_path = NULL;
+GAPIInterface *g_gapi = NULL;
+
+bool ProcessSystemMessages() {
+ return true;
+}
+
+} // namespace command_buffer
+
+using o3d::String;
+using o3d::command_buffer::g_program_path;
+using o3d::command_buffer::g_gapi;
+using o3d::command_buffer::GAPIGL;
+using o3d::command_buffer::XWindowWrapper;
+
+
+// Creates a GL-compatible window of specified dimensions.
+Window CreateWindow(Display *display, unsigned int width, unsigned int height) {
+ int attribs[] = {
+ GLX_RGBA,
+ GLX_DOUBLEBUFFER,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ None
+ };
+ XVisualInfo *visualInfo = glXChooseVisual(display,
+ DefaultScreen(display),
+ attribs);
+ Window root_window = RootWindow(display, visualInfo->screen);
+ Colormap colorMap = XCreateColormap(display, root_window, visualInfo->visual,
+ AllocNone);
+
+ XSetWindowAttributes windowAttributes;
+ windowAttributes.colormap = colorMap;
+ windowAttributes.border_pixel = 0;
+ windowAttributes.event_mask = StructureNotifyMask;
+ Window window = XCreateWindow(display, root_window,
+ 0, 0, width, height, 0, visualInfo->depth,
+ InputOutput, visualInfo->visual,
+ CWBorderPixel|CWColormap|CWEventMask,
+ &windowAttributes);
+ if (!window) return 0;
+ XMapWindow(display, window);
+ XSync(display, True);
+ return window;
+}
+
+// Creates a window, initializes the GAPI instance.
+int main(int argc, char *argv[]) {
+ String program_path = argv[0];
+
+ // Remove all characters starting with last '/'.
+ size_t backslash_pos = program_path.rfind('/');
+ if (backslash_pos != String::npos) {
+ program_path.erase(backslash_pos);
+ }
+ g_program_path = &program_path;
+
+ GAPIGL gl_gapi;
+ g_gapi = &gl_gapi;
+
+ Display *display = XOpenDisplay(0);
+ if (!display) {
+ LOG(FATAL) << "Could not open the display.";
+ return 1;
+ }
+
+ Window window = CreateWindow(display, 300, 300);
+ if (!window) {
+ LOG(FATAL) << "Could not create a window.";
+ return 1;
+ }
+
+ XWindowWrapper wrapper(display, window);
+ gl_gapi.set_window_wrapper(&wrapper);
+
+ int ret = big_test_main(argc, argv);
+
+ g_gapi = NULL;
+ g_program_path = NULL;
+ return ret;
+}
diff --git a/o3d/gpu/command_buffer/service/cmd_buffer_engine.h b/o3d/gpu/command_buffer/service/cmd_buffer_engine.h
new file mode 100644
index 0000000..74ad649
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/cmd_buffer_engine.h
@@ -0,0 +1,70 @@
+/*
+ * 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 the CommandBufferEngine class, providing the main loop for
+// the service, exposing the RPC API, managing the command parser.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H_
+
+#include "base/basictypes.h"
+
+namespace command_buffer {
+
+class CommandBufferEngine {
+ public:
+ CommandBufferEngine() {
+ }
+
+ virtual ~CommandBufferEngine() {
+ }
+
+ // Gets the base address of a registered shared memory buffer.
+ // Parameters:
+ // shm_id: the identifier for the shared memory buffer.
+ virtual void *GetSharedMemoryAddress(int32 shm_id) = 0;
+
+ // Gets the size of a registered shared memory buffer.
+ // Parameters:
+ // shm_id: the identifier for the shared memory buffer.
+ virtual size_t GetSharedMemorySize(int32 shm_id) = 0;
+
+ // Sets the token value.
+ virtual void set_token(int32 token) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CommandBufferEngine);
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H_
diff --git a/o3d/gpu/command_buffer/service/cmd_parser.cc b/o3d/gpu/command_buffer/service/cmd_parser.cc
new file mode 100644
index 0000000..b3486ec
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/cmd_parser.cc
@@ -0,0 +1,112 @@
+/*
+ * 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 implementation of the command parser.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/cmd_parser.h"
+// TODO(gman): remove this so we can use this code for different formats.
+#include "gpu/command_buffer/common/o3d_cmd_format.h"
+
+namespace command_buffer {
+
+CommandParser::CommandParser(void *shm_address,
+ size_t shm_size,
+ ptrdiff_t offset,
+ size_t size,
+ CommandBufferOffset start_get,
+ AsyncAPIInterface *handler)
+ : get_(start_get),
+ put_(start_get),
+ handler_(handler) {
+ // check proper alignments.
+ DCHECK_EQ(0, (reinterpret_cast<intptr_t>(shm_address)) % 4);
+ DCHECK_EQ(0, offset % 4);
+ DCHECK_EQ(0u, size % 4);
+ // check that the command buffer fits into the memory buffer.
+ DCHECK_GE(shm_size, offset + size);
+ char * buffer_begin = static_cast<char *>(shm_address) + offset;
+ buffer_ = reinterpret_cast<CommandBufferEntry *>(buffer_begin);
+ entry_count_ = size / 4;
+}
+
+// Process one command, reading the header from the command buffer, and
+// forwarding the command index and the arguments to the handler.
+// Note that:
+// - validation needs to happen on a copy of the data (to avoid race
+// conditions). This function only validates the header, leaving the arguments
+// validation to the handler, so it can pass a reference to them.
+// - get_ is modified *after* the command has been executed.
+parse_error::ParseError CommandParser::ProcessCommand() {
+ CommandBufferOffset get = get_;
+ if (get == put_) return parse_error::kParseNoError;
+
+ CommandHeader header = buffer_[get].value_header;
+ if (header.size == 0) {
+ DLOG(INFO) << "Error: zero sized command in command buffer";
+ return parse_error::kParseInvalidSize;
+ }
+
+ if (header.size + get > entry_count_) {
+ DLOG(INFO) << "Error: get offset out of bounds";
+ return parse_error::kParseOutOfBounds;
+ }
+
+ parse_error::ParseError result = handler_->DoCommand(
+ header.command, header.size - 1, buffer_ + get);
+ // TODO(gman): If you want to log errors this is the best place to catch them.
+ // It seems like we need an official way to turn on a debug mode and
+ // get these errors.
+ if (result != parse_error::kParseNoError) {
+ ReportError(header.command, result);
+ }
+ get_ = (get + header.size) % entry_count_;
+ return result;
+}
+
+void CommandParser::ReportError(unsigned int command_id,
+ parse_error::ParseError result) {
+ DLOG(INFO) << "Error: " << result << " for Command "
+ << handler_->GetCommandName(command_id);
+}
+
+// Processes all the commands, while the buffer is not empty. Stop if an error
+// is encountered.
+parse_error::ParseError CommandParser::ProcessAllCommands() {
+ while (!IsEmpty()) {
+ parse_error::ParseError error = ProcessCommand();
+ if (error) return error;
+ }
+ return parse_error::kParseNoError;
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/cmd_parser.h b/o3d/gpu/command_buffer/service/cmd_parser.h
new file mode 100644
index 0000000..2209cf8
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/cmd_parser.h
@@ -0,0 +1,115 @@
+/*
+ * 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 command parser class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H_
+
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+
+namespace command_buffer {
+
+class AsyncAPIInterface;
+
+// Command parser class. This class parses commands from a shared memory
+// buffer, to implement some asynchronous RPC mechanism.
+class CommandParser {
+ public:
+ CommandParser(void *shm_address,
+ size_t shm_size,
+ ptrdiff_t offset,
+ size_t size,
+ CommandBufferOffset start_get,
+ AsyncAPIInterface *handler);
+
+ // Gets the "get" pointer. The get pointer is an index into the command
+ // buffer considered as an array of CommandBufferEntry.
+ CommandBufferOffset get() const { return get_; }
+
+ // Sets the "put" pointer. The put pointer is an index into the command
+ // buffer considered as an array of CommandBufferEntry.
+ void set_put(CommandBufferOffset put) { put_ = put; }
+
+ // Gets the "put" pointer. The put pointer is an index into the command
+ // buffer considered as an array of CommandBufferEntry.
+ CommandBufferOffset put() const { return put_; }
+
+ // Checks whether there are commands to process.
+ bool IsEmpty() const { return put_ == get_; }
+
+ // Processes one command, updating the get pointer. This will return an error
+ // if there are no commands in the buffer.
+ parse_error::ParseError ProcessCommand();
+
+ // Processes all commands until get == put.
+ parse_error::ParseError ProcessAllCommands();
+
+ // Reports an error.
+ void ReportError(unsigned int command_id, parse_error::ParseError result);
+
+ private:
+ CommandBufferOffset get_;
+ CommandBufferOffset put_;
+ CommandBufferEntry *buffer_;
+ size_t entry_count_;
+ AsyncAPIInterface *handler_;
+};
+
+// This class defines the interface for an asynchronous API handler, that
+// is responsible for de-multiplexing commands and their arguments.
+class AsyncAPIInterface {
+ public:
+ AsyncAPIInterface() {}
+ virtual ~AsyncAPIInterface() {}
+
+ // Executes a command.
+ // Parameters:
+ // command: the command index.
+ // arg_count: the number of CommandBufferEntry arguments.
+ // cmd_data: the command data.
+ // Returns:
+ // parse_error::NO_ERROR if no error was found, one of
+ // parse_error::ParseError otherwise.
+ virtual parse_error::ParseError DoCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data) = 0;
+
+ // Returns a name for a command. Useful for logging / debuging.
+ virtual const char* GetCommandName(unsigned int command_id) const = 0;
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H_
diff --git a/o3d/gpu/command_buffer/service/cmd_parser_test.cc b/o3d/gpu/command_buffer/service/cmd_parser_test.cc
new file mode 100644
index 0000000..3c9871e
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/cmd_parser_test.cc
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ */
+
+
+// Tests for the command parser.
+
+#include "gpu/command_buffer/service/precompile.h"
+
+#include "tests/common/win/testing_common.h"
+#include "gpu/command_buffer/service/cmd_parser.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "base/scoped_ptr.h"
+
+namespace command_buffer {
+
+using testing::Return;
+using testing::Mock;
+using testing::Truly;
+using testing::Sequence;
+using testing::_;
+
+// Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and
+// a fixed size memory buffer. Also provides a simple API to create a
+// CommandParser.
+class CommandParserTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ api_mock_.reset(new AsyncAPIMock);
+ buffer_entry_count_ = 20;
+ buffer_.reset(new CommandBufferEntry[buffer_entry_count_]);
+ }
+ virtual void TearDown() {}
+
+ // Adds a DoCommand expectation in the mock.
+ void AddDoCommandExpect(parse_error::ParseError _return,
+ unsigned int command,
+ unsigned int arg_count,
+ CommandBufferEntry *args) {
+ EXPECT_CALL(*api_mock(), DoCommand(command, arg_count,
+ Truly(AsyncAPIMock::IsArgs(arg_count, args))))
+ .InSequence(sequence_)
+ .WillOnce(Return(_return));
+ }
+
+ // Creates a parser, with a buffer of the specified size (in entries).
+ CommandParser *MakeParser(unsigned int entry_count) {
+ size_t shm_size = buffer_entry_count_ *
+ sizeof(CommandBufferEntry); // NOLINT
+ size_t command_buffer_size = entry_count *
+ sizeof(CommandBufferEntry); // NOLINT
+ DCHECK_LE(command_buffer_size, shm_size);
+ return new CommandParser(buffer(),
+ shm_size,
+ 0,
+ command_buffer_size,
+ 0,
+ api_mock());
+ }
+
+ unsigned int buffer_entry_count() { return 20; }
+ AsyncAPIMock *api_mock() { return api_mock_.get(); }
+ CommandBufferEntry *buffer() { return buffer_.get(); }
+ private:
+ unsigned int buffer_entry_count_;
+ scoped_ptr<AsyncAPIMock> api_mock_;
+ scoped_array<CommandBufferEntry> buffer_;
+ Sequence sequence_;
+};
+
+// Tests initialization conditions.
+TEST_F(CommandParserTest, TestInit) {
+ scoped_ptr<CommandParser> parser(MakeParser(10));
+ EXPECT_EQ(0u, parser->get());
+ EXPECT_EQ(0u, parser->put());
+ EXPECT_TRUE(parser->IsEmpty());
+}
+
+// Tests simple commands.
+TEST_F(CommandParserTest, TestSimple) {
+ scoped_ptr<CommandParser> parser(MakeParser(10));
+ CommandBufferOffset put = parser->put();
+ CommandHeader header;
+
+ // add a single command, no args
+ header.size = 1;
+ header.command = 123;
+ buffer()[put++].value_header = header;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+
+ AddDoCommandExpect(parse_error::kParseNoError, 123, 0, NULL);
+ EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ // add a single command, 2 args
+ header.size = 3;
+ header.command = 456;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 2134;
+ buffer()[put++].value_float = 1.f;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+
+ CommandBufferEntry param_array[2];
+ param_array[0].value_int32 = 2134;
+ param_array[1].value_float = 1.f;
+ AddDoCommandExpect(parse_error::kParseNoError, 456, 2, param_array);
+ EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+}
+
+// Tests having multiple commands in the buffer.
+TEST_F(CommandParserTest, TestMultipleCommands) {
+ scoped_ptr<CommandParser> parser(MakeParser(10));
+ CommandBufferOffset put = parser->put();
+ CommandHeader header;
+
+ // add 2 commands, test with single ProcessCommand()
+ header.size = 2;
+ header.command = 789;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 5151;
+
+ CommandBufferOffset put_cmd2 = put;
+ header.size = 2;
+ header.command = 2121;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 3434;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+
+ CommandBufferEntry param_array[2];
+ param_array[0].value_int32 = 5151;
+ AddDoCommandExpect(parse_error::kParseNoError, 789, 1, param_array);
+ param_array[1].value_int32 = 3434;
+ AddDoCommandExpect(parse_error::kParseNoError, 2121, 1,
+ param_array+1);
+
+ EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand());
+ EXPECT_EQ(put_cmd2, parser->get());
+ EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ // add 2 commands again, test with ProcessAllCommands()
+ header.size = 2;
+ header.command = 4545;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 5656;
+
+ header.size = 2;
+ header.command = 6767;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 7878;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+
+ param_array[0].value_int32 = 5656;
+ AddDoCommandExpect(parse_error::kParseNoError, 4545, 1, param_array);
+ param_array[1].value_int32 = 7878;
+ AddDoCommandExpect(parse_error::kParseNoError, 6767, 1,
+ param_array+1);
+
+ EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+}
+
+// Tests that the parser will wrap correctly at the end of the buffer.
+TEST_F(CommandParserTest, TestWrap) {
+ scoped_ptr<CommandParser> parser(MakeParser(5));
+ CommandBufferOffset put = parser->put();
+ CommandHeader header;
+
+ // add 3 commands with no args (1 word each)
+ for (unsigned int i = 0; i < 3; ++i) {
+ header.size = 1;
+ header.command = i;
+ buffer()[put++].value_header = header;
+ AddDoCommandExpect(parse_error::kParseNoError, i, 0, NULL);
+ }
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ // add 1 command with 1 arg (2 words). That should put us at the end of the
+ // buffer.
+ header.size = 2;
+ header.command = 3;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 5;
+ CommandBufferEntry param;
+ param.value_int32 = 5;
+ AddDoCommandExpect(parse_error::kParseNoError, 3, 1, &param);
+
+ DCHECK_EQ(5u, put);
+ put = 0;
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ // add 1 command with 1 arg (2 words).
+ header.size = 2;
+ header.command = 4;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 6;
+ param.value_int32 = 6;
+ AddDoCommandExpect(parse_error::kParseNoError, 4, 1, &param);
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+}
+
+// Tests error conditions.
+TEST_F(CommandParserTest, TestError) {
+ scoped_ptr<CommandParser> parser(MakeParser(5));
+ CommandBufferOffset put = parser->put();
+ CommandHeader header;
+
+ // Generate a command with size 0.
+ header.size = 0;
+ header.command = 3;
+ buffer()[put++].value_header = header;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(parse_error::kParseInvalidSize,
+ parser->ProcessAllCommands());
+ // check that no DoCommand call was made.
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ parser.reset(MakeParser(5));
+ put = parser->put();
+
+ // Generate a command with size 6, extends beyond the end of the buffer.
+ header.size = 6;
+ header.command = 3;
+ buffer()[put++].value_header = header;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(parse_error::kParseOutOfBounds,
+ parser->ProcessAllCommands());
+ // check that no DoCommand call was made.
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ parser.reset(MakeParser(5));
+ put = parser->put();
+
+ // Generates 2 commands.
+ header.size = 1;
+ header.command = 3;
+ buffer()[put++].value_header = header;
+ CommandBufferOffset put_post_fail = put;
+ header.size = 1;
+ header.command = 4;
+ buffer()[put++].value_header = header;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ // have the first command fail to parse.
+ AddDoCommandExpect(parse_error::kParseUnknownCommand, 3, 0, NULL);
+ EXPECT_EQ(parse_error::kParseUnknownCommand,
+ parser->ProcessAllCommands());
+ // check that only one command was executed, and that get reflects that
+ // correctly.
+ EXPECT_EQ(put_post_fail, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+ // make the second one succeed, and check that the parser recovered fine.
+ AddDoCommandExpect(parse_error::kParseNoError, 4, 0, NULL);
+ EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/common_decoder.cc b/o3d/gpu/command_buffer/service/common_decoder.cc
new file mode 100644
index 0000000..22bf445
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/common_decoder.cc
@@ -0,0 +1,122 @@
+/*
+ * 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 "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+
+namespace command_buffer {
+
+void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id,
+ unsigned int offset,
+ unsigned int size) {
+ void* shm_addr = engine_->GetSharedMemoryAddress(shm_id);
+ if (!shm_addr) return NULL;
+ size_t shm_size = engine_->GetSharedMemorySize(shm_id);
+ unsigned int end = offset + size;
+ if (end > shm_size || end < offset) {
+ return NULL;
+ }
+ return static_cast<int8 *>(shm_addr) + offset;
+}
+
+const char* CommonDecoder::GetCommonCommandName(
+ cmd::CommandId command_id) const {
+ return cmd::GetCommandName(command_id);
+}
+
+namespace {
+
+// A struct to hold info about each command.
+struct CommandInfo {
+ int arg_flags; // How to handle the arguments for this command
+ int arg_count; // How many arguments are expected for this command.
+};
+
+// A table of CommandInfo for all the commands.
+const CommandInfo g_command_info[] = {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) { \
+ cmd::name::kArgFlags, \
+ sizeof(cmd::name) / sizeof(CommandBufferEntry) - 1, }, /* NOLINT */ \
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+};
+
+} // anonymous namespace.
+
+// Decode command with its arguments, and call the corresponding method.
+// Note: args is a pointer to the command buffer. As such, it could be changed
+// by a (malicious) client at any time, so if validation has to happen, it
+// should operate on a copy of them.
+parse_error::ParseError CommonDecoder::DoCommonCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data) {
+ if (command < arraysize(g_command_info)) {
+ const CommandInfo& info = g_command_info[command];
+ unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
+ if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
+ (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
+ switch (command) {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) \
+ case cmd::name::kCmdId: \
+ return Handle ## name( \
+ arg_count, \
+ *static_cast<const cmd::name*>(cmd_data)); \
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+ }
+ } else {
+ return parse_error::kParseInvalidArguments;
+ }
+ }
+ return DoCommonCommand(command, arg_count, cmd_data);
+ return parse_error::kParseUnknownCommand;
+}
+
+parse_error::ParseError CommonDecoder::HandleNoop(
+ uint32 arg_count,
+ const cmd::Noop& args) {
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError CommonDecoder::HandleSetToken(
+ uint32 arg_count,
+ const cmd::SetToken& args) {
+ engine_->set_token(args.token);
+ return parse_error::kParseNoError;
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/common_decoder.h b/o3d/gpu/command_buffer/service/common_decoder.h
new file mode 100644
index 0000000..25d1dbe
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/common_decoder.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_COMMON_DECODER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CROSS_COMMON_DECODER_H_
+
+#include "gpu/command_buffer/service/cmd_parser.h"
+
+namespace command_buffer {
+
+class CommandBufferEngine;
+
+// This class is a helper base class for implementing the common parts of the
+// o3d/gl2 command buffer decoder.
+class CommonDecoder : public AsyncAPIInterface {
+ public:
+ typedef parse_error::ParseError ParseError;
+
+ CommonDecoder() : engine_(NULL) {
+ }
+ virtual ~CommonDecoder() {
+ }
+
+ // Sets the engine, to get shared memory buffers from, and to set the token
+ // to.
+ void set_engine(CommandBufferEngine* engine) {
+ engine_ = engine;
+ }
+
+ protected:
+ // Executes a common command.
+ // Parameters:
+ // command: the command index.
+ // arg_count: the number of CommandBufferEntry arguments.
+ // cmd_data: the command data.
+ // Returns:
+ // parse_error::NO_ERROR if no error was found, one of
+ // parse_error::ParseError otherwise.
+ parse_error::ParseError DoCommonCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data);
+
+ // Gets the address of shared memory data, given a shared memory ID and an
+ // offset. Also checks that the size is consistent with the shared memory
+ // size.
+ // Parameters:
+ // shm_id: the id of the shared memory buffer.
+ // offset: the offset of the data in the shared memory buffer.
+ // size: the size of the data.
+ // Returns:
+ // NULL if shm_id isn't a valid shared memory buffer ID or if the size
+ // check fails. Return a pointer to the data otherwise.
+ void* GetAddressAndCheckSize(unsigned int shm_id,
+ unsigned int offset,
+ unsigned int size);
+
+ // Gets an name for a common command.
+ const char* GetCommonCommandName(cmd::CommandId command_id) const;
+
+ private:
+ // Generate a member function prototype for each command in an automated and
+ // typesafe way.
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) \
+ parse_error::ParseError Handle ## name( \
+ unsigned int arg_count, \
+ const cmd::name& args); \
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+
+ CommandBufferEngine* engine_;
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_COMMON_DECODER_H_
+
diff --git a/o3d/gpu/command_buffer/service/d3d9_utils.h b/o3d/gpu/command_buffer/service/d3d9_utils.h
new file mode 100644
index 0000000..5938ac0
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/d3d9_utils.h
@@ -0,0 +1,145 @@
+/*
+ * 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 a few utilities for Direct3D.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_D3D9_UTILS_H_
+#define GPU_COMMAND_BUFFER_SERVICE_D3D9_UTILS_H_
+
+#ifndef NOMINMAX
+// windows.h defines min() and max() as macros, conflicting with std::min and
+// std::max unless NOMINMAX is defined.
+#define NOMINMAX
+#endif
+#include <windows.h>
+#include <d3d9.h>
+#include <d3dx9.h>
+#include <dxerr.h>
+#include <algorithm>
+#include "gpu/command_buffer/common/gapi_interface.h"
+
+#if defined (_DEBUG)
+
+#ifndef HR
+#define HR(x) { \
+ HRESULT hr = x; \
+ if (FAILED(hr)) { \
+ LOG(ERROR) << "DirectX error at " << __FILE__ << ":" << __LINE__ \
+ << " when calling " << #x << ": " << DXGetErrorStringA(hr); \
+ } \
+ }
+#endif
+
+#else // _DEBUG
+
+#ifndef HR
+#define HR(x) x;
+#endif
+
+#endif // _DEBUG
+
+namespace command_buffer {
+
+union FloatAndDWORD {
+ float float_value;
+ DWORD dword_value;
+};
+
+// Bit casts a float into a DWORD. That's what D3D expects for some values.
+inline DWORD FloatAsDWORD(float value) {
+ volatile FloatAndDWORD float_and_dword;
+ float_and_dword.float_value = value;
+ return float_and_dword.dword_value;
+}
+
+// Clamps a float to [0 .. 1] and maps it to [0 .. 255]
+inline unsigned int FloatToClampedByte(float value) {
+ value = std::min(1.f, std::max(0.f, value));
+ return static_cast<unsigned int>(value * 255);
+}
+
+// Converts a RGBA color into a D3DCOLOR
+inline D3DCOLOR RGBAToD3DCOLOR(const o3d::RGBA &color) {
+ return D3DCOLOR_RGBA(FloatToClampedByte(color.red),
+ FloatToClampedByte(color.green),
+ FloatToClampedByte(color.blue),
+ FloatToClampedByte(color.alpha));
+}
+
+static bool D3DSemanticToCBSemantic(
+ D3DDECLUSAGE semantic,
+ unsigned int semantic_index,
+ vertex_struct::Semantic *out_semantic,
+ unsigned int *out_semantic_index) {
+ // TODO: what meaning do we really want to put to our semantics ? How
+ // do they match the semantics that are set in the effect ? What combination
+ // of (semantic, index) are supposed to work ?
+ // TODO(gman): This is just plain wrong! Fix it. Converting binormal to
+ // texcoord 7 means there will be conflicts if I have both a Binormal and a
+ // texcoord 7 or 2 binormals both of which we have examples of already in O3D!
+ switch (semantic) {
+ case D3DDECLUSAGE_POSITION:
+ if (semantic_index != 0) return false;
+ *out_semantic = vertex_struct::kPosition;
+ *out_semantic_index = 0;
+ return true;
+ case D3DDECLUSAGE_NORMAL:
+ if (semantic_index != 0) return false;
+ *out_semantic = vertex_struct::kNormal;
+ *out_semantic_index = 0;
+ return true;
+ case D3DDECLUSAGE_TANGENT:
+ if (semantic_index != 0) return false;
+ *out_semantic = vertex_struct::kTexCoord;
+ *out_semantic_index = 6;
+ return true;
+ case D3DDECLUSAGE_BINORMAL:
+ if (semantic_index != 0) return false;
+ *out_semantic = vertex_struct::kTexCoord;
+ *out_semantic_index = 7;
+ return true;
+ case D3DDECLUSAGE_COLOR:
+ if (semantic_index > 1) return false;
+ *out_semantic = vertex_struct::kColor;
+ *out_semantic_index = semantic_index;
+ return true;
+ case D3DDECLUSAGE_TEXCOORD:
+ *out_semantic = vertex_struct::kTexCoord;
+ *out_semantic_index = semantic_index;
+ return true;
+ default:
+ return false;
+ }
+}
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_D3D9_UTILS_H_
diff --git a/o3d/gpu/command_buffer/service/effect_d3d9.cc b/o3d/gpu/command_buffer/service/effect_d3d9.cc
new file mode 100644
index 0000000..4bfae53
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/effect_d3d9.cc
@@ -0,0 +1,679 @@
+/*
+ * 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 implementation of the D3D9 versions of the
+// Effect resource.
+// This file also contains the related GAPID3D9 function implementations.
+
+#include "gpu/command_buffer/service/precompile.h"
+
+#include <algorithm>
+#include "gpu/command_buffer/service/d3d9_utils.h"
+#include "gpu/command_buffer/service/geometry_d3d9.h"
+#include "gpu/command_buffer/service/gapi_d3d9.h"
+#include "gpu/command_buffer/service/effect_d3d9.h"
+#include "gpu/command_buffer/service/sampler_d3d9.h"
+#include "gpu/command_buffer/service/effect_utils.h"
+
+// TODO: remove link-dependency on D3DX.
+
+namespace command_buffer {
+namespace o3d {
+
+// Logs the D3D effect error, from either the buffer, or GetLastError().
+static void LogFXError(LPD3DXBUFFER error_buffer) {
+ if (error_buffer) {
+ LPVOID compile_errors = error_buffer->GetBufferPointer();
+ LOG(ERROR) << "Failed to compile effect: "
+ << static_cast<char *>(compile_errors);
+ } else {
+ HLOCAL hLocal = NULL;
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ GetLastError(),
+ 0,
+ reinterpret_cast<wchar_t*>(&hLocal),
+ 0,
+ NULL);
+ wchar_t* msg = reinterpret_cast<wchar_t*>(LocalLock(hLocal));
+ LOG(ERROR) << "Failed to compile effect: " << msg;
+ LocalFree(hLocal);
+ }
+}
+
+EffectD3D9::EffectD3D9(GAPID3D9 *gapi,
+ ID3DXEffect *d3d_effect,
+ ID3DXConstantTable *fs_constant_table,
+ IDirect3DVertexShader9 *d3d_vertex_shader)
+ : gapi_(gapi),
+ d3d_effect_(d3d_effect),
+ fs_constant_table_(fs_constant_table),
+ d3d_vertex_shader_(d3d_vertex_shader),
+ sync_parameters_(false) {
+ for (unsigned int i = 0; i < kMaxSamplerUnits; ++i) {
+ samplers_[i] = kInvalidResource;
+ }
+ SetStreams();
+}
+// Releases the D3D effect.
+EffectD3D9::~EffectD3D9() {
+ for (ParamList::iterator it = params_.begin(); it != params_.end(); ++it) {
+ (*it)->ResetEffect();
+ }
+ DCHECK(d3d_effect_);
+ d3d_effect_->Release();
+ DCHECK(fs_constant_table_);
+ fs_constant_table_->Release();
+ DCHECK(d3d_vertex_shader_);
+ d3d_vertex_shader_->Release();
+}
+
+// Compiles the effect, and checks that the effect conforms to what we expect
+// (no extra technique or pass in the effect code, since one is implicitly added
+// using the program entry points) and that it validates. If successful, wrap
+// the D3D effect into a new EffectD3D9.
+EffectD3D9 *EffectD3D9::Create(GAPID3D9 *gapi,
+ const String& effect_code,
+ const String& vertex_program_entry,
+ const String& fragment_program_entry) {
+ String prepared_effect = effect_code +
+ "technique Shaders { "
+ " pass p0 { "
+ " VertexShader = compile vs_2_0 " + vertex_program_entry + "();"
+ " PixelShader = compile ps_2_0 " + fragment_program_entry + "();"
+ " }"
+ "};";
+ ID3DXEffect *d3d_effect = NULL;
+ LPD3DXBUFFER error_buffer;
+ IDirect3DDevice9 *device = gapi->d3d_device();
+ if (gapi->D3DXCreateEffect(device,
+ prepared_effect.c_str(),
+ prepared_effect.size(),
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ &d3d_effect,
+ &error_buffer) != D3D_OK) {
+ LogFXError(error_buffer);
+ return NULL;
+ }
+ // check that .
+ D3DXEFFECT_DESC effect_desc;
+ HR(d3d_effect->GetDesc(&effect_desc));
+ if (effect_desc.Techniques != 1) {
+ LOG(ERROR) << "Only 1 technique is allowed in an effect.";
+ d3d_effect->Release();
+ return NULL;
+ }
+ D3DXHANDLE technique = d3d_effect->GetTechnique(0);
+ DCHECK(technique);
+ if (d3d_effect->ValidateTechnique(technique) != D3D_OK) {
+ LOG(ERROR) << "Technique doesn't validate.";
+ d3d_effect->Release();
+ return NULL;
+ }
+ D3DXTECHNIQUE_DESC technique_desc;
+ HR(d3d_effect->GetTechniqueDesc(technique, &technique_desc));
+ if (technique_desc.Passes != 1) {
+ LOG(ERROR) << "Only 1 pass is allowed in an effect.";
+ d3d_effect->Release();
+ return NULL;
+ }
+ d3d_effect->SetTechnique(technique);
+ D3DXHANDLE pass = d3d_effect->GetPass(technique, 0);
+ D3DXPASS_DESC pass_desc;
+ HR(d3d_effect->GetPassDesc(pass, &pass_desc));
+ ID3DXConstantTable *table = NULL;
+ HR(gapi->D3DXGetShaderConstantTable(pass_desc.pPixelShaderFunction,
+ &table));
+ if (!table) {
+ LOG(ERROR) << "Could not get the constant table.";
+ d3d_effect->Release();
+ return NULL;
+ }
+ IDirect3DVertexShader9 *d3d_vertex_shader = NULL;
+ HR(device->CreateVertexShader(pass_desc.pVertexShaderFunction,
+ &d3d_vertex_shader));
+ if (!d3d_vertex_shader) {
+ d3d_effect->Release();
+ table->Release();
+ DLOG(ERROR) << "Failed to create vertex shader";
+ return NULL;
+ }
+
+ return new EffectD3D9(gapi, d3d_effect, table, d3d_vertex_shader);
+}
+
+// Begins rendering with the effect, setting all the appropriate states.
+bool EffectD3D9::Begin() {
+ UINT numpasses;
+ HR(d3d_effect_->Begin(&numpasses, 0));
+ HR(d3d_effect_->BeginPass(0));
+ sync_parameters_ = false;
+ return SetSamplers();
+}
+
+// Terminates rendering with the effect, resetting all the appropriate states.
+void EffectD3D9::End() {
+ HR(d3d_effect_->EndPass());
+ HR(d3d_effect_->End());
+}
+
+// Gets the parameter count from the D3D effect description.
+unsigned int EffectD3D9::GetParamCount() {
+ D3DXEFFECT_DESC effect_desc;
+ HR(d3d_effect_->GetDesc(&effect_desc));
+ return effect_desc.Parameters;
+}
+
+// Gets the number of input streams from the shader.
+unsigned int EffectD3D9::GetStreamCount() {
+ return streams_.size();
+}
+
+// Retrieves the matching DataType from a D3D parameter description.
+static effect_param::DataType GetDataTypeFromD3D(
+ const D3DXPARAMETER_DESC &desc) {
+ switch (desc.Type) {
+ case D3DXPT_FLOAT:
+ switch (desc.Class) {
+ case D3DXPC_SCALAR:
+ return effect_param::kFloat1;
+ case D3DXPC_VECTOR:
+ switch (desc.Columns) {
+ case 2:
+ return effect_param::kFloat2;
+ case 3:
+ return effect_param::kFloat3;
+ case 4:
+ return effect_param::kFloat4;
+ default:
+ return effect_param::kUnknown;
+ }
+ case D3DXPC_MATRIX_ROWS:
+ case D3DXPC_MATRIX_COLUMNS:
+ if (desc.Columns == 4 && desc.Rows == 4) {
+ return effect_param::kMatrix4;
+ } else {
+ return effect_param::kUnknown;
+ }
+ default:
+ return effect_param::kUnknown;
+ }
+ case D3DXPT_INT:
+ if (desc.Class == D3DXPC_SCALAR) {
+ return effect_param::kInt;
+ } else {
+ return effect_param::kUnknown;
+ }
+ case D3DXPT_BOOL:
+ if (desc.Class == D3DXPC_SCALAR) {
+ return effect_param::kBool;
+ } else {
+ return effect_param::kUnknown;
+ }
+ case D3DXPT_SAMPLER:
+ case D3DXPT_SAMPLER2D:
+ case D3DXPT_SAMPLER3D:
+ case D3DXPT_SAMPLERCUBE:
+ if (desc.Class == D3DXPC_OBJECT) {
+ return effect_param::kSampler;
+ } else {
+ return effect_param::kUnknown;
+ }
+ case D3DXPT_TEXTURE:
+ case D3DXPT_TEXTURE1D:
+ case D3DXPT_TEXTURE2D:
+ case D3DXPT_TEXTURE3D:
+ case D3DXPT_TEXTURECUBE:
+ if (desc.Class == D3DXPC_OBJECT) {
+ return effect_param::kTexture;
+ } else {
+ return effect_param::kUnknown;
+ }
+ default:
+ return effect_param::kUnknown;
+ }
+}
+
+// Gets a handle to the selected parameter, and wraps it into an
+// EffectParamD3D9 if successful.
+EffectParamD3D9 *EffectD3D9::CreateParam(unsigned int index) {
+ D3DXHANDLE handle = d3d_effect_->GetParameter(NULL, index);
+ if (!handle) return NULL;
+ return EffectParamD3D9::Create(this, handle);
+}
+
+// Gets a handle to the selected parameter, and wraps it into an
+// EffectParamD3D9 if successful.
+EffectParamD3D9 *EffectD3D9::CreateParamByName(const char *name) {
+ D3DXHANDLE handle = d3d_effect_->GetParameterByName(NULL, name);
+ if (!handle) return NULL;
+ return EffectParamD3D9::Create(this, handle);
+}
+
+bool EffectD3D9::CommitParameters() {
+ if (sync_parameters_) {
+ sync_parameters_ = false;
+ d3d_effect_->CommitChanges();
+ return SetSamplers();
+ } else {
+ return true;
+ }
+}
+
+bool EffectD3D9::SetSamplers() {
+ IDirect3DDevice9 *d3d_device = gapi_->d3d_device();
+ bool result = true;
+ for (unsigned int i = 0; i < kMaxSamplerUnits; ++i) {
+ SamplerD3D9 *sampler = gapi_->GetSampler(samplers_[i]);
+ if (sampler) {
+ result &= sampler->ApplyStates(gapi_, i);
+ } else {
+ HR(d3d_device->SetTexture(i, NULL));
+ }
+ }
+ return result;
+}
+
+bool EffectD3D9::SetStreams() {
+ if (!d3d_vertex_shader_) {
+ return false;
+ }
+ UINT size;
+ d3d_vertex_shader_->GetFunction(NULL, &size);
+ scoped_array<DWORD> function(new DWORD[size]);
+ d3d_vertex_shader_->GetFunction(function.get(), &size);
+
+ UINT num_semantics;
+ HR(gapi_->D3DXGetShaderInputSemantics(function.get(),
+ NULL,
+ &num_semantics));
+ scoped_array<D3DXSEMANTIC> semantics(new D3DXSEMANTIC[num_semantics]);
+ HR(gapi_->D3DXGetShaderInputSemantics(function.get(),
+ semantics.get(),
+ &num_semantics));
+
+ streams_.resize(num_semantics);
+ for (UINT i = 0; i < num_semantics; ++i) {
+ vertex_struct::Semantic semantic;
+ unsigned int semantic_index;
+ if (D3DSemanticToCBSemantic(static_cast<D3DDECLUSAGE>(semantics[i].Usage),
+ static_cast<int>(semantics[i].UsageIndex),
+ &semantic, &semantic_index)) {
+ streams_[i].semantic = semantic;
+ streams_[i].semantic_index = semantic_index;
+ }
+ }
+ return true;
+}
+
+void EffectD3D9::LinkParam(EffectParamD3D9 *param) {
+ params_.push_back(param);
+}
+
+void EffectD3D9::UnlinkParam(EffectParamD3D9 *param) {
+ std::remove(params_.begin(), params_.end(), param);
+}
+
+// Fills the Desc structure, appending name and semantic if any, and if enough
+// room is available in the buffer.
+bool EffectD3D9::GetStreamDesc(unsigned int index,
+ unsigned int size,
+ void *data) {
+ using effect_stream::Desc;
+ if (size < sizeof(Desc)) // NOLINT
+ return false;
+
+ Desc *desc = static_cast<Desc *>(data);
+ *desc = streams_[index];
+ return true;
+}
+
+EffectParamD3D9::EffectParamD3D9(effect_param::DataType data_type,
+ EffectD3D9 *effect,
+ D3DXHANDLE handle)
+ : EffectParam(data_type),
+ effect_(effect),
+ handle_(handle),
+ sampler_units_(NULL),
+ sampler_unit_count_(0) {
+ DCHECK(effect_);
+ effect_->LinkParam(this);
+}
+
+EffectParamD3D9::~EffectParamD3D9() {
+ if (effect_) effect_->UnlinkParam(this);
+}
+
+EffectParamD3D9 *EffectParamD3D9::Create(EffectD3D9 *effect,
+ D3DXHANDLE handle) {
+ DCHECK(effect);
+ D3DXPARAMETER_DESC desc;
+ HR(effect->d3d_effect_->GetParameterDesc(handle, &desc));
+ effect_param::DataType data_type = GetDataTypeFromD3D(desc);
+ EffectParamD3D9 *param = new EffectParamD3D9(data_type, effect, handle);
+ if (data_type == effect_param::kSampler) {
+ ID3DXConstantTable *table = effect->fs_constant_table_;
+ DCHECK(table);
+ D3DXHANDLE sampler_handle = table->GetConstantByName(NULL, desc.Name);
+ if (sampler_handle) {
+ D3DXCONSTANT_DESC desc_array[kMaxSamplerUnits];
+ unsigned int num_desc = kMaxSamplerUnits;
+ table->GetConstantDesc(sampler_handle, desc_array, &num_desc);
+ // We have no good way of querying how many descriptions would really be
+ // returned as we're capping the number to kMaxSamplerUnits (which should
+ // be more than sufficient). If however we do end up with the max number
+ // there's a chance that there were actually more so let's log it.
+ if (num_desc == kMaxSamplerUnits) {
+ DLOG(WARNING) << "Number of constant descriptions might have exceeded "
+ << "the maximum of " << kMaxSamplerUnits;
+ }
+ param->sampler_unit_count_ = 0;
+ if (num_desc > 0) {
+ param->sampler_units_.reset(new unsigned int[num_desc]);
+ for (unsigned int desc_index = 0; desc_index < num_desc; desc_index++) {
+ D3DXCONSTANT_DESC constant_desc = desc_array[desc_index];
+ if (constant_desc.Class == D3DXPC_OBJECT &&
+ (constant_desc.Type == D3DXPT_SAMPLER ||
+ constant_desc.Type == D3DXPT_SAMPLER2D ||
+ constant_desc.Type == D3DXPT_SAMPLER3D ||
+ constant_desc.Type == D3DXPT_SAMPLERCUBE)) {
+ param->sampler_units_[param->sampler_unit_count_++] =
+ constant_desc.RegisterIndex;
+ }
+ }
+ }
+ }
+ // if the sampler hasn't been found in the constant table, that means it
+ // isn't referenced, hence it doesn't use any sampler unit.
+ }
+ return param;
+}
+
+// Fills the Desc structure, appending name and semantic if any, and if enough
+// room is available in the buffer.
+bool EffectParamD3D9::GetDesc(unsigned int size, void *data) {
+ using effect_param::Desc;
+ if (size < sizeof(Desc)) // NOLINT
+ return false;
+ if (!effect_)
+ return false;
+ ID3DXEffect *d3d_effect = effect_->d3d_effect_;
+ D3DXPARAMETER_DESC d3d_desc;
+ HR(d3d_effect->GetParameterDesc(handle_, &d3d_desc));
+ unsigned int name_size =
+ d3d_desc.Name ? static_cast<unsigned int>(strlen(d3d_desc.Name)) + 1 : 0;
+ unsigned int semantic_size = d3d_desc.Semantic ?
+ static_cast<unsigned int>(strlen(d3d_desc.Semantic)) + 1 : 0;
+ unsigned int total_size = sizeof(Desc) + name_size + semantic_size; // NOLINT
+
+ Desc *desc = static_cast<Desc *>(data);
+ memset(desc, 0, sizeof(*desc));
+ desc->size = total_size;
+ desc->data_type = data_type();
+ desc->data_size = GetDataSize(data_type());
+ desc->name_offset = 0;
+ desc->name_size = name_size;
+ desc->num_elements = d3d_desc.Elements;
+ desc->semantic_offset = 0;
+ desc->semantic_size = semantic_size;
+ unsigned int current_offset = sizeof(Desc);
+ if (d3d_desc.Name && current_offset + name_size <= size) {
+ desc->name_offset = current_offset;
+ memcpy(static_cast<char *>(data) + current_offset,
+ d3d_desc.Name, name_size);
+ current_offset += name_size;
+ }
+ if (d3d_desc.Semantic && current_offset + semantic_size <= size) {
+ desc->semantic_offset = current_offset;
+ memcpy(static_cast<char *>(data) + current_offset,
+ d3d_desc.Semantic, semantic_size);
+ current_offset += semantic_size;
+ }
+ return true;
+}
+
+// Sets the data into the D3D effect parameter, using the appropriate D3D call.
+bool EffectParamD3D9::SetData(GAPID3D9 *gapi,
+ unsigned int size,
+ const void * data) {
+ if (!effect_)
+ return false;
+ ID3DXEffect *d3d_effect = effect_->d3d_effect_;
+ effect_param::DataType type = data_type();
+ if (size < effect_param::GetDataSize(type)) return false;
+ switch (type) {
+ case effect_param::kFloat1:
+ HR(d3d_effect->SetFloat(handle_, *static_cast<const float *>(data)));
+ break;
+ case effect_param::kFloat2:
+ HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data),
+ 2));
+ break;
+ case effect_param::kFloat3:
+ HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data),
+ 3));
+ break;
+ case effect_param::kFloat4:
+ HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data),
+ 4));
+ break;
+ case effect_param::kMatrix4:
+ HR(d3d_effect->SetMatrix(handle_,
+ reinterpret_cast<const D3DXMATRIX *>(data)));
+ break;
+ case effect_param::kInt:
+ HR(d3d_effect->SetInt(handle_, *static_cast<const int *>(data)));
+ break;
+ case effect_param::kBool:
+ HR(d3d_effect->SetBool(handle_, *static_cast<const bool *>(data)?1:0));
+ break;
+ case effect_param::kSampler: {
+ ResourceId id = *static_cast<const ResourceId *>(data);
+ for (unsigned int i = 0; i < sampler_unit_count_; ++i) {
+ effect_->samplers_[sampler_units_[i]] = id;
+ }
+ break;
+ }
+ case effect_param::kTexture: {
+ // TODO(rlp): finish
+ break;
+ }
+ default:
+ DLOG(ERROR) << "Invalid parameter type.";
+ return false;
+ }
+ if (effect_ == gapi->current_effect()) {
+ effect_->sync_parameters_ = true;
+ }
+ return true;
+}
+
+// Calls EffectD3D9::Create, and assign the result to the resource ID.
+// If changing the current effect, dirty it.
+parse_error::ParseError GAPID3D9::CreateEffect(
+ ResourceId id,
+ unsigned int size,
+ const void *data) {
+ if (id == current_effect_id_) DirtyEffect();
+ // Even though Assign would Destroy the effect at id, we do it explicitly in
+ // case the creation fails.
+ effects_.Destroy(id);
+ // Data is vp_main \0 fp_main \0 effect_text.
+ String vertex_program_entry;
+ String fragment_program_entry;
+ String effect_code;
+ if (!ParseEffectData(size, data,
+ &vertex_program_entry,
+ &fragment_program_entry,
+ &effect_code)) {
+ return parse_error::kParseInvalidArguments;
+ }
+ EffectD3D9 * effect = EffectD3D9::Create(this, effect_code,
+ vertex_program_entry,
+ fragment_program_entry);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ effects_.Assign(id, effect);
+ return parse_error::kParseNoError;
+}
+
+// Destroys the Effect resource.
+// If destroying the current effect, dirty it.
+parse_error::ParseError GAPID3D9::DestroyEffect(ResourceId id) {
+ if (id == current_effect_id_) DirtyEffect();
+ return effects_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Sets the current effect ID, dirtying the current effect.
+parse_error::ParseError GAPID3D9::SetEffect(ResourceId id) {
+ DirtyEffect();
+ current_effect_id_ = id;
+ return parse_error::kParseNoError;
+}
+
+// Gets the param count from the effect and store it in the memory buffer.
+parse_error::ParseError GAPID3D9::GetParamCount(
+ ResourceId id,
+ unsigned int size,
+ void *data) {
+ EffectD3D9 *effect = effects_.Get(id);
+ if (!effect || size < sizeof(Uint32)) // NOLINT
+ return parse_error::kParseInvalidArguments;
+ *static_cast<Uint32 *>(data) = effect->GetParamCount();
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::CreateParam(
+ ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int index) {
+ EffectD3D9 *effect = effects_.Get(effect_id);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ EffectParamD3D9 *param = effect->CreateParam(index);
+ if (!param) return parse_error::kParseInvalidArguments;
+ effect_params_.Assign(param_id, param);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::CreateParamByName(
+ ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int size,
+ const void *name) {
+ EffectD3D9 *effect = effects_.Get(effect_id);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ std::string string_name(static_cast<const char *>(name), size);
+ EffectParamD3D9 *param = effect->CreateParamByName(string_name.c_str());
+ if (!param) return parse_error::kParseInvalidArguments;
+ effect_params_.Assign(param_id, param);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::DestroyParam(ResourceId id) {
+ return effect_params_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPID3D9::SetParamData(
+ ResourceId id,
+ unsigned int size,
+ const void *data) {
+ EffectParamD3D9 *param = effect_params_.Get(id);
+ if (!param) return parse_error::kParseInvalidArguments;
+ return param->SetData(this, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPID3D9::GetParamDesc(
+ ResourceId id,
+ unsigned int size,
+ void *data) {
+ EffectParamD3D9 *param = effect_params_.Get(id);
+ if (!param) return parse_error::kParseInvalidArguments;
+ return param->GetDesc(size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Gets the stream count from the effect and stores it in the memory buffer.
+parse_error::ParseError GAPID3D9::GetStreamCount(
+ ResourceId id,
+ unsigned int size,
+ void *data) {
+ EffectD3D9 *effect = effects_.Get(id);
+ if (!effect || size < sizeof(Uint32)) // NOLINT
+ return parse_error::kParseInvalidArguments;
+ *static_cast<Uint32 *>(data) = effect->GetStreamCount();
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::GetStreamDesc(
+ ResourceId id,
+ unsigned int index,
+ unsigned int size,
+ void *data) {
+ EffectD3D9 *effect = effects_.Get(id);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ return effect->GetStreamDesc(index, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+
+// If the current effect is valid, call End on it, and tag for revalidation.
+void GAPID3D9::DirtyEffect() {
+ if (validate_effect_) return;
+ DCHECK(current_effect_);
+ current_effect_->End();
+ current_effect_ = NULL;
+ validate_effect_ = true;
+}
+
+// Gets the current effect, and calls Begin on it (if successful).
+// Should only be called if the current effect is not valid.
+bool GAPID3D9::ValidateEffect() {
+ DCHECK(validate_effect_);
+ DCHECK(!current_effect_);
+ current_effect_ = effects_.Get(current_effect_id_);
+ if (!current_effect_) return false;
+ validate_effect_ = false;
+ return current_effect_->Begin();
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/effect_d3d9.h b/o3d/gpu/command_buffer/service/effect_d3d9.h
new file mode 100644
index 0000000..db2df41
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/effect_d3d9.h
@@ -0,0 +1,139 @@
+/*
+ * 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 definition of the D3D9 versions of effect-related
+// resource classes.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_EFFECT_D3D9_H_
+#define GPU_COMMAND_BUFFER_SERVICE_EFFECT_D3D9_H_
+
+#include <vector>
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/d3d9_utils.h"
+#include "gpu/command_buffer/service/resource.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class GAPID3D9;
+class EffectD3D9;
+
+// ps_2_0 limit
+static const unsigned int kMaxSamplerUnits = 16;
+
+// D3D version of EffectParam. This class keeps a reference to the D3D effect.
+class EffectParamD3D9: public EffectParam {
+ public:
+ EffectParamD3D9(effect_param::DataType data_type,
+ EffectD3D9 *effect,
+ D3DXHANDLE handle);
+ virtual ~EffectParamD3D9();
+
+ // Sets the data into the D3D effect parameter.
+ bool SetData(GAPID3D9 *gapi, unsigned int size, const void * data);
+
+ // Gets the description of the parameter.
+ bool GetDesc(unsigned int size, void *data);
+
+ // Resets the effect back-pointer. This is called when the effect gets
+ // destroyed, to invalidate the parameter.
+ void ResetEffect() { effect_ = NULL; }
+
+ static EffectParamD3D9 *Create(EffectD3D9 *effect, D3DXHANDLE handle);
+ private:
+ EffectD3D9 *effect_;
+ D3DXHANDLE handle_;
+ unsigned int sampler_unit_count_;
+ scoped_array<unsigned int> sampler_units_;
+};
+
+// D3D9 version of Effect.
+class EffectD3D9 : public Effect {
+ public:
+ EffectD3D9(GAPID3D9 *gapi,
+ ID3DXEffect *d3d_effect,
+ ID3DXConstantTable *fs_constant_table,
+ IDirect3DVertexShader9 *d3d_vertex_shader);
+ virtual ~EffectD3D9();
+ // Compiles and creates an effect from source code.
+ static EffectD3D9 *Create(GAPID3D9 *gapi,
+ const String &effect_code,
+ const String &vertex_program_entry,
+ const String &fragment_program_entry);
+ // Applies the effect states (vertex shader, pixel shader) to D3D.
+ bool Begin();
+ // Resets the effect states (vertex shader, pixel shader) to D3D.
+ void End();
+ // Commits parameters to D3D, if they were modified while the effect is
+ // active.
+ bool CommitParameters();
+
+ // Gets the number of parameters in the effect.
+ unsigned int GetParamCount();
+ // Creates an effect parameter with the specified index.
+ EffectParamD3D9 *CreateParam(unsigned int index);
+ // Creates an effect parameter of the specified name.
+ EffectParamD3D9 *CreateParamByName(const char *name);
+ // Gets the number of stream inputs for the effect.
+ unsigned int GetStreamCount();
+ // Gets the stream data with the specified index.
+ bool GetStreamDesc(unsigned int index, unsigned int size, void *data);
+ private:
+ typedef std::vector<EffectParamD3D9 *> ParamList;
+ typedef std::vector<effect_stream::Desc> StreamList;
+
+ // Links a param into this effect.
+ void LinkParam(EffectParamD3D9 *param);
+ // Unlinks a param into this effect.
+ void UnlinkParam(EffectParamD3D9 *param);
+ // Sets sampler states.
+ bool SetSamplers();
+ // Sets streams vector.
+ bool SetStreams();
+
+ GAPID3D9* gapi_;
+ ID3DXEffect *d3d_effect_;
+ IDirect3DVertexShader9 *d3d_vertex_shader_;
+ ID3DXConstantTable *fs_constant_table_;
+ ParamList params_;
+ StreamList streams_;
+ bool sync_parameters_;
+ ResourceId samplers_[kMaxSamplerUnits];
+
+ friend class EffectParamD3D9;
+ DISALLOW_COPY_AND_ASSIGN(EffectD3D9);
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_EFFECT_D3D9_H_
diff --git a/o3d/gpu/command_buffer/service/effect_gl.cc b/o3d/gpu/command_buffer/service/effect_gl.cc
new file mode 100644
index 0000000..b8f9601
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/effect_gl.cc
@@ -0,0 +1,852 @@
+/*
+ * 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 implementation of the EffectParamGL and EffectGL
+// classes, as well as the effect-related GAPI functions on GL.
+
+#include "gpu/command_buffer/service/precompile.h"
+
+#include <map>
+
+#include "base/cross/std_functional.h"
+#include "gpu/command_buffer/service/effect_gl.h"
+#include "gpu/command_buffer/service/gapi_gl.h"
+#include "gpu/command_buffer/service/effect_utils.h"
+
+namespace command_buffer {
+namespace o3d {
+
+EffectParamGL::EffectParamGL(effect_param::DataType data_type,
+ EffectGL *effect,
+ unsigned int param_index)
+ : EffectParam(data_type),
+ effect_(effect),
+ low_level_param_index_(param_index) {
+ DCHECK(effect_);
+ effect_->LinkParam(this);
+}
+
+EffectParamGL::~EffectParamGL() {
+ if (effect_)
+ effect_->UnlinkParam(this);
+}
+
+static effect_param::DataType CgTypeToCBType(CGtype cg_type) {
+ switch (cg_type) {
+ case CG_FLOAT:
+ case CG_FLOAT1:
+ return effect_param::kFloat1;
+ case CG_FLOAT2:
+ return effect_param::kFloat2;
+ case CG_FLOAT3:
+ return effect_param::kFloat3;
+ case CG_FLOAT4:
+ return effect_param::kFloat4;
+ case CG_INT:
+ case CG_INT1:
+ return effect_param::kInt;
+ case CG_BOOL:
+ case CG_BOOL1:
+ return effect_param::kBool;
+ case CG_FLOAT4x4:
+ return effect_param::kMatrix4;
+ case CG_SAMPLER:
+ case CG_SAMPLER1D:
+ case CG_SAMPLER2D:
+ case CG_SAMPLER3D:
+ case CG_SAMPLERCUBE:
+ return effect_param::kSampler;
+ case CG_TEXTURE:
+ return effect_param::kTexture;
+ default : {
+ DLOG(INFO) << "Cannot convert CGtype "
+ << cgGetTypeString(cg_type)
+ << " to a Param type.";
+ return effect_param::kUnknown;
+ }
+ }
+}
+
+EffectParamGL *EffectParamGL::Create(EffectGL *effect,
+ unsigned int index) {
+ DCHECK(effect);
+ const EffectGL::LowLevelParam &low_level_param =
+ effect->low_level_params_[index];
+ CGparameter cg_param = EffectGL::GetEitherCgParameter(low_level_param);
+ CGtype cg_type = cgGetParameterType(cg_param);
+ if (cg_type == CG_ARRAY) {
+ cg_type = cgGetParameterType(cgGetArrayParameter(cg_param, 0));
+ }
+ effect_param::DataType type = CgTypeToCBType(cg_type);
+
+ if (type == effect_param::kUnknown)
+ return NULL;
+ return new EffectParamGL(type, effect, index);
+}
+
+// Fills the Desc structure, appending name and semantic if any, and if enough
+// room is available in the buffer.
+bool EffectParamGL::GetDesc(unsigned int size, void *data) {
+ using effect_param::Desc;
+ if (size < sizeof(Desc)) // NOLINT
+ return false;
+ if (!effect_)
+ return false;
+ const EffectGL::LowLevelParam &low_level_param =
+ effect_->low_level_params_[low_level_param_index_];
+ CGparameter cg_param = EffectGL::GetEitherCgParameter(low_level_param);
+ const char *name = low_level_param.name;
+ const char* semantic = cgGetParameterSemantic(cg_param);
+ int num_elements = cgGetArraySize(cg_param, 0);
+ unsigned int name_size =
+ name ? static_cast<unsigned int>(strlen(name)) + 1 : 0;
+ unsigned int semantic_size = semantic ?
+ static_cast<unsigned int>(strlen(semantic)) + 1 : 0;
+ unsigned int total_size = sizeof(Desc) + name_size + semantic_size; // NOLINT
+
+ Desc *desc = static_cast<Desc *>(data);
+ memset(desc, 0, sizeof(*desc));
+ desc->size = total_size;
+ desc->data_type = data_type();
+ desc->data_size = GetDataSize(data_type());
+ desc->name_offset = 0;
+ desc->name_size = name_size;
+ desc->semantic_offset = 0;
+ desc->num_elements = num_elements;
+ desc->semantic_size = semantic_size;
+ unsigned int current_offset = sizeof(Desc);
+ if (name && current_offset + name_size <= size) {
+ desc->name_offset = current_offset;
+ memcpy(static_cast<char *>(data) + current_offset, name, name_size);
+ current_offset += name_size;
+ }
+ if (semantic && current_offset + semantic_size <= size) {
+ desc->semantic_offset = current_offset;
+ memcpy(static_cast<char *>(data) + current_offset, semantic, semantic_size);
+ current_offset += semantic_size;
+ }
+ return true;
+}
+
+// Sets the data into the Cg effect parameter, using the appropriate Cg call.
+bool EffectParamGL::SetData(GAPIGL *gapi,
+ unsigned int size,
+ const void * data) {
+ if (!effect_)
+ return false;
+
+ EffectGL::LowLevelParam &low_level_param =
+ effect_->low_level_params_[low_level_param_index_];
+
+ if (low_level_param.num_elements != 0) {
+ DLOG(ERROR) << "Attempt to set array parameter to value.";
+ return false;
+ }
+
+ CGparameter vp_param = low_level_param.vp_param;
+ CGparameter fp_param = low_level_param.fp_param;
+ effect_param::DataType type = data_type();
+ if (size < effect_param::GetDataSize(type))
+ return false;
+
+ switch (type) {
+ case effect_param::kFloat1:
+ if (vp_param)
+ cgSetParameter1f(vp_param, *static_cast<const float *>(data));
+ if (fp_param)
+ cgSetParameter1f(fp_param, *static_cast<const float *>(data));
+ break;
+ case effect_param::kFloat2:
+ if (vp_param)
+ cgSetParameter2fv(vp_param, static_cast<const float *>(data));
+ if (fp_param)
+ cgSetParameter2fv(fp_param, static_cast<const float *>(data));
+ break;
+ case effect_param::kFloat3:
+ if (vp_param)
+ cgSetParameter3fv(vp_param, static_cast<const float *>(data));
+ if (fp_param)
+ cgSetParameter3fv(fp_param, static_cast<const float *>(data));
+ break;
+ case effect_param::kFloat4:
+ if (vp_param)
+ cgSetParameter4fv(vp_param, static_cast<const float *>(data));
+ if (fp_param)
+ cgSetParameter4fv(fp_param, static_cast<const float *>(data));
+ break;
+ case effect_param::kMatrix4:
+ if (vp_param)
+ cgSetMatrixParameterfr(vp_param, static_cast<const float *>(data));
+ if (fp_param)
+ cgSetMatrixParameterfr(fp_param, static_cast<const float *>(data));
+ break;
+ case effect_param::kInt:
+ if (vp_param) cgSetParameter1i(vp_param, *static_cast<const int *>(data));
+ if (fp_param) cgSetParameter1i(fp_param, *static_cast<const int *>(data));
+ break;
+ case effect_param::kBool: {
+ int bool_value = *static_cast<const bool *>(data)?1:0;
+ if (vp_param) cgSetParameter1i(vp_param, bool_value);
+ if (fp_param) cgSetParameter1i(fp_param, bool_value);
+ break;
+ }
+ case effect_param::kSampler: {
+ DCHECK_GE(low_level_param.sampler_ids.size(), 1U);
+ low_level_param.sampler_ids[0] = *static_cast<const ResourceId *>(data);
+ if (effect_ == gapi->current_effect()) {
+ gapi->DirtyEffect();
+ }
+ break;
+ }
+ default:
+ DLOG(ERROR) << "Invalid parameter type.";
+ return false;
+ }
+ return true;
+}
+EffectGL::EffectGL(CGprogram vertex_program,
+ CGprogram fragment_program)
+ : vertex_program_(vertex_program),
+ fragment_program_(fragment_program),
+ update_samplers_(true) {
+}
+
+EffectGL::~EffectGL() {
+ for (ParamList::iterator it = params_.begin();
+ it != params_.end(); ++it) {
+ (*it)->ResetEffect();
+ }
+}
+
+void EffectGL::LinkParam(EffectParamGL *param) {
+ params_.push_back(param);
+}
+
+void EffectGL::UnlinkParam(EffectParamGL *param) {
+ std::remove(params_.begin(), params_.end(), param);
+}
+
+// Rewrites vertex program assembly code to match GL semantics for clipping.
+// This parses the source, breaking it down into pieces:
+// - declaration ("!!ARBvp1.0")
+// - comments (that contain the parameter information)
+// - instructions
+// - "END" token.
+// Then it rewrites the instructions so that 'result.position' doesn't get
+// written directly, instead it is written to a temporary variable. Then a
+// transformation is done on that variable before outputing to
+// 'result.position':
+// - offset x an y by half a pixel (times w).
+// - remap z from [0..w] to [-w..w].
+//
+// Note that for the 1/2 pixel offset, we need a parameter that depends on the
+// current viewport. This is done through 'program.env[0]' which is shared
+// across all programs (so we only have to update it once when we change the
+// viewport), because Cg won't use them currently (it uses 'program.local'
+// instead).
+static bool RewriteVertexProgramSource(String *source) {
+ String::size_type pos = source->find('\n');
+ if (pos == String::npos) {
+ DLOG(ERROR) << "could not find program declaration";
+ return false;
+ }
+ String decl(*source, 0, pos + 1);
+ String::size_type start_comments = pos + 1;
+ // skip the comments that contain the parameters etc.
+ for (; pos < source->size(); pos = source->find('\n', pos)) {
+ ++pos;
+ if (pos >= source->size())
+ break;
+ if ((*source)[pos] != '#')
+ break;
+ }
+ if (pos >= source->size()) {
+ // we only found comments.
+ return false;
+ }
+ String comments(*source, start_comments, pos - start_comments);
+
+ String::size_type end_token = source->find("\nEND", pos + 1);
+ if (end_token == String::npos) {
+ DLOG(ERROR) << "Compiled shader doesn't have an END token";
+ return false;
+ }
+ String instructions(*source, pos, end_token + 1 - pos);
+
+ // Replace accesses to 'result.position' by accesses to our temp variable
+ // '$O3D_HPOS'.
+ // '$' is a valid symbol for identifiers, but Cg doesn't seem to be using
+ // it, so we can use it to ensure we don't have name conflicts.
+ static const char kOutPositionRegister[] = "result.position";
+ for (String::size_type i = instructions.find(kOutPositionRegister);
+ i < String::npos; i = instructions.find(kOutPositionRegister, i)) {
+ instructions.replace(i, strlen(kOutPositionRegister), "$O3D_HPOS");
+ }
+
+ *source = decl +
+ comments +
+ // .x = 1/viewport.width; .y = 1/viewport.height; .z = 2.0;
+ "PARAM $O3D_HELPER = program.env[0];\n"
+ "TEMP $O3D_HPOS;\n" +
+ instructions +
+ // hpos.x <- hpos.x + hpos.w / viewport.width;
+ // hpos.y <- hpos.y - hpos.w / viewport.height;
+ "MAD $O3D_HPOS.xy, $O3D_HELPER.xyyy, $O3D_HPOS.w, $O3D_HPOS.xyyy;\n"
+ // hpos.z <- hpos.z * 2 - hpos.w
+ "MAD $O3D_HPOS.z, $O3D_HPOS.z, $O3D_HELPER.z, -$O3D_HPOS.w;\n"
+ "MOV result.position, $O3D_HPOS;\n"
+ "END\n";
+ return true;
+}
+
+EffectGL *EffectGL::Create(GAPIGL *gapi,
+ const String& effect_code,
+ const String& vertex_program_entry,
+ const String& fragment_program_entry) {
+ CGcontext context = gapi->cg_context();
+ // Compile the original vertex program once, to get the ARBVP1 assembly code.
+ CGprogram original_vp = cgCreateProgram(
+ context, CG_SOURCE, effect_code.c_str(), CG_PROFILE_ARBVP1,
+ vertex_program_entry.c_str(), NULL);
+ const char* listing = cgGetLastListing(context);
+ if (original_vp == NULL) {
+ DLOG(ERROR) << "Effect Compile Error: " << cgGetErrorString(cgGetError())
+ << " : " << listing;
+ return NULL;
+ }
+
+ if (listing && listing[0] != 0) {
+ DLOG(WARNING) << "Effect Compile Warnings: " << listing;
+ }
+
+ String vp_assembly = cgGetProgramString(original_vp, CG_COMPILED_PROGRAM);
+ cgDestroyProgram(original_vp);
+ if (!RewriteVertexProgramSource(&vp_assembly)) {
+ return NULL;
+ }
+ CGprogram vertex_program = cgCreateProgram(
+ context, CG_OBJECT, vp_assembly.c_str(), CG_PROFILE_ARBVP1,
+ vertex_program_entry.c_str(), NULL);
+ listing = cgGetLastListing(context);
+ if (vertex_program == NULL) {
+ DLOG(ERROR) << "Effect post-rewrite Compile Error: "
+ << cgGetErrorString(cgGetError()) << " : " << listing;
+ return false;
+ }
+
+ if (listing && listing[0] != 0) {
+ DLOG(WARNING) << "Effect post-rewrite compile warnings: " << listing;
+ }
+
+ CHECK_GL_ERROR();
+
+ // If the program rewrite introduced some syntax or semantic errors, we won't
+ // know it until we load the program (through a GL error).
+ // So flush all GL errors first...
+ do {} while (glGetError() != GL_NO_ERROR);
+
+ // ... Then load the program ...
+ cgGLLoadProgram(vertex_program);
+
+ // ... And check for GL errors.
+ if (glGetError() != GL_NO_ERROR) {
+ DLOG(ERROR) << "Effect post-rewrite GL Error: "
+ << glGetString(GL_PROGRAM_ERROR_STRING_ARB)
+ << "\nSource: \n"
+ << vp_assembly;
+ return NULL;
+ }
+
+ CGprogram fragment_program = cgCreateProgram(
+ context, CG_SOURCE, effect_code.c_str(), CG_PROFILE_ARBFP1,
+ fragment_program_entry.c_str(), NULL);
+ listing = cgGetLastListing(context);
+ if (fragment_program == NULL) {
+ DLOG(ERROR) << "Effect Compile Error: "
+ << cgGetErrorString(cgGetError()) << " : "
+ << listing;
+ return NULL;
+ }
+
+ if (listing && listing[0] != 0) {
+ DLOG(WARNING) << "Effect Compile Warnings: " << listing;
+ }
+
+ cgGLLoadProgram(fragment_program);
+
+ // Also check for GL errors, in case Cg managed to compile, but generated a
+ // bad program.
+ if (glGetError() != GL_NO_ERROR) {
+ DLOG(ERROR) << "Effect GL Error: "
+ << glGetString(GL_PROGRAM_ERROR_STRING_ARB);
+ return false;
+ }
+ EffectGL *effect = new EffectGL(vertex_program, fragment_program);
+ effect->Initialize();
+ return effect;
+}
+
+int EffectGL::GetLowLevelParamIndexByName(const char *name) {
+ DCHECK(name);
+ for (unsigned int index = 0; index < low_level_params_.size(); ++index) {
+ if (!strcmp(name, low_level_params_[index].name)) {
+ return index;
+ }
+ }
+ return -1;
+}
+
+void EffectGL::AddLowLevelParams(CGprogram prog, CGenum name_space, bool vp) {
+ // Iterate through parameters and add them to the vector of low level
+ // parameters, visiting only CGparameters that have had storage allocated to
+ // them, and add the params to the low_level_params_ vector.
+ for (CGparameter cg_param = cgGetFirstParameter(prog, name_space);
+ cg_param != NULL;
+ cg_param = cgGetNextParameter(cg_param)) {
+ CGenum variability = cgGetParameterVariability(cg_param);
+ if (variability != CG_UNIFORM)
+ continue;
+ CGenum direction = cgGetParameterDirection(cg_param);
+ if (direction != CG_IN)
+ continue;
+ const char *name = cgGetParameterName(cg_param);
+ if (!name)
+ continue;
+
+ CGtype cg_type = cgGetParameterType(cg_param);
+
+ int num_elements;
+ if (cg_type == CG_ARRAY) {
+ num_elements = cgGetArraySize(cg_param, 0);
+ // Substitute the first element's type for our type.
+ cg_type = cgGetParameterType(cgGetArrayParameter(cg_param, 0));
+ } else {
+ num_elements = 0;
+ }
+
+ int index = GetLowLevelParamIndexByName(name);
+ if (index < 0) {
+ LowLevelParam param;
+ param.name = name;
+ param.vp_param = NULL;
+ param.fp_param = NULL;
+ param.num_elements = num_elements;
+
+ index = low_level_params_.size();
+ if (cg_type == CG_SAMPLER ||
+ cg_type == CG_SAMPLER1D ||
+ cg_type == CG_SAMPLER2D ||
+ cg_type == CG_SAMPLER3D ||
+ cg_type == CG_SAMPLERCUBE) {
+ sampler_params_.push_back(index);
+ if (num_elements == 0) {
+ param.sampler_ids.push_back(kInvalidResource);
+ } else {
+ param.sampler_ids.resize(num_elements);
+ std::vector<ResourceId>::iterator iter;
+ for (iter = param.sampler_ids.begin();
+ iter != param.sampler_ids.end();
+ ++iter) {
+ *iter = kInvalidResource;
+ }
+ }
+ }
+ low_level_params_.push_back(param);
+ }
+
+ if (vp) {
+ low_level_params_[index].vp_param = cg_param;
+ } else {
+ low_level_params_[index].fp_param = cg_param;
+ }
+ }
+}
+
+typedef std::pair<String, effect_stream::Desc> SemanticMapElement;
+typedef std::map<String, effect_stream::Desc> SemanticMap;
+
+// The map batween the semantics on vertex program varying parameters names
+// and vertex attribute indices under the VP_30 profile.
+// TODO(gman): remove this.
+SemanticMapElement semantic_map_array[] = {
+ SemanticMapElement("POSITION",
+ effect_stream::Desc(vertex_struct::kPosition, 0)),
+ SemanticMapElement("ATTR0",
+ effect_stream::Desc(vertex_struct::kPosition, 0)),
+ SemanticMapElement("BLENDWEIGHT",
+ effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)),
+ SemanticMapElement("ATTR1",
+ effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)),
+ SemanticMapElement("NORMAL",
+ effect_stream::Desc(vertex_struct::kNormal, 0)),
+ SemanticMapElement("ATTR2",
+ effect_stream::Desc(vertex_struct::kNormal, 0)),
+ SemanticMapElement("COLOR0",
+ effect_stream::Desc(vertex_struct::kColor, 0)),
+ SemanticMapElement("DIFFUSE",
+ effect_stream::Desc(vertex_struct::kColor, 0)),
+ SemanticMapElement("ATTR3",
+ effect_stream::Desc(vertex_struct::kColor, 0)),
+ SemanticMapElement("COLOR1",
+ effect_stream::Desc(vertex_struct::kColor, 1)),
+ SemanticMapElement("SPECULAR",
+ effect_stream::Desc(vertex_struct::kColor, 1)),
+ SemanticMapElement("ATTR4",
+ effect_stream::Desc(vertex_struct::kColor, 1)),
+ SemanticMapElement("TESSFACTOR",
+ effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)),
+ SemanticMapElement("FOGCOORD",
+ effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)),
+ SemanticMapElement("ATTR5",
+ effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)),
+ SemanticMapElement("PSIZE",
+ effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)),
+ SemanticMapElement("ATTR6",
+ effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)),
+ SemanticMapElement("BLENDINDICES",
+ effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)),
+ SemanticMapElement("ATTR7",
+ effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)),
+ SemanticMapElement("TEXCOORD0",
+ effect_stream::Desc(vertex_struct::kTexCoord, 0)),
+ SemanticMapElement("ATTR8",
+ effect_stream::Desc(vertex_struct::kTexCoord, 0)),
+ SemanticMapElement("TEXCOORD1",
+ effect_stream::Desc(vertex_struct::kTexCoord, 1)),
+ SemanticMapElement("ATTR9",
+ effect_stream::Desc(vertex_struct::kTexCoord, 1)),
+ SemanticMapElement("TEXCOORD2",
+ effect_stream::Desc(vertex_struct::kTexCoord, 2)),
+ SemanticMapElement("ATTR10",
+ effect_stream::Desc(vertex_struct::kTexCoord, 2)),
+ SemanticMapElement("TEXCOORD3",
+ effect_stream::Desc(vertex_struct::kTexCoord, 3)),
+ SemanticMapElement("ATTR11",
+ effect_stream::Desc(vertex_struct::kTexCoord, 3)),
+ SemanticMapElement("TEXCOORD4",
+ effect_stream::Desc(vertex_struct::kTexCoord, 4)),
+ SemanticMapElement("ATTR12",
+ effect_stream::Desc(vertex_struct::kTexCoord, 4)),
+ SemanticMapElement("TEXCOORD5",
+ effect_stream::Desc(vertex_struct::kTexCoord, 5)),
+ SemanticMapElement("ATTR13",
+ effect_stream::Desc(vertex_struct::kTexCoord, 5)),
+ SemanticMapElement("TEXCOORD6",
+ effect_stream::Desc(vertex_struct::kTexCoord, 6)),
+ SemanticMapElement("TANGENT",
+ effect_stream::Desc(vertex_struct::kTexCoord, 6)),
+ SemanticMapElement("ATTR14",
+ effect_stream::Desc(vertex_struct::kTexCoord, 7)),
+ SemanticMapElement("TEXCOORD7",
+ effect_stream::Desc(vertex_struct::kTexCoord, 7)),
+ SemanticMapElement("BINORMAL",
+ effect_stream::Desc(vertex_struct::kTexCoord, 8)),
+ SemanticMapElement("ATTR15",
+ effect_stream::Desc(vertex_struct::kTexCoord, 8))
+};
+
+static SemanticMap semantic_map(semantic_map_array,
+ semantic_map_array +
+ arraysize(semantic_map_array));
+
+void EffectGL::Initialize() {
+ AddLowLevelParams(vertex_program_, CG_PROGRAM, true);
+ AddLowLevelParams(vertex_program_, CG_GLOBAL, true);
+ AddLowLevelParams(fragment_program_, CG_PROGRAM, false);
+ AddLowLevelParams(fragment_program_, CG_GLOBAL, false);
+
+ AddStreams(vertex_program_, CG_PROGRAM);
+ AddStreams(vertex_program_, CG_GLOBAL);
+}
+
+// Loop over all leaf parameters, and find the ones that are bound to a
+// semantic.
+void EffectGL::AddStreams(CGprogram prog, CGenum name_space) {
+ for (CGparameter cg_param = cgGetFirstLeafParameter(prog, name_space);
+ cg_param != NULL;
+ cg_param = cgGetNextLeafParameter(cg_param)) {
+ CGenum variability = cgGetParameterVariability(cg_param);
+ if (variability != CG_VARYING)
+ continue;
+ CGenum direction = cgGetParameterDirection(cg_param);
+ if (direction != CG_IN)
+ continue;
+ const char* cg_semantic = cgGetParameterSemantic(cg_param);
+ if (cg_semantic == NULL)
+ continue;
+
+ SemanticMap::iterator iter = semantic_map.find(String(cg_semantic));
+ if (iter == semantic_map.end()) {
+ streams_.push_back(effect_stream::Desc(
+ vertex_struct::kUnknownSemantic, 0));
+ } else {
+ streams_.push_back(iter->second);
+ }
+ }
+}
+
+// Begins rendering with the effect, setting all the appropriate states.
+bool EffectGL::Begin(GAPIGL *gapi) {
+ cgGLBindProgram(vertex_program_);
+ cgGLBindProgram(fragment_program_);
+
+ // sampler->ApplyStates will mess with the texture binding on unit 0, so we
+ // do 2 passes.
+ // First to set the sampler states on the texture
+ for (unsigned int i = 0; i < sampler_params_.size(); ++i) {
+ unsigned int param_index = sampler_params_[i];
+ std::vector<ResourceId> &ids = low_level_params_[param_index].sampler_ids;
+ for (std::vector<ResourceId>::iterator iter = ids.begin();
+ iter != ids.end();
+ ++iter) {
+ ResourceId id = *iter;
+ if (id != kInvalidResource) {
+ SamplerGL *sampler = gapi->GetSampler(id);
+ if (!sampler->ApplyStates(gapi)) {
+ return false;
+ }
+ }
+ }
+ }
+ // Second to enable/disable the sampler params.
+ for (unsigned int i = 0; i < sampler_params_.size(); ++i) {
+ unsigned int param_index = sampler_params_[i];
+ const LowLevelParam &ll_param = low_level_params_[param_index];
+ std::vector<ResourceId> &ids = low_level_params_[param_index].sampler_ids;
+ // TODO(petersont): Rewrite the following so it handles arrays of samplers
+ // instead of simply bailing.
+ if (cgGetParameterType(ll_param.fp_param) == CG_ARRAY)
+ return false;
+ for (std::vector<ResourceId>::iterator iter = ids.begin();
+ iter != ids.end();
+ ++iter) {
+ ResourceId id = *iter;
+ if (id != kInvalidResource) {
+ SamplerGL *sampler = gapi->GetSampler(id);
+ GLuint gl_texture = sampler->gl_texture();
+ cgGLSetTextureParameter(ll_param.fp_param, gl_texture);
+ cgGLEnableTextureParameter(ll_param.fp_param);
+ } else {
+ cgGLSetTextureParameter(ll_param.fp_param, 0);
+ cgGLDisableTextureParameter(ll_param.fp_param);
+ }
+ }
+ }
+ return true;
+}
+
+// Terminates rendering with the effect, resetting all the appropriate states.
+void EffectGL::End(GAPIGL *gapi) {
+}
+
+// Gets the parameter count from the list.
+unsigned int EffectGL::GetParamCount() const {
+ return low_level_params_.size();
+}
+
+// Gets the number of input streams from the shader.
+unsigned int EffectGL::GetStreamCount() const {
+ return streams_.size();
+}
+
+// Gets a handle to the selected parameter, and wraps it into an
+// EffectParamGL if successful.
+EffectParamGL *EffectGL::CreateParam(unsigned int index) {
+ if (index >= GetParamCount())
+ return NULL;
+ return EffectParamGL::Create(this, index);
+}
+
+// Provided enough room is available in the buffer, fills the Desc structure,
+// appending name and semantic if any.
+bool EffectGL::GetStreamDesc(unsigned int index,
+ unsigned int size,
+ void *data) {
+ using effect_stream::Desc;
+ if (size < sizeof(Desc) || index >= streams_.size()) // NOLINT
+ return false;
+
+ Desc *desc = static_cast<Desc *>(data);
+ *desc = streams_[index];
+ return true;
+}
+
+// Gets a handle to the selected parameter, and wraps it into an
+// EffectParamGL if successful.
+EffectParamGL *EffectGL::CreateParamByName(const char *name) {
+ int index = GetLowLevelParamIndexByName(name);
+ if (index < 0) return NULL;
+ return EffectParamGL::Create(this, index);
+}
+
+parse_error::ParseError GAPIGL::CreateEffect(ResourceId id,
+ unsigned int size,
+ const void *data) {
+ if (id == current_effect_id_) DirtyEffect();
+ // Even though Assign would Destroy the effect at id, we do it explicitly in
+ // case the creation fails.
+ effects_.Destroy(id);
+ // Data is vp_main \0 fp_main \0 effect_text.
+ String vertex_program_entry;
+ String fragment_program_entry;
+ String effect_code;
+ if (!ParseEffectData(size, data,
+ &vertex_program_entry,
+ &fragment_program_entry,
+ &effect_code)) {
+ return parse_error::kParseInvalidArguments;
+ }
+ EffectGL * effect = EffectGL::Create(this, effect_code,
+ vertex_program_entry,
+ fragment_program_entry);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ effects_.Assign(id, effect);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::DestroyEffect(ResourceId id) {
+ if (id == current_effect_id_) DirtyEffect();
+ return effects_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::SetEffect(ResourceId id) {
+ DirtyEffect();
+ current_effect_id_ = id;
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::GetParamCount(ResourceId id,
+ unsigned int size,
+ void *data) {
+ EffectGL *effect = effects_.Get(id);
+ if (!effect || size < sizeof(Uint32)) // NOLINT
+ return parse_error::kParseInvalidArguments;
+ *static_cast<Uint32 *>(data) = effect->GetParamCount();
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::CreateParam(ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int index) {
+ EffectGL *effect = effects_.Get(effect_id);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ EffectParamGL *param = effect->CreateParam(index);
+ if (!param) return parse_error::kParseInvalidArguments;
+ effect_params_.Assign(param_id, param);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::CreateParamByName(ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int size,
+ const void *name) {
+ EffectGL *effect = effects_.Get(effect_id);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ std::string string_name(static_cast<const char *>(name), size);
+ EffectParamGL *param = effect->CreateParamByName(string_name.c_str());
+ if (!param) return parse_error::kParseInvalidArguments;
+ effect_params_.Assign(param_id, param);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::DestroyParam(ResourceId id) {
+ return effect_params_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::SetParamData(ResourceId id,
+ unsigned int size,
+ const void *data) {
+ EffectParamGL *param = effect_params_.Get(id);
+ if (!param) return parse_error::kParseInvalidArguments;
+ return param->SetData(this, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::GetParamDesc(ResourceId id,
+ unsigned int size,
+ void *data) {
+ EffectParamGL *param = effect_params_.Get(id);
+ if (!param) return parse_error::kParseInvalidArguments;
+ return param->GetDesc(size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::GetStreamCount(
+ ResourceId id,
+ unsigned int size,
+ void *data) {
+ EffectGL *effect = effects_.Get(id);
+ if (!effect || size < sizeof(Uint32)) // NOLINT
+ return parse_error::kParseInvalidArguments;
+ *static_cast<Uint32 *>(data) = effect->GetStreamCount();
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::GetStreamDesc(ResourceId id,
+ unsigned int index,
+ unsigned int size,
+ void *data) {
+ EffectGL *effect = effects_.Get(id);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ return effect->GetStreamDesc(index, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// If the current effect is valid, call End on it, and tag for revalidation.
+void GAPIGL::DirtyEffect() {
+ if (validate_effect_) return;
+ DCHECK(current_effect_);
+ current_effect_->End(this);
+ current_effect_ = NULL;
+ validate_effect_ = true;
+}
+
+// Gets the current effect, and calls Begin on it (if successful).
+// Should only be called if the current effect is not valid.
+bool GAPIGL::ValidateEffect() {
+ DCHECK(validate_effect_);
+ DCHECK(!current_effect_);
+ current_effect_ = effects_.Get(current_effect_id_);
+ if (!current_effect_) return false;
+ validate_effect_ = false;
+ return current_effect_->Begin(this);
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/effect_gl.h b/o3d/gpu/command_buffer/service/effect_gl.h
new file mode 100644
index 0000000..b38cc92
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/effect_gl.h
@@ -0,0 +1,162 @@
+/*
+ * 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 declaration of the EffectParamGL and EffectGL classes.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_EFFECT_GL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_EFFECT_GL_H_
+
+#include <vector>
+
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/resource.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class GAPIGL;
+class EffectGL;
+
+// GL version of EffectParam.
+class EffectParamGL: public EffectParam {
+ public:
+ EffectParamGL(effect_param::DataType data_type,
+ EffectGL *effect,
+ unsigned int param_index);
+ virtual ~EffectParamGL();
+
+ // Sets the data into the GL effect parameter.
+ bool SetData(GAPIGL *gapi, unsigned int size, const void * data);
+
+ // Gets the description of the parameter.
+ bool GetDesc(unsigned int size, void *data);
+
+ // Resets the effect back-pointer. This is called when the effect gets
+ // destroyed, to invalidate the parameter.
+ void ResetEffect() { effect_ = NULL; }
+
+ // Creates an EffectParamGL from the EffectGL, by index.
+ static EffectParamGL *Create(EffectGL *effect,
+ unsigned int index);
+ private:
+ EffectGL *effect_;
+ unsigned int low_level_param_index_;
+ DISALLOW_COPY_AND_ASSIGN(EffectParamGL);
+};
+
+// GL version of Effect.
+class EffectGL : public Effect {
+ public:
+ EffectGL(CGprogram vertex_program,
+ CGprogram fragment_program);
+ virtual ~EffectGL();
+
+ // Compiles and creates an effect from source code.
+ static EffectGL *Create(GAPIGL *gapi,
+ const String &effect_code,
+ const String &vertex_program_entry,
+ const String &fragment_program_entry);
+
+ // Applies the effect states (vertex shader, pixel shader) to GL.
+ bool Begin(GAPIGL *gapi);
+
+ // Resets the effect states (vertex shader, pixel shader) to GL.
+ void End(GAPIGL *gapi);
+
+ // Gets the number of parameters in the effect.
+ unsigned int GetParamCount() const;
+
+ // Gets the number of streams in the effect.
+ unsigned int GetStreamCount() const;
+
+ // Creates an effect parameter with the specified index.
+ EffectParamGL *CreateParam(unsigned int index);
+
+ // Gets the stream data with the specified index.
+ bool GetStreamDesc(unsigned int index, unsigned int size, void *data);
+
+ // Creates an effect parameter of the specified name.
+ EffectParamGL *CreateParamByName(const char *name);
+
+ private:
+ struct LowLevelParam {
+ const char *name;
+ CGparameter vp_param;
+ CGparameter fp_param;
+ int num_elements;
+ std::vector<ResourceId> sampler_ids;
+ };
+ typedef std::vector<LowLevelParam> LowLevelParamList;
+ typedef std::vector<EffectParamGL *> ParamList;
+ typedef std::vector<effect_stream::Desc> StreamList;
+
+ static CGparameter GetEitherCgParameter(
+ const LowLevelParam &low_level_param) {
+ return low_level_param.vp_param ?
+ low_level_param.vp_param : low_level_param.fp_param;
+ }
+
+ int GetLowLevelParamIndexByName(const char *name);
+ void AddLowLevelParams(CGprogram prog, CGenum name_space, bool vp);
+ void AddStreams(CGprogram prog, CGenum name_space);
+
+ // Creates the low level structures.
+ void Initialize();
+
+ // Links a param into this effect.
+ void LinkParam(EffectParamGL *param);
+
+ // Unlinks a param into this effect.
+ void UnlinkParam(EffectParamGL *param);
+
+ CGprogram vertex_program_;
+ CGprogram fragment_program_;
+ // List of all the Params created.
+ ParamList params_;
+ StreamList streams_;
+ // List of all the Cg parameters present in either the vertex program or the
+ // fragment program.
+ LowLevelParamList low_level_params_;
+
+ // List of the indices of the low level params that are samplers.
+ std::vector<unsigned int> sampler_params_;
+ bool update_samplers_;
+
+ friend class EffectParamGL;
+ DISALLOW_COPY_AND_ASSIGN(EffectGL);
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_EFFECT_GL_H_
diff --git a/o3d/gpu/command_buffer/service/effect_utils.cc b/o3d/gpu/command_buffer/service/effect_utils.cc
new file mode 100644
index 0000000..021b49f
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/effect_utils.cc
@@ -0,0 +1,69 @@
+/*
+ * 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 implements effect related utilities.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/effect_utils.h"
+
+namespace command_buffer {
+
+bool ParseEffectData(unsigned int size,
+ const void *data,
+ String *vertex_program_entry,
+ String *fragment_program_entry,
+ String *effect_code) {
+ const char *data_char = static_cast<const char *>(data);
+ unsigned int index = 0;
+
+ for (; index < size && data_char[index]; ++index) { }
+ if (index >= size) return false;
+ *vertex_program_entry = String(data_char, index);
+ ++index; // skip \0
+ unsigned int fragment_program_entry_begin = index;
+
+ for (; index < size && data_char[index]; ++index) { }
+ if (index >= size) return false;
+ *fragment_program_entry = String(data_char + fragment_program_entry_begin,
+ index - fragment_program_entry_begin);
+ ++index; // skip \0
+ unsigned int effect_code_begin = index;
+
+ // text doesn't have to be 0-terminated, but look for one so that we don't
+ // construct a std::string with a '\0' in it.
+ for (; index < size && data_char[index]; ++index) { }
+ *effect_code = String(data_char + effect_code_begin,
+ index - effect_code_begin);
+ return true;
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/effect_utils.h b/o3d/gpu/command_buffer/service/effect_utils.h
new file mode 100644
index 0000000..ae22fb9
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/effect_utils.h
@@ -0,0 +1,54 @@
+/*
+ * 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 declares some effect related utilities.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_
+
+#include "gpu/command_buffer/common/types.h"
+
+namespace command_buffer {
+
+// This function parses the data passed to the CreateEffect commands, which
+// follows the following format:
+// vertex_program_entry \0 fragment_program_entry \0 effect_code
+// It returns the various components.
+bool ParseEffectData(unsigned int size,
+ const void *data,
+ String *vertex_program_entry,
+ String *fragment_program_entry,
+ String *effect_code);
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_
diff --git a/o3d/gpu/command_buffer/service/effect_utils_test.cc b/o3d/gpu/command_buffer/service/effect_utils_test.cc
new file mode 100644
index 0000000..695291e
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/effect_utils_test.cc
@@ -0,0 +1,87 @@
+/*
+ * 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 unit tests for the effect utilities.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "tests/common/win/testing_common.h"
+#include "gpu/command_buffer/service/cross/effect_utils.h"
+
+namespace o3d {
+namespace command_buffer {
+
+TEST(ParseEffectDataTest, ValidData) {
+ // Tests well-formed data.
+ const char kEffect[] = "vertex_entry\0fragment_entry\0effect code";
+ String vertex_program_entry;
+ String fragment_program_entry;
+ String effect_code;
+ EXPECT_TRUE(ParseEffectData(sizeof(kEffect), kEffect, &vertex_program_entry,
+ &fragment_program_entry, &effect_code));
+ EXPECT_EQ(vertex_program_entry, "vertex_entry");
+ EXPECT_EQ(fragment_program_entry, "fragment_entry");
+ EXPECT_EQ(effect_code, "effect code");
+
+ // The terminal \0 isn't needed, check that we parse correctly without it.
+ EXPECT_TRUE(ParseEffectData(sizeof(kEffect)-1, kEffect,
+ &vertex_program_entry, &fragment_program_entry,
+ &effect_code));
+ EXPECT_EQ(vertex_program_entry, "vertex_entry");
+ EXPECT_EQ(fragment_program_entry, "fragment_entry");
+ EXPECT_EQ(effect_code, "effect code");
+}
+
+TEST(ParseEffectDataTest, InvalidData) {
+ const char kEffect[] = "vertex_entry\0fragment_entry\0effect code";
+ String vertex_program_entry;
+ String fragment_program_entry;
+ String effect_code;
+ // 0-size
+ EXPECT_FALSE(ParseEffectData(0, kEffect,
+ &vertex_program_entry, &fragment_program_entry,
+ &effect_code));
+ // Only vertex_entry, no \0
+ EXPECT_FALSE(ParseEffectData(strlen("vertex_entry"), kEffect,
+ &vertex_program_entry, &fragment_program_entry,
+ &effect_code));
+ // Only vertex_entry\0
+ EXPECT_FALSE(ParseEffectData(strlen("vertex_entry") + 1, kEffect,
+ &vertex_program_entry, &fragment_program_entry,
+ &effect_code));
+ // Only vertex_entry\0fragment_entry, no \0
+ EXPECT_FALSE(ParseEffectData(strlen("vertex_entry.fragment_entry"), kEffect,
+ &vertex_program_entry, &fragment_program_entry,
+ &effect_code));
+}
+
+} // namespace command_buffer
+} // namespace o3d
diff --git a/o3d/gpu/command_buffer/service/gapi_d3d9.cc b/o3d/gpu/command_buffer/service/gapi_d3d9.cc
new file mode 100644
index 0000000..8ca8cfd
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/gapi_d3d9.cc
@@ -0,0 +1,393 @@
+/*
+ * 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 implementation of the GAPID3D9 class.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/gapi_d3d9.h"
+
+namespace command_buffer {
+namespace o3d {
+
+GAPID3D9::GAPID3D9()
+ : d3d_module_(NULL),
+ d3dx_module_(NULL),
+ d3d_(NULL),
+ d3d_device_(NULL),
+ hwnd_(NULL),
+ current_vertex_struct_(0),
+ validate_streams_(true),
+ max_vertices_(0),
+ current_effect_id_(0),
+ validate_effect_(true),
+ current_effect_(NULL),
+ vertex_buffers_(),
+ index_buffers_(),
+ vertex_structs_(),
+ back_buffer_surface_(NULL),
+ back_buffer_depth_surface_(NULL),
+ current_surface_id_(kInvalidResource),
+ current_depth_surface_id_(kInvalidResource),
+ direct3d_create9_(NULL),
+ get_shader_constant_table_(NULL),
+ create_effect_(NULL),
+ get_shader_input_semantics_(NULL) {}
+
+GAPID3D9::~GAPID3D9() {}
+
+// Initializes a D3D interface and device, and sets basic states.
+bool GAPID3D9::Initialize() {
+ if (!FindDirect3DFunctions()) {
+ Destroy();
+ return false;
+ }
+
+ d3d_ = Direct3DCreate(D3D_SDK_VERSION);
+ if (NULL == d3d_) {
+ LOG(ERROR) << "Failed to create the initial D3D9 Interface";
+ Destroy();
+ return false;
+ }
+ d3d_device_ = NULL;
+
+ D3DDISPLAYMODE d3ddm;
+ d3d_->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
+ // NOTE: make sure the backbuffer matches this format, as it is
+ // currently currently assumed to be 32-bit 8X8R8G8B
+
+ D3DPRESENT_PARAMETERS d3dpp;
+ ZeroMemory(&d3dpp, sizeof(d3dpp));
+ d3dpp.Windowed = TRUE;
+ d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ d3dpp.BackBufferFormat = d3ddm.Format;
+ d3dpp.EnableAutoDepthStencil = TRUE;
+ d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
+ d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; // wait for vsync
+ // Note: SwapEffect=DISCARD is req. for multisample to function
+ // Note: AutoDepthStencilFormat is 16-bit (not the usual 8-bit)
+
+ // query multisampling
+ const int kNumTypesToCheck = 4;
+ D3DMULTISAMPLE_TYPE multisample_types[] = { D3DMULTISAMPLE_5_SAMPLES,
+ D3DMULTISAMPLE_4_SAMPLES,
+ D3DMULTISAMPLE_2_SAMPLES,
+ D3DMULTISAMPLE_NONE };
+ DWORD multisample_quality = 0;
+ for (int i = 0; i < kNumTypesToCheck; ++i) {
+ // check back-buffer for multisampling at level "i";
+ // back buffer = 32-bit XRGB (i.e. no alpha)
+ if (SUCCEEDED(d3d_->CheckDeviceMultiSampleType(
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ D3DFMT_X8R8G8B8,
+ true, // result is windowed
+ multisample_types[i],
+ &multisample_quality))) {
+ // back buffer succeeded, now check depth-buffer
+ // depth buffer = 24-bit, stencil = 8-bit
+ // NOTE: 8-bit not 16-bit like the D3DPRESENT_PARAMETERS
+ if (SUCCEEDED(d3d_->CheckDeviceMultiSampleType(
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ D3DFMT_D24S8,
+ true, // result is windowed
+ multisample_types[i],
+ &multisample_quality))) {
+ d3dpp.MultiSampleType = multisample_types[i];
+ d3dpp.MultiSampleQuality = multisample_quality - 1;
+ break;
+ }
+ }
+ }
+ // D3DCREATE_FPU_PRESERVE is there because Firefox 3 relies on specific FPU
+ // flags for its UI rendering. Apparently Firefox 2 does not, though we don't
+ // currently propagate that info.
+ // TODO: check if FPU_PRESERVE has a significant perf hit, in which
+ // case find out if we can disable it for Firefox 2/other browsers, and/or if
+ // it makes sense to switch FPU flags before/after every DX call.
+ DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE;
+ if (!SUCCEEDED(d3d_->CreateDevice(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ hwnd_,
+ flags,
+ &d3dpp,
+ &d3d_device_))) {
+ LOG(ERROR) << "Failed to create the D3D Device";
+ Destroy();
+ return false;
+ }
+ // initialise the d3d graphics state.
+ HR(d3d_device_->SetRenderState(D3DRS_LIGHTING, FALSE));
+ HR(d3d_device_->SetRenderState(D3DRS_ZENABLE, TRUE));
+ HR(d3d_device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE));
+ return true;
+}
+
+// Deletes the D3D9 Device and releases the D3D interface.
+void GAPID3D9::Destroy() {
+ vertex_buffers_.DestroyAllResources();
+ index_buffers_.DestroyAllResources();
+ vertex_structs_.DestroyAllResources();
+ effects_.DestroyAllResources();
+ effect_params_.DestroyAllResources();
+ textures_.DestroyAllResources();
+ samplers_.DestroyAllResources();
+ render_surfaces_.DestroyAllResources();
+ depth_surfaces_.DestroyAllResources();
+ if (d3d_device_) {
+ d3d_device_->Release();
+ d3d_device_ = NULL;
+ }
+ if (d3d_) {
+ d3d_->Release();
+ d3d_ = NULL;
+ }
+ if (d3dx_module_) {
+ FreeLibrary(d3dx_module_);
+ d3dx_module_ = NULL;
+ get_shader_constant_table_ = NULL;
+ create_effect_ = NULL;
+ get_shader_input_semantics_ = NULL;
+ }
+ if (d3d_module_) {
+ FreeLibrary(d3d_module_);
+ d3d_module_ = NULL;
+ direct3d_create9_ = NULL;
+ }
+}
+
+// Begins the frame.
+void GAPID3D9::BeginFrame() {
+ HR(d3d_device_->GetRenderTarget(0, &back_buffer_surface_));
+ HR(d3d_device_->GetDepthStencilSurface(&back_buffer_depth_surface_));
+ HR(d3d_device_->BeginScene());
+}
+
+// Ends the frame, presenting the back buffer.
+void GAPID3D9::EndFrame() {
+ DirtyEffect();
+ HR(d3d_device_->EndScene());
+ HR(d3d_device_->Present(NULL, NULL, NULL, NULL));
+
+ // Release the back-buffer references.
+ back_buffer_surface_ = NULL;
+ back_buffer_depth_surface_ = NULL;
+}
+
+// Clears the selected buffers.
+void GAPID3D9::Clear(unsigned int buffers,
+ const RGBA &color,
+ float depth,
+ unsigned int stencil) {
+ DWORD flags = (buffers & kColor ? D3DCLEAR_TARGET : 0) |
+ (buffers & kDepth ? D3DCLEAR_ZBUFFER : 0) |
+ (buffers & kStencil ? D3DCLEAR_STENCIL : 0);
+ HR(d3d_device_->Clear(0,
+ NULL,
+ flags,
+ D3DCOLOR_COLORVALUE(color.red,
+ color.green,
+ color.blue,
+ color.alpha),
+ depth,
+ stencil));
+}
+
+// Sets the viewport.
+void GAPID3D9::SetViewport(unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height,
+ float z_min,
+ float z_max) {
+ D3DVIEWPORT9 viewport = {x, y, width, height, z_min, z_max};
+ HR(d3d_device_->SetViewport(&viewport));
+}
+
+// Converts an unsigned int RGBA color into an unsigned int ARGB (DirectX)
+// color.
+static unsigned int RGBAToARGB(unsigned int rgba) {
+ return (rgba >> 8) | (rgba << 24);
+}
+
+// Sets the current VertexStruct. Just keep track of the ID.
+parse_error::ParseError GAPID3D9::SetVertexStruct(ResourceId id) {
+ current_vertex_struct_ = id;
+ validate_streams_ = true;
+ return parse_error::kParseNoError;
+}
+
+bool GAPID3D9::FindDirect3DFunctions() {
+ d3d_module_ = LoadLibrary(TEXT("d3d9.dll"));
+ if (NULL == d3d_module_) {
+ LOG(ERROR) << "Failed to load d3d9.dll";
+ return false;
+ }
+
+ direct3d_create9_ = reinterpret_cast<Direct3DCreate9Proc>(
+ GetProcAddress(d3d_module_, "Direct3DCreate9"));
+ if (NULL == direct3d_create9_) {
+ LOG(ERROR) << "Failed to find Direct3DCreate9 in d3d9.dll";
+ Destroy();
+ return false;
+ }
+
+ d3dx_module_ = LoadLibrary(TEXT("d3dx9_36.dll"));
+ if (NULL == d3d_module_) {
+ LOG(ERROR) << "Failed to load d3dx9_36.dll";
+ return false;
+ }
+
+ get_shader_constant_table_ = reinterpret_cast<D3DXGetShaderConstantTableProc>(
+ GetProcAddress(d3dx_module_, "D3DXGetShaderConstantTable"));
+ if (NULL == get_shader_constant_table_) {
+ LOG(ERROR) << "Failed to find D3DXGetShaderConstantTable in d3dx9_36.dll";
+ Destroy();
+ return false;
+ }
+
+ create_effect_ = reinterpret_cast<D3DXCreateEffectProc>(
+ GetProcAddress(d3dx_module_, "D3DXCreateEffect"));
+ if (NULL == create_effect_) {
+ LOG(ERROR) << "Failed to find D3DXCreateEffect in d3dx9_36.dll";
+ Destroy();
+ return false;
+ }
+
+ get_shader_input_semantics_ =
+ reinterpret_cast<D3DXGetShaderInputSemanticsProc>(
+ GetProcAddress(d3dx_module_, "D3DXGetShaderInputSemantics"));
+ if (NULL == get_shader_input_semantics_) {
+ LOG(ERROR) << "Failed to find D3DXGetShaderInputSemantics in d3dx9_36.dll";
+ Destroy();
+ return false;
+ }
+
+ return true;
+}
+
+// Sets in D3D the input streams of the current vertex struct.
+bool GAPID3D9::ValidateStreams() {
+ DCHECK(validate_streams_);
+ VertexStructD3D9 *vertex_struct = vertex_structs_.Get(current_vertex_struct_);
+ if (!vertex_struct) {
+ LOG(ERROR) << "Drawing with invalid streams.";
+ return false;
+ }
+ max_vertices_ = vertex_struct->SetStreams(this);
+ validate_streams_ = false;
+ return max_vertices_ > 0;
+}
+
+// Converts a GAPID3D9::PrimitiveType to a D3DPRIMITIVETYPE.
+static D3DPRIMITIVETYPE D3DPrimitive(
+ PrimitiveType primitive_type) {
+ switch (primitive_type) {
+ case kPoints:
+ return D3DPT_POINTLIST;
+ case kLines:
+ return D3DPT_LINELIST;
+ case kLineStrips:
+ return D3DPT_LINESTRIP;
+ case kTriangles:
+ return D3DPT_TRIANGLELIST;
+ case kTriangleStrips:
+ return D3DPT_TRIANGLESTRIP;
+ case kTriangleFans:
+ return D3DPT_TRIANGLEFAN;
+ default:
+ LOG(FATAL) << "Invalid primitive type";
+ return D3DPT_POINTLIST;
+ }
+}
+
+// Draws with the current vertex struct.
+parse_error::ParseError GAPID3D9::Draw(
+ PrimitiveType primitive_type,
+ unsigned int first,
+ unsigned int count) {
+ if (validate_streams_ && !ValidateStreams()) {
+ // TODO: add proper error management
+ return parse_error::kParseInvalidArguments;
+ }
+ if (validate_effect_ && !ValidateEffect()) {
+ // TODO: add proper error management
+ return parse_error::kParseInvalidArguments;
+ }
+ DCHECK(current_effect_);
+ if (!current_effect_->CommitParameters()) {
+ return parse_error::kParseInvalidArguments;
+ }
+ if (first + count > max_vertices_) {
+ // TODO: add proper error management
+ return parse_error::kParseInvalidArguments;
+ }
+ HR(d3d_device_->DrawPrimitive(D3DPrimitive(primitive_type), first, count));
+ return parse_error::kParseNoError;
+}
+
+// Draws with the current vertex struct.
+parse_error::ParseError GAPID3D9::DrawIndexed(
+ PrimitiveType primitive_type,
+ ResourceId index_buffer_id,
+ unsigned int first,
+ unsigned int count,
+ unsigned int min_index,
+ unsigned int max_index) {
+ IndexBufferD3D9 *index_buffer = index_buffers_.Get(index_buffer_id);
+ if (!index_buffer) return parse_error::kParseInvalidArguments;
+ if (validate_streams_ && !ValidateStreams()) {
+ // TODO: add proper error management
+ return parse_error::kParseInvalidArguments;
+ }
+ if (validate_effect_ && !ValidateEffect()) {
+ // TODO: add proper error management
+ return parse_error::kParseInvalidArguments;
+ }
+ DCHECK(current_effect_);
+ if (!current_effect_->CommitParameters()) {
+ return parse_error::kParseInvalidArguments;
+ }
+ if ((min_index >= max_vertices_) || (max_index > max_vertices_)) {
+ // TODO: add proper error management
+ return parse_error::kParseInvalidArguments;
+ }
+
+ HR(d3d_device_->SetIndices(index_buffer->d3d_index_buffer()));
+ HR(d3d_device_->DrawIndexedPrimitive(D3DPrimitive(primitive_type), 0,
+ min_index, max_index - min_index + 1,
+ first, count));
+ return parse_error::kParseNoError;
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/gapi_d3d9.h b/o3d/gpu/command_buffer/service/gapi_d3d9.h
new file mode 100644
index 0000000..1056dc1
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/gapi_d3d9.h
@@ -0,0 +1,508 @@
+/*
+ * 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 GAPID3D9 class, implementing the GAPI interface for
+// D3D9.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GAPI_D3D9_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GAPI_D3D9_H_
+
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/d3d9_utils.h"
+#include "gpu/command_buffer/service/geometry_d3d9.h"
+#include "gpu/command_buffer/service/effect_d3d9.h"
+#include "gpu/command_buffer/service/texture_d3d9.h"
+#include "gpu/command_buffer/service/sampler_d3d9.h"
+#include "gpu/command_buffer/service/render_surface_d3d9.h"
+
+namespace command_buffer {
+namespace o3d {
+
+// This class implements the GAPI interface for D3D9.
+class GAPID3D9 : public GAPIInterface {
+ public:
+ GAPID3D9();
+ virtual ~GAPID3D9();
+
+ void set_hwnd(HWND hwnd) { hwnd_ = hwnd; }
+ HWND hwnd() const { return hwnd_; }
+
+ // Initializes the graphics context, bound to a window.
+ // Returns:
+ // true if successful.
+ virtual bool Initialize();
+
+ // Destroys the graphics context.
+ virtual void Destroy();
+
+ // Implements the BeginFrame function for D3D9.
+ virtual void BeginFrame();
+
+ // Implements the EndFrame function for D3D9.
+ virtual void EndFrame();
+
+ // Implements the Clear function for D3D9.
+ virtual void Clear(unsigned int buffers,
+ const RGBA &color,
+ float depth,
+ unsigned int stencil);
+
+ // Implements the SetViewport function for D3D9.
+ virtual void SetViewport(unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height,
+ float z_min,
+ float z_max);
+
+ // Implements the CreateVertexBuffer function for D3D9.
+ virtual ParseError CreateVertexBuffer(ResourceId id,
+ unsigned int size,
+ unsigned int flags);
+
+ // Implements the DestroyVertexBuffer function for D3D9.
+ virtual ParseError DestroyVertexBuffer(ResourceId id);
+
+ // Implements the SetVertexBufferData function for D3D9.
+ virtual ParseError SetVertexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data);
+
+ // Implements the GetVertexBufferData function for D3D9.
+ virtual ParseError GetVertexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data);
+
+ // Implements the CreateIndexBuffer function for D3D9.
+ virtual ParseError CreateIndexBuffer(ResourceId id,
+ unsigned int size,
+ unsigned int flags);
+
+ // Implements the DestroyIndexBuffer function for D3D9.
+ virtual ParseError DestroyIndexBuffer(ResourceId id);
+
+ // Implements the SetIndexBufferData function for D3D9.
+ virtual ParseError SetIndexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data);
+
+ // Implements the GetIndexBufferData function for D3D9.
+ virtual ParseError GetIndexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data);
+
+ // Implements the CreateVertexStruct function for D3D9.
+ virtual ParseError CreateVertexStruct(ResourceId id,
+ unsigned int input_count);
+
+ // Implements the DestroyVertexStruct function for D3D9.
+ virtual ParseError DestroyVertexStruct(ResourceId id);
+
+ // Implements the SetVertexInput function for D3D9.
+ virtual ParseError SetVertexInput(ResourceId vertex_struct_id,
+ unsigned int input_index,
+ ResourceId vertex_buffer_id,
+ unsigned int offset,
+ unsigned int stride,
+ vertex_struct::Type type,
+ vertex_struct::Semantic semantic,
+ unsigned int semantic_index);
+
+ // Implements the SetVertexStruct function for D3D9.
+ virtual ParseError SetVertexStruct(ResourceId id);
+
+ // Implements the Draw function for D3D9.
+ virtual ParseError Draw(PrimitiveType primitive_type,
+ unsigned int first,
+ unsigned int count);
+
+ // Implements the DrawIndexed function for D3D9.
+ virtual ParseError DrawIndexed(PrimitiveType primitive_type,
+ ResourceId index_buffer_id,
+ unsigned int first,
+ unsigned int count,
+ unsigned int min_index,
+ unsigned int max_index);
+
+ // Implements the CreateEffect function for D3D9.
+ virtual ParseError CreateEffect(ResourceId id,
+ unsigned int size,
+ const void *data);
+
+ // Implements the DestroyEffect function for D3D9.
+ virtual ParseError DestroyEffect(ResourceId id);
+
+ // Implements the SetEffect function for D3D9.
+ virtual ParseError SetEffect(ResourceId id);
+
+ // Implements the GetParamCount function for D3D9.
+ virtual ParseError GetParamCount(ResourceId id,
+ unsigned int size,
+ void *data);
+
+ // Implements the CreateParam function for D3D9.
+ virtual ParseError CreateParam(ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int index);
+
+ // Implements the CreateParamByName function for D3D9.
+ virtual ParseError CreateParamByName(ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int size,
+ const void *name);
+
+ // Implements the DestroyParam function for D3D9.
+ virtual ParseError DestroyParam(ResourceId id);
+
+ // Implements the SetParamData function for D3D9.
+ virtual ParseError SetParamData(ResourceId id,
+ unsigned int size,
+ const void *data);
+
+ // Implements the GetParamDesc function for D3D9.
+ virtual ParseError GetParamDesc(ResourceId id,
+ unsigned int size,
+ void *data);
+
+ // Implements the GetStreamCount function for D3D9.
+ virtual ParseError GetStreamCount(ResourceId id,
+ unsigned int size,
+ void *data);
+
+ // Implements the GetStreamDesc function for D3D9.
+ virtual ParseError GetStreamDesc(ResourceId id,
+ unsigned int index,
+ unsigned int size,
+ void *data);
+
+ // Implements the CreateTexture2D function for D3D9.
+ virtual ParseError CreateTexture2D(ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+
+ // Implements the CreateTexture3D function for D3D9.
+ virtual ParseError CreateTexture3D(ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+
+ // Implements the CreateTextureCube function for D3D9.
+ virtual ParseError CreateTextureCube(ResourceId id,
+ unsigned int side,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+
+ // Implements the SetTextureData function for D3D9.
+ virtual ParseError SetTextureData(ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data);
+
+ // Implements the GetTextureData function for D3D9.
+ virtual ParseError GetTextureData(ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data);
+
+ // Implements the DestroyTexture function for D3D9.
+ virtual ParseError DestroyTexture(ResourceId id);
+
+ // Implements the CreateSampler function for D3D9.
+ virtual ParseError CreateSampler(ResourceId id);
+
+ // Implements the DestroySampler function for D3D9.
+ virtual ParseError DestroySampler(ResourceId id);
+
+ // Implements the SetSamplerStates function for D3D9.
+ virtual ParseError SetSamplerStates(ResourceId id,
+ sampler::AddressingMode addressing_u,
+ sampler::AddressingMode addressing_v,
+ sampler::AddressingMode addressing_w,
+ sampler::FilteringMode mag_filter,
+ sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter,
+ unsigned int max_anisotropy);
+
+ // Implements the SetSamplerBorderColor function for D3D9.
+ virtual ParseError SetSamplerBorderColor(ResourceId id, const RGBA &color);
+
+ // Implements the SetSamplerTexture function for D3D9.
+ virtual ParseError SetSamplerTexture(ResourceId id, ResourceId texture_id);
+
+ // Implements the SetScissor function for D3D9.
+ virtual void SetScissor(bool enable,
+ unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height);
+
+ // Implements the SetPointLineRaster function for D3D9.
+ virtual void SetPointLineRaster(bool line_smooth,
+ bool point_sprite,
+ float point_size);
+
+ // Implements the SetPolygonOffset function for D3D9.
+ virtual void SetPolygonOffset(float slope_factor, float units);
+
+ // Implements the SetPolygonRaster function for D3D9.
+ virtual void SetPolygonRaster(PolygonMode fill_mode,
+ FaceCullMode cull_mode);
+
+ // Implements the SetAlphaTest function for D3D9.
+ virtual void SetAlphaTest(bool enable,
+ float reference,
+ Comparison comp);
+
+ // Implements the SetDepthTest function for D3D9.
+ virtual void SetDepthTest(bool enable,
+ bool write_enable,
+ Comparison comp);
+
+ // Implements the SetStencilTest function for D3D9.
+ virtual void SetStencilTest(bool enable,
+ bool separate_ccw,
+ unsigned int write_mask,
+ unsigned int compare_mask,
+ unsigned int ref,
+ Uint32 func_ops);
+
+ // Implements the SetColorWritefunction for D3D9.
+ virtual void SetColorWrite(bool red,
+ bool green,
+ bool blue,
+ bool alpha,
+ bool dither);
+
+ // Implements the SetBlending function for D3D9.
+ virtual void SetBlending(bool enable,
+ bool separate_alpha,
+ BlendEq color_eq,
+ BlendFunc color_src_func,
+ BlendFunc color_dst_func,
+ BlendEq alpha_eq,
+ BlendFunc alpha_src_func,
+ BlendFunc alpha_dst_func);
+
+ // Implements the SetBlendingColor function for D3D9.
+ virtual void SetBlendingColor(const RGBA &color);
+
+ // Implements the CreateRenderSurface function for D3D9.
+ virtual ParseError CreateRenderSurface(ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int mip_level,
+ unsigned int side,
+ ResourceId texture_id);
+
+ // Implements the DestroyRenderSurface function for D3D9.
+ virtual ParseError DestroyRenderSurface(ResourceId id);
+
+ // Implements the CreateDepthSurface function for D3D9.
+ virtual ParseError CreateDepthSurface(ResourceId id,
+ unsigned int width,
+ unsigned int height);
+
+ // Implements teh DestroyDepthSurface function for D3D9.
+ virtual ParseError DestroyDepthSurface(ResourceId id);
+
+ // Implements the SetRenderSurface function for D3D9.
+ virtual ParseError SetRenderSurface(ResourceId render_surface_id,
+ ResourceId depth_stencil_id);
+
+ // Implements the SetBackSurfaces function for D3D9.
+ virtual void SetBackSurfaces();
+
+ // Gets the D3D9 device.
+ IDirect3DDevice9 *d3d_device() const { return d3d_device_; }
+
+ // Gets a vertex buffer by resource ID.
+ VertexBufferD3D9 *GetVertexBuffer(ResourceId id) {
+ return vertex_buffers_.Get(id);
+ }
+
+ // Gets a texture by resource ID.
+ TextureD3D9 *GetTexture(ResourceId id) {
+ return textures_.Get(id);
+ }
+
+ // Gets a sampler by resource ID.
+ SamplerD3D9 *GetSampler(ResourceId id) {
+ return samplers_.Get(id);
+ }
+
+ EffectD3D9 *current_effect() { return current_effect_; }
+
+ // Direct3D functions cannot be called directly because the DLLs are loaded
+ // dynamically via LoadLibrary. If you need to add another Direct3D function
+ // add another function here, a typedef matching the signature and a member
+ // variable of that type below. Then add code to FindDirect3DFunctions to
+ // get the address of that function out of the DLL and assign it to the
+ // member variable. Be careful to initialize the value of the variable to
+ // NULL in the constructor and to set it to again NULL in Destroy.
+
+ IDirect3D9* Direct3DCreate(UINT version) {
+ DCHECK(direct3d_create9_);
+ return direct3d_create9_(version);
+ }
+
+ HRESULT D3DXGetShaderConstantTable(const DWORD* function,
+ LPD3DXCONSTANTTABLE* table) {
+ DCHECK(get_shader_constant_table_);
+ return get_shader_constant_table_(function, table);
+ }
+
+ HRESULT D3DXCreateEffect(LPDIRECT3DDEVICE9 device,
+ LPCVOID src_data,
+ UINT src_data_len,
+ CONST D3DXMACRO * defines,
+ LPD3DXINCLUDE include,
+ DWORD flags,
+ LPD3DXEFFECTPOOL pool,
+ LPD3DXEFFECT * effect,
+ LPD3DXBUFFER * compilation_errors) {
+ DCHECK(create_effect_);
+ return create_effect_(device, src_data, src_data_len, defines, include,
+ flags, pool, effect, compilation_errors);
+ }
+
+ HRESULT D3DXGetShaderInputSemantics(const DWORD* function,
+ D3DXSEMANTIC* semantics,
+ UINT* count) {
+ DCHECK(get_shader_input_semantics_);
+ return get_shader_input_semantics_(function, semantics, count);
+ }
+
+ private:
+ bool FindDirect3DFunctions();
+
+ // Validates the current vertex struct to D3D, setting the streams.
+ bool ValidateStreams();
+ // Validates the current effect to D3D. This sends the effect states to D3D.
+ bool ValidateEffect();
+ // "Dirty" the current effect. This resets the effect states to D3D, and
+ // requires ValidateEffect() to be called before further draws occur.
+ void DirtyEffect();
+
+ // Module handle for d3d9.dll.
+ HMODULE d3d_module_;
+
+ // Module handle for d3dx9_n.dll
+ HMODULE d3dx_module_;
+
+ LPDIRECT3D9 d3d_;
+ LPDIRECT3DDEVICE9 d3d_device_;
+ HWND hwnd_;
+ ResourceId current_vertex_struct_;
+ bool validate_streams_;
+ unsigned int max_vertices_;
+ ResourceId current_effect_id_;
+ bool validate_effect_;
+ EffectD3D9 *current_effect_;
+ IDirect3DSurface9* back_buffer_surface_;
+ IDirect3DSurface9* back_buffer_depth_surface_;
+ ResourceId current_surface_id_;
+ ResourceId current_depth_surface_id_;
+
+ ResourceMap<VertexBufferD3D9> vertex_buffers_;
+ ResourceMap<IndexBufferD3D9> index_buffers_;
+ ResourceMap<VertexStructD3D9> vertex_structs_;
+ ResourceMap<EffectD3D9> effects_;
+ ResourceMap<EffectParamD3D9> effect_params_;
+ ResourceMap<TextureD3D9> textures_;
+ ResourceMap<SamplerD3D9> samplers_;
+ ResourceMap<RenderSurfaceD3D9> render_surfaces_;
+ ResourceMap<RenderDepthStencilSurfaceD3D9> depth_surfaces_;
+
+ typedef IDirect3D9* (WINAPI *Direct3DCreate9Proc)(UINT version);
+ Direct3DCreate9Proc direct3d_create9_;
+
+ typedef HRESULT (WINAPI *D3DXGetShaderConstantTableProc)(
+ const DWORD* function,
+ LPD3DXCONSTANTTABLE* table);
+ D3DXGetShaderConstantTableProc get_shader_constant_table_;
+
+ typedef HRESULT (WINAPI *D3DXCreateEffectProc)(
+ LPDIRECT3DDEVICE9 device,
+ LPCVOID src_data,
+ UINT src_data_len,
+ CONST D3DXMACRO * defines,
+ LPD3DXINCLUDE include,
+ DWORD flags,
+ LPD3DXEFFECTPOOL pool,
+ LPD3DXEFFECT * effect,
+ LPD3DXBUFFER * compilation_errors);
+ D3DXCreateEffectProc create_effect_;
+
+ typedef HRESULT (WINAPI *D3DXGetShaderInputSemanticsProc)(
+ const DWORD* function,
+ D3DXSEMANTIC* semantics,
+ UINT* count);
+ D3DXGetShaderInputSemanticsProc get_shader_input_semantics_;
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GAPI_D3D9_H_
+
diff --git a/o3d/gpu/command_buffer/service/gapi_decoder.cc b/o3d/gpu/command_buffer/service/gapi_decoder.cc
new file mode 100644
index 0000000..4d91b69
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/gapi_decoder.cc
@@ -0,0 +1,940 @@
+/*
+ * 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 class contains the implementation of the GAPI decoder class, decoding
+// GAPI commands into calls to a GAPIInterface class.
+
+#include "gpu/command_buffer/service/precompile.h"
+
+#include "base/cross/bits.h"
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/gapi_decoder.h"
+
+namespace command_buffer {
+namespace o3d {
+
+namespace {
+
+// Returns the address of the first byte after a struct.
+template <typename T>
+const void* AddressAfterStruct(const T& pod) {
+ return reinterpret_cast<const uint8*>(&pod) + sizeof(pod);
+}
+
+// Returns the size in bytes of the data of an Immediate command, a command with
+// its data inline in the command buffer.
+template <typename T>
+unsigned int ImmediateDataSize(uint32 arg_count, const T& pod) {
+ return static_cast<unsigned int>(
+ (arg_count + 1 - ComputeNumEntries(sizeof(pod))) *
+ sizeof(CommandBufferEntry)); // NOLINT
+}
+
+// A struct to hold info about each command.
+struct CommandInfo {
+ int arg_flags; // How to handle the arguments for this command
+ int arg_count; // How many arguments are expected for this command.
+};
+
+// A table of CommandInfo for all the commands.
+const CommandInfo g_command_info[] = {
+ #define O3D_COMMAND_BUFFER_CMD_OP(name) { \
+ name::kArgFlags, \
+ sizeof(name) / sizeof(CommandBufferEntry) - 1, }, /* NOLINT */ \
+
+ O3D_COMMAND_BUFFER_CMDS(O3D_COMMAND_BUFFER_CMD_OP)
+
+ #undef O3D_COMMAND_BUFFER_CMD_OP
+};
+
+} // anonymous namespace.
+
+// Decode command with its arguments, and call the corresponding method.
+// Note: args is a pointer to the command buffer. As such, it could be changed
+// by a (malicious) client at any time, so if validation has to happen, it
+// should operate on a copy of them.
+parse_error::ParseError GAPIDecoder::DoCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data) {
+ unsigned int command_index = command - kStartPoint - 1;
+ if (command_index < arraysize(g_command_info)) {
+ const CommandInfo& info = g_command_info[command_index];
+ unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
+ if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
+ (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
+ switch (command) {
+ #define O3D_COMMAND_BUFFER_CMD_OP(name) \
+ case name::kCmdId: \
+ return Handle ## name( \
+ arg_count, \
+ *static_cast<const name*>(cmd_data)); \
+
+ O3D_COMMAND_BUFFER_CMDS(O3D_COMMAND_BUFFER_CMD_OP)
+
+ #undef O3D_COMMAND_BUFFER_CMD_OP
+ }
+ } else {
+ return parse_error::kParseInvalidArguments;
+ }
+ }
+ return DoCommonCommand(command, arg_count, cmd_data);
+ return parse_error::kParseUnknownCommand;
+}
+
+ // Overridden from AsyncAPIInterface.
+const char* GAPIDecoder::GetCommandName(unsigned int command_id) const {
+ if (command_id > kStartPoint && command_id < kNumCommands) {
+ return o3d::GetCommandName(static_cast<CommandId>(command_id));
+ }
+ return GetCommonCommandName(static_cast<cmd::CommandId>(command_id));
+}
+
+parse_error::ParseError GAPIDecoder::HandleBeginFrame(
+ uint32 arg_count,
+ const BeginFrame& args) {
+ gapi_->BeginFrame();
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleEndFrame(
+ uint32 arg_count,
+ const EndFrame& args) {
+ gapi_->EndFrame();
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleClear(
+ uint32 arg_count,
+ const Clear& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 buffers = args.buffers;
+ if (buffers & ~kAllBuffers)
+ return parse_error::kParseInvalidArguments;
+ RGBA rgba;
+ rgba.red = args.red;
+ rgba.green = args.green;
+ rgba.blue = args.blue;
+ rgba.alpha = args.alpha;
+ gapi_->Clear(buffers, rgba, args.depth, args.stencil);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetViewport(
+ uint32 arg_count,
+ const SetViewport& args) {
+ gapi_->SetViewport(args.left,
+ args.top,
+ args.width,
+ args.height,
+ args.z_min,
+ args.z_max);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateVertexBuffer(
+ uint32 arg_count,
+ const CreateVertexBuffer& args) {
+ return gapi_->CreateVertexBuffer(
+ args.vertex_buffer_id, args.size, args.flags);
+}
+
+parse_error::ParseError GAPIDecoder::HandleDestroyVertexBuffer(
+ uint32 arg_count,
+ const DestroyVertexBuffer& args) {
+ return gapi_->DestroyVertexBuffer(args.vertex_buffer_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetVertexBufferDataImmediate(
+ uint32 arg_count,
+ const SetVertexBufferDataImmediate& args) {
+ uint32 size = ImmediateDataSize(arg_count, args);
+ if (size == 0) {
+ return parse_error::kParseNoError;
+ }
+ return gapi_->SetVertexBufferData(args.vertex_buffer_id, args.offset,
+ size,
+ AddressAfterStruct(args));
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetVertexBufferData(
+ uint32 arg_count,
+ const SetVertexBufferData& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->SetVertexBufferData(
+ args.vertex_buffer_id, args.offset, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleGetVertexBufferData(
+ uint32 arg_count,
+ const GetVertexBufferData& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->GetVertexBufferData(
+ args.vertex_buffer_id, args.offset, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateIndexBuffer(
+ uint32 arg_count,
+ const CreateIndexBuffer& args) {
+ return gapi_->CreateIndexBuffer(args.index_buffer_id, args.size, args.flags);
+}
+
+parse_error::ParseError GAPIDecoder::HandleDestroyIndexBuffer(
+ uint32 arg_count,
+ const DestroyIndexBuffer& args) {
+ return gapi_->DestroyIndexBuffer(args.index_buffer_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetIndexBufferDataImmediate(
+ uint32 arg_count,
+ const SetIndexBufferDataImmediate& args) {
+ uint32 size = ImmediateDataSize(arg_count, args);
+ if (size == 0) {
+ return parse_error::kParseNoError;
+ }
+ return gapi_->SetIndexBufferData(args.index_buffer_id, args.offset, size,
+ AddressAfterStruct(args));
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetIndexBufferData(
+ uint32 arg_count,
+ const SetIndexBufferData& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->SetIndexBufferData(
+ args.index_buffer_id, args.offset, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleGetIndexBufferData(
+ uint32 arg_count,
+ const GetIndexBufferData& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->GetIndexBufferData(
+ args.index_buffer_id, args.offset, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateVertexStruct(
+ uint32 arg_count,
+ const CreateVertexStruct& args) {
+ return gapi_->CreateVertexStruct(args.vertex_struct_id, args.input_count);
+}
+
+parse_error::ParseError GAPIDecoder::HandleDestroyVertexStruct(
+ uint32 arg_count,
+ const DestroyVertexStruct& args) {
+ return gapi_->DestroyVertexStruct(args.vertex_struct_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetVertexInput(
+ uint32 arg_count,
+ const SetVertexInput& args) {
+ unsigned int type_stride_semantic = args.type_stride_semantic;
+ unsigned int semantic_index =
+ SetVertexInput::SemanticIndex::Get(type_stride_semantic);
+ unsigned int semantic =
+ SetVertexInput::Semantic::Get(type_stride_semantic);
+ unsigned int type =
+ SetVertexInput::Type::Get(type_stride_semantic);
+ unsigned int stride =
+ SetVertexInput::Stride::Get(type_stride_semantic);
+ if (semantic >= vertex_struct::kNumSemantics ||
+ type >= vertex_struct::kNumTypes || stride == 0)
+ return parse_error::kParseInvalidArguments;
+ return gapi_->SetVertexInput(
+ args.vertex_struct_id, args.input_index, args.vertex_buffer_id,
+ args.offset, stride,
+ static_cast<vertex_struct::Type>(type),
+ static_cast<vertex_struct::Semantic>(semantic),
+ semantic_index);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetVertexStruct(
+ uint32 arg_count,
+ const SetVertexStruct& args) {
+ return gapi_->SetVertexStruct(args.vertex_struct_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleDraw(
+ uint32 arg_count,
+ const Draw& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 primitive_type = args.primitive_type;
+ if (primitive_type >= kMaxPrimitiveType)
+ return parse_error::kParseInvalidArguments;
+ return gapi_->Draw(
+ static_cast<PrimitiveType>(primitive_type),
+ args.first, args.count);
+}
+
+parse_error::ParseError GAPIDecoder::HandleDrawIndexed(
+ uint32 arg_count,
+ const DrawIndexed& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 primitive_type = args.primitive_type;
+ if (primitive_type >= kMaxPrimitiveType)
+ return parse_error::kParseInvalidArguments;
+ return gapi_->DrawIndexed(
+ static_cast<PrimitiveType>(primitive_type),
+ args.index_buffer_id,
+ args.first, args.count, args.min_index, args.max_index);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateEffect(
+ uint32 arg_count,
+ const CreateEffect& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->CreateEffect(args.effect_id, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateEffectImmediate(
+ uint32 arg_count,
+ const CreateEffectImmediate& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ uint32 data_size = ImmediateDataSize(arg_count, args);
+ if (size > data_size) {
+ return parse_error::kParseInvalidArguments;
+ }
+ if (data_size == 0) {
+ return parse_error::kParseNoError;
+ }
+ return gapi_->CreateEffect(args.effect_id, size, AddressAfterStruct(args));
+}
+
+parse_error::ParseError GAPIDecoder::HandleDestroyEffect(
+ uint32 arg_count,
+ const DestroyEffect& args) {
+ return gapi_->DestroyEffect(args.effect_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetEffect(
+ uint32 arg_count,
+ const SetEffect& args) {
+ return gapi_->SetEffect(args.effect_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleGetParamCount(
+ uint32 arg_count,
+ const GetParamCount& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->GetParamCount(args.effect_id, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateParam(
+ uint32 arg_count,
+ const CreateParam& args) {
+ return gapi_->CreateParam(args.param_id, args.effect_id, args.index);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateParamByName(
+ uint32 arg_count,
+ const CreateParamByName& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->CreateParamByName(args.param_id, args.effect_id, size,
+ data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateParamByNameImmediate(
+ uint32 arg_count,
+ const CreateParamByNameImmediate& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ uint32 data_size = ImmediateDataSize(arg_count, args);
+ if (size > data_size)
+ return parse_error::kParseInvalidArguments;
+ if (data_size == 0) {
+ return parse_error::kParseNoError;
+ }
+ return gapi_->CreateParamByName(args.param_id, args.effect_id, size,
+ AddressAfterStruct(args));
+}
+
+parse_error::ParseError GAPIDecoder::HandleDestroyParam(
+ uint32 arg_count,
+ const DestroyParam& args) {
+ return gapi_->DestroyParam(args.param_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetParamData(
+ uint32 arg_count,
+ const SetParamData& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->SetParamData(args.param_id, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetParamDataImmediate(
+ uint32 arg_count,
+ const SetParamDataImmediate& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ uint32 data_size = ImmediateDataSize(arg_count, args);
+ if (size > data_size) {
+ return parse_error::kParseInvalidArguments;
+ }
+ if (data_size == 0) {
+ return parse_error::kParseNoError;
+ }
+ return gapi_->SetParamData(args.param_id, size, AddressAfterStruct(args));
+}
+
+parse_error::ParseError GAPIDecoder::HandleGetParamDesc(
+ uint32 arg_count,
+ const GetParamDesc& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->GetParamDesc(args.param_id, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleGetStreamCount(
+ uint32 arg_count,
+ const GetStreamCount& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->GetStreamCount(args.effect_id, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleGetStreamDesc(
+ uint32 arg_count,
+ const GetStreamDesc& args) {
+ // Pull out some values so they can't be changed by another thread after we've
+ // validated them.
+ uint32 size = args.size;
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset,
+ size);
+ if (!data) return parse_error::kParseInvalidArguments;
+ return gapi_->GetStreamDesc(args.effect_id, args.index, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleDestroyTexture(
+ uint32 arg_count,
+ const DestroyTexture& args) {
+ return gapi_->DestroyTexture(args.texture_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateTexture2d(
+ uint32 arg_count,
+ const CreateTexture2d& args) {
+ unsigned int width_height = args.width_height;
+ unsigned int levels_format_flags = args.levels_format_flags;
+ unsigned int width = CreateTexture2d::Width::Get(width_height);
+ unsigned int height = CreateTexture2d::Height::Get(width_height);
+ unsigned int levels = CreateTexture2d::Levels::Get(levels_format_flags);
+ unsigned int unused = CreateTexture2d::Unused::Get(levels_format_flags);
+ unsigned int format = CreateTexture2d::Format::Get(levels_format_flags);
+ unsigned int flags = CreateTexture2d::Flags::Get(levels_format_flags);
+ unsigned int max_levels =
+ 1 + ::o3d::base::bits::Log2Ceiling(std::max(width, height));
+ if ((width == 0) || (height == 0) || (levels > max_levels) ||
+ (unused != 0) || (format == texture::kUnknown) || (levels == 0))
+ return parse_error::kParseInvalidArguments;
+ bool enable_render_surfaces = !!flags;
+ return gapi_->CreateTexture2D(args.texture_id, width, height, levels,
+ static_cast<texture::Format>(format), flags,
+ enable_render_surfaces);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateTexture3d(
+ uint32 arg_count,
+ const CreateTexture3d& args) {
+ unsigned int width_height = args.width_height;
+ unsigned int depth_unused = args.depth_unused;
+ unsigned int levels_format_flags = args.levels_format_flags;
+ unsigned int width = CreateTexture3d::Width::Get(width_height);
+ unsigned int height = CreateTexture3d::Height::Get(width_height);
+ unsigned int depth = CreateTexture3d::Depth::Get(depth_unused);
+ unsigned int unused1 = CreateTexture3d::Unused1::Get(depth_unused);
+ unsigned int levels = CreateTexture3d::Levels::Get(levels_format_flags);
+ unsigned int unused2 = CreateTexture3d::Unused2::Get(levels_format_flags);
+ unsigned int format = CreateTexture3d::Format::Get(levels_format_flags);
+ unsigned int flags = CreateTexture3d::Flags::Get(levels_format_flags);
+ unsigned int max_levels =
+ 1 + ::o3d::base::bits::Log2Ceiling(std::max(depth, std::max(width, height)));
+ if ((width == 0) || (height == 0) || (depth == 0) ||
+ (levels > max_levels) || (unused1 != 0) || (unused2 != 0) ||
+ (format == texture::kUnknown) || (levels == 0))
+ return parse_error::kParseInvalidArguments;
+ bool enable_render_surfaces = !!flags;
+ return gapi_->CreateTexture3D(args.texture_id, width, height, depth, levels,
+ static_cast<texture::Format>(format), flags,
+ enable_render_surfaces);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateTextureCube(
+ uint32 arg_count,
+ const CreateTextureCube& args) {
+ unsigned int side_unused = args.edge_length;
+ unsigned int levels_format_flags = args.levels_format_flags;
+ unsigned int side = CreateTextureCube::Side::Get(side_unused);
+ unsigned int unused1 = CreateTextureCube::Unused1::Get(side_unused);
+ unsigned int levels = CreateTextureCube::Levels::Get(levels_format_flags);
+ unsigned int unused2 = CreateTextureCube::Unused2::Get(levels_format_flags);
+ unsigned int format = CreateTextureCube::Format::Get(levels_format_flags);
+ unsigned int flags = CreateTextureCube::Flags::Get(levels_format_flags);
+ unsigned int max_levels = 1 + ::o3d::base::bits::Log2Ceiling(side);
+ if ((side == 0) || (levels > max_levels) || (unused1 != 0) ||
+ (unused2 != 0) || (format == texture::kUnknown) || (levels == 0))
+ return parse_error::kParseInvalidArguments;
+ bool enable_render_surfaces = !!flags;
+ return gapi_->CreateTextureCube(args.texture_id, side, levels,
+ static_cast<texture::Format>(format),
+ flags, enable_render_surfaces);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetTextureData(
+ uint32 arg_count,
+ const SetTextureData& args) {
+ unsigned int x_y = args.x_y;
+ unsigned int width_height = args.width_height;
+ unsigned int z_depth = args.z_depth;
+ unsigned int level_face = args.level_face;
+ unsigned int size = args.size;
+ unsigned int x = SetTextureData::X::Get(x_y);
+ unsigned int y = SetTextureData::Y::Get(x_y);
+ unsigned int width = SetTextureData::Width::Get(width_height);
+ unsigned int height = SetTextureData::Height::Get(width_height);
+ unsigned int z = SetTextureData::Z::Get(z_depth);
+ unsigned int depth = SetTextureData::Depth::Get(z_depth);
+ unsigned int level = SetTextureData::Level::Get(level_face);
+ unsigned int face = SetTextureData::Face::Get(level_face);
+ unsigned int unused = SetTextureData::Unused::Get(level_face);
+ const void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset, size);
+ if (face >= 6 || unused != 0 || !data)
+ return parse_error::kParseInvalidArguments;
+ return gapi_->SetTextureData(
+ args.texture_id, x, y, z, width, height, depth, level,
+ static_cast<texture::Face>(face), args.row_pitch,
+ args.slice_pitch, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetTextureDataImmediate(
+ uint32 arg_count,
+ const SetTextureDataImmediate& args) {
+ unsigned int x_y = args.x_y;
+ unsigned int width_height = args.width_height;
+ unsigned int z_depth = args.z_depth;
+ unsigned int level_face = args.level_face;
+ unsigned int size = args.size;
+ unsigned int x = SetTextureDataImmediate::X::Get(x_y);
+ unsigned int y = SetTextureDataImmediate::Y::Get(x_y);
+ unsigned int width = SetTextureDataImmediate::Width::Get(width_height);
+ unsigned int height = SetTextureDataImmediate::Height::Get(width_height);
+ unsigned int z = SetTextureDataImmediate::Z::Get(z_depth);
+ unsigned int depth = SetTextureDataImmediate::Depth::Get(z_depth);
+ unsigned int level = SetTextureDataImmediate::Level::Get(level_face);
+ unsigned int face = SetTextureDataImmediate::Face::Get(level_face);
+ unsigned int unused = SetTextureDataImmediate::Unused::Get(level_face);
+ uint32 data_size = ImmediateDataSize(arg_count, args);
+ if (face >= 6 || unused != 0 ||
+ size > data_size)
+ return parse_error::kParseInvalidArguments;
+ if (data_size == 0) {
+ return parse_error::kParseNoError;
+ }
+ return gapi_->SetTextureData(
+ args.texture_id, x, y, z, width, height, depth, level,
+ static_cast<texture::Face>(face), args.row_pitch,
+ args.slice_pitch, size, AddressAfterStruct(args));
+}
+
+parse_error::ParseError GAPIDecoder::HandleGetTextureData(
+ uint32 arg_count,
+ const GetTextureData& args) {
+ unsigned int x_y = args.x_y;
+ unsigned int width_height = args.width_height;
+ unsigned int z_depth = args.z_depth;
+ unsigned int level_face = args.level_face;
+ unsigned int size = args.size;
+ unsigned int x = GetTextureData::X::Get(x_y);
+ unsigned int y = GetTextureData::Y::Get(x_y);
+ unsigned int width = GetTextureData::Width::Get(width_height);
+ unsigned int height = GetTextureData::Height::Get(width_height);
+ unsigned int z = GetTextureData::Z::Get(z_depth);
+ unsigned int depth = GetTextureData::Depth::Get(z_depth);
+ unsigned int level = GetTextureData::Level::Get(level_face);
+ unsigned int face = GetTextureData::Face::Get(level_face);
+ unsigned int unused = GetTextureData::Unused::Get(level_face);
+ void *data = GetAddressAndCheckSize(args.shared_memory.id,
+ args.shared_memory.offset, size);
+ if (face >= 6 || unused != 0 || !data)
+ return parse_error::kParseInvalidArguments;
+ return gapi_->GetTextureData(
+ args.texture_id, x, y, z, width, height, depth, level,
+ static_cast<texture::Face>(face), args.row_pitch,
+ args.slice_pitch, size, data);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateSampler(
+ uint32 arg_count,
+ const CreateSampler& args) {
+ return gapi_->CreateSampler(args.sampler_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleDestroySampler(
+ uint32 arg_count,
+ const DestroySampler& args) {
+ return gapi_->DestroySampler(args.sampler_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetSamplerStates(
+ uint32 arg_count,
+ const SetSamplerStates& args) {
+ Uint32 arg = args.sampler_states;
+ if (SetSamplerStates::Unused::Get(arg) != 0)
+ return parse_error::kParseInvalidArguments;
+ unsigned int address_u_value = SetSamplerStates::AddressingU::Get(arg);
+ unsigned int address_v_value = SetSamplerStates::AddressingV::Get(arg);
+ unsigned int address_w_value = SetSamplerStates::AddressingW::Get(arg);
+ unsigned int mag_filter_value = SetSamplerStates::MagFilter::Get(arg);
+ unsigned int min_filter_value = SetSamplerStates::MinFilter::Get(arg);
+ unsigned int mip_filter_value = SetSamplerStates::MipFilter::Get(arg);
+ unsigned int max_anisotropy = SetSamplerStates::MaxAnisotropy::Get(arg);
+ if (address_u_value >= sampler::kNumAddressingMode ||
+ address_v_value >= sampler::kNumAddressingMode ||
+ address_w_value >= sampler::kNumAddressingMode ||
+ mag_filter_value >= sampler::kNumFilteringMode ||
+ min_filter_value >= sampler::kNumFilteringMode ||
+ mip_filter_value >= sampler::kNumFilteringMode ||
+ mag_filter_value == sampler::kNone ||
+ min_filter_value == sampler::kNone ||
+ max_anisotropy == 0) {
+ return parse_error::kParseInvalidArguments;
+ }
+ gapi_->SetSamplerStates(
+ args.sampler_id,
+ static_cast<sampler::AddressingMode>(address_u_value),
+ static_cast<sampler::AddressingMode>(address_v_value),
+ static_cast<sampler::AddressingMode>(address_w_value),
+ static_cast<sampler::FilteringMode>(mag_filter_value),
+ static_cast<sampler::FilteringMode>(min_filter_value),
+ static_cast<sampler::FilteringMode>(mip_filter_value),
+ max_anisotropy);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetSamplerBorderColor(
+ uint32 arg_count,
+ const SetSamplerBorderColor& args) {
+ RGBA rgba;
+ rgba.red = args.red;
+ rgba.green = args.green;
+ rgba.blue = args.blue;
+ rgba.alpha = args.alpha;
+ return gapi_->SetSamplerBorderColor(args.sampler_id, rgba);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetSamplerTexture(
+ uint32 arg_count,
+ const SetSamplerTexture& args) {
+ return gapi_->SetSamplerTexture(args.sampler_id, args.texture_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetScissor(
+ uint32 arg_count,
+ const SetScissor& args) {
+ Uint32 x_y_enable = args.x_y_enable;
+ if (SetScissor::Unused::Get(x_y_enable) != 0)
+ return parse_error::kParseInvalidArguments;
+ unsigned int x = SetScissor::X::Get(x_y_enable);
+ unsigned int y = SetScissor::Y::Get(x_y_enable);
+ bool enable = SetScissor::Enable::Get(x_y_enable) != 0;
+ Uint32 width_height = args.width_height;
+ unsigned int width = SetScissor::Width::Get(width_height);
+ unsigned int height = SetScissor::Height::Get(width_height);
+ gapi_->SetScissor(enable, x, y, width, height);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetPolygonOffset(
+ uint32 arg_count,
+ const SetPolygonOffset& args) {
+ gapi_->SetPolygonOffset(args.slope_factor, args.units);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetPointLineRaster(
+ uint32 arg_count,
+ const SetPointLineRaster& args) {
+ Uint32 enables = args.enables;
+ if (SetPointLineRaster::Unused::Get(enables) != 0)
+ return parse_error::kParseInvalidArguments;
+ bool line_smooth = !!SetPointLineRaster::LineSmoothEnable::Get(enables);
+ bool point_sprite = !!SetPointLineRaster::PointSpriteEnable::Get(enables);
+ gapi_->SetPointLineRaster(line_smooth, point_sprite, args.point_size);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetPolygonRaster(
+ uint32 arg_count,
+ const SetPolygonRaster& args) {
+ Uint32 fill_cull = args.fill_cull;
+ unsigned int fill_value = SetPolygonRaster::FillMode::Get(fill_cull);
+ unsigned int cull_value = SetPolygonRaster::CullMode::Get(fill_cull);
+ if (SetPolygonRaster::Unused::Get(fill_cull) != 0 ||
+ fill_value >= kNumPolygonMode ||
+ cull_value >= kNumFaceCullMode)
+ return parse_error::kParseInvalidArguments;
+ gapi_->SetPolygonRaster(
+ static_cast<PolygonMode>(fill_value),
+ static_cast<FaceCullMode>(cull_value));
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetAlphaTest(
+ uint32 arg_count,
+ const SetAlphaTest& args) {
+ Uint32 func_enable = args.func_enable;
+ if (SetAlphaTest::Unused::Get(func_enable) != 0)
+ return parse_error::kParseInvalidArguments;
+ // Check that the bitmask get cannot generate values outside of the
+ // allowed range.
+ COMPILE_ASSERT(SetAlphaTest::Func::kMask <
+ kNumComparison,
+ set_alpha_test_Func_may_produce_invalid_values);
+ Comparison comp = static_cast<Comparison>(
+ SetAlphaTest::Func::Get(func_enable));
+ bool enable = SetAlphaTest::Enable::Get(func_enable) != 0;
+ gapi_->SetAlphaTest(enable, args.value, comp);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetDepthTest(
+ uint32 arg_count,
+ const SetDepthTest& args) {
+ Uint32 func_enable = args.func_enable;
+ if (SetDepthTest::Unused::Get(func_enable) != 0)
+ return parse_error::kParseInvalidArguments;
+ // Check that the bitmask get cannot generate values outside of the
+ // allowed range.
+ COMPILE_ASSERT(SetDepthTest::Func::kMask <
+ kNumComparison,
+ set_alpha_test_Func_may_produce_invalid_values);
+ Comparison comp = static_cast<Comparison>(
+ SetDepthTest::Func::Get(func_enable));
+ bool write_enable = SetDepthTest::WriteEnable::Get(func_enable) != 0;
+ bool enable = SetDepthTest::Enable::Get(func_enable) != 0;
+ gapi_->SetDepthTest(enable, write_enable, comp);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetStencilTest(
+ uint32 arg_count,
+ const SetStencilTest& args) {
+ Uint32 arg0 = args.stencil_args0;
+ Uint32 arg1 = args.stencil_args1;
+ if (SetStencilTest::Unused0::Get(arg0) != 0 ||
+ SetStencilTest::Unused1::Get(arg1) != 0 ||
+ SetStencilTest::Unused2::Get(arg1) != 0)
+ return parse_error::kParseInvalidArguments;
+ unsigned int write_mask = SetStencilTest::WriteMask::Get(arg0);
+ unsigned int compare_mask = SetStencilTest::CompareMask::Get(arg0);
+ unsigned int ref = SetStencilTest::ReferenceValue::Get(arg0);
+ bool enable = SetStencilTest::Enable::Get(arg0) != 0;
+ bool separate_ccw = SetStencilTest::SeparateCCW::Get(arg0) != 0;
+ gapi_->SetStencilTest(enable, separate_ccw, write_mask, compare_mask, ref,
+ arg1);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetColorWrite(
+ uint32 arg_count,
+ const SetColorWrite& args) {
+ Uint32 enables = args.flags;
+ if (SetColorWrite::Unused::Get(enables) != 0)
+ return parse_error::kParseInvalidArguments;
+ bool red = SetColorWrite::RedMask::Get(enables) != 0;
+ bool green = SetColorWrite::GreenMask::Get(enables) != 0;
+ bool blue = SetColorWrite::BlueMask::Get(enables) != 0;
+ bool alpha = SetColorWrite::AlphaMask::Get(enables) != 0;
+ bool dither = SetColorWrite::DitherEnable::Get(enables) != 0;
+ gapi_->SetColorWrite(red, green, blue, alpha, dither);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetBlending(
+ uint32 arg_count,
+ const SetBlending& args) {
+ Uint32 arg = args.blend_settings;
+ bool enable = SetBlending::Enable::Get(arg) != 0;
+ bool separate_alpha = SetBlending::SeparateAlpha::Get(arg) != 0;
+ unsigned int color_eq = SetBlending::ColorEq::Get(arg);
+ unsigned int color_src = SetBlending::ColorSrcFunc::Get(arg);
+ unsigned int color_dst = SetBlending::ColorDstFunc::Get(arg);
+ unsigned int alpha_eq = SetBlending::AlphaEq::Get(arg);
+ unsigned int alpha_src = SetBlending::AlphaSrcFunc::Get(arg);
+ unsigned int alpha_dst = SetBlending::AlphaDstFunc::Get(arg);
+ if (SetBlending::Unused0::Get(arg) != 0 ||
+ SetBlending::Unused1::Get(arg) != 0 ||
+ color_eq >= kNumBlendEq ||
+ color_src >= kNumBlendFunc ||
+ color_dst >= kNumBlendFunc ||
+ alpha_eq >= kNumBlendEq ||
+ alpha_src >= kNumBlendFunc ||
+ alpha_dst >= kNumBlendFunc)
+ return parse_error::kParseInvalidArguments;
+ gapi_->SetBlending(enable,
+ separate_alpha,
+ static_cast<BlendEq>(color_eq),
+ static_cast<BlendFunc>(color_src),
+ static_cast<BlendFunc>(color_dst),
+ static_cast<BlendEq>(alpha_eq),
+ static_cast<BlendFunc>(alpha_src),
+ static_cast<BlendFunc>(alpha_dst));
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetBlendingColor(
+ uint32 arg_count,
+ const SetBlendingColor& args) {
+ RGBA rgba;
+ rgba.red = args.red;
+ rgba.green = args.green;
+ rgba.blue = args.blue;
+ rgba.alpha = args.alpha;
+ gapi_->SetBlendingColor(rgba);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateRenderSurface(
+ uint32 arg_count,
+ const CreateRenderSurface& args) {
+ unsigned int width_height = args.width_height;
+ unsigned int width = CreateRenderSurface::Width::Get(width_height);
+ unsigned int height = CreateRenderSurface::Height::Get(width_height);
+ unsigned int levels_side = args.levels_side;
+ unsigned int mip_level = CreateRenderSurface::Levels::Get(levels_side);
+ unsigned int side = CreateRenderSurface::Side::Get(levels_side);
+ return gapi_->CreateRenderSurface(args.render_surface_id,
+ width, height, mip_level,
+ side, args.texture_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleDestroyRenderSurface(
+ uint32 arg_count,
+ const DestroyRenderSurface& args) {
+ return gapi_->DestroyRenderSurface(args.render_surface_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleCreateDepthSurface(
+ uint32 arg_count,
+ const CreateDepthSurface& args) {
+ unsigned int width_height = args.width_height;
+ unsigned int width = CreateDepthSurface::Width::Get(width_height);
+ unsigned int height = CreateDepthSurface::Height::Get(width_height);
+ return gapi_->CreateDepthSurface(args.depth_surface_id, width, height);
+}
+
+parse_error::ParseError GAPIDecoder::HandleDestroyDepthSurface(
+ uint32 arg_count,
+ const DestroyDepthSurface& args) {
+ return gapi_->DestroyDepthSurface(args.depth_surface_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetRenderSurface(
+ uint32 arg_count,
+ const SetRenderSurface& args) {
+ return gapi_->SetRenderSurface(args.render_surface_id, args.depth_surface_id);
+}
+
+parse_error::ParseError GAPIDecoder::HandleSetBackSurfaces(
+ uint32 arg_count,
+ const SetBackSurfaces& args) {
+ gapi_->SetBackSurfaces();
+ return parse_error::kParseNoError;
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/gapi_decoder.h b/o3d/gpu/command_buffer/service/gapi_decoder.h
new file mode 100644
index 0000000..e043598
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/gapi_decoder.h
@@ -0,0 +1,81 @@
+/*
+ * 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 GAPI decoder class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H_
+
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/common/o3d_cmd_format.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class GAPIInterface;
+
+// This class implements the AsyncAPIInterface interface, decoding GAPI
+// commands and sending them to a GAPI interface.
+class GAPIDecoder : public CommonDecoder {
+ public:
+ typedef parse_error::ParseError ParseError;
+
+ explicit GAPIDecoder(GAPIInterface *gapi) : gapi_(gapi) {}
+ virtual ~GAPIDecoder() {}
+
+ // Overridden from AsyncAPIInterface.
+ virtual ParseError DoCommand(unsigned int command,
+ unsigned int arg_count,
+ const void* args);
+
+ // Overridden from AsyncAPIInterface.
+ virtual const char* GetCommandName(unsigned int command_id) const;
+
+ private:
+ // Generate a member function prototype for each command in an automated and
+ // typesafe way.
+ #define GPU_COMMAND_BUFFER_CMD_OP(name) \
+ ParseError Handle ## name( \
+ unsigned int arg_count, \
+ const o3d::name& args); \
+
+ O3D_COMMAND_BUFFER_CMDS(GPU_COMMAND_BUFFER_CMD_OP)
+
+ #undef GPU_COMMAND_BUFFER_CMD_OP
+
+ GAPIInterface *gapi_;
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H_
diff --git a/o3d/gpu/command_buffer/service/gapi_gl.cc b/o3d/gpu/command_buffer/service/gapi_gl.cc
new file mode 100644
index 0000000..c5f82de
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/gapi_gl.cc
@@ -0,0 +1,420 @@
+/*
+ * 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 implements the GAPIGL class.
+
+#include "gpu/command_buffer/service/precompile.h"
+
+#include <build/build_config.h>
+
+#include "gpu/command_buffer/service/gapi_gl.h"
+
+#ifdef OS_LINUX
+#include "gpu/command_buffer/service/linux/x_utils.h"
+#endif // OS_LINUX
+
+namespace command_buffer {
+namespace o3d {
+
+GAPIGL::GAPIGL()
+ : cg_context_(NULL),
+#ifdef OS_LINUX
+ window_(NULL),
+#endif
+#ifdef OS_WIN
+ hwnd_(NULL),
+ device_context_(NULL),
+ gl_context_(NULL),
+#endif
+ anti_aliased_(false),
+ current_vertex_struct_(kInvalidResource),
+ validate_streams_(true),
+ max_vertices_(0),
+ current_effect_id_(kInvalidResource),
+ validate_effect_(true),
+ current_effect_(NULL) {
+}
+
+GAPIGL::~GAPIGL() {
+}
+
+bool GAPIGL::Initialize() {
+ if (!InitPlatformSpecific())
+ return false;
+ if (!InitCommon())
+ return false;
+ CHECK_GL_ERROR();
+ return true;
+}
+
+#if defined(OS_WIN)
+static const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = {
+ sizeof(kPixelFormatDescriptor), // Size of structure.
+ 1, // Default version.
+ PFD_DRAW_TO_WINDOW | // Window drawing support.
+ PFD_SUPPORT_OPENGL | // OpenGL support.
+ PFD_DOUBLEBUFFER, // Double buffering support (not stereo).
+ PFD_TYPE_RGBA, // RGBA color mode (not indexed).
+ 24, // 24 bit color mode.
+ 0, 0, 0, 0, 0, 0, // Don't set RGB bits & shifts.
+ 8, 0, // 8 bit alpha
+ 0, // No accumulation buffer.
+ 0, 0, 0, 0, // Ignore accumulation bits.
+ 24, // 24 bit z-buffer size.
+ 8, // 8-bit stencil buffer.
+ 0, // No aux buffer.
+ PFD_MAIN_PLANE, // Main drawing plane (not overlay).
+ 0, // Reserved.
+ 0, 0, 0, // Layer masks ignored.
+};
+
+LRESULT CALLBACK IntermediateWindowProc(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return ::DefWindowProc(window, message, w_param, l_param);
+}
+
+// Helper routine that returns the highest quality pixel format supported on
+// the current platform. Returns true upon success.
+static bool GetWindowsPixelFormat(HWND window,
+ bool anti_aliased,
+ int* pixel_format) {
+ // We must initialize a GL context before we can determine the multi-sampling
+ // supported on the current hardware, so we create an intermediate window
+ // and context here.
+ HINSTANCE module_handle;
+ if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ reinterpret_cast<wchar_t*>(IntermediateWindowProc),
+ &module_handle)) {
+ return false;
+ }
+
+ WNDCLASS intermediate_class;
+ intermediate_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ intermediate_class.lpfnWndProc = IntermediateWindowProc;
+ intermediate_class.cbClsExtra = 0;
+ intermediate_class.cbWndExtra = 0;
+ intermediate_class.hInstance = module_handle;
+ intermediate_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ intermediate_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ intermediate_class.hbrBackground = NULL;
+ intermediate_class.lpszMenuName = NULL;
+ intermediate_class.lpszClassName = L"Intermediate GL Window";
+
+ ATOM class_registration = ::RegisterClass(&intermediate_class);
+ if (!class_registration) {
+ return false;
+ }
+
+ HWND intermediate_window = ::CreateWindow(
+ reinterpret_cast<wchar_t*>(class_registration),
+ L"",
+ WS_OVERLAPPEDWINDOW,
+ 0, 0,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (!intermediate_window) {
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return false;
+ }
+
+ HDC intermediate_dc = ::GetDC(intermediate_window);
+ int format_index = ::ChoosePixelFormat(intermediate_dc,
+ &kPixelFormatDescriptor);
+ if (format_index == 0) {
+ DLOG(ERROR) << "Unable to get the pixel format for GL context.";
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return false;
+ }
+ if (!::SetPixelFormat(intermediate_dc, format_index,
+ &kPixelFormatDescriptor)) {
+ DLOG(ERROR) << "Unable to set the pixel format for GL context.";
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return false;
+ }
+
+ // Store the pixel format without multisampling.
+ *pixel_format = format_index;
+ HGLRC gl_context = ::wglCreateContext(intermediate_dc);
+ if (::wglMakeCurrent(intermediate_dc, gl_context)) {
+ // GL context was successfully created and applied to the window's DC.
+ // Startup GLEW, the GL extensions wrangler.
+ GLenum glew_error = ::glewInit();
+ if (glew_error == GLEW_OK) {
+ DLOG(INFO) << "Initialized GLEW " << ::glewGetString(GLEW_VERSION);
+ } else {
+ DLOG(ERROR) << "Unable to initialise GLEW : "
+ << ::glewGetErrorString(glew_error);
+ ::wglMakeCurrent(intermediate_dc, NULL);
+ ::wglDeleteContext(gl_context);
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return false;
+ }
+
+ // If the multi-sample extensions are present, query the api to determine
+ // the pixel format.
+ if (anti_aliased && WGLEW_ARB_pixel_format && WGLEW_ARB_multisample) {
+ int pixel_attributes[] = {
+ WGL_SAMPLES_ARB, 4,
+ WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
+ WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
+ WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
+ WGL_COLOR_BITS_ARB, 24,
+ WGL_ALPHA_BITS_ARB, 8,
+ WGL_DEPTH_BITS_ARB, 24,
+ WGL_STENCIL_BITS_ARB, 8,
+ WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
+ WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
+ 0, 0};
+
+ float pixel_attributes_f[] = {0, 0};
+ int msaa_pixel_format;
+ unsigned int num_formats;
+
+ // Query for the highest sampling rate supported, starting at 4x.
+ static const int kSampleCount[] = {4, 2};
+ static const int kNumSamples = 2;
+ for (int sample = 0; sample < kNumSamples; ++sample) {
+ pixel_attributes[1] = kSampleCount[sample];
+ if (GL_TRUE == ::wglChoosePixelFormatARB(intermediate_dc,
+ pixel_attributes,
+ pixel_attributes_f,
+ 1,
+ &msaa_pixel_format,
+ &num_formats)) {
+ *pixel_format = msaa_pixel_format;
+ break;
+ }
+ }
+ }
+ }
+
+ ::wglMakeCurrent(intermediate_dc, NULL);
+ ::wglDeleteContext(gl_context);
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return true;
+}
+#endif
+
+bool GAPIGL::InitPlatformSpecific() {
+#if defined(OS_WIN)
+ device_context_ = ::GetDC(hwnd_);
+
+ int pixel_format;
+
+ if (!GetWindowsPixelFormat(hwnd_,
+ anti_aliased(),
+ &pixel_format)) {
+ DLOG(ERROR) << "Unable to determine optimal pixel format for GL context.";
+ return false;
+ }
+
+ if (!::SetPixelFormat(device_context_, pixel_format,
+ &kPixelFormatDescriptor)) {
+ DLOG(ERROR) << "Unable to set the pixel format for GL context.";
+ return false;
+ }
+
+ gl_context_ = ::wglCreateContext(device_context_);
+ if (!gl_context_) {
+ DLOG(ERROR) << "Failed to create GL context.";
+ return false;
+ }
+
+ if (!::wglMakeCurrent(device_context_, gl_context_)) {
+ DLOG(ERROR) << "Unable to make gl context current.";
+ return false;
+ }
+#elif defined(OS_LINUX)
+ DCHECK(window_);
+ if (!window_->Initialize())
+ return false;
+ if (!window_->MakeCurrent())
+ return false;
+#endif
+
+ return true;
+}
+
+bool GAPIGL::InitCommon() {
+ if (!InitGlew())
+ return false;
+ InitCG();
+
+ // Initialize global GL settings.
+ // Tell GL that texture buffers can be single-byte aligned.
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+ glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+ // Get the initial viewport (set to the window size) to set up the helper
+ // constant.
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ SetViewport(viewport[0], viewport[1], viewport[2], viewport[3], 0.f, 1.f);
+ CHECK_GL_ERROR();
+
+ ::glGenFramebuffersEXT(1, &render_surface_framebuffer_);
+ CHECK_GL_ERROR();
+ return true;
+}
+
+void GAPIGL::InitCG() {
+ cg_context_ = cgCreateContext();
+ // Set up all Cg State Assignments for OpenGL.
+ cgGLRegisterStates(cg_context_);
+ cgGLSetDebugMode(CG_FALSE);
+ // Enable the profiles we use.
+ cgGLEnableProfile(CG_PROFILE_ARBVP1);
+ cgGLEnableProfile(CG_PROFILE_ARBFP1);
+}
+
+bool GAPIGL::InitGlew() {
+ DLOG(INFO) << "Initializing GL and GLEW for GAPI.";
+
+ GLenum glew_error = glewInit();
+ if (glew_error != GLEW_OK) {
+ DLOG(ERROR) << "Unable to initialise GLEW : "
+ << ::glewGetErrorString(glew_error);
+ return false;
+ }
+
+ // Check to see that we can use the OpenGL vertex attribute APIs
+ // TODO(petersont): Return false if this check fails, but because some
+ // Intel hardware does not support OpenGL 2.0, yet does support all of the
+ // extensions we require, we only log an error. A future CL should change
+ // this check to ensure that all of the extension strings we require are
+ // present.
+ if (!GLEW_VERSION_2_0) {
+ DLOG(ERROR) << "GL drivers do not have OpenGL 2.0 functionality.";
+ }
+
+ bool extensions_found = true;
+ if (!GLEW_ARB_vertex_buffer_object) {
+ // NOTE: Linux NVidia drivers claim to support OpenGL 2.0 when using
+ // indirect rendering (e.g. remote X), but it is actually lying. The
+ // ARB_vertex_buffer_object functions silently no-op (!) when using
+ // indirect rendering, leading to crashes. Fortunately, in that case, the
+ // driver claims to not support ARB_vertex_buffer_object, so fail in that
+ // case.
+ DLOG(ERROR) << "GL drivers do not support vertex buffer objects.";
+ extensions_found = false;
+ }
+ if (!GLEW_EXT_framebuffer_object) {
+ DLOG(ERROR) << "GL drivers do not support framebuffer objects.";
+ extensions_found = false;
+ }
+ // Check for necessary extensions
+ if (!GLEW_VERSION_2_0 && !GLEW_EXT_stencil_two_side) {
+ DLOG(ERROR) << "Two sided stencil extension missing.";
+ extensions_found = false;
+ }
+ if (!GLEW_VERSION_1_4 && !GLEW_EXT_blend_func_separate) {
+ DLOG(ERROR) <<"Separate blend func extension missing.";
+ extensions_found = false;
+ }
+ if (!GLEW_VERSION_2_0 && !GLEW_EXT_blend_equation_separate) {
+ DLOG(ERROR) << "Separate blend function extension missing.";
+ extensions_found = false;
+ }
+ if (!extensions_found)
+ return false;
+
+ return true;
+}
+
+void GAPIGL::Destroy() {
+ vertex_buffers_.DestroyAllResources();
+ index_buffers_.DestroyAllResources();
+ vertex_structs_.DestroyAllResources();
+ effects_.DestroyAllResources();
+ effect_params_.DestroyAllResources();
+ // textures_.DestroyAllResources();
+ // samplers_.DestroyAllResources();
+ cgDestroyContext(cg_context_);
+ cg_context_ = NULL;
+#ifdef OS_LINUX
+ DCHECK(window_);
+ window_->Destroy();
+#endif
+}
+
+void GAPIGL::BeginFrame() {
+}
+
+void GAPIGL::EndFrame() {
+#ifdef OS_WIN
+ ::SwapBuffers(device_context_);
+#endif
+
+#ifdef OS_LINUX
+ DCHECK(window_);
+ window_->SwapBuffers();
+#endif
+
+ CHECK_GL_ERROR();
+}
+
+void GAPIGL::Clear(unsigned int buffers,
+ const RGBA &color,
+ float depth,
+ unsigned int stencil) {
+ glClearColor(color.red, color.green, color.blue, color.alpha);
+ glClearDepth(depth);
+ glClearStencil(stencil);
+ glClear((buffers & kColor ? GL_COLOR_BUFFER_BIT : 0) |
+ (buffers & kDepth ? GL_DEPTH_BUFFER_BIT : 0) |
+ (buffers & kStencil ? GL_STENCIL_BUFFER_BIT : 0));
+ CHECK_GL_ERROR();
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/gapi_gl.h b/o3d/gpu/command_buffer/service/gapi_gl.h
new file mode 100644
index 0000000..0719fba
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/gapi_gl.h
@@ -0,0 +1,465 @@
+/*
+ * 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 GAPIGL class, implementing the GAPI interface for
+// GL.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GAPI_GL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GAPI_GL_H_
+
+#include <build/build_config.h>
+#include <GL/glew.h>
+#include <Cg/cg.h>
+#include <Cg/cgGL.h>
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/effect_gl.h"
+#include "gpu/command_buffer/service/geometry_gl.h"
+#include "gpu/command_buffer/service/render_surface_gl.h"
+#include "gpu/command_buffer/service/sampler_gl.h"
+#include "gpu/command_buffer/service/texture_gl.h"
+
+namespace command_buffer {
+namespace o3d {
+#if defined(OS_LINUX)
+class XWindowWrapper;
+#endif // defined(OS_LINUX)
+
+// This class implements the GAPI interface for GL.
+class GAPIGL : public GAPIInterface {
+ public:
+ GAPIGL();
+ virtual ~GAPIGL();
+
+#if defined(OS_LINUX)
+ void set_window_wrapper(XWindowWrapper *window) { window_ = window; }
+#elif defined(OS_WIN)
+ void set_hwnd(HWND hwnd) { hwnd_ = hwnd; }
+
+ HWND hwnd() const {
+ return hwnd_;
+ }
+#endif
+
+ // Initializes the graphics context, bound to a window.
+ // Returns:
+ // true if successful.
+ virtual bool Initialize();
+
+ // Initailizes Cg.
+ void InitCG();
+
+ // Helper function for Initailize that inits just glew.
+ bool InitGlew();
+
+ // Destroys the graphics context.
+ virtual void Destroy();
+
+ // Implements the BeginFrame function for GL.
+ virtual void BeginFrame();
+
+ // Implements the EndFrame function for GL.
+ virtual void EndFrame();
+
+ // Implements the Clear function for GL.
+ virtual void Clear(unsigned int buffers,
+ const RGBA &color,
+ float depth,
+ unsigned int stencil);
+
+ // Implements the SetViewport function for GL.
+ virtual void SetViewport(unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height,
+ float z_min,
+ float z_max);
+
+ // Implements the CreateVertexBuffer function for GL.
+ virtual ParseError CreateVertexBuffer(ResourceId id,
+ unsigned int size,
+ unsigned int flags);
+
+ // Implements the DestroyVertexBuffer function for GL.
+ virtual ParseError DestroyVertexBuffer(ResourceId id);
+
+ // Implements the SetVertexBufferData function for GL.
+ virtual ParseError SetVertexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data);
+
+ // Implements the GetVertexBufferData function for GL.
+ virtual ParseError GetVertexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data);
+
+ // Implements the CreateIndexBuffer function for GL.
+ virtual ParseError CreateIndexBuffer(ResourceId id,
+ unsigned int size,
+ unsigned int flags);
+
+ // Implements the DestroyIndexBuffer function for GL.
+ virtual ParseError DestroyIndexBuffer(ResourceId id);
+
+ // Implements the SetIndexBufferData function for GL.
+ virtual ParseError SetIndexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data);
+
+ // Implements the GetIndexBufferData function for GL.
+ virtual ParseError GetIndexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data);
+
+ // Implements the CreateVertexStruct function for GL.
+ virtual ParseError CreateVertexStruct(ResourceId id,
+ unsigned int input_count);
+
+ // Implements the DestroyVertexStruct function for GL.
+ virtual ParseError DestroyVertexStruct(ResourceId id);
+
+ // Implements the SetVertexInput function for GL.
+ virtual ParseError SetVertexInput(ResourceId vertex_struct_id,
+ unsigned int input_index,
+ ResourceId vertex_buffer_id,
+ unsigned int offset,
+ unsigned int stride,
+ vertex_struct::Type type,
+ vertex_struct::Semantic semantic,
+ unsigned int semantic_index);
+
+ // Implements the SetVertexStruct function for GL.
+ virtual ParseError SetVertexStruct(ResourceId id);
+
+ // Implements the Draw function for GL.
+ virtual ParseError Draw(PrimitiveType primitive_type,
+ unsigned int first,
+ unsigned int count);
+
+ // Implements the DrawIndexed function for GL.
+ virtual ParseError DrawIndexed(PrimitiveType primitive_type,
+ ResourceId index_buffer_id,
+ unsigned int first,
+ unsigned int count,
+ unsigned int min_index,
+ unsigned int max_index);
+
+ // Implements the CreateEffect function for GL.
+ virtual ParseError CreateEffect(ResourceId id,
+ unsigned int size,
+ const void *data);
+
+ // Implements the DestroyEffect function for GL.
+ virtual ParseError DestroyEffect(ResourceId id);
+
+ // Implements the SetEffect function for GL.
+ virtual ParseError SetEffect(ResourceId id);
+
+ // Implements the GetParamCount function for GL.
+ virtual ParseError GetParamCount(ResourceId id,
+ unsigned int size,
+ void *data);
+
+ // Implements the CreateParam function for GL.
+ virtual ParseError CreateParam(ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int index);
+
+ // Implements the CreateParamByName function for GL.
+ virtual ParseError CreateParamByName(ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int size,
+ const void *name);
+
+ // Implements the DestroyParam function for GL.
+ virtual ParseError DestroyParam(ResourceId id);
+
+ // Implements the SetParamData function for GL.
+ virtual ParseError SetParamData(ResourceId id,
+ unsigned int size,
+ const void *data);
+
+ // Implements the GetParamDesc function for GL.
+ virtual ParseError GetParamDesc(ResourceId id,
+ unsigned int size,
+ void *data);
+
+ // Implements the GetStreamCount function for GL.
+ virtual ParseError GetStreamCount(ResourceId id,
+ unsigned int size,
+ void *data);
+
+ // Implements the GetStreamDesc function for GL.
+ virtual ParseError GetStreamDesc(ResourceId id,
+ unsigned int index,
+ unsigned int size,
+ void *data);
+
+ // Implements the CreateTexture2D function for GL.
+ virtual ParseError CreateTexture2D(ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+
+ // Implements the CreateTexture3D function for GL.
+ virtual ParseError CreateTexture3D(ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+
+ // Implements the CreateTextureCube function for GL.
+ virtual ParseError CreateTextureCube(ResourceId id,
+ unsigned int side,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+
+ // Implements the SetTextureData function for GL.
+ virtual ParseError SetTextureData(ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data);
+
+ // Implements the GetTextureData function for GL.
+ virtual ParseError GetTextureData(ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data);
+
+ // Implements the DestroyTexture function for GL.
+ virtual ParseError DestroyTexture(ResourceId id);
+
+ // Implements the CreateSampler function for GL.
+ virtual ParseError CreateSampler(ResourceId id);
+
+ // Implements the DestroySampler function for GL.
+ virtual ParseError DestroySampler(ResourceId id);
+
+ // Implements the SetSamplerStates function for GL.
+ virtual ParseError SetSamplerStates(ResourceId id,
+ sampler::AddressingMode addressing_u,
+ sampler::AddressingMode addressing_v,
+ sampler::AddressingMode addressing_w,
+ sampler::FilteringMode mag_filter,
+ sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter,
+ unsigned int max_anisotropy);
+
+ // Implements the SetSamplerBorderColor function for GL.
+ virtual ParseError SetSamplerBorderColor(ResourceId id, const RGBA &color);
+
+ // Implements the SetSamplerTexture function for GL.
+ virtual ParseError SetSamplerTexture(ResourceId id, ResourceId texture_id);
+
+ // Implements the SetScissor function for GL.
+ virtual void SetScissor(bool enable,
+ unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height);
+
+ // Implements the SetPointLineRaster function for GL.
+ virtual void SetPointLineRaster(bool line_smooth,
+ bool point_sprite,
+ float point_size);
+
+ // Implements the SetPolygonOffset function for GL.
+ virtual void SetPolygonOffset(float slope_factor, float units);
+
+ // Implements the SetPolygonRaster function for GL.
+ virtual void SetPolygonRaster(PolygonMode fill_mode,
+ FaceCullMode cull_mode);
+
+ // Implements the SetAlphaTest function for GL.
+ virtual void SetAlphaTest(bool enable,
+ float reference,
+ Comparison comp);
+
+ // Implements the SetDepthTest function for GL.
+ virtual void SetDepthTest(bool enable,
+ bool write_enable,
+ Comparison comp);
+
+ // Implements the SetStencilTest function for GL.
+ virtual void SetStencilTest(bool enable,
+ bool separate_ccw,
+ unsigned int write_mask,
+ unsigned int compare_mask,
+ unsigned int ref,
+ Uint32 func_ops);
+
+ // Implements the SetColorWritefunction for GL.
+ virtual void SetColorWrite(bool red,
+ bool green,
+ bool blue,
+ bool alpha,
+ bool dither);
+
+ // Implements the SetBlending function for GL.
+ virtual void SetBlending(bool enable,
+ bool separate_alpha,
+ BlendEq color_eq,
+ BlendFunc color_src_func,
+ BlendFunc color_dst_func,
+ BlendEq alpha_eq,
+ BlendFunc alpha_src_func,
+ BlendFunc alpha_dst_func);
+
+ // Implements the SetBlendingColor function for GL.
+ virtual void SetBlendingColor(const RGBA &color);
+
+ // Implements the CreateRenderSurface function for GL.
+ virtual ParseError CreateRenderSurface(ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int mip_level,
+ unsigned int side,
+ ResourceId texture_id);
+
+ // Implements the DestroyRenderSurface function for GL.
+ virtual ParseError DestroyRenderSurface(ResourceId id);
+
+ // Implements the CreateDepthSurface function for GL.
+ virtual ParseError CreateDepthSurface(ResourceId id,
+ unsigned int width,
+ unsigned int height);
+
+ // Implements the DestroyDepthSurface function for GL.
+ virtual ParseError DestroyDepthSurface(ResourceId id);
+
+ // Implements the SetRenderSurface function for GL.
+ virtual ParseError SetRenderSurface(ResourceId render_surface_id,
+ ResourceId depth_stencil_id);
+
+ // Implements the SetBackSurfaces function for GL.
+ virtual void SetBackSurfaces();
+
+ // Gets a vertex buffer by resource ID.
+ VertexBufferGL *GetVertexBuffer(ResourceId id) {
+ return vertex_buffers_.Get(id);
+ }
+
+ // Gets a texture by resource ID.
+ TextureGL *GetTexture(ResourceId id) {
+ return textures_.Get(id);
+ }
+
+ // Gets a sampler by resource ID.
+ SamplerGL *GetSampler(ResourceId id) {
+ return samplers_.Get(id);
+ }
+ void set_anti_aliased(bool anti_aliased) { anti_aliased_ = anti_aliased; }
+
+ bool anti_aliased() const { return anti_aliased_; }
+
+ CGcontext cg_context() const { return cg_context_; }
+
+ EffectGL *current_effect() const { return current_effect_; }
+ // "Dirty" the current effect. This resets the vertex and fragment program,
+ // and requires ValidateEffect() to be called before further draws occur.
+ void DirtyEffect();
+ private:
+ bool InitPlatformSpecific();
+ bool InitCommon();
+ // Validates the current vertex struct to GL, setting the vertex attributes.
+ bool ValidateStreams();
+ // Validates the current effect to GL. This sets the vertex and fragment
+ // programs, and updates parameters if needed.
+ bool ValidateEffect();
+
+ CGcontext cg_context_;
+
+#if defined(OS_LINUX)
+ XWindowWrapper *window_;
+#elif defined(OS_WIN)
+ // Handle to the GL device.
+ HWND hwnd_;
+ HDC device_context_;
+ HGLRC gl_context_;
+#endif
+
+ bool anti_aliased_;
+ ResourceId current_vertex_struct_;
+ bool validate_streams_;
+ unsigned int max_vertices_;
+ ResourceId current_effect_id_;
+ bool validate_effect_;
+ EffectGL *current_effect_;
+ ResourceId current_surface_id_;
+ ResourceId current_depth_surface_id_;
+ GLuint render_surface_framebuffer_;
+
+ ResourceMap<VertexBufferGL> vertex_buffers_;
+ ResourceMap<IndexBufferGL> index_buffers_;
+ ResourceMap<VertexStructGL> vertex_structs_;
+ ResourceMap<EffectGL> effects_;
+ ResourceMap<EffectParamGL> effect_params_;
+ ResourceMap<TextureGL> textures_;
+ ResourceMap<SamplerGL> samplers_;
+ ResourceMap<RenderSurfaceGL> render_surfaces_;
+ ResourceMap<RenderDepthStencilSurfaceGL> depth_surfaces_;
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GAPI_GL_H_
diff --git a/o3d/gpu/command_buffer/service/geometry_d3d9.cc b/o3d/gpu/command_buffer/service/geometry_d3d9.cc
new file mode 100644
index 0000000..c3b5eb5
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/geometry_d3d9.cc
@@ -0,0 +1,439 @@
+/*
+ * 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 implementation of the D3D9 versions of the
+// VertexBuffer, IndexBuffer and VertexStruct resources.
+// This file also contains the related GAPID3D9 function implementations.
+
+#include "gpu/command_buffer/service/precompile.h"
+
+#include <algorithm>
+
+#include "gpu/command_buffer/service/d3d9_utils.h"
+#include "gpu/command_buffer/service/geometry_d3d9.h"
+#include "gpu/command_buffer/service/gapi_d3d9.h"
+
+namespace command_buffer {
+namespace o3d {
+
+// Destroys the D3D9 vertex buffer.
+VertexBufferD3D9::~VertexBufferD3D9() {
+ DCHECK(d3d_vertex_buffer_ != NULL);
+ if (d3d_vertex_buffer_) {
+ d3d_vertex_buffer_->Release();
+ d3d_vertex_buffer_ = NULL;
+ }
+}
+
+// Creates a D3D9 vertex buffer.
+void VertexBufferD3D9::Create(GAPID3D9 *gapi) {
+ DCHECK(d3d_vertex_buffer_ == NULL);
+
+ DWORD d3d_usage = (flags() & vertex_buffer::kDynamic) ? D3DUSAGE_DYNAMIC : 0;
+ D3DPOOL d3d_pool = D3DPOOL_MANAGED;
+ HR(gapi->d3d_device()->CreateVertexBuffer(size(), d3d_usage, 0, d3d_pool,
+ &d3d_vertex_buffer_, NULL));
+}
+
+// Sets the data into the D3D9 vertex buffer, using Lock() and memcpy.
+bool VertexBufferD3D9::SetData(unsigned int offset,
+ unsigned int size,
+ const void *data) {
+ if (!d3d_vertex_buffer_) {
+ LOG(ERROR) << "Calling SetData on a non-initialized VertexBufferD3D9.";
+ return false;
+ }
+ if ((offset >= this->size()) || (offset + size > this->size())) {
+ LOG(ERROR) << "Invalid size or offset on VertexBufferD3D9::SetData.";
+ return false;
+ }
+ void *ptr = NULL;
+ DWORD lock_flags = 0;
+ // If we are setting the full buffer, discard the old data. That's only
+ // possible to do for a dynamic d3d vertex buffer.
+ if ((offset == 0) && (size == this->size()) &&
+ (flags() & vertex_buffer::kDynamic))
+ lock_flags = D3DLOCK_DISCARD;
+ HR(d3d_vertex_buffer_->Lock(offset, size, &ptr, lock_flags));
+ memcpy(ptr, data, size);
+ HR(d3d_vertex_buffer_->Unlock());
+ return true;
+}
+
+// Gets the data from the D3D9 vertex buffer, using Lock() and memcpy.
+bool VertexBufferD3D9::GetData(unsigned int offset,
+ unsigned int size,
+ void *data) {
+ if (!d3d_vertex_buffer_) {
+ LOG(ERROR) << "Calling SetData on a non-initialized VertexBufferD3D9.";
+ return false;
+ }
+ if ((offset >= this->size()) || (offset + size > this->size())) {
+ LOG(ERROR) << "Invalid size or offset on VertexBufferD3D9::SetData.";
+ return false;
+ }
+ void *ptr = NULL;
+ DWORD lock_flags = D3DLOCK_READONLY;
+ HR(d3d_vertex_buffer_->Lock(offset, size, &ptr, lock_flags));
+ memcpy(data, ptr, size);
+ HR(d3d_vertex_buffer_->Unlock());
+ return true;
+}
+
+// Destroys the D3D9 index buffer.
+IndexBufferD3D9::~IndexBufferD3D9() {
+ DCHECK(d3d_index_buffer_ != NULL);
+ if (d3d_index_buffer_) {
+ d3d_index_buffer_->Release();
+ d3d_index_buffer_ = NULL;
+ }
+}
+
+// Creates a D3D9 index buffer.
+void IndexBufferD3D9::Create(GAPID3D9 *gapi) {
+ DCHECK(d3d_index_buffer_ == NULL);
+
+ DWORD d3d_usage = (flags() & index_buffer::kDynamic) ? D3DUSAGE_DYNAMIC : 0;
+ D3DFORMAT d3d_format =
+ (flags() & index_buffer::kIndex32Bit) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
+ D3DPOOL d3d_pool = D3DPOOL_MANAGED;
+ HR(gapi->d3d_device()->CreateIndexBuffer(size(), d3d_usage, d3d_format,
+ d3d_pool, &d3d_index_buffer_,
+ NULL));
+}
+
+// Sets the data into the D3D9 index buffer, using Lock() and memcpy.
+bool IndexBufferD3D9::SetData(unsigned int offset,
+ unsigned int size,
+ const void *data) {
+ if (!d3d_index_buffer_) {
+ LOG(ERROR) << "Calling SetData on a non-initialized IndexBufferD3D9.";
+ return false;
+ }
+ if ((offset >= this->size()) || (offset + size > this->size())) {
+ LOG(ERROR) << "Invalid size or offset on IndexBufferD3D9::SetData.";
+ return false;
+ }
+ void *ptr = NULL;
+ DWORD lock_flags = 0;
+ // If we are setting the full buffer, discard the old data. That's only
+ // possible to do for a dynamic d3d index buffer.
+ if ((offset == 0) && (size == this->size()) &&
+ (flags() & index_buffer::kDynamic))
+ lock_flags = D3DLOCK_DISCARD;
+ HR(d3d_index_buffer_->Lock(offset, size, &ptr, lock_flags));
+ memcpy(ptr, data, size);
+ HR(d3d_index_buffer_->Unlock());
+ return true;
+}
+
+// Gets the data from the D3D9 index buffer, using Lock() and memcpy.
+bool IndexBufferD3D9::GetData(unsigned int offset,
+ unsigned int size,
+ void *data) {
+ if (!d3d_index_buffer_) {
+ LOG(ERROR) << "Calling SetData on a non-initialized IndexBufferD3D9.";
+ return false;
+ }
+ if ((offset >= this->size()) || (offset + size > this->size())) {
+ LOG(ERROR) << "Invalid size or offset on IndexBufferD3D9::SetData.";
+ return false;
+ }
+ void *ptr = NULL;
+ DWORD lock_flags = D3DLOCK_READONLY;
+ HR(d3d_index_buffer_->Lock(offset, size, &ptr, lock_flags));
+ memcpy(data, ptr, size);
+ HR(d3d_index_buffer_->Unlock());
+ return true;
+}
+
+// Sets the input element in the VertexStruct resource.
+void VertexStructD3D9::SetInput(unsigned int input_index,
+ ResourceId vertex_buffer_id,
+ unsigned int offset,
+ unsigned int stride,
+ vertex_struct::Type type,
+ vertex_struct::Semantic semantic,
+ unsigned int semantic_index) {
+ Element &element = GetElement(input_index);
+ element.vertex_buffer = vertex_buffer_id;
+ element.offset = offset;
+ element.stride = stride;
+ element.type = type;
+ element.semantic = semantic;
+ element.semantic_index = semantic_index;
+ dirty_ = true;
+}
+
+// Sets the vdecl and stream sources in D3D9. Compiles them if needed.
+unsigned int VertexStructD3D9::SetStreams(GAPID3D9 *gapi) {
+ IDirect3DDevice9 *d3d_device = gapi->d3d_device();
+ if (dirty_) Compile(d3d_device);
+ HR(d3d_device->SetVertexDeclaration(d3d_vertex_decl_));
+ unsigned int max_vertices = UINT_MAX;
+ for (unsigned int i = 0; i < streams_.size(); ++i) {
+ const StreamPair &pair = streams_[i];
+ VertexBufferD3D9 *vertex_buffer = gapi->GetVertexBuffer(pair.first);
+ if (!vertex_buffer) {
+ max_vertices = 0;
+ continue;
+ }
+ HR(d3d_device->SetStreamSource(i, vertex_buffer->d3d_vertex_buffer(), 0,
+ pair.second));
+
+ // TODO(apatrick): A zero size stride is valid. It means the first element
+ // in the vertex buffer will be used for every vertex. There doesn't seem
+ // to be enough information here to determine whether a zero stride
+ // vertex buffer is big enough to contain a single element.
+ if (pair.second != 0) {
+ max_vertices = std::min(max_vertices,
+ vertex_buffer->size() / pair.second);
+ }
+ }
+ return max_vertices;
+}
+
+// Converts a vertex_struct::Type to a D3DDECLTYPE.
+static D3DDECLTYPE D3DType(vertex_struct::Type type) {
+ switch (type) {
+ case vertex_struct::kFloat1:
+ return D3DDECLTYPE_FLOAT1;
+ case vertex_struct::kFloat2:
+ return D3DDECLTYPE_FLOAT2;
+ case vertex_struct::kFloat3:
+ return D3DDECLTYPE_FLOAT3;
+ case vertex_struct::kFloat4:
+ return D3DDECLTYPE_FLOAT4;
+ case vertex_struct::kUChar4N:
+ return D3DDECLTYPE_UBYTE4N;
+ case vertex_struct::kNumTypes:
+ break;
+ }
+ LOG(FATAL) << "Invalid type";
+ return D3DDECLTYPE_FLOAT1;
+}
+
+// Converts a vertex_struct::Semantic to a D3DDECLUSAGE.
+static D3DDECLUSAGE D3DUsage(vertex_struct::Semantic semantic) {
+ switch (semantic) {
+ case vertex_struct::kPosition:
+ return D3DDECLUSAGE_POSITION;
+ case vertex_struct::kNormal:
+ return D3DDECLUSAGE_NORMAL;
+ case vertex_struct::kColor:
+ return D3DDECLUSAGE_COLOR;
+ case vertex_struct::kTexCoord:
+ return D3DDECLUSAGE_TEXCOORD;
+ case vertex_struct::kNumSemantics:
+ break;
+ }
+ LOG(FATAL) << "Invalid type";
+ return D3DDECLUSAGE_POSITION;
+}
+
+// Destroys the d3d vertex declaration.
+VertexStructD3D9::~VertexStructD3D9() {
+ Destroy();
+}
+
+void VertexStructD3D9::Destroy() {
+ if (d3d_vertex_decl_) {
+ d3d_vertex_decl_->Release();
+ d3d_vertex_decl_ = NULL;
+ }
+ streams_.clear();
+}
+
+// Compiles a stream map and a d3d vertex declaration from the list of inputs.
+// 2 inputs that use the same vertex buffer and stride will use the same
+// d3d stream.
+void VertexStructD3D9::Compile(IDirect3DDevice9 *d3d_device) {
+ DCHECK(dirty_);
+ Destroy();
+ streams_.reserve(count_);
+ scoped_array<D3DVERTEXELEMENT9> d3d_elements(
+ new D3DVERTEXELEMENT9[count_ + 1]);
+ memset(d3d_elements.get(), 0, sizeof(D3DVERTEXELEMENT9) * (count_ + 1));
+ // build streams_ like a set, but the order matters.
+ for (unsigned int i = 0; i < count_ ; ++i) {
+ Element &element = GetElement(i);
+ D3DVERTEXELEMENT9 &d3d_element = d3d_elements[i];
+ StreamPair pair(element.vertex_buffer, element.stride);
+ std::vector<StreamPair>::iterator it =
+ std::find(streams_.begin(), streams_.end(), pair);
+ unsigned int stream_index = 0;
+ if (it == streams_.end()) {
+ streams_.push_back(pair);
+ stream_index = static_cast<unsigned int>(streams_.size() - 1);
+ } else {
+ stream_index = it - streams_.begin();
+ }
+ d3d_element.Stream = stream_index;
+ d3d_element.Offset = element.offset;
+ d3d_element.Type = D3DType(element.type);
+ d3d_element.Usage = D3DUsage(element.semantic);
+ d3d_element.UsageIndex = element.semantic_index;
+ }
+ D3DVERTEXELEMENT9 &end = d3d_elements[count_];
+ end.Stream = 0xFF;
+ end.Type = D3DDECLTYPE_UNUSED;
+ HR(d3d_device->CreateVertexDeclaration(d3d_elements.get(),
+ &d3d_vertex_decl_));
+ dirty_ = false;
+}
+
+// Creates and assigns a VertexBufferD3D9 resource.
+parse_error::ParseError GAPID3D9::CreateVertexBuffer(
+ ResourceId id,
+ unsigned int size,
+ unsigned int flags) {
+ VertexBufferD3D9 *vertex_buffer = new VertexBufferD3D9(size, flags);
+ vertex_buffer->Create(this);
+ vertex_buffers_.Assign(id, vertex_buffer);
+ return parse_error::kParseNoError;
+}
+
+// Destroys a VertexBufferD3D9 resource.
+parse_error::ParseError GAPID3D9::DestroyVertexBuffer(ResourceId id) {
+ return vertex_buffers_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Copies the data into the VertexBufferD3D9 resource.
+parse_error::ParseError GAPID3D9::SetVertexBufferData(
+ ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data) {
+ VertexBufferD3D9 *vertex_buffer = vertex_buffers_.Get(id);
+ if (!vertex_buffer) return parse_error::kParseInvalidArguments;
+ return vertex_buffer->SetData(offset, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Copies the data from the VertexBufferD3D9 resource.
+parse_error::ParseError GAPID3D9::GetVertexBufferData(
+ ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data) {
+ VertexBufferD3D9 *vertex_buffer = vertex_buffers_.Get(id);
+ if (!vertex_buffer) return parse_error::kParseInvalidArguments;
+ return vertex_buffer->GetData(offset, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Creates and assigns an IndexBufferD3D9 resource.
+parse_error::ParseError GAPID3D9::CreateIndexBuffer(
+ ResourceId id,
+ unsigned int size,
+ unsigned int flags) {
+ IndexBufferD3D9 *index_buffer = new IndexBufferD3D9(size, flags);
+ index_buffer->Create(this);
+ index_buffers_.Assign(id, index_buffer);
+ return parse_error::kParseNoError;
+}
+
+// Destroys an IndexBufferD3D9 resource.
+parse_error::ParseError GAPID3D9::DestroyIndexBuffer(ResourceId id) {
+ return index_buffers_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Copies the data into the IndexBufferD3D9 resource.
+parse_error::ParseError GAPID3D9::SetIndexBufferData(
+ ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data) {
+ IndexBufferD3D9 *index_buffer = index_buffers_.Get(id);
+ if (!index_buffer) return parse_error::kParseInvalidArguments;
+ return index_buffer->SetData(offset, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Copies the data from the IndexBufferD3D9 resource.
+parse_error::ParseError GAPID3D9::GetIndexBufferData(
+ ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data) {
+ IndexBufferD3D9 *index_buffer = index_buffers_.Get(id);
+ if (!index_buffer) return parse_error::kParseInvalidArguments;
+ return index_buffer->GetData(offset, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Creates and assigns a VertexStructD3D9 resource.
+parse_error::ParseError GAPID3D9::CreateVertexStruct(
+ ResourceId id, unsigned int input_count) {
+ if (id == current_vertex_struct_) validate_streams_ = true;
+ VertexStructD3D9 *vertex_struct = new VertexStructD3D9(input_count);
+ vertex_structs_.Assign(id, vertex_struct);
+ return parse_error::kParseNoError;
+}
+
+// Destroys a VertexStructD3D9 resource.
+parse_error::ParseError GAPID3D9::DestroyVertexStruct(ResourceId id) {
+ if (id == current_vertex_struct_) validate_streams_ = true;
+ return vertex_structs_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Sets an input into a VertexStructD3D9 resource.
+parse_error::ParseError GAPID3D9::SetVertexInput(
+ ResourceId vertex_struct_id,
+ unsigned int input_index,
+ ResourceId vertex_buffer_id,
+ unsigned int offset,
+ unsigned int stride,
+ vertex_struct::Type type,
+ vertex_struct::Semantic semantic,
+ unsigned int semantic_index) {
+ if (vertex_buffer_id == current_vertex_struct_) validate_streams_ = true;
+ VertexStructD3D9 *vertex_struct = vertex_structs_.Get(vertex_struct_id);
+ if (!vertex_struct || input_index >= vertex_struct->count())
+ return parse_error::kParseInvalidArguments;
+ vertex_struct->SetInput(input_index, vertex_buffer_id, offset, stride, type,
+ semantic, semantic_index);
+ return parse_error::kParseNoError;
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/geometry_d3d9.h b/o3d/gpu/command_buffer/service/geometry_d3d9.h
new file mode 100644
index 0000000..50f534d
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/geometry_d3d9.h
@@ -0,0 +1,126 @@
+/*
+ * 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 definition of the D3D9 versions of geometry-related
+// resource classes.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_D3D9_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_D3D9_H_
+
+#include <vector>
+#include <utility>
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/d3d9_utils.h"
+#include "gpu/command_buffer/service/resource.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class GAPID3D9;
+
+// D3D9 version of VertexBuffer.
+class VertexBufferD3D9 : public VertexBuffer {
+ public:
+ VertexBufferD3D9(unsigned int size, unsigned int flags)
+ : VertexBuffer(size, flags),
+ d3d_vertex_buffer_(NULL) {}
+ virtual ~VertexBufferD3D9();
+ // Creates the D3D vertex buffer.
+ void Create(GAPID3D9 *gapi);
+ // Sets the data into the D3D vertex buffer.
+ bool SetData(unsigned int offset, unsigned int size, const void *data);
+ // Gets the data from the D3D vertex buffer.
+ bool GetData(unsigned int offset, unsigned int size, void *data);
+
+ // Gets the D3D vertex buffer.
+ IDirect3DVertexBuffer9 * d3d_vertex_buffer() { return d3d_vertex_buffer_; }
+ private:
+ IDirect3DVertexBuffer9 *d3d_vertex_buffer_;
+ DISALLOW_COPY_AND_ASSIGN(VertexBufferD3D9);
+};
+
+// D3D9 version of IndexBuffer.
+class IndexBufferD3D9 : public IndexBuffer {
+ public:
+ IndexBufferD3D9(unsigned int size, unsigned int flags)
+ : IndexBuffer(size, flags),
+ d3d_index_buffer_(NULL) {}
+ virtual ~IndexBufferD3D9();
+ // Creates the D3D index buffer.
+ void Create(GAPID3D9 *gapi);
+ // Sets the data into the D3D index buffer.
+ bool SetData(unsigned int offset, unsigned int size, const void *data);
+ // Gets the data from the D3D index buffer.
+ bool GetData(unsigned int offset, unsigned int size, void *data);
+
+ // Gets the D3D index buffer.
+ IDirect3DIndexBuffer9 *d3d_index_buffer() const { return d3d_index_buffer_; }
+ private:
+ IDirect3DIndexBuffer9 *d3d_index_buffer_;
+ DISALLOW_COPY_AND_ASSIGN(IndexBufferD3D9);
+};
+
+// D3D9 version of VertexStruct.
+class VertexStructD3D9 : public VertexStruct {
+ public:
+ explicit VertexStructD3D9(unsigned int count)
+ : VertexStruct(count),
+ dirty_(true),
+ d3d_vertex_decl_(NULL) {}
+ virtual ~VertexStructD3D9();
+ // Adds an input to the vertex struct.
+ void SetInput(unsigned int input_index,
+ ResourceId vertex_buffer_id,
+ unsigned int offset,
+ unsigned int stride,
+ vertex_struct::Type type,
+ vertex_struct::Semantic semantic,
+ unsigned int semantic_index);
+ // Sets the input streams to D3D.
+ unsigned int SetStreams(GAPID3D9 *gapi);
+ private:
+ // Destroys the vertex declaration and stream map.
+ void Destroy();
+ // Compiles the vertex declaration and stream map.
+ void Compile(IDirect3DDevice9 *d3d_device);
+
+ bool dirty_;
+ typedef std::pair<ResourceId, unsigned int> StreamPair;
+ std::vector<StreamPair> streams_;
+ IDirect3DVertexDeclaration9 *d3d_vertex_decl_;
+ DISALLOW_COPY_AND_ASSIGN(VertexStructD3D9);
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_D3D9_H_
diff --git a/o3d/gpu/command_buffer/service/geometry_gl.cc b/o3d/gpu/command_buffer/service/geometry_gl.cc
new file mode 100644
index 0000000..13390a9
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/geometry_gl.cc
@@ -0,0 +1,554 @@
+/*
+ * 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 implementation of the VertexBufferGL, IndexBufferGL
+// and VertexStructGL classes, as well as the geometry-related GAPI functions.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/gapi_gl.h"
+#include "gpu/command_buffer/service/geometry_gl.h"
+
+namespace command_buffer {
+namespace o3d {
+
+VertexBufferGL::~VertexBufferGL() {
+ glDeleteBuffers(1, &gl_buffer_);
+ CHECK_GL_ERROR();
+}
+
+// Creates the GL buffer object.
+void VertexBufferGL::Create() {
+ glGenBuffers(1, &gl_buffer_);
+ glBindBuffer(GL_ARRAY_BUFFER, gl_buffer_);
+ GLenum usage =
+ (flags() & vertex_buffer::kDynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW;
+ glBufferData(GL_ARRAY_BUFFER, size(), NULL, usage);
+ CHECK_GL_ERROR();
+}
+
+// Sets the data into the GL buffer object.
+bool VertexBufferGL::SetData(unsigned int offset,
+ unsigned int size,
+ const void *data) {
+ if (!gl_buffer_) {
+ LOG(ERROR) << "Calling SetData on a non-initialized VertexBufferGL.";
+ return false;
+ }
+ if ((offset >= this->size()) || (offset + size > this->size())) {
+ LOG(ERROR) << "Invalid size or offset on VertexBufferGL::SetData.";
+ return false;
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, gl_buffer_);
+ glBufferSubData(GL_ARRAY_BUFFER, offset, size, data);
+ CHECK_GL_ERROR();
+ return true;
+}
+
+// Gets the data from the GL buffer object.
+bool VertexBufferGL::GetData(unsigned int offset,
+ unsigned int size,
+ void *data) {
+ if (!gl_buffer_) {
+ LOG(ERROR) << "Calling GetData on a non-initialized VertexBufferGL.";
+ return false;
+ }
+ if ((offset >= this->size()) || (offset + size > this->size())) {
+ LOG(ERROR) << "Invalid size or offset on VertexBufferGL::GetData.";
+ return false;
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, gl_buffer_);
+ glGetBufferSubData(GL_ARRAY_BUFFER, offset, size, data);
+ CHECK_GL_ERROR();
+ return true;
+}
+
+IndexBufferGL::~IndexBufferGL() {
+ glDeleteBuffers(1, &gl_buffer_);
+}
+
+// Creates the GL buffer object.
+void IndexBufferGL::Create() {
+ glGenBuffers(1, &gl_buffer_);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_buffer_);
+ GLenum usage =
+ (flags() & vertex_buffer::kDynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW;
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, size(), NULL, usage);
+ CHECK_GL_ERROR();
+}
+
+// Sets the data into the GL buffer object.
+bool IndexBufferGL::SetData(unsigned int offset,
+ unsigned int size,
+ const void *data) {
+ if (!gl_buffer_) {
+ LOG(ERROR) << "Calling SetData on a non-initialized IndexBufferGL.";
+ return false;
+ }
+ if ((offset >= this->size()) || (offset + size > this->size())) {
+ LOG(ERROR) << "Invalid size or offset on IndexBufferGL::SetData.";
+ return false;
+ }
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_buffer_);
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, data);
+ CHECK_GL_ERROR();
+ return true;
+}
+
+// Gets the data from the GL buffer object.
+bool IndexBufferGL::GetData(unsigned int offset,
+ unsigned int size,
+ void *data) {
+ if (!gl_buffer_) {
+ LOG(ERROR) << "Calling GetData on a non-initialized IndexBufferGL.";
+ return false;
+ }
+ if ((offset >= this->size()) || (offset + size > this->size())) {
+ LOG(ERROR) << "Invalid size or offset on IndexBufferGL::GetData.";
+ return false;
+ }
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_buffer_);
+ glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, data);
+ CHECK_GL_ERROR();
+ return true;
+}
+
+// Sets the input element in the VertexStruct resource.
+void VertexStructGL::SetInput(unsigned int input_index,
+ ResourceId vertex_buffer_id,
+ unsigned int offset,
+ unsigned int stride,
+ vertex_struct::Type type,
+ vertex_struct::Semantic semantic,
+ unsigned int semantic_index) {
+ Element &element = GetElement(input_index);
+ element.vertex_buffer = vertex_buffer_id;
+ element.offset = offset;
+ element.stride = stride;
+ element.type = type;
+ element.semantic = semantic;
+ element.semantic_index = semantic_index;
+ dirty_ = true;
+}
+
+namespace {
+
+inline ptrdiff_t OffsetToPtrDiff(unsigned int offset) {
+ return static_cast<ptrdiff_t>(offset);
+}
+
+inline void* OffsetToPtr(ptrdiff_t offset) {
+ return reinterpret_cast<void*>(offset);
+}
+
+} // anonymous namespace
+
+unsigned int VertexStructGL::SetStreams(GAPIGL *gapi) {
+ if (dirty_) Compile();
+ unsigned int max_vertices = UINT_MAX;
+ for (unsigned int i = 0; i < kMaxAttribs; ++i) {
+ const AttribDesc &attrib = attribs_[i];
+ if (attrib.vertex_buffer_id == kInvalidResource) {
+ if (i == 0) {
+ glDisableClientState(GL_VERTEX_ARRAY);
+ } else {
+ glDisableVertexAttribArray(i);
+ }
+ } else {
+ glEnableVertexAttribArray(i);
+ VertexBufferGL *vertex_buffer =
+ gapi->GetVertexBuffer(attrib.vertex_buffer_id);
+ if (!vertex_buffer) {
+ glDisableVertexAttribArray(i);
+ max_vertices = 0;
+ continue;
+ }
+ DCHECK_NE(vertex_buffer->gl_buffer(), 0);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer->gl_buffer());
+ glVertexAttribPointer(i, attrib.size, attrib.type, attrib.normalized,
+ attrib.stride,
+ OffsetToPtr(attrib.offset));
+ max_vertices = std::min(max_vertices,
+ vertex_buffer->size() / attrib.stride);
+ }
+ }
+ CHECK_GL_ERROR();
+ return max_vertices;
+}
+
+namespace {
+
+// from the ARB_vertex_program extension, at
+// http://www.opengl.org/registry/specs/ARB/vertex_program.txt
+//
+// Generic
+// Attribute Conventional Attribute Conventional Attribute Command
+// --------- ------------------------ ------------------------------
+// 0 vertex position Vertex
+// 1 vertex weights 0-3 WeightARB, VertexWeightEXT
+// 2 normal Normal
+// 3 primary color Color
+// 4 secondary color SecondaryColorEXT
+// 5 fog coordinate FogCoordEXT
+// 6 - -
+// 7 - -
+// 8 texture coordinate set 0 MultiTexCoord(TEXTURE0, ...)
+// 9 texture coordinate set 1 MultiTexCoord(TEXTURE1, ...)
+// 10 texture coordinate set 2 MultiTexCoord(TEXTURE2, ...)
+// 11 texture coordinate set 3 MultiTexCoord(TEXTURE3, ...)
+// 12 texture coordinate set 4 MultiTexCoord(TEXTURE4, ...)
+// 13 texture coordinate set 5 MultiTexCoord(TEXTURE5, ...)
+// 14 texture coordinate set 6 MultiTexCoord(TEXTURE6, ...)
+// 15 texture coordinate set 7 MultiTexCoord(TEXTURE7, ...)
+// 8+n texture coordinate set n MultiTexCoord(TEXTURE0+n, ...)
+//
+// Note: we only accept at most 8 texture coordinates for maximum compatibility
+// with DirectX.
+
+inline unsigned int GetAttribIndex(vertex_struct::Semantic semantic,
+ unsigned int semantic_index) {
+ switch (semantic) {
+ case vertex_struct::kPosition:
+ DCHECK_EQ(semantic_index, 0);
+ return 0;
+ case vertex_struct::kNormal:
+ DCHECK_EQ(semantic_index, 0);
+ return 2;
+ case vertex_struct::kColor:
+ DCHECK_LT(semantic_index, 2U);
+ return 3 + semantic_index;
+ case vertex_struct::kTexCoord:
+ DCHECK_LT(semantic_index, 8U);
+ return 8 + semantic_index;
+ default:
+ DLOG(FATAL) << "Not reached.";
+ return 0;
+ }
+}
+
+inline void ExtractSizeTypeNormalized(vertex_struct::Type type,
+ GLint *size,
+ GLenum *gl_type,
+ GLboolean *normalized) {
+ switch (type) {
+ case vertex_struct::kFloat1:
+ case vertex_struct::kFloat2:
+ case vertex_struct::kFloat3:
+ case vertex_struct::kFloat4:
+ *size = type - vertex_struct::kFloat1 + 1;
+ *gl_type = GL_FLOAT;
+ *normalized = false;
+ break;
+ case vertex_struct::kUChar4N:
+ *size = 4;
+ *gl_type = GL_UNSIGNED_BYTE;
+ *normalized = true;
+ break;
+ default:
+ DLOG(FATAL) << "Not reached.";
+ break;
+ }
+}
+
+} // anonymous namespace
+
+#ifndef COMPILER_MSVC
+// Although required by the spec, this causes problems on MSVC. It is needed by
+// GCC.
+const unsigned int VertexStructGL::kMaxAttribs;
+#endif
+
+void VertexStructGL::Compile() {
+ DCHECK(dirty_);
+ for (unsigned int i = 0; i < kMaxAttribs; ++i) {
+ attribs_[i].vertex_buffer_id = kInvalidResource;
+ }
+ for (unsigned int i = 0; i < count_ ; ++i) {
+ const Element &element = GetElement(i);
+ unsigned int index = GetAttribIndex(element.semantic,
+ element.semantic_index);
+ DCHECK_LT(index, kMaxAttribs);
+ AttribDesc &attrib = attribs_[index];
+ attrib.vertex_buffer_id = element.vertex_buffer;
+ ExtractSizeTypeNormalized(element.type, &attrib.size, &attrib.type,
+ &attrib.normalized);
+ attrib.stride = element.stride;
+ attrib.offset = OffsetToPtrDiff(element.offset);
+ }
+ dirty_ = false;
+}
+
+parse_error::ParseError GAPIGL::CreateVertexBuffer(ResourceId id,
+ unsigned int size,
+ unsigned int flags) {
+ VertexBufferGL *vertex_buffer = new VertexBufferGL(size, flags);
+ vertex_buffer->Create();
+ vertex_buffers_.Assign(id, vertex_buffer);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::DestroyVertexBuffer(ResourceId id) {
+ return vertex_buffers_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::SetVertexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data) {
+ VertexBufferGL *vertex_buffer = vertex_buffers_.Get(id);
+ if (!vertex_buffer) return parse_error::kParseInvalidArguments;
+ return vertex_buffer->SetData(offset, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::GetVertexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data) {
+ VertexBufferGL *vertex_buffer = vertex_buffers_.Get(id);
+ if (!vertex_buffer) return parse_error::kParseInvalidArguments;
+ return vertex_buffer->GetData(offset, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::CreateIndexBuffer(ResourceId id,
+ unsigned int size,
+ unsigned int flags) {
+ IndexBufferGL *index_buffer = new IndexBufferGL(size, flags);
+ index_buffer->Create();
+ index_buffers_.Assign(id, index_buffer);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::DestroyIndexBuffer(ResourceId id) {
+ return index_buffers_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::SetIndexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ const void *data) {
+ IndexBufferGL *index_buffer = index_buffers_.Get(id);
+ if (!index_buffer) return parse_error::kParseInvalidArguments;
+ return index_buffer->SetData(offset, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::GetIndexBufferData(ResourceId id,
+ unsigned int offset,
+ unsigned int size,
+ void *data) {
+ IndexBufferGL *index_buffer = index_buffers_.Get(id);
+ if (!index_buffer) return parse_error::kParseInvalidArguments;
+ return index_buffer->GetData(offset, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::CreateVertexStruct(
+ ResourceId id,
+ unsigned int input_count) {
+ if (id == current_vertex_struct_) validate_streams_ = true;
+ VertexStructGL *vertex_struct = new VertexStructGL(input_count);
+ vertex_structs_.Assign(id, vertex_struct);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::DestroyVertexStruct(ResourceId id) {
+ if (id == current_vertex_struct_) validate_streams_ = true;
+ return vertex_structs_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::SetVertexInput(
+ ResourceId vertex_struct_id,
+ unsigned int input_index,
+ ResourceId vertex_buffer_id,
+ unsigned int offset,
+ unsigned int stride,
+ vertex_struct::Type type,
+ vertex_struct::Semantic semantic,
+ unsigned int semantic_index) {
+ switch (semantic) {
+ case vertex_struct::kPosition:
+ if (semantic_index != 0) {
+ return parse_error::kParseInvalidArguments;
+ }
+ break;
+ case vertex_struct::kNormal:
+ if (semantic_index != 0) {
+ return parse_error::kParseInvalidArguments;
+ }
+ break;
+ case vertex_struct::kColor:
+ if (semantic_index >= 2) {
+ return parse_error::kParseInvalidArguments;
+ }
+ break;
+ case vertex_struct::kTexCoord:
+ if (semantic_index >= 8) {
+ return parse_error::kParseInvalidArguments;
+ }
+ break;
+ default:
+ DLOG(FATAL) << "Not reached.";
+ break;
+ }
+ if (vertex_buffer_id == current_vertex_struct_) validate_streams_ = true;
+ VertexStructGL *vertex_struct = vertex_structs_.Get(vertex_struct_id);
+ if (!vertex_struct || input_index >= vertex_struct->count())
+ return parse_error::kParseInvalidArguments;
+ vertex_struct->SetInput(input_index, vertex_buffer_id, offset, stride, type,
+ semantic, semantic_index);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::SetVertexStruct(ResourceId id) {
+ current_vertex_struct_ = id;
+ validate_streams_ = true;
+ return parse_error::kParseNoError;
+}
+
+bool GAPIGL::ValidateStreams() {
+ DCHECK(validate_streams_);
+ VertexStructGL *vertex_struct = vertex_structs_.Get(current_vertex_struct_);
+ if (!vertex_struct) {
+ LOG(ERROR) << "Drawing with invalid streams.";
+ return false;
+ }
+ max_vertices_ = vertex_struct->SetStreams(this);
+ validate_streams_ = false;
+ return max_vertices_ > 0;
+}
+
+namespace {
+
+void PrimitiveTypeToGL(o3d::PrimitiveType primitive_type,
+ GLenum *gl_mode,
+ unsigned int *count) {
+ switch (primitive_type) {
+ case o3d::kPoints:
+ *gl_mode = GL_POINTS;
+ break;
+ case o3d::kLines:
+ *gl_mode = GL_LINES;
+ *count *= 2;
+ break;
+ case o3d::kLineStrips:
+ *gl_mode = GL_LINE_STRIP;
+ ++*count;
+ break;
+ case o3d::kTriangles:
+ *gl_mode = GL_TRIANGLES;
+ *count *= 3;
+ break;
+ case o3d::kTriangleStrips:
+ *gl_mode = GL_TRIANGLE_STRIP;
+ *count += 2;
+ break;
+ case o3d::kTriangleFans:
+ *gl_mode = GL_TRIANGLE_FAN;
+ *count += 2;
+ break;
+ default:
+ LOG(FATAL) << "Invalid primitive type";
+ break;
+ }
+}
+
+} // anonymous namespace
+
+parse_error::ParseError GAPIGL::Draw(o3d::PrimitiveType primitive_type,
+ unsigned int first,
+ unsigned int count) {
+ if (validate_effect_ && !ValidateEffect()) {
+ return parse_error::kParseInvalidArguments;
+ }
+ DCHECK(current_effect_);
+ if (validate_streams_ && !ValidateStreams()) {
+ return parse_error::kParseInvalidArguments;
+ }
+ GLenum gl_mode = GL_POINTS;
+ PrimitiveTypeToGL(primitive_type, &gl_mode, &count);
+ if (first + count > max_vertices_) {
+ return parse_error::kParseInvalidArguments;
+ }
+ glDrawArrays(gl_mode, first, count);
+ CHECK_GL_ERROR();
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::DrawIndexed(
+ o3d::PrimitiveType primitive_type,
+ ResourceId index_buffer_id,
+ unsigned int first,
+ unsigned int count,
+ unsigned int min_index,
+ unsigned int max_index) {
+ IndexBufferGL *index_buffer = index_buffers_.Get(index_buffer_id);
+ if (!index_buffer) return parse_error::kParseInvalidArguments;
+ if (validate_effect_ && !ValidateEffect()) {
+ return parse_error::kParseInvalidArguments;
+ }
+ DCHECK(current_effect_);
+ if (validate_streams_ && !ValidateStreams()) {
+ return parse_error::kParseInvalidArguments;
+ }
+ if ((min_index >= max_vertices_) || (max_index > max_vertices_)) {
+ return parse_error::kParseInvalidArguments;
+ }
+ GLenum gl_mode = GL_POINTS;
+ PrimitiveTypeToGL(primitive_type, &gl_mode, &count);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer->gl_buffer());
+ GLenum index_type = (index_buffer->flags() & index_buffer::kIndex32Bit) ?
+ GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
+ GLuint index_size = (index_buffer->flags() & index_buffer::kIndex32Bit) ?
+ sizeof(GLuint) : sizeof(GLushort); // NOLINT
+ GLuint offset = first * index_size;
+ if (offset + count * index_size > index_buffer->size()) {
+ return parse_error::kParseInvalidArguments;
+ }
+ glDrawRangeElements(gl_mode, min_index, max_index, count, index_type,
+ OffsetToPtr(offset));
+ CHECK_GL_ERROR();
+ return parse_error::kParseNoError;
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/geometry_gl.h b/o3d/gpu/command_buffer/service/geometry_gl.h
new file mode 100644
index 0000000..b4d4b5f
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/geometry_gl.h
@@ -0,0 +1,144 @@
+/*
+ * 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 declares the VertexBufferGL, IndexBufferGL and VertexStructGL
+// classes.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_GL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_GL_H_
+
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/resource.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class GAPIGL;
+
+// GL version of VertexBuffer.
+class VertexBufferGL : public VertexBuffer {
+ public:
+ VertexBufferGL(unsigned int size, unsigned int flags)
+ : VertexBuffer(size, flags),
+ gl_buffer_(0) {}
+ virtual ~VertexBufferGL();
+
+ // Creates the GL vertex buffer.
+ void Create();
+
+ // Sets the data into the GL vertex buffer.
+ bool SetData(unsigned int offset, unsigned int size, const void *data);
+
+ // Gets the data from the GL vertex buffer.
+ bool GetData(unsigned int offset, unsigned int size, void *data);
+
+ // Gets the GL vertex buffer.
+ GLuint gl_buffer() const { return gl_buffer_; }
+
+ private:
+ GLuint gl_buffer_;
+ DISALLOW_COPY_AND_ASSIGN(VertexBufferGL);
+};
+
+// GL version of IndexBuffer.
+class IndexBufferGL : public IndexBuffer {
+ public:
+ IndexBufferGL(unsigned int size, unsigned int flags)
+ : IndexBuffer(size, flags),
+ gl_buffer_(0) {}
+ virtual ~IndexBufferGL();
+
+ // Creates the GL index buffer.
+ void Create();
+
+ // Sets the data into the GL index buffer.
+ bool SetData(unsigned int offset, unsigned int size, const void *data);
+
+ // Gets the data from the GL index buffer.
+ bool GetData(unsigned int offset, unsigned int size, void *data);
+
+ // Gets the GL index buffer.
+ GLuint gl_buffer() const { return gl_buffer_; }
+
+ private:
+ GLuint gl_buffer_;
+ DISALLOW_COPY_AND_ASSIGN(IndexBufferGL);
+};
+
+// GL version of VertexStruct.
+class VertexStructGL : public VertexStruct {
+ public:
+ explicit VertexStructGL(unsigned int count)
+ : VertexStruct(count),
+ dirty_(true) {}
+ virtual ~VertexStructGL() {}
+
+ // Adds an input to the vertex struct.
+ void SetInput(unsigned int input_index,
+ ResourceId vertex_buffer_id,
+ unsigned int offset,
+ unsigned int stride,
+ vertex_struct::Type type,
+ vertex_struct::Semantic semantic,
+ unsigned int semantic_index);
+
+ // Sets the input streams to GL.
+ unsigned int SetStreams(GAPIGL *gapi);
+
+ private:
+ static const unsigned int kMaxAttribs = 16;
+
+ // This struct describes the parameters that are passed to
+ // glVertexAttribPointer.
+ struct AttribDesc {
+ ResourceId vertex_buffer_id;
+ GLint size;
+ GLenum type;
+ GLboolean normalized;
+ GLsizei stride;
+ ptrdiff_t offset;
+ };
+
+ // Compiles the vertex declaration into the attribute array.
+ void Compile();
+
+ bool dirty_;
+ AttribDesc attribs_[kMaxAttribs];
+ DISALLOW_COPY_AND_ASSIGN(VertexStructGL);
+};
+
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_GL_H_
diff --git a/o3d/gpu/command_buffer/service/gl_utils.h b/o3d/gpu/command_buffer/service/gl_utils.h
new file mode 100644
index 0000000..292b2d6
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/gl_utils.h
@@ -0,0 +1,60 @@
+/*
+ * 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 includes all the necessary GL/Cg headers and implements some useful
+// utilities.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_
+
+#include <GL/glew.h>
+#if defined(OS_WIN)
+#include <GL/wglew.h>
+#endif
+#include <Cg/cg.h>
+#include <Cg/cgGL.h>
+#include <build/build_config.h>
+
+#define GL_GLEXT_PROTOTYPES
+
+// Define this for extra GL error debugging (slower).
+// #define GL_ERROR_DEBUGGING
+#ifdef GL_ERROR_DEBUGGING
+#define CHECK_GL_ERROR() do { \
+ GLenum gl_error = glGetError(); \
+ LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
+ } while (0)
+#else // GL_ERROR_DEBUGGING
+#define CHECK_GL_ERROR() void(0)
+#endif // GL_ERROR_DEBUGGING
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_
diff --git a/o3d/gpu/command_buffer/service/mocks.h b/o3d/gpu/command_buffer/service/mocks.h
new file mode 100644
index 0000000..dbfb160
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/mocks.h
@@ -0,0 +1,108 @@
+/*
+ * 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 definitions for mock objects, used for testing.
+
+// TODO: This file "manually" defines some mock objects. Using gMock
+// would be definitely preferable, unfortunately it doesn't work on Windows
+// yet.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H_
+
+#include <vector>
+#include "gmock/gmock.h"
+#include "gpu/command_buffer/service/cmd_parser.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+
+namespace command_buffer {
+
+// Mocks an AsyncAPIInterface, using GMock.
+class AsyncAPIMock : public AsyncAPIInterface {
+ public:
+ AsyncAPIMock() {
+ testing::DefaultValue<parse_error::ParseError>::Set(
+ parse_error::kParseNoError);
+ }
+
+ // Predicate that matches args passed to DoCommand, by looking at the values.
+ class IsArgs {
+ public:
+ IsArgs(unsigned int arg_count, const void* args)
+ : arg_count_(arg_count),
+ args_(static_cast<CommandBufferEntry*>(const_cast<void*>(args))) {
+ }
+
+ bool operator() (const void* _args) const {
+ const CommandBufferEntry* args =
+ static_cast<const CommandBufferEntry*>(_args) + 1;
+ for (unsigned int i = 0; i < arg_count_; ++i) {
+ if (args[i].value_uint32 != args_[i].value_uint32) return false;
+ }
+ return true;
+ }
+
+ private:
+ unsigned int arg_count_;
+ CommandBufferEntry *args_;
+ };
+
+ MOCK_METHOD3(DoCommand, parse_error::ParseError(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data));
+
+ const char* GetCommandName(unsigned int command_id) const {
+ return "";
+ };
+
+ // Sets the engine, to forward SetToken commands to it.
+ void set_engine(CommandBufferEngine *engine) { engine_ = engine; }
+
+ // Forwards the SetToken commands to the engine.
+ void SetToken(unsigned int command,
+ unsigned int arg_count,
+ const void* _args) {
+ DCHECK(engine_);
+ DCHECK_EQ(1u, command);
+ DCHECK_EQ(1u, arg_count);
+ const CommandBufferEntry* args =
+ static_cast<const CommandBufferEntry*>(_args);
+ engine_->set_token(args[0].value_uint32);
+ }
+ private:
+ CommandBufferEngine *engine_;
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H_
diff --git a/o3d/gpu/command_buffer/service/precompile.cc b/o3d/gpu/command_buffer/service/precompile.cc
new file mode 100644
index 0000000..3e219b0
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/precompile.cc
@@ -0,0 +1,33 @@
+/*
+ * 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 "gpu/command_buffer/service/precompile.h"
diff --git a/o3d/gpu/command_buffer/service/precompile.h b/o3d/gpu/command_buffer/service/precompile.h
new file mode 100644
index 0000000..55d2b21
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/precompile.h
@@ -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 includes for common headers used by command buffer server
+// files. It is used for pre-compiled header support.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_PRECOMPILE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CROSS_PRECOMPILE_H_
+
+#include <build/build_config.h>
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include <assert.h>
+#include <algorithm>
+#include <map>
+#include <vector>
+
+#endif // O3D_CORE_CROSS_PRECOMPILE_H_
diff --git a/o3d/gpu/command_buffer/service/render_surface_d3d9.cc b/o3d/gpu/command_buffer/service/render_surface_d3d9.cc
new file mode 100644
index 0000000..a3880f8
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/render_surface_d3d9.cc
@@ -0,0 +1,230 @@
+/*
+ * 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 implements the D3D9 versions of the render surface resources,
+// as well as the related GAPID3D9 function implementations.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/render_surface_d3d9.h"
+#include "gpu/command_buffer/service/gapi_d3d9.h"
+#include "gpu/command_buffer/service/texture_d3d9.h"
+
+
+namespace command_buffer {
+namespace o3d {
+
+RenderSurfaceD3D9::RenderSurfaceD3D9(int width,
+ int height,
+ int mip_level,
+ int side,
+ TextureD3D9 *texture,
+ IDirect3DSurface9 *direct3d_surface)
+ : width_(width),
+ height_(height),
+ mip_level_(mip_level),
+ texture_(texture),
+ direct3d_surface_(direct3d_surface) {
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+ DCHECK_GT(mip_level, -1);
+ DCHECK(texture);
+}
+
+RenderSurfaceD3D9* RenderSurfaceD3D9::Create(GAPID3D9 *gapi,
+ int width,
+ int height,
+ int mip_level,
+ int side,
+ TextureD3D9 *texture) {
+ DCHECK(gapi);
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+ DCHECK_GT(mip_level, -1);
+ DCHECK(texture);
+ CComPtr<IDirect3DSurface9> direct3d_surface_handle;
+ bool success =
+ texture->CreateRenderSurface(width, height, mip_level, side,
+ &direct3d_surface_handle);
+ if (!success || direct3d_surface_handle == NULL) {
+ // If the surface was not created properly, delete and return nothing.
+ return NULL;
+ }
+ RenderSurfaceD3D9 *render_surface =
+ new RenderSurfaceD3D9(width,
+ height,
+ mip_level,
+ side,
+ texture,
+ direct3d_surface_handle);
+ return render_surface;
+}
+
+RenderDepthStencilSurfaceD3D9::RenderDepthStencilSurfaceD3D9(
+ int width,
+ int height,
+ IDirect3DSurface9 *direct3d_surface)
+ : width_(width),
+ height_(height),
+ direct3d_surface_(direct3d_surface) {
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+}
+
+RenderDepthStencilSurfaceD3D9* RenderDepthStencilSurfaceD3D9::Create(
+ GAPID3D9 *gapi,
+ int width,
+ int height) {
+ DCHECK(gapi);
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+
+ CComPtr<IDirect3DSurface9> direct3d_surface;
+ gapi->d3d_device()->CreateDepthStencilSurface(
+ width,
+ height,
+ D3DFMT_D24S8, // d3d format
+ D3DMULTISAMPLE_NONE, // multisampling type
+ 0, // multisample quality level
+ FALSE, // z-buffer discarding disabled
+ &direct3d_surface,
+ NULL); // This parameter is required to be NULL.
+ if (direct3d_surface == NULL) {
+ return NULL;
+ }
+ RenderDepthStencilSurfaceD3D9 *depth_stencil =
+ new RenderDepthStencilSurfaceD3D9(width, height, direct3d_surface);
+ return depth_stencil;
+}
+
+// GAPI Interface functions ---------------------------------------------------
+
+// Copies the data from a texture resource.
+parse_error::ParseError GAPID3D9::CreateRenderSurface(
+ ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int mip_level,
+ unsigned int side,
+ ResourceId texture_id) {
+ if (id == current_surface_id_) {
+ // This will delete the current surface which would be bad.
+ return parse_error::kParseInvalidArguments;
+ }
+ TextureD3D9 *texture = textures_.Get(texture_id);
+ if (!texture->render_surfaces_enabled()) {
+ return parse_error::kParseInvalidArguments;
+ } else {
+ RenderSurfaceD3D9 *render_surface = RenderSurfaceD3D9::Create(this,
+ width,
+ height,
+ mip_level,
+ side,
+ texture);
+ if (render_surface == NULL) {
+ return parse_error::kParseInvalidArguments;
+ }
+ render_surfaces_.Assign(id, render_surface);
+ }
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::DestroyRenderSurface(ResourceId id) {
+ if (id == current_surface_id_) {
+ return parse_error::kParseInvalidArguments;
+ }
+ return render_surfaces_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPID3D9::CreateDepthSurface(
+ ResourceId id,
+ unsigned int width,
+ unsigned int height) {
+ if (id == current_depth_surface_id_) {
+ // This will delete the current surface which would be bad.
+ return parse_error::kParseInvalidArguments;
+ }
+ RenderDepthStencilSurfaceD3D9 *depth_surface =
+ RenderDepthStencilSurfaceD3D9::Create(this, width, height);
+ if (depth_surface == NULL) {
+ return parse_error::kParseInvalidArguments;
+ }
+ depth_surfaces_.Assign(id, depth_surface);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::DestroyDepthSurface(ResourceId id) {
+ if (id == current_depth_surface_id_) {
+ return parse_error::kParseInvalidArguments;
+ }
+ return depth_surfaces_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPID3D9::SetRenderSurface(
+ ResourceId render_surface_id,
+ ResourceId depth_stencil_id) {
+ RenderSurfaceD3D9 *d3d_render_surface =
+ render_surfaces_.Get(render_surface_id);
+ RenderDepthStencilSurfaceD3D9 *d3d_render_depth_surface =
+ depth_surfaces_.Get(depth_stencil_id);
+
+ if (d3d_render_surface == NULL && d3d_render_depth_surface == NULL) {
+ return parse_error::kParseInvalidArguments;
+ }
+
+ IDirect3DSurface9 *d3d_surface =
+ d3d_render_surface ? d3d_render_surface->direct3d_surface() : NULL;
+ IDirect3DSurface9 *d3d_depth_surface = d3d_render_depth_surface ?
+ d3d_render_depth_surface->direct3d_surface() : NULL;
+
+ // Get the device and set the render target and the depth stencil surface.
+ IDirect3DDevice9 *device = this->d3d_device();
+
+ HR(device->SetRenderTarget(0, d3d_surface));
+ HR(device->SetDepthStencilSurface(d3d_depth_surface));
+ current_surface_id_ = render_surface_id;
+ current_depth_surface_id_ = depth_stencil_id;
+ return parse_error::kParseNoError;
+}
+
+void GAPID3D9::SetBackSurfaces() {
+ // Get the device and set the render target and the depth stencil surface.
+ IDirect3DDevice9 *device = this->d3d_device();
+ HR(d3d_device()->SetRenderTarget(0, back_buffer_surface_));
+ HR(d3d_device()->SetDepthStencilSurface(back_buffer_depth_surface_));
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/render_surface_d3d9.h b/o3d/gpu/command_buffer/service/render_surface_d3d9.h
new file mode 100644
index 0000000..4769f1f
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/render_surface_d3d9.h
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_D3D9_H_
+#define GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_D3D9_H_
+
+// This file contains the definition of the D3D9 versions of
+// render surface-related resource classes.
+
+#include <d3d9.h>
+#include "base/scoped_ptr.h"
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/resource.h"
+#include "gpu/command_buffer/service/d3d9_utils.h"
+#include "gpu/command_buffer/service/texture_d3d9.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class GAPID3D9;
+
+// The RenderSurfaceD3D class represents a render surface resource in the d3d
+// backend of the command buffer server.
+class RenderSurfaceD3D9 : public RenderSurface {
+ public:
+
+ // Creates a render surface resource based on D3D.
+ // Parameters:
+ // width - width of the surface to be created. Must match width of texture
+ // at mip_level.
+ // height - height of the surface to be created. Must match width of
+ // texture at mip_level.
+ // mip_level - mip level of the texture to which the render surface maps.
+ // side - side of a cube if texture is a cube texture. Does not apply to
+ // texture 2d's.
+ // texture - the texture to which this render surface maps. Not owned by
+ // the RenderSurfaceD3D9.
+ // direct3d_surface - a surface to be used as this render surface's
+ // rendering surface. The new RenderSurfaceD3D9 will own the
+ // direct3d_surface.
+ RenderSurfaceD3D9(int width,
+ int height,
+ int mip_level,
+ int side,
+ TextureD3D9 *texture,
+ IDirect3DSurface9 *direct3d_surface);
+
+ // Destructor for the render surface.
+ virtual ~RenderSurfaceD3D9() {}
+
+ // Performs the setup necessary to create a render surface resource based on
+ // D3D and returns a new one if possibe.
+ // Parameters:
+ // gapi - the gapi interface to D3D.
+ // width - width of the surface to be created. Must match width of texture
+ // at mip_level.
+ // height - height of the surface to be created. Must match width of
+ // texture at mip_level.
+ // mip_level - mip level of the texture to which the render surface maps.
+ // side - side of a cube if texture is a cube texture. Does not apply to
+ // texture 2d's.
+ // texture - the texture to which this render surface maps.
+ // Returns:
+ // a new RenderSurfaceD3D9 or NULL on failure
+ static RenderSurfaceD3D9* Create(GAPID3D9 *gapi,
+ int width,
+ int height,
+ int mip_level,
+ int side,
+ TextureD3D9 *texture);
+
+ // Returns a reference to the actual direct3d surface that is rendered to.
+ IDirect3DSurface9* direct3d_surface() const {
+ return direct3d_surface_;
+ }
+ private:
+ CComPtr<IDirect3DSurface9> direct3d_surface_;
+ int width_;
+ int height_;
+ int mip_level_;
+ TextureD3D9 *texture_;
+ DISALLOW_COPY_AND_ASSIGN(RenderSurfaceD3D9);
+};
+
+// The RenderDepthStencilSurfaceD3D class represents a depth stencil surface
+// resource in the d3d backend of the command buffer server.
+class RenderDepthStencilSurfaceD3D9 : public RenderDepthStencilSurface {
+ public:
+
+ // Creates a depth stencil surface resource based on D3D.
+ // Parameters:
+ // width - width of the surface to be created.
+ // height - height of the surface to be created.
+ // direct3d_surface - a surface to be used as this depth stencil surface's
+ // rendering rendering surface. The new RenderDepthStencilSurfaceD3D9
+ // will own the direct3d_surface.
+ RenderDepthStencilSurfaceD3D9(int width,
+ int height,
+ IDirect3DSurface9 *direct3d_surface);
+
+ // Destructor for the depth stencil surface.
+ virtual ~RenderDepthStencilSurfaceD3D9() {}
+
+
+ // Performs the setup necessary to create a depth stencil surface resource
+ // based on D3D and returns a new one if possibe.
+ // Parameters:
+ // gapi - the gapi interface to D3D.
+ // width - width of the surface to be created.
+ // height - height of the surface to be created.
+ // Returns:
+ // a new RenderDepthStencilSurfaceD3D9 or NULL on failure.
+ static RenderDepthStencilSurfaceD3D9* Create(GAPID3D9 *gapi,
+ int width,
+ int height);
+
+ // Returns a reference to the actual direct3d surface that is rendered to.
+ IDirect3DSurface9* direct3d_surface() const {
+ return direct3d_surface_;
+ }
+ private:
+ CComPtr<IDirect3DSurface9> direct3d_surface_;
+ int width_;
+ int height_;
+ DISALLOW_COPY_AND_ASSIGN(RenderDepthStencilSurfaceD3D9);
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_D3D9_H_
+
diff --git a/o3d/gpu/command_buffer/service/render_surface_gl.cc b/o3d/gpu/command_buffer/service/render_surface_gl.cc
new file mode 100644
index 0000000..5485323
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/render_surface_gl.cc
@@ -0,0 +1,262 @@
+/*
+ * 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 implements the OpenGL versions of the render surface resources,
+// as well as the related GAPIGL function implementations.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/gapi_gl.h"
+#include "gpu/command_buffer/service/render_surface_gl.h"
+
+
+namespace command_buffer {
+namespace o3d {
+
+RenderSurfaceGL::RenderSurfaceGL(int width,
+ int height,
+ int mip_level,
+ int side,
+ TextureGL *texture)
+ : width_(width), height_(height), mip_level_(mip_level), texture_(texture) {
+}
+
+RenderSurfaceGL* RenderSurfaceGL::Create(int width,
+ int height,
+ int mip_level,
+ int side,
+ TextureGL *texture) {
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+ DCHECK_GE(mip_level, 0);
+ DCHECK(texture);
+
+ RenderSurfaceGL* render_surface =
+ new RenderSurfaceGL(width, height, mip_level, side, texture);
+ return render_surface;
+}
+
+RenderDepthStencilSurfaceGL::RenderDepthStencilSurfaceGL(
+ int width,
+ int height)
+ : width_(width), height_(height) {
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+
+ // If packed depth stencil is supported, create only one buffer for both
+ // depth and stencil.
+ if (GLEW_EXT_packed_depth_stencil) {
+ glGenRenderbuffersEXT(1, render_buffers_);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffers_[0]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
+ GL_DEPTH24_STENCIL8_EXT,
+ width,
+ height);
+ CHECK_GL_ERROR();
+ render_buffers_[1] = render_buffers_[0];
+ } else {
+ glGenRenderbuffersEXT(2, render_buffers_);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffers_[0]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
+ GL_DEPTH_COMPONENT24,
+ width,
+ height);
+ CHECK_GL_ERROR();
+
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffers_[1]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
+ GL_STENCIL_INDEX8_EXT,
+ width,
+ height);
+ CHECK_GL_ERROR();
+ }
+}
+
+RenderDepthStencilSurfaceGL* RenderDepthStencilSurfaceGL::Create(
+ int width,
+ int height) {
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+
+ return new RenderDepthStencilSurfaceGL(height, width);
+}
+
+// Copies the data from a texture resource.
+parse_error::ParseError GAPIGL::CreateRenderSurface(
+ ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int mip_level,
+ unsigned int side,
+ ResourceId texture_id) {
+ if (id == current_surface_id_) {
+ // This will delete the current surface which would be bad.
+ return parse_error::kParseInvalidArguments;
+ }
+ TextureGL *texture = textures_.Get(texture_id);
+ if (!texture->render_surfaces_enabled()) {
+ return parse_error::kParseInvalidArguments;
+ } else {
+ RenderSurfaceGL* render_surface = RenderSurfaceGL::Create(width,
+ height,
+ mip_level,
+ side,
+ texture);
+ if (render_surface == NULL) {
+ return parse_error::kParseInvalidArguments;
+ }
+ render_surfaces_.Assign(id, render_surface);
+ }
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::DestroyRenderSurface(ResourceId id) {
+ if (id == current_surface_id_) {
+ return parse_error::kParseInvalidArguments;
+ }
+ return render_surfaces_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::CreateDepthSurface(
+ ResourceId id,
+ unsigned int width,
+ unsigned int height) {
+ if (id == current_depth_surface_id_) {
+ // This will delete the current surface which would be bad.
+ return parse_error::kParseInvalidArguments;
+ }
+ RenderDepthStencilSurfaceGL* depth_surface =
+ RenderDepthStencilSurfaceGL::Create(width, height);
+ if (depth_surface == NULL) {
+ return parse_error::kParseInvalidArguments;
+ }
+ depth_surfaces_.Assign(id, depth_surface);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::DestroyDepthSurface(ResourceId id) {
+ if (id == current_depth_surface_id_) {
+ return parse_error::kParseInvalidArguments;
+ }
+ return depth_surfaces_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+void ResetBoundAttachments() {
+#ifdef _DEBUG
+ GLint bound_framebuffer;
+ ::glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &bound_framebuffer);
+ DCHECK(bound_framebuffer != 0);
+#endif
+
+ // Reset the bound attachments to the current framebuffer object.
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT,
+ 0);
+
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ 0);
+
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ 0);
+
+ CHECK_GL_ERROR();
+}
+
+bool BindDepthStencilBuffer(const RenderDepthStencilSurfaceGL* gl_surface) {
+ // Bind both the depth and stencil attachments.
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ gl_surface->depth_buffer());
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ gl_surface->stencil_buffer());
+
+ // Check for errors.
+ GLenum framebuffer_status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (GL_FRAMEBUFFER_COMPLETE_EXT != framebuffer_status) {
+ return false;
+ }
+
+ CHECK_GL_ERROR();
+ return true;
+}
+
+parse_error::ParseError GAPIGL::SetRenderSurface(
+ ResourceId render_surface_id,
+ ResourceId depth_stencil_id) {
+ if (render_surfaces_.Get(render_surface_id) == NULL &&
+ depth_surfaces_.Get(depth_stencil_id) == NULL) {
+ return parse_error::kParseInvalidArguments;
+ }
+
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER, render_surface_framebuffer_);
+ ResetBoundAttachments();
+
+ RenderSurfaceGL* render_surface = render_surfaces_.Get(render_surface_id);
+ RenderDepthStencilSurfaceGL* depth_surface =
+ depth_surfaces_.Get(render_surface_id);
+
+ if (!render_surface->texture()->
+ InstallFrameBufferObjects(render_surface) ||
+ !BindDepthStencilBuffer(depth_surface)) {
+ return parse_error::kParseInvalidArguments;
+ }
+
+ // RenderSurface rendering is performed with an inverted Y, so the front
+ // face winding must be changed to clock-wise. See comments for
+ // UpdateHelperConstant.
+ glFrontFace(GL_CW);
+
+ current_surface_id_ = render_surface_id;
+ current_depth_surface_id_ = depth_stencil_id;
+ return parse_error::kParseNoError;
+}
+
+void GAPIGL::SetBackSurfaces() {
+ // Bind the default context, and restore the default front-face winding.
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ glFrontFace(GL_CCW);
+}
+
+} // namespace o3d
+} // namespace command_buffer
+
diff --git a/o3d/gpu/command_buffer/service/render_surface_gl.h b/o3d/gpu/command_buffer/service/render_surface_gl.h
new file mode 100644
index 0000000..01d6137
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/render_surface_gl.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_GL_H__
+#define GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_GL_H__
+
+// This file contains the definition of the OpenGL versions of
+// render surface-related resource classes.
+
+#include "gpu/command_buffer/service/texture_gl.h"
+#include "gpu/command_buffer/service/resource.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class RenderSurfaceGL : public RenderSurface {
+ public:
+ RenderSurfaceGL(int width,
+ int height,
+ int mip_level,
+ int side,
+ TextureGL *texture);
+ virtual ~RenderSurfaceGL() {}
+
+ static RenderSurfaceGL* Create(int width,
+ int height,
+ int mip_level,
+ int side,
+ TextureGL *texture);
+ TextureGL* texture() {
+ return texture_;
+ }
+
+ int width() {
+ return width_;
+ }
+
+ int height() {
+ return height_;
+ }
+
+ int mip_level() {
+ return mip_level_;
+ }
+
+ int side() {
+ return side_;
+ }
+ private:
+ unsigned int width_;
+ unsigned int height_;
+ unsigned int mip_level_;
+ unsigned int side_;
+ TextureGL* texture_;
+ DISALLOW_COPY_AND_ASSIGN(RenderSurfaceGL);
+};
+
+class RenderDepthStencilSurfaceGL : public RenderDepthStencilSurface {
+ public:
+ RenderDepthStencilSurfaceGL(int width,
+ int height);
+ virtual ~RenderDepthStencilSurfaceGL() {}
+
+ static RenderDepthStencilSurfaceGL* Create(
+ int width,
+ int height);
+
+ GLuint depth_buffer() const {
+ return render_buffers_[0];
+ }
+
+ GLuint stencil_buffer() const {
+ return render_buffers_[1];
+ }
+
+ private:
+ // Handles to the depth and stencil render-buffers, respectively.
+ GLuint render_buffers_[2];
+ unsigned int width_;
+ unsigned int height_;
+ DISALLOW_COPY_AND_ASSIGN(RenderDepthStencilSurfaceGL);
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_WIN_GL_RENDER_SURFACE_GL_H__
+
diff --git a/o3d/gpu/command_buffer/service/resource.cc b/o3d/gpu/command_buffer/service/resource.cc
new file mode 100644
index 0000000..1208d30
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/resource.cc
@@ -0,0 +1,101 @@
+/*
+ * 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 implementation of ResourceMapBase.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/resource.h"
+
+namespace command_buffer {
+
+// Assigns a resource to a resource ID, by setting it at the right location
+// into the list, resizing the list if necessary, and destroying an existing
+// resource if one existed already.
+void ResourceMapBase::Assign(ResourceId id, Resource *resource) {
+ if (id >= resources_.size()) {
+ resources_.resize(id + 1, NULL);
+ } else {
+ Resource *&entry = resources_[id];
+ if (entry) {
+ delete entry;
+ entry = NULL;
+ }
+ }
+ DCHECK(resources_[id] == NULL);
+ resources_[id] = resource;
+}
+
+// Destroys a resource contained in the map, setting its entry to NULL. If
+// necessary, this will trim the list.
+bool ResourceMapBase::Destroy(ResourceId id) {
+ if (id >= resources_.size()) {
+ return false;
+ }
+ Resource *&entry = resources_[id];
+ if (entry) {
+ delete entry;
+ entry = NULL;
+
+ // Removing the last element, we can trim the list.
+ // TODO: this may not be optimal to do every time. Investigate if it
+ // becomes an issue, and add a threshold before we resize.
+ if (id == resources_.size() - 1) {
+ size_t last_valid = resources_.max_size();
+ for (unsigned int i = id; i < resources_.size(); --i) {
+ if (resources_[i]) {
+ last_valid = i;
+ break;
+ }
+ }
+ if (last_valid == resources_.max_size()) {
+ resources_.clear();
+ } else {
+ resources_.resize(last_valid + 1);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+// Goes over all non-NULL entries in the list, destroying them, then clears the
+// list.
+void ResourceMapBase::DestroyAllResources() {
+ for (Container::iterator i = resources_.begin(); i != resources_.end(); ++i) {
+ if (*i) {
+ delete *i;
+ }
+ }
+ resources_.clear();
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/resource.h b/o3d/gpu/command_buffer/service/resource.h
new file mode 100644
index 0000000..20e3038
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/resource.h
@@ -0,0 +1,268 @@
+/*
+ * 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 definition for resource classes and the resource map.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H_
+
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "gpu/command_buffer/common/resource.h"
+
+namespace command_buffer {
+
+// Base class for resources, just providing a common Destroy function.
+class Resource {
+ public:
+ Resource() {}
+ virtual ~Resource() {}
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Resource);
+};
+
+// VertexBuffer class, representing a vertex buffer resource.
+class VertexBuffer: public Resource {
+ public:
+ VertexBuffer(unsigned int size, unsigned int flags)
+ : size_(size),
+ flags_(flags) {}
+ virtual ~VertexBuffer() {}
+
+ // Returns the vertex buffer flags.
+ unsigned int flags() const { return flags_; }
+ // Sets the vertex buffer flags.
+ void set_flags(unsigned int flags) { flags_ = flags; }
+ // Returns the vertex buffer size.
+ unsigned int size() const { return size_; }
+ // Sets the vertex buffer size.
+ void set_size(unsigned int size) { size_ = size; }
+ protected:
+ unsigned int size_;
+ unsigned int flags_;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexBuffer);
+};
+
+// IndexBuffer class, representing an index buffer resource.
+class IndexBuffer: public Resource {
+ public:
+ IndexBuffer(unsigned int size, unsigned int flags)
+ : size_(size),
+ flags_(flags) {}
+ virtual ~IndexBuffer() {}
+
+ // Returns the index buffer flags.
+ unsigned int flags() const { return flags_; }
+ // Sets the index buffer flags.
+ void set_flags(unsigned int flags) { flags_ = flags; }
+ // Returns the index buffer size.
+ unsigned int size() const { return size_; }
+ // Sets the index buffer size.
+ void set_size(unsigned int size) { size_ = size; }
+ protected:
+ unsigned int size_;
+ unsigned int flags_;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexBuffer);
+};
+
+// VertexStruct class, representing a vertex struct resource.
+class VertexStruct: public Resource {
+ public:
+ // The representation of an input data stream.
+ struct Element {
+ ResourceId vertex_buffer;
+ unsigned int offset;
+ unsigned int stride;
+ vertex_struct::Type type;
+ vertex_struct::Semantic semantic;
+ unsigned int semantic_index;
+ };
+
+ explicit VertexStruct(unsigned int count)
+ : count_(count),
+ elements_(new Element[count]) {
+ memset(elements_.get(), 0, count * sizeof(Element)); // NOLINT
+ }
+
+ // Returns the number of inputs in this struct.
+ unsigned int count() const { return count_; }
+ // Returns an element by index.
+ Element &GetElement(unsigned int i) {
+ DCHECK_GT(count_, i);
+ return elements_[i];
+ }
+ protected:
+ unsigned int count_;
+ scoped_array<Element> elements_;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexStruct);
+};
+
+// Effect class, representing an effect.
+class Effect: public Resource {
+ public:
+ Effect() {}
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Effect);
+};
+
+// EffectParam class, representing an effect parameter.
+class EffectParam: public Resource {
+ public:
+ explicit EffectParam(effect_param::DataType data_type)
+ : data_type_(data_type) {
+ }
+
+ // Gets the data type of this parameter.
+ effect_param::DataType data_type() const { return data_type_; }
+ private:
+ effect_param::DataType data_type_;
+ DISALLOW_COPY_AND_ASSIGN(EffectParam);
+};
+
+// Texture class, representing a texture resource.
+class Texture: public Resource {
+ public:
+ Texture(texture::Type type,
+ unsigned int levels,
+ texture::Format format,
+ bool enable_render_surfaces,
+ unsigned int flags)
+ : type_(type),
+ levels_(levels),
+ format_(format),
+ render_surfaces_enabled_(enable_render_surfaces),
+ flags_(flags) {}
+ virtual ~Texture() {}
+
+ // Returns the type of the texture.
+ texture::Type type() const { return type_; }
+ // Returns the texture flags.
+ unsigned int flags() const { return flags_; }
+ // Returns the texture format.
+ texture::Format format() const { return format_; }
+ // Returns whether the texture supports render surfaces
+ bool render_surfaces_enabled() const { return render_surfaces_enabled_; }
+ // Returns the number of mipmap levels in the texture.
+ unsigned int levels() const { return levels_; }
+ private:
+ texture::Type type_;
+ unsigned int levels_;
+ texture::Format format_;
+ bool render_surfaces_enabled_;
+ unsigned int flags_;
+ DISALLOW_COPY_AND_ASSIGN(Texture);
+};
+
+// RenderSurface class, representing a render surface/target
+class RenderSurface: public Resource {
+ public:
+ RenderSurface() {}
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderSurface);
+};
+
+// RenderSurface class, representing a render surface/target
+class RenderDepthStencilSurface: public Resource {
+ public:
+ RenderDepthStencilSurface() {}
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderDepthStencilSurface);
+};
+
+
+// Texture class, representing a sampler resource.
+class Sampler: public Resource {
+ public:
+ Sampler() {}
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Sampler);
+};
+
+// Base of ResourceMap. Contains most of the implementation of ResourceMap, to
+// avoid template bloat.
+class ResourceMapBase {
+ public:
+ ResourceMapBase() : resources_() {}
+ ~ResourceMapBase() {}
+
+ // Assigns a resource to a resource ID. Assigning a resource to an ID that
+ // already has an existing resource will destroy that existing resource. The
+ // map takes ownership of the resource.
+ void Assign(ResourceId id, Resource* resource);
+ // Destroys a resource.
+ bool Destroy(ResourceId id);
+ // Destroy all resources.
+ void DestroyAllResources();
+ // Gets a resource by ID.
+ Resource *Get(ResourceId id) {
+ return (id < resources_.size()) ? resources_[id] : NULL;
+ }
+ private:
+ typedef std::vector<Resource *> Container;
+ Container resources_;
+};
+
+// Resource Map class, allowing resource ID <-> Resource association. This is a
+// dense map, optimized for retrieval (O(1)).
+template<class T> class ResourceMap {
+ public:
+ ResourceMap() : container_() {}
+ ~ResourceMap() {}
+
+ // Assigns a resource to a resource ID. Assigning a resource to an ID that
+ // already has an existing resource will destroy that existing resource. The
+ // map takes ownership of the resource.
+ void Assign(ResourceId id, T* resource) {
+ container_.Assign(id, resource);
+ }
+ // Destroys a resource.
+ bool Destroy(ResourceId id) {
+ return container_.Destroy(id);
+ }
+ // Destroy all resources.
+ void DestroyAllResources() {
+ return container_.DestroyAllResources();
+ }
+ // Gets a resource by ID.
+ T *Get(ResourceId id) {
+ return static_cast<T*>(container_.Get(id));
+ }
+ private:
+ ResourceMapBase container_;
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H_
diff --git a/o3d/gpu/command_buffer/service/resource_test.cc b/o3d/gpu/command_buffer/service/resource_test.cc
new file mode 100644
index 0000000..3e95dfb
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/resource_test.cc
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+
+// Tests for the ResourceMap.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "tests/common/win/testing_common.h"
+#include "gpu/command_buffer/service/resource.h"
+
+namespace command_buffer {
+
+// Mock resource implementation that checks for leaks.
+class ResourceMock : public Resource {
+ public:
+ ResourceMock() : Resource() {
+ ++instance_count_;
+ }
+ virtual ~ResourceMock() {
+ --instance_count_;
+ }
+
+ // Returns the instance count. The instance count is increased in the
+ // constructor and decreased in the destructor, to track leaks. The reason is
+ // that we can't mock the destructor, though we want to make sure the mock is
+ // destroyed.
+ static int instance_count() { return instance_count_; }
+ private:
+ static int instance_count_;
+ DISALLOW_COPY_AND_ASSIGN(ResourceMock);
+};
+int ResourceMock::instance_count_ = 0;
+
+// Test fixture for ResourceMap test. Creates a ResourceMap using a mock
+// Resource, and checks for ResourceMock leaks.
+class ResourceMapTest : public testing::Test {
+ protected:
+ typedef ResourceMap<ResourceMock> Map;
+ virtual void SetUp() {
+ instance_count_ = ResourceMock::instance_count();
+ map_.reset(new Map());
+ }
+ virtual void TearDown() {
+ CheckLeaks();
+ }
+
+ // Makes sure we didn't leak any ResourceMock object.
+ void CheckLeaks() {
+ EXPECT_EQ(instance_count_, ResourceMock::instance_count());
+ }
+
+ Map *map() const { return map_.get(); }
+ private:
+ int instance_count_;
+ scoped_ptr<Map> map_;
+};
+
+TEST_F(ResourceMapTest, TestMap) {
+ // check that initial mapping is empty.
+ EXPECT_EQ(NULL, map()->Get(0));
+ EXPECT_EQ(NULL, map()->Get(1));
+ EXPECT_EQ(NULL, map()->Get(392));
+
+ // create a new resource, assign it to an ID.
+ ResourceMock *resource = new ResourceMock();
+ map()->Assign(123, resource);
+ EXPECT_EQ(resource, map()->Get(123));
+
+ // Destroy the resource, making sure the object is deleted.
+ EXPECT_EQ(true, map()->Destroy(123));
+ EXPECT_EQ(false, map()->Destroy(123)); // destroying again should fail.
+ resource = NULL;
+ CheckLeaks();
+
+ // create a new resource, add it to the map, and make sure it gets deleted
+ // when we assign a new resource to that ID.
+ resource = new ResourceMock();
+ map()->Assign(1, resource);
+ resource = new ResourceMock();
+ map()->Assign(1, resource);
+ EXPECT_EQ(resource, map()->Get(1)); // check that we have the new resource.
+ EXPECT_EQ(true, map()->Destroy(1));
+ CheckLeaks();
+
+ // Adds 3 resources, then call DestroyAllResources().
+ resource = new ResourceMock();
+ map()->Assign(1, resource);
+ resource = new ResourceMock();
+ map()->Assign(2, resource);
+ resource = new ResourceMock();
+ map()->Assign(3, resource);
+ map()->DestroyAllResources();
+ EXPECT_EQ(NULL, map()->Get(1));
+ EXPECT_EQ(NULL, map()->Get(2));
+ EXPECT_EQ(NULL, map()->Get(3));
+ CheckLeaks();
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/sampler_d3d9.cc b/o3d/gpu/command_buffer/service/sampler_d3d9.cc
new file mode 100644
index 0000000..e4c3b26
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/sampler_d3d9.cc
@@ -0,0 +1,199 @@
+/*
+ * 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 implementation of the SamplerD3D9 class.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/gapi_d3d9.h"
+#include "gpu/command_buffer/service/sampler_d3d9.h"
+#include "gpu/command_buffer/service/texture_d3d9.h"
+
+namespace command_buffer {
+namespace o3d {
+
+namespace {
+
+// Converts an addressing mode to corresponding D3D values.
+D3DTEXTUREADDRESS AddressModeToD3D(sampler::AddressingMode mode) {
+ switch (mode) {
+ case sampler::kWrap:
+ return D3DTADDRESS_WRAP;
+ case sampler::kMirrorRepeat:
+ return D3DTADDRESS_MIRROR;
+ case sampler::kClampToEdge:
+ return D3DTADDRESS_CLAMP;
+ case sampler::kClampToBorder:
+ return D3DTADDRESS_BORDER;
+ }
+ DLOG(FATAL) << "Not reached";
+ return D3DTADDRESS_WRAP;
+}
+
+// Converts a filtering mode to corresponding D3D values.
+D3DTEXTUREFILTERTYPE FilteringModeToD3D(sampler::FilteringMode mode) {
+ switch (mode) {
+ case sampler::kNone:
+ return D3DTEXF_NONE;
+ case sampler::kPoint:
+ return D3DTEXF_POINT;
+ case sampler::kLinear:
+ return D3DTEXF_LINEAR;
+ }
+ DLOG(FATAL) << "Not reached";
+ return D3DTEXF_POINT;
+}
+
+} // anonymous namespace
+
+SamplerD3D9::SamplerD3D9()
+ : texture_id_(kInvalidResource) {
+ SetStates(sampler::kClampToEdge,
+ sampler::kClampToEdge,
+ sampler::kClampToEdge,
+ sampler::kLinear,
+ sampler::kLinear,
+ sampler::kPoint,
+ 1);
+ RGBA black = {0, 0, 0, 1};
+ SetBorderColor(black);
+}
+
+bool SamplerD3D9::ApplyStates(GAPID3D9 *gapi, unsigned int unit) const {
+ DCHECK(gapi);
+ TextureD3D9 *texture = gapi->GetTexture(texture_id_);
+ if (!texture) {
+ return false;
+ }
+ IDirect3DDevice9 *d3d_device = gapi->d3d_device();
+ HR(d3d_device->SetTexture(unit, texture->d3d_base_texture()));
+ HR(d3d_device->SetSamplerState(unit, D3DSAMP_ADDRESSU, d3d_address_u_));
+ HR(d3d_device->SetSamplerState(unit, D3DSAMP_ADDRESSV, d3d_address_v_));
+ HR(d3d_device->SetSamplerState(unit, D3DSAMP_ADDRESSW, d3d_address_w_));
+ HR(d3d_device->SetSamplerState(unit, D3DSAMP_MAGFILTER, d3d_mag_filter_));
+ HR(d3d_device->SetSamplerState(unit, D3DSAMP_MINFILTER, d3d_min_filter_));
+ HR(d3d_device->SetSamplerState(unit, D3DSAMP_MIPFILTER, d3d_mip_filter_));
+ HR(d3d_device->SetSamplerState(unit, D3DSAMP_MAXANISOTROPY,
+ d3d_max_anisotropy_));
+ HR(d3d_device->SetSamplerState(unit, D3DSAMP_BORDERCOLOR, d3d_border_color_));
+ return true;
+}
+
+void SamplerD3D9::SetStates(sampler::AddressingMode addressing_u,
+ sampler::AddressingMode addressing_v,
+ sampler::AddressingMode addressing_w,
+ sampler::FilteringMode mag_filter,
+ sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter,
+ unsigned int max_anisotropy) {
+ // These are validated in GAPIDecoder.cc
+ DCHECK_NE(mag_filter, sampler::kNone);
+ DCHECK_NE(min_filter, sampler::kNone);
+ DCHECK_GT(max_anisotropy, 0U);
+ d3d_address_u_ = AddressModeToD3D(addressing_u);
+ d3d_address_v_ = AddressModeToD3D(addressing_v);
+ d3d_address_w_ = AddressModeToD3D(addressing_w);
+ d3d_mag_filter_ = FilteringModeToD3D(mag_filter);
+ d3d_min_filter_ = FilteringModeToD3D(min_filter);
+ d3d_mip_filter_ = FilteringModeToD3D(mip_filter);
+ if (max_anisotropy > 1) {
+ d3d_mag_filter_ = D3DTEXF_ANISOTROPIC;
+ d3d_min_filter_ = D3DTEXF_ANISOTROPIC;
+ }
+ d3d_max_anisotropy_ = max_anisotropy;
+}
+
+void SamplerD3D9::SetBorderColor(const RGBA &color) {
+ d3d_border_color_ = RGBAToD3DCOLOR(color);
+}
+
+parse_error::ParseError GAPID3D9::CreateSampler(
+ ResourceId id) {
+ // Dirty effect, because this sampler id may be used
+ DirtyEffect();
+ samplers_.Assign(id, new SamplerD3D9());
+ return parse_error::kParseNoError;
+}
+
+// Destroys the Sampler resource.
+parse_error::ParseError GAPID3D9::DestroySampler(ResourceId id) {
+ // Dirty effect, because this sampler id may be used
+ DirtyEffect();
+ return samplers_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPID3D9::SetSamplerStates(
+ ResourceId id,
+ sampler::AddressingMode addressing_u,
+ sampler::AddressingMode addressing_v,
+ sampler::AddressingMode addressing_w,
+ sampler::FilteringMode mag_filter,
+ sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter,
+ unsigned int max_anisotropy) {
+ SamplerD3D9 *sampler = samplers_.Get(id);
+ if (!sampler)
+ return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this sampler id may be used
+ DirtyEffect();
+ sampler->SetStates(addressing_u, addressing_v, addressing_w,
+ mag_filter, min_filter, mip_filter, max_anisotropy);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::SetSamplerBorderColor(
+ ResourceId id,
+ const RGBA &color) {
+ SamplerD3D9 *sampler = samplers_.Get(id);
+ if (!sampler)
+ return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this sampler id may be used
+ DirtyEffect();
+ sampler->SetBorderColor(color);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::SetSamplerTexture(
+ ResourceId id,
+ ResourceId texture_id) {
+ SamplerD3D9 *sampler = samplers_.Get(id);
+ if (!sampler)
+ return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this sampler id may be used
+ DirtyEffect();
+ sampler->SetTexture(texture_id);
+ return parse_error::kParseNoError;
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/sampler_d3d9.h b/o3d/gpu/command_buffer/service/sampler_d3d9.h
new file mode 100644
index 0000000..55a6e9a
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/sampler_d3d9.h
@@ -0,0 +1,85 @@
+/*
+ * 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 definition of the SamplerD3D9 class, implementing
+// samplers for D3D.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SAMPLER_D3D9_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SAMPLER_D3D9_H_
+
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/d3d9_utils.h"
+#include "gpu/command_buffer/service/resource.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class GAPID3D9;
+
+// D3D9 version of Sampler.
+class SamplerD3D9 : public Sampler {
+ public:
+ SamplerD3D9();
+
+ // Applies sampler states to D3D.
+ bool ApplyStates(GAPID3D9 *gapi, unsigned int unit) const;
+
+ // Sets sampler states.
+ void SetStates(sampler::AddressingMode addressing_u,
+ sampler::AddressingMode addressing_v,
+ sampler::AddressingMode addressing_w,
+ sampler::FilteringMode mag_filter,
+ sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter,
+ unsigned int max_anisotropy);
+
+ // Sets the border color states.
+ void SetBorderColor(const RGBA &color);
+
+ // Sets the texture.
+ void SetTexture(ResourceId texture) { texture_id_ = texture; }
+ private:
+ D3DTEXTUREADDRESS d3d_address_u_;
+ D3DTEXTUREADDRESS d3d_address_v_;
+ D3DTEXTUREADDRESS d3d_address_w_;
+ D3DTEXTUREFILTERTYPE d3d_mag_filter_;
+ D3DTEXTUREFILTERTYPE d3d_min_filter_;
+ D3DTEXTUREFILTERTYPE d3d_mip_filter_;
+ DWORD d3d_max_anisotropy_;
+ D3DCOLOR d3d_border_color_;
+ ResourceId texture_id_;
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_SAMPLER_D3D9_H_
diff --git a/o3d/gpu/command_buffer/service/sampler_gl.cc b/o3d/gpu/command_buffer/service/sampler_gl.cc
new file mode 100644
index 0000000..32335e1
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/sampler_gl.cc
@@ -0,0 +1,238 @@
+/*
+ * 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 implements the sampler-related GAPI functions on GL.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/gapi_gl.h"
+#include "gpu/command_buffer/service/sampler_gl.h"
+
+namespace command_buffer {
+namespace o3d {
+
+namespace {
+
+// Gets the GL enum corresponding to an addressing mode.
+GLenum GLAddressMode(sampler::AddressingMode o3d_mode) {
+ switch (o3d_mode) {
+ case sampler::kWrap:
+ return GL_REPEAT;
+ case sampler::kMirrorRepeat:
+ return GL_MIRRORED_REPEAT;
+ case sampler::kClampToEdge:
+ return GL_CLAMP_TO_EDGE;
+ case sampler::kClampToBorder:
+ return GL_CLAMP_TO_BORDER;
+ default:
+ DLOG(FATAL) << "Not Reached";
+ return GL_REPEAT;
+ }
+}
+
+// Gets the GL enum for the minification filter based on the command buffer min
+// and mip filtering modes.
+GLenum GLMinFilter(sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter) {
+ switch (min_filter) {
+ case sampler::kPoint:
+ if (mip_filter == sampler::kNone)
+ return GL_NEAREST;
+ else if (mip_filter == sampler::kPoint)
+ return GL_NEAREST_MIPMAP_NEAREST;
+ else if (mip_filter == sampler::kLinear)
+ return GL_NEAREST_MIPMAP_LINEAR;
+ case sampler::kLinear:
+ if (mip_filter == sampler::kNone)
+ return GL_LINEAR;
+ else if (mip_filter == sampler::kPoint)
+ return GL_LINEAR_MIPMAP_NEAREST;
+ else if (mip_filter == sampler::kLinear)
+ return GL_LINEAR_MIPMAP_LINEAR;
+ default:
+ DLOG(FATAL) << "Not Reached";
+ return GL_LINEAR_MIPMAP_NEAREST;
+ }
+}
+
+// Gets the GL enum for the magnification filter based on the command buffer mag
+// filtering mode.
+GLenum GLMagFilter(sampler::FilteringMode mag_filter) {
+ switch (mag_filter) {
+ case sampler::kPoint:
+ return GL_NEAREST;
+ case sampler::kLinear:
+ return GL_LINEAR;
+ default:
+ DLOG(FATAL) << "Not Reached";
+ return GL_LINEAR;
+ }
+}
+
+// Gets the GL enum representing the GL target based on the texture type.
+GLenum GLTextureTarget(texture::Type type) {
+ switch (type) {
+ case texture::kTexture2d:
+ return GL_TEXTURE_2D;
+ case texture::kTexture3d:
+ return GL_TEXTURE_3D;
+ case texture::kTextureCube:
+ return GL_TEXTURE_CUBE_MAP;
+ default:
+ DLOG(FATAL) << "Not Reached";
+ return GL_TEXTURE_2D;
+ }
+}
+
+} // anonymous namespace
+
+SamplerGL::SamplerGL()
+ : texture_id_(kInvalidResource),
+ gl_texture_(0) {
+ SetStates(sampler::kClampToEdge,
+ sampler::kClampToEdge,
+ sampler::kClampToEdge,
+ sampler::kLinear,
+ sampler::kLinear,
+ sampler::kPoint,
+ 1);
+ RGBA black = {0, 0, 0, 1};
+ SetBorderColor(black);
+}
+
+bool SamplerGL::ApplyStates(GAPIGL *gapi) {
+ DCHECK(gapi);
+ TextureGL *texture = gapi->GetTexture(texture_id_);
+ if (!texture) {
+ gl_texture_ = 0;
+ return false;
+ }
+ GLenum target = GLTextureTarget(texture->type());
+ gl_texture_ = texture->gl_texture();
+ glBindTexture(target, gl_texture_);
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, gl_wrap_s_);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, gl_wrap_t_);
+ glTexParameteri(target, GL_TEXTURE_WRAP_R, gl_wrap_r_);
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, gl_min_filter_);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, gl_mag_filter_);
+ glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy_);
+ glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, gl_border_color_);
+ return true;
+}
+
+void SamplerGL::SetStates(sampler::AddressingMode addressing_u,
+ sampler::AddressingMode addressing_v,
+ sampler::AddressingMode addressing_w,
+ sampler::FilteringMode mag_filter,
+ sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter,
+ unsigned int max_anisotropy) {
+ // These are validated in GAPIDecoder.cc
+ DCHECK_NE(mag_filter, sampler::kNone);
+ DCHECK_NE(min_filter, sampler::kNone);
+ DCHECK_GT(max_anisotropy, 0U);
+ gl_wrap_s_ = GLAddressMode(addressing_u);
+ gl_wrap_t_ = GLAddressMode(addressing_v);
+ gl_wrap_r_ = GLAddressMode(addressing_w);
+ gl_mag_filter_ = GLMagFilter(mag_filter);
+ gl_min_filter_ = GLMinFilter(min_filter, mip_filter);
+ gl_max_anisotropy_ = max_anisotropy;
+}
+
+void SamplerGL::SetBorderColor(const RGBA &color) {
+ gl_border_color_[0] = color.red;
+ gl_border_color_[1] = color.green;
+ gl_border_color_[2] = color.blue;
+ gl_border_color_[3] = color.alpha;
+}
+
+parse_error::ParseError GAPIGL::CreateSampler(
+ ResourceId id) {
+ // Dirty effect, because this sampler id may be used.
+ DirtyEffect();
+ samplers_.Assign(id, new SamplerGL());
+ return parse_error::kParseNoError;
+}
+
+// Destroys the Sampler resource.
+parse_error::ParseError GAPIGL::DestroySampler(ResourceId id) {
+ // Dirty effect, because this sampler id may be used.
+ DirtyEffect();
+ return samplers_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPIGL::SetSamplerStates(
+ ResourceId id,
+ sampler::AddressingMode addressing_u,
+ sampler::AddressingMode addressing_v,
+ sampler::AddressingMode addressing_w,
+ sampler::FilteringMode mag_filter,
+ sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter,
+ unsigned int max_anisotropy) {
+ SamplerGL *sampler = samplers_.Get(id);
+ if (!sampler)
+ return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this sampler id may be used.
+ DirtyEffect();
+ sampler->SetStates(addressing_u, addressing_v, addressing_w,
+ mag_filter, min_filter, mip_filter, max_anisotropy);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::SetSamplerBorderColor(
+ ResourceId id,
+ const RGBA &color) {
+ SamplerGL *sampler = samplers_.Get(id);
+ if (!sampler)
+ return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this sampler id may be used.
+ DirtyEffect();
+ sampler->SetBorderColor(color);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPIGL::SetSamplerTexture(
+ ResourceId id,
+ ResourceId texture_id) {
+ SamplerGL *sampler = samplers_.Get(id);
+ if (!sampler)
+ return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this sampler id may be used.
+ DirtyEffect();
+ sampler->SetTexture(texture_id);
+ return parse_error::kParseNoError;
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/sampler_gl.h b/o3d/gpu/command_buffer/service/sampler_gl.h
new file mode 100644
index 0000000..8809ea5
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/sampler_gl.h
@@ -0,0 +1,87 @@
+/*
+ * 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 declares the SamplerGL class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SAMPLER_GL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SAMPLER_GL_H_
+
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/resource.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class GAPIGL;
+
+// GL version of Sampler.
+class SamplerGL : public Sampler {
+ public:
+ SamplerGL();
+
+ // Applies sampler states to GL.
+ bool ApplyStates(GAPIGL *gapi);
+
+ // Sets sampler states.
+ void SetStates(sampler::AddressingMode addressing_u,
+ sampler::AddressingMode addressing_v,
+ sampler::AddressingMode addressing_w,
+ sampler::FilteringMode mag_filter,
+ sampler::FilteringMode min_filter,
+ sampler::FilteringMode mip_filter,
+ unsigned int max_anisotropy);
+
+ // Sets the border color states.
+ void SetBorderColor(const o3d::RGBA &color);
+
+ // Sets the texture.
+ void SetTexture(ResourceId texture) { texture_id_ = texture; }
+
+ GLuint gl_texture() const { return gl_texture_; }
+
+ private:
+ GLenum gl_wrap_s_;
+ GLenum gl_wrap_t_;
+ GLenum gl_wrap_r_;
+ GLenum gl_mag_filter_;
+ GLenum gl_min_filter_;
+ GLuint gl_max_anisotropy_;
+ GLfloat gl_border_color_[4];
+ GLuint gl_texture_;
+ ResourceId texture_id_;
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_SAMPLER_GL_H_
diff --git a/o3d/gpu/command_buffer/service/states_d3d9.cc b/o3d/gpu/command_buffer/service/states_d3d9.cc
new file mode 100644
index 0000000..7abcada
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/states_d3d9.cc
@@ -0,0 +1,355 @@
+/*
+ * 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 implementation of the state-related GAPID3D9
+// functions.
+
+#include "gpu/command_buffer/service/precompile.h"
+
+#include <algorithm>
+
+#include "gpu/command_buffer/common/o3d_cmd_format.h"
+#include "gpu/command_buffer/service/gapi_d3d9.h"
+
+namespace command_buffer {
+namespace o3d {
+
+namespace {
+
+// Checks that a command_buffer enum matches a D3D enum so that it can be
+// converted quickly.
+#define CHECK_CB_ENUM_MATCHES_D3D(CB_ENUM, D3D_ENUM) \
+ COMPILE_ASSERT(CB_ENUM + 1 == D3D_ENUM, \
+ CB_ENUM ## _plus_1_not_ ## D3D_ENUM)
+
+// Converts values from the PolygonMode enum to corresponding D3D values
+inline D3DFILLMODE PolygonModeToD3D(PolygonMode fill_mode) {
+ DCHECK_LT(fill_mode, kNumPolygonMode);
+
+ // Check that all acceptable values translate to D3D values by adding 1.
+
+ CHECK_CB_ENUM_MATCHES_D3D(kPolygonModePoints, D3DFILL_POINT);
+ CHECK_CB_ENUM_MATCHES_D3D(kPolygonModeLines, D3DFILL_WIREFRAME);
+ CHECK_CB_ENUM_MATCHES_D3D(kPolygonModeFill, D3DFILL_SOLID);
+ return static_cast<D3DFILLMODE>(fill_mode + 1);
+}
+
+// Converts values from the FaceCullMode enum to corresponding D3D values
+inline D3DCULL FaceCullModeToD3D(FaceCullMode cull_mode) {
+ DCHECK_LT(cull_mode, kNumFaceCullMode);
+
+ // Check that all acceptable values translate to D3D values by adding 1.
+ CHECK_CB_ENUM_MATCHES_D3D(kCullNone, D3DCULL_NONE);
+ CHECK_CB_ENUM_MATCHES_D3D(kCullCW, D3DCULL_CW);
+ CHECK_CB_ENUM_MATCHES_D3D(kCullCCW, D3DCULL_CCW);
+ return static_cast<D3DCULL>(cull_mode + 1);
+}
+
+// Converts values from the Comparison enum to corresponding D3D values
+inline D3DCMPFUNC ComparisonToD3D(Comparison comp) {
+ DCHECK_LT(comp, kNumComparison);
+
+ // Check that all acceptable values translate to D3D values by adding 1.
+ CHECK_CB_ENUM_MATCHES_D3D(kNever, D3DCMP_NEVER);
+ CHECK_CB_ENUM_MATCHES_D3D(kLess, D3DCMP_LESS);
+ CHECK_CB_ENUM_MATCHES_D3D(kEqual, D3DCMP_EQUAL);
+ CHECK_CB_ENUM_MATCHES_D3D(kLEqual, D3DCMP_LESSEQUAL);
+ CHECK_CB_ENUM_MATCHES_D3D(kGreater, D3DCMP_GREATER);
+ CHECK_CB_ENUM_MATCHES_D3D(kNotEqual, D3DCMP_NOTEQUAL);
+ CHECK_CB_ENUM_MATCHES_D3D(kGEqual, D3DCMP_GREATEREQUAL);
+ CHECK_CB_ENUM_MATCHES_D3D(kAlways, D3DCMP_ALWAYS);
+ return static_cast<D3DCMPFUNC>(comp + 1);
+}
+
+// Converts values from the StencilOp enum to corresponding D3D values
+inline D3DSTENCILOP StencilOpToD3D(StencilOp stencil_op) {
+ DCHECK_LT(stencil_op, kNumStencilOp);
+
+ // Check that all acceptable values translate to D3D values by adding 1.
+ CHECK_CB_ENUM_MATCHES_D3D(kKeep, D3DSTENCILOP_KEEP);
+ CHECK_CB_ENUM_MATCHES_D3D(kZero, D3DSTENCILOP_ZERO);
+ CHECK_CB_ENUM_MATCHES_D3D(kReplace, D3DSTENCILOP_REPLACE);
+ CHECK_CB_ENUM_MATCHES_D3D(kIncNoWrap, D3DSTENCILOP_INCRSAT);
+ CHECK_CB_ENUM_MATCHES_D3D(kDecNoWrap, D3DSTENCILOP_DECRSAT);
+ CHECK_CB_ENUM_MATCHES_D3D(kInvert, D3DSTENCILOP_INVERT);
+ CHECK_CB_ENUM_MATCHES_D3D(kIncWrap, D3DSTENCILOP_INCR);
+ CHECK_CB_ENUM_MATCHES_D3D(kDecWrap, D3DSTENCILOP_DECR);
+ return static_cast<D3DSTENCILOP>(stencil_op + 1);
+}
+
+// Converts values from the BlendEq enum to corresponding D3D values
+inline D3DBLENDOP BlendEqToD3D(BlendEq blend_eq) {
+ DCHECK_LT(blend_eq, kNumBlendEq);
+ // Check that all acceptable values translate to D3D values by adding 1.
+ CHECK_CB_ENUM_MATCHES_D3D(kBlendEqAdd, D3DBLENDOP_ADD);
+ CHECK_CB_ENUM_MATCHES_D3D(kBlendEqSub, D3DBLENDOP_SUBTRACT);
+ CHECK_CB_ENUM_MATCHES_D3D(kBlendEqRevSub, D3DBLENDOP_REVSUBTRACT);
+ CHECK_CB_ENUM_MATCHES_D3D(kBlendEqMin, D3DBLENDOP_MIN);
+ CHECK_CB_ENUM_MATCHES_D3D(kBlendEqMax, D3DBLENDOP_MAX);
+ return static_cast<D3DBLENDOP>(blend_eq + 1);
+}
+
+// Converts values from the BlendFunc enum to corresponding D3D values
+D3DBLEND BlendFuncToD3D(BlendFunc blend_func) {
+ // The D3DBLEND enum values don't map 1-to-1 to BlendFunc, so we use a switch
+ // here.
+ switch (blend_func) {
+ case kBlendFuncZero:
+ return D3DBLEND_ZERO;
+ case kBlendFuncOne:
+ return D3DBLEND_ONE;
+ case kBlendFuncSrcColor:
+ return D3DBLEND_SRCCOLOR;
+ case kBlendFuncInvSrcColor:
+ return D3DBLEND_INVSRCCOLOR;
+ case kBlendFuncSrcAlpha:
+ return D3DBLEND_SRCALPHA;
+ case kBlendFuncInvSrcAlpha:
+ return D3DBLEND_INVSRCALPHA;
+ case kBlendFuncDstAlpha:
+ return D3DBLEND_DESTALPHA;
+ case kBlendFuncInvDstAlpha:
+ return D3DBLEND_INVDESTALPHA;
+ case kBlendFuncDstColor:
+ return D3DBLEND_DESTCOLOR;
+ case kBlendFuncInvDstColor:
+ return D3DBLEND_INVDESTCOLOR;
+ case kBlendFuncSrcAlphaSaturate:
+ return D3DBLEND_SRCALPHASAT;
+ case kBlendFuncBlendColor:
+ return D3DBLEND_BLENDFACTOR;
+ case kBlendFuncInvBlendColor:
+ return D3DBLEND_INVBLENDFACTOR;
+ default:
+ DLOG(FATAL) << "Invalid BlendFunc";
+ return D3DBLEND_ZERO;
+ }
+}
+
+// Decodes stencil test function and operations from the bitfield.
+void DecodeStencilFuncOps(Uint32 params,
+ Comparison *func,
+ StencilOp *pass,
+ StencilOp *fail,
+ StencilOp *zfail) {
+ // Sanity check. The value has already been tested in
+ // GAPIDecoder::DecodeSetStencilTest in gapi_decoder.cc.
+ DCHECK_EQ(SetStencilTest::Unused1::Get(params), 0);
+ // Check that the bitmask get cannot generate values outside of the allowed
+ // range.
+ COMPILE_ASSERT(SetStencilTest::CWFunc::kMask <
+ kNumComparison,
+ set_stencil_test_CWFunc_may_produce_invalid_values);
+ *func = static_cast<Comparison>(SetStencilTest::CWFunc::Get(params));
+
+ COMPILE_ASSERT(SetStencilTest::CWPassOp::kMask <
+ kNumStencilOp,
+ set_stencil_test_CWPassOp_may_produce_invalid_values);
+ *pass = static_cast<StencilOp>(SetStencilTest::CWPassOp::Get(params));
+
+ COMPILE_ASSERT(SetStencilTest::CWFailOp::kMask <
+ kNumStencilOp,
+ set_stencil_test_CWFailOp_may_produce_invalid_values);
+ *fail = static_cast<StencilOp>(SetStencilTest::CWFailOp::Get(params));
+
+ COMPILE_ASSERT(SetStencilTest::CWZFailOp::kMask <
+ kNumStencilOp,
+ set_stencil_test_CWZFailOp_may_produce_invalid_values);
+ *zfail = static_cast<StencilOp>(SetStencilTest::CWZFailOp::Get(params));
+}
+
+} // anonymous namespace
+
+void GAPID3D9::SetScissor(bool enable,
+ unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height) {
+ HR(d3d_device_->SetRenderState(D3DRS_SCISSORTESTENABLE,
+ enable ? TRUE : FALSE));
+ RECT rect = {x, y, x + width, y + height};
+ HR(d3d_device_->SetScissorRect(&rect));
+}
+
+void GAPID3D9::SetPolygonOffset(float slope_factor, float units) {
+ HR(d3d_device_->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS,
+ FloatAsDWORD(slope_factor)));
+ // TODO: this value is hard-coded currently because we only create a
+ // 24-bit depth buffer. Move this to a member of GAPID3D9 if this changes.
+ const float kUnitScale = 1.f / (1 << 24);
+ HR(d3d_device_->SetRenderState(D3DRS_DEPTHBIAS,
+ FloatAsDWORD(units * kUnitScale)));
+}
+
+void GAPID3D9::SetPointLineRaster(bool line_smooth,
+ bool point_sprite,
+ float point_size) {
+ HR(d3d_device_->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE,
+ line_smooth ? TRUE : FALSE));
+ HR(d3d_device_->SetRenderState(D3DRS_POINTSPRITEENABLE,
+ point_sprite ? TRUE : FALSE));
+ HR(d3d_device_->SetRenderState(D3DRS_POINTSIZE,
+ FloatAsDWORD(point_size)));
+}
+
+void GAPID3D9::SetPolygonRaster(PolygonMode fill_mode,
+ FaceCullMode cull_mode) {
+ HR(d3d_device_->SetRenderState(D3DRS_FILLMODE, PolygonModeToD3D(fill_mode)));
+ HR(d3d_device_->SetRenderState(D3DRS_CULLMODE, FaceCullModeToD3D(cull_mode)));
+}
+
+void GAPID3D9::SetAlphaTest(bool enable,
+ float reference,
+ Comparison comp) {
+ HR(d3d_device_->SetRenderState(D3DRS_ALPHABLENDENABLE,
+ enable ? TRUE : FALSE));
+ HR(d3d_device_->SetRenderState(D3DRS_ALPHAREF,
+ FloatToClampedByte(reference)));
+ HR(d3d_device_->SetRenderState(D3DRS_ALPHAFUNC, ComparisonToD3D(comp)));
+}
+
+void GAPID3D9::SetDepthTest(bool enable,
+ bool write_enable,
+ Comparison comp) {
+ HR(d3d_device_->SetRenderState(D3DRS_ZENABLE,
+ enable ? TRUE : FALSE));
+ HR(d3d_device_->SetRenderState(D3DRS_ZWRITEENABLE,
+ write_enable ? TRUE : FALSE));
+ HR(d3d_device_->SetRenderState(D3DRS_ZFUNC, ComparisonToD3D(comp)));
+}
+
+void GAPID3D9::SetStencilTest(bool enable,
+ bool separate_ccw,
+ unsigned int write_mask,
+ unsigned int compare_mask,
+ unsigned int ref,
+ Uint32 func_ops) {
+ HR(d3d_device_->SetRenderState(D3DRS_STENCILENABLE,
+ enable ? TRUE : FALSE));
+ HR(d3d_device_->SetRenderState(D3DRS_STENCILWRITEMASK, write_mask));
+ HR(d3d_device_->SetRenderState(D3DRS_STENCILMASK, compare_mask));
+ HR(d3d_device_->SetRenderState(D3DRS_STENCILREF, ref));
+
+ Comparison func;
+ StencilOp pass;
+ StencilOp fail;
+ StencilOp zfail;
+ DecodeStencilFuncOps(func_ops, &func, &pass, &fail, &zfail);
+ HR(d3d_device_->SetRenderState(D3DRS_STENCILFUNC,
+ ComparisonToD3D(func)));
+ HR(d3d_device_->SetRenderState(D3DRS_STENCILPASS,
+ StencilOpToD3D(pass)));
+ HR(d3d_device_->SetRenderState(D3DRS_STENCILFAIL,
+ StencilOpToD3D(fail)));
+ HR(d3d_device_->SetRenderState(D3DRS_STENCILZFAIL,
+ StencilOpToD3D(zfail)));
+
+ if (separate_ccw) {
+ HR(d3d_device_->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE));
+ // Check that the definition of the counter-clockwise func/ops match the
+ // clockwise ones, just shifted by 16 bits, so that we can use
+ // DecodeStencilFuncOps on both of them.
+#define CHECK_CCW_MATCHES_CW(FIELD) \
+ COMPILE_ASSERT(SetStencilTest::CW ## FIELD::kLength == \
+ SetStencilTest::CCW ## FIELD::kLength, \
+ CCW ## FIELD ## _length_does_not_match_ ## CW ## FIELD); \
+ COMPILE_ASSERT(SetStencilTest::CW ## FIELD::kShift + 16 == \
+ SetStencilTest::CCW ## FIELD::kShift, \
+ CCW ## FIELD ## _shift_does_not_match_ ## CW ## FIELD)
+ CHECK_CCW_MATCHES_CW(Func);
+ CHECK_CCW_MATCHES_CW(PassOp);
+ CHECK_CCW_MATCHES_CW(FailOp);
+ CHECK_CCW_MATCHES_CW(ZFailOp);
+#undef CHECK_CCW_MATCHES_CW
+ // Extract upper 16 bits.
+ Uint32 ccw_func_ops = BitField<16, 16>::Get(func_ops);
+
+ DecodeStencilFuncOps(ccw_func_ops, &func, &pass, &fail, &zfail);
+ HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILFUNC,
+ ComparisonToD3D(func)));
+ HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILPASS,
+ StencilOpToD3D(pass)));
+ HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILFAIL,
+ StencilOpToD3D(fail)));
+ HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILZFAIL,
+ StencilOpToD3D(zfail)));
+ } else {
+ HR(d3d_device_->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE));
+ }
+}
+
+void GAPID3D9::SetColorWrite(bool red,
+ bool green,
+ bool blue,
+ bool alpha,
+ bool dither) {
+ Uint32 mask = red ? D3DCOLORWRITEENABLE_RED : 0;
+ mask |= green ? D3DCOLORWRITEENABLE_GREEN : 0;
+ mask |= blue ? D3DCOLORWRITEENABLE_BLUE : 0;
+ mask |= alpha ? D3DCOLORWRITEENABLE_ALPHA : 0;
+ HR(d3d_device_->SetRenderState(D3DRS_COLORWRITEENABLE, mask));
+ HR(d3d_device_->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE));
+}
+
+void GAPID3D9::SetBlending(bool enable,
+ bool separate_alpha,
+ BlendEq color_eq,
+ BlendFunc color_src_func,
+ BlendFunc color_dst_func,
+ BlendEq alpha_eq,
+ BlendFunc alpha_src_func,
+ BlendFunc alpha_dst_func) {
+ HR(d3d_device_->SetRenderState(D3DRS_ALPHABLENDENABLE,
+ enable ? TRUE : FALSE));
+ HR(d3d_device_->SetRenderState(D3DRS_BLENDOP, BlendEqToD3D(color_eq)));
+ HR(d3d_device_->SetRenderState(D3DRS_SRCBLEND,
+ BlendFuncToD3D(color_src_func)));
+ HR(d3d_device_->SetRenderState(D3DRS_DESTBLEND,
+ BlendFuncToD3D(color_dst_func)));
+ if (separate_alpha) {
+ HR(d3d_device_->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE));
+ HR(d3d_device_->SetRenderState(D3DRS_BLENDOP, BlendEqToD3D(alpha_eq)));
+ HR(d3d_device_->SetRenderState(D3DRS_SRCBLEND,
+ BlendFuncToD3D(alpha_src_func)));
+ HR(d3d_device_->SetRenderState(D3DRS_DESTBLEND,
+ BlendFuncToD3D(alpha_dst_func)));
+ } else {
+ HR(d3d_device_->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE));
+ }
+}
+
+void GAPID3D9::SetBlendingColor(const RGBA &color) {
+ HR(d3d_device_->SetRenderState(D3DRS_BLENDFACTOR, RGBAToD3DCOLOR(color)));
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/states_gl.cc b/o3d/gpu/command_buffer/service/states_gl.cc
new file mode 100644
index 0000000..2d6fce4
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/states_gl.cc
@@ -0,0 +1,346 @@
+/*
+ * 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 implements the render state-related GAPI functions on GL.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/common/o3d_cmd_format.h"
+#include "gpu/command_buffer/service/gapi_gl.h"
+
+namespace command_buffer {
+namespace o3d {
+
+namespace {
+
+GLenum kGLPolygonModes[] = {
+ GL_POINT,
+ GL_LINE,
+ GL_FILL,
+};
+COMPILE_ASSERT(o3d::kNumPolygonMode == arraysize(kGLPolygonModes),
+ kGLPolygonModes_does_not_match_command_buffer_PolygonMode);
+
+GLenum kGLComparison[] = {
+ GL_NEVER,
+ GL_LESS,
+ GL_EQUAL,
+ GL_LEQUAL,
+ GL_GREATER,
+ GL_NOTEQUAL,
+ GL_GEQUAL,
+ GL_ALWAYS,
+};
+COMPILE_ASSERT(o3d::kNumComparison == arraysize(kGLComparison),
+ kGLComparison_does_not_match_command_buffer_Comparison);
+
+GLenum kGLBlendFunc[] = {
+ GL_ZERO,
+ GL_ONE,
+ GL_SRC_COLOR,
+ GL_ONE_MINUS_SRC_COLOR,
+ GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA,
+ GL_DST_ALPHA,
+ GL_ONE_MINUS_DST_ALPHA,
+ GL_DST_COLOR,
+ GL_ONE_MINUS_DST_COLOR,
+ GL_SRC_ALPHA_SATURATE,
+ GL_CONSTANT_COLOR,
+ GL_ONE_MINUS_CONSTANT_COLOR,
+};
+COMPILE_ASSERT(o3d::kNumBlendFunc == arraysize(kGLBlendFunc),
+ kGLBlendFunc_does_not_match_command_buffer_BlendFunc);
+
+GLenum kGLBlendEq[] = {
+ GL_FUNC_ADD,
+ GL_FUNC_SUBTRACT,
+ GL_FUNC_REVERSE_SUBTRACT,
+ GL_MIN,
+ GL_MAX,
+};
+COMPILE_ASSERT(o3d::kNumBlendEq == arraysize(kGLBlendEq),
+ kGLBlendEq_does_not_match_command_buffer_BlendEq);
+
+GLenum kGLStencilOp[] = {
+ GL_KEEP,
+ GL_ZERO,
+ GL_REPLACE,
+ GL_INCR,
+ GL_DECR,
+ GL_INVERT,
+ GL_INCR_WRAP,
+ GL_DECR_WRAP,
+};
+COMPILE_ASSERT(o3d::kNumStencilOp == arraysize(kGLStencilOp),
+ kGLStencilOp_does_not_match_command_buffer_StencilOp);
+
+// Check that the definition of the counter-clockwise func/ops match the
+// clockwise ones, just shifted by 16 bits, so that we can use
+// DecodeStencilFuncOps on both of them.
+#define CHECK_CCW_MATCHES_CW(FIELD) \
+ COMPILE_ASSERT(o3d::SetStencilTest::CW ## FIELD::kLength == \
+ o3d::SetStencilTest::CCW ## FIELD::kLength, \
+ CCW ## FIELD ## _length_does_not_match_ ## CW ## FIELD); \
+ COMPILE_ASSERT(o3d::SetStencilTest::CW ## FIELD::kShift + 16 == \
+ o3d::SetStencilTest::CCW ## FIELD::kShift, \
+ CCW ## FIELD ## _shift_does_not_match_ ## CW ## FIELD)
+
+CHECK_CCW_MATCHES_CW(Func);
+CHECK_CCW_MATCHES_CW(PassOp);
+CHECK_CCW_MATCHES_CW(FailOp);
+CHECK_CCW_MATCHES_CW(ZFailOp);
+
+#undef CHECK_CCW_MATCHES_CW
+
+// Decodes stencil test function and operations from the bitfield.
+void DecodeStencilFuncOps(Uint32 params,
+ GLenum *func,
+ GLenum *pass,
+ GLenum *fail,
+ GLenum *zfail) {
+ // Sanity check. The value has already been tested in
+ // GAPIDecoder::DecodeSetStencilTest in gapi_decoder.cc.
+ DCHECK_EQ(o3d::SetStencilTest::Unused1::Get(params), 0);
+ // Check that the bitmask get cannot generate values outside of the allowed
+ // range.
+ COMPILE_ASSERT(o3d::SetStencilTest::CWFunc::kMask <
+ o3d::kNumComparison,
+ set_stencil_test_CWFunc_may_produce_invalid_values);
+ *func = kGLComparison[o3d::SetStencilTest::CWFunc::Get(params)];
+
+ COMPILE_ASSERT(o3d::SetStencilTest::CWPassOp::kMask <
+ o3d::kNumStencilOp,
+ set_stencil_test_CWPassOp_may_produce_invalid_values);
+ *pass = kGLStencilOp[o3d::SetStencilTest::CWPassOp::Get(params)];
+
+ COMPILE_ASSERT(o3d::SetStencilTest::CWFailOp::kMask <
+ o3d::kNumStencilOp,
+ set_stencil_test_CWFailOp_may_produce_invalid_values);
+ *fail = kGLStencilOp[o3d::SetStencilTest::CWFailOp::Get(params)];
+
+ COMPILE_ASSERT(o3d::SetStencilTest::CWZFailOp::kMask <
+ o3d::kNumStencilOp,
+ set_stencil_test_CWZFailOp_may_produce_invalid_values);
+ *zfail = kGLStencilOp[o3d::SetStencilTest::CWZFailOp::Get(params)];
+}
+
+} // anonymous namespace
+
+void GAPIGL::SetViewport(unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height,
+ float z_min,
+ float z_max) {
+ glViewport(x, y, width, height);
+ glDepthRange(z_min, z_max);
+ // Update the helper constant used for the D3D -> GL remapping.
+ // See effect_gl.cc for details.
+ glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0,
+ 1.f / width, 1.f / height, 2.f, 0.f);
+ CHECK_GL_ERROR();
+}
+
+void GAPIGL::SetScissor(bool enable,
+ unsigned int x,
+ unsigned int y,
+ unsigned int width,
+ unsigned int height) {
+ if (enable) {
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(x, y, width, height);
+ } else {
+ glDisable(GL_SCISSOR_TEST);
+ }
+}
+
+void GAPIGL::SetPointLineRaster(bool line_smooth,
+ bool point_sprite,
+ float point_size) {
+ if (line_smooth) {
+ glEnable(GL_LINE_SMOOTH);
+ } else {
+ glDisable(GL_LINE_SMOOTH);
+ }
+ if (point_sprite) {
+ glEnable(GL_POINT_SPRITE);
+ // TODO: check which TC gets affected by point sprites in D3D.
+ glActiveTextureARB(GL_TEXTURE0);
+ glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
+ } else {
+ glActiveTextureARB(GL_TEXTURE0);
+ glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_FALSE);
+ glDisable(GL_POINT_SPRITE);
+ }
+ glPointSize(point_size);
+}
+
+void GAPIGL::SetPolygonOffset(float slope_factor, float units) {
+ glPolygonOffset(slope_factor, units);
+}
+
+void GAPIGL::SetPolygonRaster(o3d::PolygonMode fill_mode,
+ o3d::FaceCullMode cull_mode) {
+ DCHECK_LT(fill_mode, kNumPolygonMode);
+ glPolygonMode(GL_FRONT_AND_BACK, kGLPolygonModes[fill_mode]);
+ DCHECK_LT(cull_mode, kNumFaceCullMode);
+ switch (cull_mode) {
+ case kCullCW:
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ break;
+ case kCullCCW:
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_FRONT);
+ break;
+ default:
+ glDisable(GL_CULL_FACE);
+ break;
+ }
+}
+
+void GAPIGL::SetAlphaTest(bool enable,
+ float reference,
+ o3d::Comparison comp) {
+ DCHECK_LT(comp, kNumComparison);
+ if (enable) {
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(kGLComparison[comp], reference);
+ } else {
+ glDisable(GL_ALPHA_TEST);
+ }
+}
+
+void GAPIGL::SetDepthTest(bool enable,
+ bool write_enable,
+ o3d::Comparison comp) {
+ DCHECK_LT(comp, kNumComparison);
+ if (enable) {
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(kGLComparison[comp]);
+ } else {
+ glDisable(GL_DEPTH_TEST);
+ }
+ glDepthMask(write_enable);
+}
+
+void GAPIGL::SetStencilTest(bool enable,
+ bool separate_ccw,
+ unsigned int write_mask,
+ unsigned int compare_mask,
+ unsigned int ref,
+ Uint32 func_ops) {
+ if (enable) {
+ glEnable(GL_STENCIL_TEST);
+ glStencilMask(write_mask);
+
+ GLenum func;
+ GLenum pass;
+ GLenum fail;
+ GLenum zfail;
+ DecodeStencilFuncOps(func_ops, &func, &pass, &fail, &zfail);
+ if (separate_ccw) {
+ glStencilFuncSeparate(GL_FRONT, func, ref, compare_mask);
+ glStencilOpSeparate(GL_FRONT, pass, fail, zfail);
+ // Extract upper 16 bits.
+ Uint32 ccw_func_ops = BitField<16, 16>::Get(func_ops);
+ GLenum ccw_func;
+ GLenum ccw_pass;
+ GLenum ccw_fail;
+ GLenum ccw_zfail;
+ DecodeStencilFuncOps(ccw_func_ops, &ccw_func, &ccw_pass, &ccw_fail,
+ &ccw_zfail);
+ glStencilFuncSeparate(GL_BACK, ccw_func, ref, compare_mask);
+ glStencilOpSeparate(GL_BACK, ccw_pass, ccw_fail, ccw_zfail);
+ } else {
+ glStencilFunc(func, ref, compare_mask);
+ glStencilOp(pass, fail, zfail);
+ }
+ } else {
+ glDisable(GL_STENCIL_TEST);
+ }
+}
+
+void GAPIGL::SetColorWrite(bool red,
+ bool green,
+ bool blue,
+ bool alpha,
+ bool dither) {
+ glColorMask(red, green, blue, alpha);
+ if (dither) {
+ glEnable(GL_DITHER);
+ } else {
+ glDisable(GL_DITHER);
+ }
+}
+
+void GAPIGL::SetBlending(bool enable,
+ bool separate_alpha,
+ BlendEq color_eq,
+ BlendFunc color_src_func,
+ BlendFunc color_dst_func,
+ BlendEq alpha_eq,
+ BlendFunc alpha_src_func,
+ BlendFunc alpha_dst_func) {
+ DCHECK_LT(color_eq, kNumBlendEq);
+ DCHECK_LT(color_src_func, kNumBlendFunc);
+ DCHECK_LT(color_dst_func, kNumBlendFunc);
+ DCHECK_LT(alpha_eq, kNumBlendEq);
+ DCHECK_LT(alpha_src_func, kNumBlendFunc);
+ DCHECK_LT(alpha_dst_func, kNumBlendFunc);
+ if (enable) {
+ glEnable(GL_BLEND);
+ GLenum gl_color_eq = kGLBlendEq[color_eq];
+ GLenum gl_color_src_func = kGLBlendFunc[color_src_func];
+ GLenum gl_color_dst_func = kGLBlendFunc[color_dst_func];
+ if (separate_alpha) {
+ GLenum gl_alpha_eq = kGLBlendEq[alpha_eq];
+ GLenum gl_alpha_src_func = kGLBlendFunc[alpha_src_func];
+ GLenum gl_alpha_dst_func = kGLBlendFunc[alpha_dst_func];
+ glBlendFuncSeparate(gl_color_src_func, gl_color_dst_func,
+ gl_alpha_src_func, gl_alpha_dst_func);
+ glBlendEquationSeparate(gl_color_eq, gl_alpha_eq);
+ } else {
+ glBlendFunc(gl_color_src_func, gl_color_dst_func);
+ glBlendEquation(gl_color_eq);
+ }
+ } else {
+ glDisable(GL_BLEND);
+ }
+}
+
+void GAPIGL::SetBlendingColor(const RGBA &color) {
+ glBlendColor(color.red, color.green, color.blue, color.alpha);
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/texture_d3d9.cc b/o3d/gpu/command_buffer/service/texture_d3d9.cc
new file mode 100644
index 0000000..9f25ff0
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/texture_d3d9.cc
@@ -0,0 +1,731 @@
+/*
+ * 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 implements the D3D9 versions of the texture resources, as well as
+// the related GAPID3D9 function implementations.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/gapi_d3d9.h"
+#include "gpu/command_buffer/service/texture_d3d9.h"
+
+namespace command_buffer {
+namespace o3d {
+
+// Converts a texture format to a D3D texture format.
+D3DFORMAT TextureD3D9::D3DFormat(texture::Format format) {
+ switch (format) {
+ case texture::kXRGB8: return D3DFMT_X8R8G8B8;
+ case texture::kARGB8: return D3DFMT_A8R8G8B8;
+ case texture::kABGR16F: return D3DFMT_A16B16G16R16F;
+ case texture::kR32F: return D3DFMT_R32F;
+ case texture::kABGR32F: return D3DFMT_A32B32G32R32F;
+ case texture::kDXT1: return D3DFMT_DXT1;
+ // TODO(petersont): Add DXT3/5 support.
+ default: return D3DFMT_UNKNOWN;
+ };
+}
+
+// Converts a cube map face to a D3D face.
+D3DCUBEMAP_FACES TextureD3D9::D3DFace(texture::Face face) {
+ switch (face) {
+ case texture::kFacePositiveX:
+ return D3DCUBEMAP_FACE_POSITIVE_X;
+ case texture::kFaceNegativeX:
+ return D3DCUBEMAP_FACE_NEGATIVE_X;
+ case texture::kFacePositiveY:
+ return D3DCUBEMAP_FACE_POSITIVE_Y;
+ case texture::kFaceNegativeY:
+ return D3DCUBEMAP_FACE_NEGATIVE_Y;
+ case texture::kFacePositiveZ:
+ return D3DCUBEMAP_FACE_POSITIVE_Z;
+ case texture::kFaceNegativeZ:
+ return D3DCUBEMAP_FACE_NEGATIVE_Z;
+ }
+ LOG(FATAL) << "Not reached.";
+ return D3DCUBEMAP_FACE_POSITIVE_X;
+}
+
+// Texture 2D functions
+
+// Destroys the 2D texture, releasing the D3D texture, and its shadow if any.
+Texture2DD3D9::~Texture2DD3D9() {
+ DCHECK(d3d_texture_);
+ d3d_texture_ = NULL;
+ if (d3d_shadow_) {
+ d3d_shadow_->Release();
+ d3d_shadow_ = NULL;
+ }
+}
+
+// Creates a 2D texture. For dynamic textures, create it in the default pool,
+// and a shadow version in the system memory pool (that we can lock). For
+// regular texture, simply create one in the managed pool.
+Texture2DD3D9 *Texture2DD3D9::Create(GAPID3D9 *gapi,
+ unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ DCHECK_GT(width, 0U);
+ DCHECK_GT(height, 0U);
+ DCHECK_GT(levels, 0U);
+ D3DFORMAT d3d_format = D3DFormat(format);
+ IDirect3DDevice9 *device = gapi->d3d_device();
+ if (enable_render_surfaces) {
+ CComPtr<IDirect3DTexture9> d3d_texture = NULL;
+ HRESULT result = device->CreateTexture(width, height, levels,
+ D3DUSAGE_RENDERTARGET, d3d_format,
+ D3DPOOL_DEFAULT, &d3d_texture,
+ NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ return new Texture2DD3D9(levels, format, flags, width, height, d3d_texture,
+ NULL, enable_render_surfaces);
+ } else if (flags & texture::kDynamic) {
+ CComPtr<IDirect3DTexture9> d3d_texture = NULL;
+ HRESULT result = device->CreateTexture(width, height, levels,
+ D3DUSAGE_DYNAMIC, d3d_format,
+ D3DPOOL_DEFAULT, &d3d_texture,
+ NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ CComPtr<IDirect3DTexture9> d3d_shadow = NULL;
+ result = device->CreateTexture(width, height, levels, D3DUSAGE_DYNAMIC,
+ d3d_format, D3DPOOL_SYSTEMMEM, &d3d_shadow,
+ NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ return new Texture2DD3D9(levels, format, flags, width, height, d3d_texture,
+ d3d_shadow, enable_render_surfaces);
+ } else {
+ CComPtr<IDirect3DTexture9> d3d_texture = NULL;
+ HRESULT result = device->CreateTexture(width, height, levels, 0, d3d_format,
+ D3DPOOL_MANAGED, &d3d_texture, NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ return new Texture2DD3D9(levels, format, flags, width, height, d3d_texture,
+ NULL, enable_render_surfaces);
+ }
+}
+
+// Sets the data in the texture, using LockRect()/UnlockRect(). For dynamic
+// textures, it copies the data to the shadow texture, then updates the actual
+// texture. For regular texture, it directly modifies the actual texture.
+bool Texture2DD3D9::SetData(GAPID3D9 *gapi,
+ const Volume &volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) {
+ DCHECK(d3d_texture_);
+ IDirect3DTexture9 *lock_texture = d3d_shadow_ ? d3d_shadow_ : d3d_texture_;
+
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level);
+ TransferInfo src_transfer_info;
+ MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch,
+ slice_pitch);
+ if (!CheckVolume(mip_info, volume) || level >= levels() ||
+ size < src_transfer_info.total_size)
+ return false;
+
+ bool full_rect = IsFullVolume(mip_info, volume);
+ D3DLOCKED_RECT locked_rect;
+ RECT rect = {volume.x, volume.y, volume.x+volume.width,
+ volume.y+volume.height};
+ DWORD lock_flags =
+ full_rect && (flags() & texture::kDynamic) ? D3DLOCK_DISCARD : 0;
+ HR(lock_texture->LockRect(level, &locked_rect, full_rect ? NULL : &rect,
+ lock_flags));
+
+ TransferInfo dst_transfer_info;
+ MakeTransferInfo(&dst_transfer_info, mip_info, volume, locked_rect.Pitch,
+ slice_pitch);
+ TransferVolume(volume, mip_info, dst_transfer_info, locked_rect.pBits,
+ src_transfer_info, data);
+
+ HR(lock_texture->UnlockRect(level));
+ if (d3d_shadow_) {
+ HR(gapi->d3d_device()->UpdateTexture(d3d_shadow_, d3d_texture_));
+ }
+ return true;
+}
+
+// Gets the data from the texture, using LockRect()/UnlockRect(). For dynamic
+// textures, it gets the data from the shadow texture, For regular texture, it
+// gets it directly from the actual texture.
+bool Texture2DD3D9::GetData(GAPID3D9 *gapi,
+ const Volume &volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) {
+ DCHECK(d3d_texture_);
+ IDirect3DTexture9 *lock_texture = d3d_shadow_ ? d3d_shadow_ : d3d_texture_;
+
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level);
+ TransferInfo dst_transfer_info;
+ MakeTransferInfo(&dst_transfer_info, mip_info, volume, row_pitch,
+ slice_pitch);
+ if (!CheckVolume(mip_info, volume) || level >= levels() ||
+ size < dst_transfer_info.total_size)
+ return false;
+
+ bool full_rect = IsFullVolume(mip_info, volume);
+ D3DLOCKED_RECT locked_rect;
+ RECT rect = {volume.x, volume.y, volume.x+volume.width,
+ volume.y+volume.height};
+ DWORD lock_flags = D3DLOCK_READONLY;
+ HR(lock_texture->LockRect(level, &locked_rect, full_rect ? NULL : &rect,
+ lock_flags));
+ TransferInfo src_transfer_info;
+ MakeTransferInfo(&src_transfer_info, mip_info, volume, locked_rect.Pitch,
+ slice_pitch);
+ TransferVolume(volume, mip_info, dst_transfer_info, data,
+ src_transfer_info, locked_rect.pBits);
+ HR(lock_texture->UnlockRect(level));
+ return true;
+}
+
+bool Texture2DD3D9::CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side,
+ IDirect3DSurface9** direct3d_surface) {
+ IDirect3DTexture9* d3d_texture =
+ static_cast<IDirect3DTexture9*>(d3d_base_texture());
+ D3DSURFACE_DESC surface_desc;
+ d3d_texture->GetLevelDesc(mip_level, &surface_desc);
+ if (width != surface_desc.Width || height != surface_desc.Height) {
+ return false;
+ }
+ HR(d3d_texture->GetSurfaceLevel(mip_level, direct3d_surface));
+ return true;
+}
+
+// Texture 3D functions
+
+// Destroys the 3D texture.
+Texture3DD3D9::~Texture3DD3D9() {
+ DCHECK(d3d_texture_);
+ d3d_texture_ = NULL;
+ if (d3d_shadow_) {
+ d3d_shadow_->Release();
+ d3d_shadow_ = NULL;
+ }
+}
+
+// Creates a 3D texture. For dynamic textures, create it in the default pool,
+// and a shadow version in the system memory pool (that we can lock). For
+// regular texture, simply create one in the managed pool.
+Texture3DD3D9 *Texture3DD3D9::Create(GAPID3D9 *gapi,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ DCHECK_GT(width, 0U);
+ DCHECK_GT(height, 0U);
+ DCHECK_GT(depth, 0U);
+ DCHECK_GT(levels, 0U);
+ D3DFORMAT d3d_format = D3DFormat(format);
+ IDirect3DDevice9 *device = gapi->d3d_device();
+ if (enable_render_surfaces) {
+ CComPtr<IDirect3DVolumeTexture9> d3d_texture = NULL;
+ HRESULT result = device->CreateVolumeTexture(width, height, depth, levels,
+ D3DUSAGE_RENDERTARGET,
+ d3d_format, D3DPOOL_DEFAULT,
+ &d3d_texture, NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ return new Texture3DD3D9(levels, format, flags, width, height, depth,
+ d3d_texture, NULL, enable_render_surfaces);
+ } else if (flags & texture::kDynamic) {
+ CComPtr<IDirect3DVolumeTexture9> d3d_texture = NULL;
+ HRESULT result = device->CreateVolumeTexture(width, height, depth, levels,
+ D3DUSAGE_DYNAMIC, d3d_format,
+ D3DPOOL_DEFAULT, &d3d_texture,
+ NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ CComPtr<IDirect3DVolumeTexture9> d3d_shadow = NULL;
+ result = device->CreateVolumeTexture(width, height, depth, levels,
+ D3DUSAGE_DYNAMIC, d3d_format,
+ D3DPOOL_SYSTEMMEM, &d3d_shadow, NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ return new Texture3DD3D9(levels, format, flags, width, height, depth,
+ d3d_texture, d3d_shadow, enable_render_surfaces);
+ } else {
+ CComPtr<IDirect3DVolumeTexture9> d3d_texture = NULL;
+ HRESULT result = device->CreateVolumeTexture(width, height, depth, levels,
+ D3DUSAGE_DYNAMIC, d3d_format,
+ D3DPOOL_MANAGED, &d3d_texture,
+ NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ return new Texture3DD3D9(levels, format, flags, width, height, depth,
+ d3d_texture, NULL, enable_render_surfaces);
+ }
+}
+
+// Sets the data in the texture, using LockBox()/UnlockBox(). For dynamic
+// textures, it copies the data to the shadow texture, then updates the actual
+// texture. For regular texture, it directly modifies the actual texture.
+bool Texture3DD3D9::SetData(GAPID3D9 *gapi,
+ const Volume &volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) {
+ DCHECK(d3d_texture_);
+ IDirect3DVolumeTexture9 *lock_texture =
+ d3d_shadow_ ? d3d_shadow_ : d3d_texture_;
+
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level);
+ TransferInfo src_transfer_info;
+ MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch,
+ slice_pitch);
+ if (!CheckVolume(mip_info, volume) || level >= levels() ||
+ size < src_transfer_info.total_size)
+ return false;
+
+ bool full_box = IsFullVolume(mip_info, volume);
+ D3DLOCKED_BOX locked_box;
+ D3DBOX box = {volume.x, volume.y, volume.z, volume.x+volume.width,
+ volume.y+volume.height, volume.z+volume.depth};
+ DWORD lock_flags =
+ full_box && (flags() & texture::kDynamic) ? D3DLOCK_DISCARD : 0;
+ HR(lock_texture->LockBox(level, &locked_box, full_box ? NULL : &box,
+ lock_flags));
+
+ TransferInfo dst_transfer_info;
+ MakeTransferInfo(&dst_transfer_info, mip_info, volume, locked_box.RowPitch,
+ locked_box.SlicePitch);
+ TransferVolume(volume, mip_info, dst_transfer_info, locked_box.pBits,
+ src_transfer_info, data);
+
+ HR(lock_texture->UnlockBox(level));
+ if (d3d_shadow_) {
+ HR(gapi->d3d_device()->UpdateTexture(d3d_shadow_, d3d_texture_));
+ }
+ return true;
+}
+
+// Gets the data from the texture, using LockBox()/UnlockBox(). For dynamic
+// textures, it gets the data from the shadow texture, For regular texture, it
+// gets it directly from the actual texture.
+bool Texture3DD3D9::GetData(GAPID3D9 *gapi,
+ const Volume &volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) {
+ DCHECK(d3d_texture_);
+ IDirect3DVolumeTexture9 *lock_texture =
+ d3d_shadow_ ? d3d_shadow_ : d3d_texture_;
+
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level);
+ TransferInfo dst_transfer_info;
+ MakeTransferInfo(&dst_transfer_info, mip_info, volume, row_pitch,
+ slice_pitch);
+ if (!CheckVolume(mip_info, volume) || level >= levels() ||
+ size < dst_transfer_info.total_size)
+ return false;
+
+ bool full_box = IsFullVolume(mip_info, volume);
+ D3DLOCKED_BOX locked_box;
+ D3DBOX box = {volume.x, volume.y, volume.z, volume.x+volume.width,
+ volume.y+volume.height, volume.z+volume.depth};
+ DWORD lock_flags = D3DLOCK_READONLY;
+ HR(lock_texture->LockBox(level, &locked_box, full_box ? NULL : &box,
+ lock_flags));
+ TransferInfo src_transfer_info;
+ MakeTransferInfo(&src_transfer_info, mip_info, volume, locked_box.RowPitch,
+ locked_box.SlicePitch);
+ TransferVolume(volume, mip_info, dst_transfer_info, data,
+ src_transfer_info, locked_box.pBits);
+ HR(lock_texture->UnlockBox(level));
+ return true;
+}
+
+bool Texture3DD3D9::CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side,
+ IDirect3DSurface9** direct3d_surface) {
+ // TODO(rlp): Currently unsupported.
+ DCHECK(false);
+ return false;
+}
+
+// Texture Cube functions.
+
+// Destroys the cube map texture, releasing the D3D texture, and its shadow if
+// any.
+TextureCubeD3D9::~TextureCubeD3D9() {
+ DCHECK(d3d_texture_);
+ d3d_texture_ = NULL;
+ if (d3d_shadow_) {
+ d3d_shadow_->Release();
+ d3d_shadow_ = NULL;
+ }
+}
+
+// Creates a cube map texture. For dynamic textures, create it in the default
+// pool, and a shadow version in the system memory pool (that we can lock). For
+// regular texture, simply create one in the managed pool.
+TextureCubeD3D9 *TextureCubeD3D9::Create(GAPID3D9 *gapi,
+ unsigned int side,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ DCHECK_GT(side, 0U);
+ DCHECK_GT(levels, 0U);
+ D3DFORMAT d3d_format = D3DFormat(format);
+ IDirect3DDevice9 *device = gapi->d3d_device();
+ if (enable_render_surfaces) {
+ CComPtr<IDirect3DCubeTexture9> d3d_texture = NULL;
+ HRESULT result = device->CreateCubeTexture(side, levels,
+ D3DUSAGE_RENDERTARGET,
+ d3d_format, D3DPOOL_DEFAULT,
+ &d3d_texture, NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ return new TextureCubeD3D9(levels, format, flags, side, d3d_texture, NULL,
+ enable_render_surfaces);
+ } else if (flags & texture::kDynamic) {
+ CComPtr<IDirect3DCubeTexture9> d3d_texture = NULL;
+ HRESULT result = device->CreateCubeTexture(side, levels, D3DUSAGE_DYNAMIC,
+ d3d_format, D3DPOOL_DEFAULT,
+ &d3d_texture, NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ CComPtr<IDirect3DCubeTexture9> d3d_shadow = NULL;
+ result = device->CreateCubeTexture(side, levels, D3DUSAGE_DYNAMIC,
+ d3d_format, D3DPOOL_SYSTEMMEM,
+ &d3d_shadow, NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ return new TextureCubeD3D9(levels, format, flags, side, d3d_texture,
+ d3d_shadow, enable_render_surfaces);
+ } else {
+ CComPtr<IDirect3DCubeTexture9> d3d_texture = NULL;
+ HRESULT result = device->CreateCubeTexture(side, levels, 0, d3d_format,
+ D3DPOOL_MANAGED, &d3d_texture,
+ NULL);
+ if (result != D3D_OK) {
+ LOG(ERROR) << "DirectX error when calling CreateTexture: "
+ << DXGetErrorStringA(result);
+ return NULL;
+ }
+ return new TextureCubeD3D9(levels, format, flags, side, d3d_texture, NULL,
+ enable_render_surfaces);
+ }
+}
+
+// Sets the data in the texture, using LockRect()/UnlockRect(). For dynamic
+// textures, it copies the data to the shadow texture, then updates the actual
+// texture. For regular texture, it directly modifies the actual texture.
+bool TextureCubeD3D9::SetData(GAPID3D9 *gapi,
+ const Volume &volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) {
+ DCHECK(d3d_texture_);
+ IDirect3DCubeTexture9 *lock_texture =
+ d3d_shadow_ ? d3d_shadow_ : d3d_texture_;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level);
+ TransferInfo src_transfer_info;
+ MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch,
+ slice_pitch);
+ if (!CheckVolume(mip_info, volume) || level >= levels() ||
+ size < src_transfer_info.total_size)
+ return false;
+
+ D3DCUBEMAP_FACES d3d_face = D3DFace(face);
+ bool full_rect = IsFullVolume(mip_info, volume);
+ D3DLOCKED_RECT locked_rect;
+ RECT rect = {volume.x, volume.y, volume.x+volume.width,
+ volume.y+volume.height};
+ DWORD lock_flags =
+ full_rect && (flags() & texture::kDynamic) ? D3DLOCK_DISCARD : 0;
+ HR(lock_texture->LockRect(d3d_face, level, &locked_rect,
+ full_rect ? NULL : &rect, lock_flags));
+
+ TransferInfo dst_transfer_info;
+ MakeTransferInfo(&dst_transfer_info, mip_info, volume, locked_rect.Pitch,
+ slice_pitch);
+ TransferVolume(volume, mip_info, dst_transfer_info, locked_rect.pBits,
+ src_transfer_info, data);
+
+ HR(lock_texture->UnlockRect(d3d_face, level));
+ if (d3d_shadow_) {
+ HR(gapi->d3d_device()->UpdateTexture(d3d_shadow_, d3d_texture_));
+ }
+ return true;
+}
+
+// Gets the data from the texture, using LockRect()/UnlockRect(). For dynamic
+// textures, it gets the data from the shadow texture, For regular texture, it
+// gets it directly from the actual texture.
+bool TextureCubeD3D9::GetData(GAPID3D9 *gapi,
+ const Volume &volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) {
+ DCHECK(d3d_texture_);
+ IDirect3DCubeTexture9 *lock_texture =
+ d3d_shadow_ ? d3d_shadow_ : d3d_texture_;
+
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level);
+ TransferInfo dst_transfer_info;
+ MakeTransferInfo(&dst_transfer_info, mip_info, volume, row_pitch,
+ slice_pitch);
+ if (!CheckVolume(mip_info, volume) || level >= levels() ||
+ size < dst_transfer_info.total_size)
+ return false;
+
+ D3DCUBEMAP_FACES d3d_face = D3DFace(face);
+ bool full_rect = IsFullVolume(mip_info, volume);
+ D3DLOCKED_RECT locked_rect;
+ RECT rect = {volume.x, volume.y, volume.x+volume.width,
+ volume.y+volume.height};
+ DWORD lock_flags = D3DLOCK_READONLY;
+ HR(lock_texture->LockRect(d3d_face, level, &locked_rect,
+ full_rect ? NULL : &rect, lock_flags));
+ TransferInfo src_transfer_info;
+ MakeTransferInfo(&src_transfer_info, mip_info, volume, locked_rect.Pitch,
+ slice_pitch);
+ TransferVolume(volume, mip_info, dst_transfer_info, data,
+ src_transfer_info, locked_rect.pBits);
+ HR(lock_texture->UnlockRect(d3d_face, level));
+ return true;
+}
+
+bool TextureCubeD3D9::CreateRenderSurface(
+ int width,
+ int height,
+ int mip_level,
+ int side,
+ IDirect3DSurface9** direct3d_surface) {
+ IDirect3DCubeTexture9* d3d_cube_texture =
+ static_cast<IDirect3DCubeTexture9*>(d3d_base_texture());
+ D3DSURFACE_DESC surface_desc;
+ d3d_cube_texture->GetLevelDesc(mip_level, &surface_desc);
+ if (width != surface_desc.Width || height != surface_desc.Height ||
+ side < 0 || side > 5) {
+ return false;
+ }
+ HR(d3d_cube_texture->GetCubeMapSurface(
+ D3DFace(static_cast<texture::Face>(side)),
+ mip_level,
+ direct3d_surface));
+ return true;
+}
+
+// GAPID3D9 functions.
+
+// Destroys a texture resource.
+parse_error::ParseError GAPID3D9::DestroyTexture(ResourceId id) {
+ // Dirty effect, because this texture id may be used
+ DirtyEffect();
+ return textures_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Creates a 2D texture resource.
+parse_error::ParseError GAPID3D9::CreateTexture2D(
+ ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ Texture2DD3D9 *texture = Texture2DD3D9::Create(this, width, height, levels,
+ format, flags,
+ enable_render_surfaces);
+ if (!texture) return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this texture id may be used
+ DirtyEffect();
+ textures_.Assign(id, texture);
+ return parse_error::kParseNoError;
+}
+
+// Creates a 3D texture resource.
+parse_error::ParseError GAPID3D9::CreateTexture3D(
+ ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ Texture3DD3D9 *texture = Texture3DD3D9::Create(this, width, height, depth,
+ levels, format, flags,
+ enable_render_surfaces);
+ if (!texture) return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this texture id may be used
+ DirtyEffect();
+ textures_.Assign(id, texture);
+ return parse_error::kParseNoError;
+}
+
+// Creates a cube map texture resource.
+parse_error::ParseError GAPID3D9::CreateTextureCube(
+ ResourceId id,
+ unsigned int side,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ TextureCubeD3D9 *texture = TextureCubeD3D9::Create(this, side, levels,
+ format, flags,
+ enable_render_surfaces);
+ if (!texture) return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this texture id may be used
+ DirtyEffect();
+ textures_.Assign(id, texture);
+ return parse_error::kParseNoError;
+}
+
+// Copies the data into a texture resource.
+parse_error::ParseError GAPID3D9::SetTextureData(
+ ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) {
+ TextureD3D9 *texture = textures_.Get(id);
+ if (!texture)
+ return parse_error::kParseInvalidArguments;
+ Volume volume = {x, y, z, width, height, depth};
+ return texture->SetData(this, volume, level, face, row_pitch, slice_pitch,
+ size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Copies the data from a texture resource.
+parse_error::ParseError GAPID3D9::GetTextureData(
+ ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) {
+ TextureD3D9 *texture = textures_.Get(id);
+ if (!texture)
+ return parse_error::kParseInvalidArguments;
+ Volume volume = {x, y, z, width, height, depth};
+ return texture->GetData(this, volume, level, face, row_pitch, slice_pitch,
+ size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/texture_d3d9.h b/o3d/gpu/command_buffer/service/texture_d3d9.h
new file mode 100644
index 0000000..de913a8
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/texture_d3d9.h
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_TEXTURE_D3D9_H_
+#define GPU_COMMAND_BUFFER_SERVICE_TEXTURE_D3D9_H_
+
+// This file contains the definition of the D3D9 versions of texture-related
+// resource classes.
+#include <atlbase.h>
+
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/d3d9_utils.h"
+#include "gpu/command_buffer/service/resource.h"
+#include "gpu/command_buffer/service/texture_utils.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class GAPID3D9;
+
+// The base class for a D3D texture resource, providing access to the base D3D
+// texture that can be assigned to an effect parameter or a sampler unit.
+class TextureD3D9 : public Texture {
+ public:
+ TextureD3D9(texture::Type type,
+ unsigned int levels,
+ texture::Format format,
+ bool enable_render_surfaces,
+ unsigned int flags)
+ : Texture(type, levels, format, enable_render_surfaces, flags) {}
+ // Gets the D3D base texture.
+ virtual IDirect3DBaseTexture9 *d3d_base_texture() const = 0;
+ // Sets data into a texture resource.
+ virtual bool SetData(GAPID3D9 *gapi,
+ const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) = 0;
+ // Gets data from a texture resource.
+ virtual bool GetData(GAPID3D9 *gapi,
+ const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) = 0;
+ // Creates the render surface, returning false if unable to.
+ virtual bool CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side,
+ IDirect3DSurface9** direct3d_surface) = 0;
+ static D3DFORMAT D3DFormat(texture::Format format);
+ static D3DCUBEMAP_FACES D3DFace(texture::Face face);
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureD3D9);
+};
+
+// A 2D texture resource for D3D.
+class Texture2DD3D9 : public TextureD3D9 {
+ public:
+ Texture2DD3D9(unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ unsigned int width,
+ unsigned int height,
+ IDirect3DTexture9 *texture,
+ IDirect3DTexture9 *shadow,
+ bool enable_render_surfaces)
+ : TextureD3D9(texture::kTexture2d, levels, format,
+ enable_render_surfaces, flags),
+ width_(width),
+ height_(height),
+ d3d_texture_(texture),
+ d3d_shadow_(shadow) {}
+ virtual ~Texture2DD3D9();
+
+ // Creates a 2D texture resource.
+ static Texture2DD3D9 *Create(GAPID3D9 *gapi,
+ unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+ // Sets data into a 2D texture resource.
+ virtual bool SetData(GAPID3D9 *gapi,
+ const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data);
+ // Gets data from a 2D texture resource.
+ virtual bool GetData(GAPID3D9 *gapi,
+ const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data);
+ // Create a render surface which matches this texture type.
+ virtual bool CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side,
+ IDirect3DSurface9** direct3d_surface);
+ // Gets the D3D base texture.
+ virtual IDirect3DBaseTexture9 *d3d_base_texture() const {
+ return d3d_texture_;
+ }
+ private:
+ unsigned int width_;
+ unsigned int height_;
+ CComPtr<IDirect3DTexture9> d3d_texture_;
+ IDirect3DTexture9 *d3d_shadow_;
+ DISALLOW_COPY_AND_ASSIGN(Texture2DD3D9);
+};
+
+// A 3D texture resource for D3D.
+class Texture3DD3D9 : public TextureD3D9 {
+ public:
+ Texture3DD3D9(unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ IDirect3DVolumeTexture9 *texture,
+ IDirect3DVolumeTexture9 *shadow,
+ bool enable_render_surfaces)
+ : TextureD3D9(texture::kTexture3d, levels, format,
+ enable_render_surfaces, flags),
+ width_(width),
+ height_(height),
+ depth_(depth),
+ d3d_texture_(texture),
+ d3d_shadow_(shadow) {}
+ virtual ~Texture3DD3D9();
+ // Creates a 3D texture resource.
+ static Texture3DD3D9 *Create(GAPID3D9 *gapi,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+ // Sets data into a 3D texture resource.
+ virtual bool SetData(GAPID3D9 *gapi,
+ const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data);
+ // Gets data from a 3D texture resource.
+ virtual bool GetData(GAPID3D9 *gapi,
+ const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data);
+ // Create a render surface which matches this texture type.
+ virtual bool CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side,
+ IDirect3DSurface9** direct3d_surface);
+ // Gets the D3D base texture.
+ virtual IDirect3DBaseTexture9 *d3d_base_texture() const {
+ return d3d_texture_;
+ }
+ private:
+ unsigned int width_;
+ unsigned int height_;
+ unsigned int depth_;
+ CComPtr<IDirect3DVolumeTexture9> d3d_texture_;
+ IDirect3DVolumeTexture9 *d3d_shadow_;
+ DISALLOW_COPY_AND_ASSIGN(Texture3DD3D9);
+};
+
+// A cube map texture resource for D3D.
+class TextureCubeD3D9 : public TextureD3D9 {
+ public:
+ TextureCubeD3D9(unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ unsigned int side,
+ IDirect3DCubeTexture9 *texture,
+ IDirect3DCubeTexture9 *shadow,
+ bool enable_render_surfaces)
+ : TextureD3D9(texture::kTextureCube, levels, format,
+ enable_render_surfaces, flags),
+ side_(side),
+ d3d_texture_(texture),
+ d3d_shadow_(shadow) {}
+ virtual ~TextureCubeD3D9();
+ // Creates a cube map texture resource.
+ static TextureCubeD3D9 *Create(GAPID3D9 *gapi,
+ unsigned int side,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+ // Sets data into a cube map texture resource.
+ virtual bool SetData(GAPID3D9 *gapi,
+ const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data);
+ // Gets data from a cube map texture resource.
+ virtual bool GetData(GAPID3D9 *gapi,
+ const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data);
+ // Create a render surface which matches this texture type.
+ virtual bool CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side,
+ IDirect3DSurface9** direct3d_surface);
+ // Gets the D3D base texture.
+ virtual IDirect3DBaseTexture9 *d3d_base_texture() const {
+ return d3d_texture_;
+ }
+ private:
+ unsigned int side_;
+ CComPtr<IDirect3DCubeTexture9> d3d_texture_;
+ IDirect3DCubeTexture9 *d3d_shadow_;
+ DISALLOW_COPY_AND_ASSIGN(TextureCubeD3D9);
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_TEXTURE_D3D9_H_
diff --git a/o3d/gpu/command_buffer/service/texture_gl.cc b/o3d/gpu/command_buffer/service/texture_gl.cc
new file mode 100644
index 0000000..386c5ec
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/texture_gl.cc
@@ -0,0 +1,767 @@
+/*
+ * 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 implements the texture-related GAPI functions on GL.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/service/gapi_gl.h"
+#include "gpu/command_buffer/service/texture_gl.h"
+
+namespace command_buffer {
+namespace o3d {
+
+namespace {
+
+// Gets the GL internal format, format and type corresponding to a command
+// buffer texture format.
+bool GetGLFormatType(texture::Format format,
+ GLenum *internal_format,
+ GLenum *gl_format,
+ GLenum *gl_type) {
+ switch (format) {
+ case texture::kXRGB8: {
+ *internal_format = GL_RGB;
+ *gl_format = GL_BGRA;
+ *gl_type = GL_UNSIGNED_BYTE;
+ break;
+ }
+ case texture::kARGB8: {
+ *internal_format = GL_RGBA;
+ *gl_format = GL_BGRA;
+ *gl_type = GL_UNSIGNED_BYTE;
+ break;
+ }
+ case texture::kABGR16F: {
+ *internal_format = GL_RGBA16F_ARB;
+ *gl_format = GL_RGBA;
+ *gl_type = GL_HALF_FLOAT_ARB;
+ break;
+ }
+ case texture::kR32F: {
+ *internal_format = GL_LUMINANCE32F_ARB;
+ *gl_format = GL_LUMINANCE;
+ *gl_type = GL_FLOAT;
+ break;
+ }
+ case texture::kABGR32F: {
+ *internal_format = GL_RGBA32F_ARB;
+ *gl_format = GL_BGRA;
+ *gl_type = GL_FLOAT;
+ break;
+ }
+ case texture::kDXT1: {
+ *internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ *gl_format = 0;
+ *gl_type = 0;
+ break;
+ }
+ // TODO(petersont): Add DXT3/5 support.
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+// Helper class used to prepare image data to match the layout that
+// glTexImage* and glCompressedTexImage* expect.
+class SetImageHelper {
+ public:
+ SetImageHelper()
+ : buffer_(NULL),
+ image_data_(NULL),
+ image_size_(0) {
+ }
+
+ // Initializes the helper with the input data, re-using the input buffer if
+ // possible, or copying it into a temporary one.
+ bool Initialize(const MipLevelInfo &mip_info,
+ const Volume& volume,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int src_size,
+ const void *data) {
+ TransferInfo src_transfer_info;
+ MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch,
+ slice_pitch);
+ if (!CheckVolume(mip_info, volume) ||
+ src_size < src_transfer_info.total_size)
+ return false;
+ if (!src_transfer_info.packed) {
+ TransferInfo dst_transfer_info;
+ MakePackedTransferInfo(&dst_transfer_info, mip_info, volume);
+ buffer_.reset(new unsigned char[dst_transfer_info.total_size]);
+ TransferVolume(volume, mip_info, dst_transfer_info, buffer_.get(),
+ src_transfer_info, data);
+ image_data_ = buffer_.get();
+ image_size_ = dst_transfer_info.total_size;
+ } else {
+ image_data_ = data;
+ image_size_ = src_transfer_info.total_size;
+ }
+ return true;
+ }
+
+ // Gets the buffer that contains the data in the GL format.
+ const void *image_data() { return image_data_; }
+ // Gets the size of the buffer as GL expects it.
+ unsigned int image_size() { return image_size_; }
+
+ private:
+ scoped_array<unsigned char> buffer_;
+ const void *image_data_;
+ unsigned int image_size_;
+ DISALLOW_COPY_AND_ASSIGN(SetImageHelper);
+};
+
+// Helper class used to retrieve image data to match the layout that
+// glGetTexImage and glGetCompressedTexImage expect.
+class GetImageHelper {
+ public:
+ GetImageHelper()
+ : dst_data_(NULL),
+ buffer_(NULL),
+ image_data_(NULL) {
+ memset(&mip_info_, 0, sizeof(mip_info_));
+ memset(&volume_, 0, sizeof(volume_));
+ memset(&dst_transfer_info_, 0, sizeof(dst_transfer_info_));
+ memset(&src_transfer_info_, 0, sizeof(src_transfer_info_));
+ }
+
+ // Initialize the helper to make available a buffer to get the data from GL.
+ // It will re-use the passed in buffer if the layout matches GL, or allocate
+ // a temporary one.
+ bool Initialize(const MipLevelInfo &mip_info,
+ const Volume& volume,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int dst_size,
+ void *dst_data) {
+ mip_info_ = mip_info;
+ volume_ = volume;
+ dst_data_ = dst_data;
+ MakeTransferInfo(&dst_transfer_info_, mip_info, volume, row_pitch,
+ slice_pitch);
+ if (!CheckVolume(mip_info, volume) ||
+ dst_size < dst_transfer_info_.total_size)
+ return false;
+
+ if (!IsFullVolume(mip_info, volume) || !dst_transfer_info_.packed) {
+ // We can only retrieve the full image from GL.
+ Volume full_volume = {
+ 0, 0, 0,
+ mip_info.width, mip_info.height, mip_info.depth
+ };
+ MakePackedTransferInfo(&src_transfer_info_, mip_info, full_volume);
+ buffer_.reset(new unsigned char[src_transfer_info_.total_size]);
+ image_data_ = buffer_.get();
+ } else {
+ image_data_ = dst_data;
+ }
+ return true;
+ }
+
+ // Finalize the helper, copying the data into the final buffer if needed.
+ void Finalize() {
+ if (!buffer_.get()) return;
+ unsigned int offset =
+ volume_.x / mip_info_.block_size_x * mip_info_.block_bpp +
+ volume_.y / mip_info_.block_size_y * src_transfer_info_.row_pitch +
+ volume_.z * src_transfer_info_.slice_pitch;
+ src_transfer_info_.row_size = dst_transfer_info_.row_size;
+ TransferVolume(volume_, mip_info_, dst_transfer_info_, dst_data_,
+ src_transfer_info_, buffer_.get() + offset);
+ }
+
+ // Gets the buffer that can receive the data from GL.
+ void *image_data() { return image_data_; }
+
+ private:
+ MipLevelInfo mip_info_;
+ Volume volume_;
+ TransferInfo dst_transfer_info_;
+ TransferInfo src_transfer_info_;
+ void *dst_data_;
+ scoped_array<unsigned char> buffer_;
+ void *image_data_;
+ DISALLOW_COPY_AND_ASSIGN(GetImageHelper);
+};
+
+} // anonymous namespace
+
+TextureGL::~TextureGL() {
+ glDeleteTextures(1, &gl_texture_);
+ CHECK_GL_ERROR();
+}
+
+Texture2DGL *Texture2DGL::Create(unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ DCHECK_GT(width, 0U);
+ DCHECK_GT(height, 0U);
+ DCHECK_GT(levels, 0U);
+ GLenum gl_internal_format = 0;
+ GLenum gl_format = 0;
+ GLenum gl_type = 0;
+ bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type);
+ DCHECK(r); // Was checked in the decoder.
+ GLuint gl_texture = 0;
+ glGenTextures(1, &gl_texture);
+ glBindTexture(GL_TEXTURE_2D, gl_texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1);
+ // glCompressedTexImage2D does't accept NULL as a parameter, so we need
+ // to pass in some data.
+ scoped_array<unsigned char> buffer;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format, width, height, 1, 0);
+ unsigned int size = GetMipLevelSize(mip_info);
+ buffer.reset(new unsigned char[size]);
+ memset(buffer.get(), 0, size);
+
+ unsigned int mip_width = width;
+ unsigned int mip_height = height;
+
+ for (unsigned int i = 0; i < levels; ++i) {
+ if (gl_format) {
+ glTexImage2D(GL_TEXTURE_2D, i, gl_internal_format, mip_width, mip_height,
+ 0, gl_format, gl_type, buffer.get());
+ } else {
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format, width, height, 1, i);
+ unsigned int size = GetMipLevelSize(mip_info);
+ glCompressedTexImage2D(GL_TEXTURE_2D, i, gl_internal_format, mip_width,
+ mip_height, 0, size, buffer.get());
+ }
+ mip_width = std::max(1U, mip_width >> 1);
+ mip_height = std::max(1U, mip_height >> 1);
+ }
+ return new Texture2DGL(
+ levels, format, enable_render_surfaces, flags, width, height, gl_texture);
+}
+
+// Sets data into a 2D texture resource.
+bool Texture2DGL::SetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) {
+ if (level >= levels())
+ return false;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level);
+ SetImageHelper helper;
+ if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data))
+ return false;
+
+ GLenum gl_internal_format = 0;
+ GLenum gl_format = 0;
+ GLenum gl_type = 0;
+ bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type);
+ DCHECK(r);
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ if (gl_format) {
+ glTexSubImage2D(GL_TEXTURE_2D, level, volume.x, volume.y, volume.width,
+ volume.height, gl_format, gl_type, helper.image_data());
+ } else {
+ glCompressedTexSubImage2D(GL_TEXTURE_2D, level, volume.x, volume.y,
+ volume.width, volume.height, gl_internal_format,
+ helper.image_size(), helper.image_data());
+ }
+ return true;
+}
+
+bool Texture2DGL::GetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) {
+ if (level >= levels())
+ return false;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level);
+ GetImageHelper helper;
+ if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data))
+ return false;
+
+ GLenum gl_internal_format = 0;
+ GLenum gl_format = 0;
+ GLenum gl_type = 0;
+ bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type);
+ DCHECK(r);
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ if (gl_format) {
+ glGetTexImage(GL_TEXTURE_2D, level, gl_format, gl_type,
+ helper.image_data());
+ } else {
+ glGetCompressedTexImage(GL_TEXTURE_2D, level, helper.image_data());
+ }
+
+ helper.Finalize();
+ return true;
+}
+
+bool Texture2DGL::CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side) {
+ return false;
+}
+
+bool Texture2DGL::InstallFrameBufferObjects(
+ RenderSurfaceGL *gl_surface) {
+ ::glFramebufferTexture2DEXT(
+ GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D,
+ gl_texture_,
+ gl_surface->mip_level());
+
+ GLenum framebuffer_status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (GL_FRAMEBUFFER_COMPLETE_EXT != framebuffer_status) {
+ return false;
+ }
+
+ return true;
+}
+
+Texture3DGL *Texture3DGL::Create(unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ DCHECK_GT(width, 0U);
+ DCHECK_GT(height, 0U);
+ DCHECK_GT(depth, 0U);
+ DCHECK_GT(levels, 0U);
+ GLenum gl_internal_format = 0;
+ GLenum gl_format = 0;
+ GLenum gl_type = 0;
+ bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type);
+ DCHECK(r); // Was checked in the decoder.
+ GLuint gl_texture = 0;
+ glGenTextures(1, &gl_texture);
+ glBindTexture(GL_TEXTURE_3D, gl_texture);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, levels - 1);
+ // glCompressedTexImage3D does't accept NULL as a parameter, so we need
+ // to pass in some data.
+ scoped_array<unsigned char> buffer;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format, width, height, depth, 0);
+ unsigned int size = GetMipLevelSize(mip_info);
+ buffer.reset(new unsigned char[size]);
+ memset(buffer.get(), 0, size);
+
+ unsigned int mip_width = width;
+ unsigned int mip_height = height;
+ unsigned int mip_depth = depth;
+ for (unsigned int i = 0; i < levels; ++i) {
+ if (gl_format) {
+ glTexImage3D(GL_TEXTURE_3D, i, gl_internal_format, mip_width, mip_height,
+ mip_depth, 0, gl_format, gl_type, buffer.get());
+ } else {
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format, width, height, depth, i);
+ unsigned int size = GetMipLevelSize(mip_info);
+ glCompressedTexImage3D(GL_TEXTURE_3D, i, gl_internal_format, mip_width,
+ mip_height, mip_depth, 0, size, buffer.get());
+ }
+ mip_width = std::max(1U, mip_width >> 1);
+ mip_height = std::max(1U, mip_height >> 1);
+ mip_depth = std::max(1U, mip_depth >> 1);
+ }
+ return new Texture3DGL(levels, format, enable_render_surfaces, flags, width,
+ height, depth, gl_texture);
+}
+
+bool Texture3DGL::SetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) {
+ if (level >= levels())
+ return false;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level);
+ SetImageHelper helper;
+ if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data))
+ return false;
+
+ GLenum gl_internal_format = 0;
+ GLenum gl_format = 0;
+ GLenum gl_type = 0;
+ bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type);
+ DCHECK(r);
+ glBindTexture(GL_TEXTURE_3D, gl_texture_);
+ if (gl_format) {
+ glTexSubImage3D(GL_TEXTURE_3D, level, volume.x, volume.y, volume.z,
+ volume.width, volume.height, volume.depth,
+ gl_format, gl_type, helper.image_data());
+ } else {
+ glCompressedTexSubImage3D(GL_TEXTURE_3D, level, volume.x, volume.y,
+ volume.z, volume.width, volume.height,
+ volume.depth, gl_internal_format,
+ helper.image_size(), helper.image_data());
+ }
+ return true;
+}
+
+bool Texture3DGL::GetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) {
+ if (level >= levels())
+ return false;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level);
+ GetImageHelper helper;
+ if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data))
+ return false;
+
+ GLenum gl_internal_format = 0;
+ GLenum gl_format = 0;
+ GLenum gl_type = 0;
+ bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type);
+ DCHECK(r);
+ glBindTexture(GL_TEXTURE_3D, gl_texture_);
+ if (gl_format) {
+ glGetTexImage(GL_TEXTURE_3D, level, gl_format, gl_type,
+ helper.image_data());
+ } else {
+ glGetCompressedTexImage(GL_TEXTURE_3D, level, helper.image_data());
+ }
+
+ helper.Finalize();
+ return true;
+}
+
+bool Texture3DGL::CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side) {
+ return false;
+}
+
+bool Texture3DGL::InstallFrameBufferObjects(
+ RenderSurfaceGL *gl_surface) {
+ return false;
+}
+
+TextureCubeGL *TextureCubeGL::Create(unsigned int side,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ DCHECK_GT(side, 0U);
+ DCHECK_GT(levels, 0U);
+ GLenum gl_internal_format = 0;
+ GLenum gl_format = 0;
+ GLenum gl_type = 0;
+ bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type);
+ DCHECK(r); // Was checked in the decoder.
+ GLuint gl_texture = 0;
+ glGenTextures(1, &gl_texture);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL,
+ levels-1);
+ // glCompressedTexImage2D does't accept NULL as a parameter, so we need
+ // to pass in some data.
+ scoped_array<unsigned char> buffer;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format, side, side, 1, 0);
+ unsigned int size = GetMipLevelSize(mip_info);
+ buffer.reset(new unsigned char[size]);
+ memset(buffer.get(), 0, size);
+
+ unsigned int mip_side = side;
+ for (unsigned int i = 0; i < levels; ++i) {
+ if (gl_format) {
+ for (unsigned int face = 0; face < 6; ++face) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i,
+ gl_internal_format, mip_side, mip_side,
+ 0, gl_format, gl_type, buffer.get());
+ }
+ } else {
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format, side, side, 1, i);
+ unsigned int size = GetMipLevelSize(mip_info);
+ for (unsigned int face = 0; face < 6; ++face) {
+ glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i,
+ gl_internal_format, mip_side, mip_side, 0, size,
+ buffer.get());
+ }
+ }
+ mip_side = std::max(1U, mip_side >> 1);
+ }
+ return new TextureCubeGL(
+ levels, format, enable_render_surfaces, flags, side, gl_texture);
+}
+
+// Check that GL_TEXTURE_CUBE_MAP_POSITIVE_X + face yields the correct GLenum.
+COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFacePositiveX ==
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X, POSITIVE_X_ENUMS_DO_NOT_MATCH);
+COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFaceNegativeX ==
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X, NEGATIVE_X_ENUMS_DO_NOT_MATCH);
+COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFacePositiveY ==
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y, POSITIVE_Y_ENUMS_DO_NOT_MATCH);
+COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFaceNegativeY ==
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, NEGATIVE_Y_ENUMS_DO_NOT_MATCH);
+COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFacePositiveZ ==
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z, POSITIVE_Z_ENUMS_DO_NOT_MATCH);
+COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFaceNegativeZ ==
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, NEGATIVE_Z_ENUMS_DO_NOT_MATCH);
+
+bool TextureCubeGL::SetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) {
+ if (level >= levels())
+ return false;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level);
+ SetImageHelper helper;
+ if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data))
+ return false;
+
+ GLenum gl_internal_format = 0;
+ GLenum gl_format = 0;
+ GLenum gl_type = 0;
+ bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type);
+ DCHECK(r);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture_);
+ GLenum face_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
+ if (gl_format) {
+ glTexSubImage2D(face_target, level, volume.x, volume.y, volume.width,
+ volume.height, gl_format, gl_type, helper.image_data());
+ } else {
+ glCompressedTexSubImage2D(face_target, level, volume.x, volume.y,
+ volume.width, volume.height, gl_internal_format,
+ helper.image_size(), helper.image_data());
+ }
+ return true;
+}
+
+bool TextureCubeGL::GetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) {
+ if (level >= levels())
+ return false;
+ MipLevelInfo mip_info;
+ MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level);
+ GetImageHelper helper;
+ if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data))
+ return false;
+
+ GLenum gl_internal_format = 0;
+ GLenum gl_format = 0;
+ GLenum gl_type = 0;
+ bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type);
+ DCHECK(r);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture_);
+ GLenum face_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
+ if (gl_format) {
+ glGetTexImage(face_target, level, gl_format, gl_type,
+ helper.image_data());
+ } else {
+ glGetCompressedTexImage(face_target, level, helper.image_data());
+ }
+
+ helper.Finalize();
+ return true;
+}
+
+bool TextureCubeGL::CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side) {
+ return false;
+}
+
+bool TextureCubeGL::InstallFrameBufferObjects(
+ RenderSurfaceGL *gl_surface) {
+ ::glFramebufferTexture2DEXT(
+ GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ gl_surface->side(),
+ gl_texture_,
+ gl_surface->mip_level());
+
+ GLenum framebuffer_status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (GL_FRAMEBUFFER_COMPLETE_EXT != framebuffer_status) {
+ return false;
+ }
+
+ return true;
+}
+
+
+// Destroys a texture resource.
+parse_error::ParseError GAPIGL::DestroyTexture(ResourceId id) {
+ // Dirty effect, because this texture id may be used.
+ DirtyEffect();
+ return textures_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Creates a 2D texture resource.
+parse_error::ParseError GAPIGL::CreateTexture2D(
+ ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ Texture2DGL *texture = Texture2DGL::Create(
+ width, height, levels, format, flags, enable_render_surfaces);
+ if (!texture) return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this texture id may be used.
+ DirtyEffect();
+ textures_.Assign(id, texture);
+ return parse_error::kParseNoError;
+}
+
+// Creates a 3D texture resource.
+parse_error::ParseError GAPIGL::CreateTexture3D(
+ ResourceId id,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ Texture3DGL *texture = Texture3DGL::Create(
+ width, height, depth, levels, format, flags, enable_render_surfaces);
+ if (!texture) return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this texture id may be used.
+ DirtyEffect();
+ textures_.Assign(id, texture);
+ return parse_error::kParseNoError;
+}
+
+// Creates a cube map texture resource.
+parse_error::ParseError GAPIGL::CreateTextureCube(
+ ResourceId id,
+ unsigned int side,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces) {
+ TextureCubeGL *texture = TextureCubeGL::Create(
+ side, levels, format, flags, enable_render_surfaces);
+ if (!texture) return parse_error::kParseInvalidArguments;
+ // Dirty effect, because this texture id may be used.
+ DirtyEffect();
+ textures_.Assign(id, texture);
+ return parse_error::kParseNoError;
+}
+
+// Copies the data into a texture resource.
+parse_error::ParseError GAPIGL::SetTextureData(
+ ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) {
+ TextureGL *texture = textures_.Get(id);
+ if (!texture)
+ return parse_error::kParseInvalidArguments;
+ Volume volume = {x, y, z, width, height, depth};
+ // Dirty effect: SetData may need to call glBindTexture which will mess up the
+ // sampler parameters.
+ DirtyEffect();
+ return texture->SetData(volume, level, face, row_pitch, slice_pitch,
+ size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Copies the data from a texture resource.
+parse_error::ParseError GAPIGL::GetTextureData(
+ ResourceId id,
+ unsigned int x,
+ unsigned int y,
+ unsigned int z,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) {
+ TextureGL *texture = textures_.Get(id);
+ if (!texture)
+ return parse_error::kParseInvalidArguments;
+ Volume volume = {x, y, z, width, height, depth};
+ // Dirty effect: GetData may need to call glBindTexture which will mess up the
+ // sampler parameters.
+ DirtyEffect();
+ return texture->GetData(volume, level, face, row_pitch, slice_pitch,
+ size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+} // namespace o3d
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/texture_gl.h b/o3d/gpu/command_buffer/service/texture_gl.h
new file mode 100644
index 0000000..d3e774c
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/texture_gl.h
@@ -0,0 +1,284 @@
+/*
+ * 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 declares the TextureGL, Texture2DGL, Texture3DGL and TextureCubeGL
+// classes.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_TEXTURE_GL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_TEXTURE_GL_H_
+
+#include "gpu/command_buffer/common/gapi_interface.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/resource.h"
+#include "gpu/command_buffer/service/texture_utils.h"
+
+namespace command_buffer {
+namespace o3d {
+
+class RenderDepthStencilSurfaceGL;
+class RenderSurfaceGL;
+
+// The base class for a GL texture resource, providing access to the base GL
+// texture that can be assigned to an effect parameter or a sampler unit.
+class TextureGL : public Texture {
+ public:
+ TextureGL(texture::Type type,
+ unsigned int levels,
+ texture::Format format,
+ bool enable_render_surfaces,
+ unsigned int flags,
+ GLuint gl_texture)
+ : Texture(type, levels, format, enable_render_surfaces, flags),
+ gl_texture_(gl_texture) {}
+ virtual ~TextureGL();
+
+ // Gets the GL texture object.
+ GLuint gl_texture() const { return gl_texture_; }
+
+ // Sets data into a texture resource.
+ virtual bool SetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data) = 0;
+
+ // Gets data from a texture resource.
+ virtual bool GetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data) = 0;
+
+ // Creates the render surface, returning false if unable to.
+ virtual bool CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side) = 0;
+
+ virtual bool InstallFrameBufferObjects(
+ RenderSurfaceGL *gl_surface) = 0;
+
+ protected:
+ const GLuint gl_texture_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureGL);
+};
+
+// A 2D texture resource for GL.
+class Texture2DGL : public TextureGL {
+ public:
+ Texture2DGL(unsigned int levels,
+ texture::Format format,
+ bool enable_render_surfaces,
+ unsigned int flags,
+ unsigned int width,
+ unsigned int height,
+ GLuint gl_texture)
+ : TextureGL(texture::kTexture2d,
+ levels,
+ format,
+ enable_render_surfaces,
+ flags,
+ gl_texture),
+ width_(width),
+ height_(height) {}
+
+ // Creates a 2D texture resource.
+ static Texture2DGL *Create(unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+
+ // Sets data into a 2D texture resource.
+ virtual bool SetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data);
+
+ // Gets data from a 2D texture resource.
+ virtual bool GetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data);
+
+ // Create a render surface which matches this texture type.
+ virtual bool CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side);
+
+ virtual bool InstallFrameBufferObjects(
+ RenderSurfaceGL *gl_surface);
+
+ private:
+ unsigned int width_;
+ unsigned int height_;
+ DISALLOW_COPY_AND_ASSIGN(Texture2DGL);
+};
+
+// A 3D texture resource for GL.
+class Texture3DGL : public TextureGL {
+ public:
+ Texture3DGL(unsigned int levels,
+ texture::Format format,
+ bool enable_render_surfaces,
+ unsigned int flags,
+ unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ GLuint gl_texture)
+ : TextureGL(texture::kTexture3d,
+ levels,
+ format,
+ enable_render_surfaces,
+ flags,
+ gl_texture),
+ width_(width),
+ height_(height),
+ depth_(depth) {}
+
+ // Creates a 3D texture resource.
+ static Texture3DGL *Create(unsigned int width,
+ unsigned int height,
+ unsigned int depth,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+
+ // Sets data into a 3D texture resource.
+ virtual bool SetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data);
+
+ // Gets data from a 3D texture resource.
+ virtual bool GetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data);
+
+ // Create a render surface which matches this texture type.
+ virtual bool CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side);
+
+ virtual bool InstallFrameBufferObjects(
+ RenderSurfaceGL *gl_surface);
+
+ private:
+ unsigned int width_;
+ unsigned int height_;
+ unsigned int depth_;
+ DISALLOW_COPY_AND_ASSIGN(Texture3DGL);
+};
+
+// A cube map texture resource for GL.
+class TextureCubeGL : public TextureGL {
+ public:
+ TextureCubeGL(unsigned int levels,
+ texture::Format format,
+ bool render_surface_enabled,
+ unsigned int flags,
+ unsigned int side,
+ GLuint gl_texture)
+ : TextureGL(texture::kTextureCube,
+ levels,
+ format,
+ render_surface_enabled,
+ flags,
+ gl_texture),
+ side_(side) {}
+
+ // Creates a cube map texture resource.
+ static TextureCubeGL *Create(unsigned int side,
+ unsigned int levels,
+ texture::Format format,
+ unsigned int flags,
+ bool enable_render_surfaces);
+
+ // Sets data into a cube map texture resource.
+ virtual bool SetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ const void *data);
+
+ // Gets data from a cube map texture resource.
+ virtual bool GetData(const Volume& volume,
+ unsigned int level,
+ texture::Face face,
+ unsigned int row_pitch,
+ unsigned int slice_pitch,
+ unsigned int size,
+ void *data);
+
+ // Create a render surface which matches this texture type.
+ virtual bool CreateRenderSurface(int width,
+ int height,
+ int mip_level,
+ int side);
+
+ virtual bool InstallFrameBufferObjects(
+ RenderSurfaceGL *gl_surface);
+
+ private:
+ unsigned int side_;
+ DISALLOW_COPY_AND_ASSIGN(TextureCubeGL);
+};
+
+} // namespace o3d
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_TEXTURE_GL_H_
diff --git a/o3d/gpu/command_buffer/service/texture_utils.cc b/o3d/gpu/command_buffer/service/texture_utils.cc
new file mode 100644
index 0000000..4aac8fa
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/texture_utils.cc
@@ -0,0 +1,105 @@
+/*
+ * 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 implementation of some utilities for textures.
+
+#include "gpu/command_buffer/service/precompile.h"
+
+#include <stdlib.h>
+
+#include "gpu/command_buffer/service/texture_utils.h"
+
+namespace command_buffer {
+
+void MakeTransferInfo(TransferInfo *transfer_info,
+ const MipLevelInfo &mip_level,
+ const Volume &volume,
+ unsigned int row_pitch,
+ unsigned int slice_pitch) {
+ transfer_info->row_pitch = row_pitch;
+ transfer_info->slice_pitch = slice_pitch;
+ transfer_info->row_size =
+ volume.width / mip_level.block_size_x * mip_level.block_bpp;
+ transfer_info->slice_size = transfer_info->row_size +
+ (volume.height / mip_level.block_size_y - 1) * row_pitch;
+ transfer_info->total_size = transfer_info->slice_size +
+ (volume.depth - 1) * slice_pitch;
+ transfer_info->packed = (transfer_info->row_size == row_pitch) &&
+ (volume.depth == 1 || transfer_info->slice_size == slice_pitch);
+}
+
+void MakePackedTransferInfo(TransferInfo *transfer_info,
+ const MipLevelInfo &mip_level,
+ const Volume &volume) {
+ transfer_info->row_size =
+ volume.width / mip_level.block_size_x * mip_level.block_bpp;
+ transfer_info->row_pitch = transfer_info->row_size;
+ transfer_info->slice_size =
+ volume.height / mip_level.block_size_y * transfer_info->row_pitch;
+ transfer_info->slice_pitch = transfer_info->slice_size;
+ transfer_info->total_size = volume.depth * transfer_info->slice_pitch;
+ transfer_info->packed = true;
+}
+
+// Transfers a volume of texels.
+void TransferVolume(const Volume &volume,
+ const MipLevelInfo &mip_level,
+ const TransferInfo &dst_transfer_info,
+ void *dst_data,
+ const TransferInfo &src_transfer_info,
+ const void *src_data) {
+ DCHECK_EQ(src_transfer_info.row_size, dst_transfer_info.row_size);
+ if (src_transfer_info.packed && dst_transfer_info.packed) {
+ // fast path
+ DCHECK_EQ(src_transfer_info.total_size, dst_transfer_info.total_size);
+ DCHECK_EQ(src_transfer_info.row_pitch, dst_transfer_info.row_pitch);
+ DCHECK_EQ(src_transfer_info.slice_pitch, dst_transfer_info.slice_pitch);
+ memcpy(dst_data, src_data, src_transfer_info.total_size);
+ } else {
+ const char *src = static_cast<const char *>(src_data);
+ char *dst = static_cast<char *>(dst_data);
+ for (unsigned int slice = 0; slice < volume.depth; ++slice) {
+ const char *row_src = src;
+ char *row_dst = dst;
+ for (unsigned int row = 0; row < volume.height;
+ row += mip_level.block_size_y) {
+ memcpy(row_dst, row_src, src_transfer_info.row_size);
+ row_src += src_transfer_info.row_pitch;
+ row_dst += dst_transfer_info.row_pitch;
+ }
+ src += src_transfer_info.slice_pitch;
+ dst += dst_transfer_info.slice_pitch;
+ }
+ }
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/texture_utils.h b/o3d/gpu/command_buffer/service/texture_utils.h
new file mode 100644
index 0000000..0ace181
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/texture_utils.h
@@ -0,0 +1,156 @@
+/*
+ * 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 declares some utilities for textures, in particular to deal with
+// in-memory texture data and layout.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_
+
+#include "gpu/command_buffer/common/logging.h"
+#include "gpu/command_buffer/common/resource.h"
+
+namespace command_buffer {
+
+// Structure describing a volume of pixels.
+struct Volume {
+ unsigned int x;
+ unsigned int y;
+ unsigned int z;
+ unsigned int width;
+ unsigned int height;
+ unsigned int depth;
+};
+
+// Structure describing the dimensions and structure of a mip level.
+struct MipLevelInfo {
+ unsigned int block_bpp;
+ unsigned int block_size_x;
+ unsigned int block_size_y;
+ unsigned int width;
+ unsigned int height;
+ unsigned int depth;
+};
+
+// Structure describing a memory layout for transfers.
+struct TransferInfo {
+ unsigned int row_size; // size in bytes of a row of blocks.
+ unsigned int row_pitch; // number of bytes between 2 successive rows.
+ unsigned int slice_size; // size in bytes of a slice of data.
+ unsigned int slice_pitch; // number of bytes between 2 successive slices.
+ unsigned int total_size; // total size of the data.
+ bool packed; // indicates whether the data is tightly packed.
+};
+
+// Round a value up, so that it is divisible by the block size.
+static inline unsigned int RoundToBlockSize(unsigned int base,
+ unsigned int block) {
+ DCHECK_GT(base, 0U);
+ DCHECK_GT(block, 0U);
+ return block + base - 1 - (base - 1) % block;
+}
+
+// Fills a MipLevelInfo structure from the base texture dimensions.
+static inline void MakeMipLevelInfo(MipLevelInfo *mip_info,
+ texture::Format format,
+ unsigned int base_width,
+ unsigned int base_height,
+ unsigned int base_depth,
+ unsigned int level) {
+ mip_info->block_bpp = texture::GetBytesPerBlock(format);
+ mip_info->block_size_x = texture::GetBlockSizeX(format);
+ mip_info->block_size_y = texture::GetBlockSizeY(format);
+ mip_info->width = RoundToBlockSize(
+ texture::GetMipMapDimension(base_width, level), mip_info->block_size_x);
+ mip_info->height = RoundToBlockSize(
+ texture::GetMipMapDimension(base_height, level), mip_info->block_size_y);
+ mip_info->depth = texture::GetMipMapDimension(base_depth, level);
+}
+
+// Gets the size in bytes of a mip level.
+static inline unsigned int GetMipLevelSize(const MipLevelInfo &mip_info) {
+ return mip_info.block_bpp * mip_info.width / mip_info.block_size_x *
+ mip_info.height / mip_info.block_size_y * mip_info.depth;
+}
+
+// Checks that [x .. x+width] is contained in [0 .. mip_width], and that both x
+// and width are divisible by block_size, and that width is positive.
+static inline bool CheckDimension(unsigned int x,
+ unsigned int width,
+ unsigned int mip_width,
+ unsigned int block_size) {
+ return x < mip_width && x+width <= mip_width && x % block_size == 0 &&
+ width % block_size == 0 && width > 0;
+}
+
+// Checks that given volume fits into a mip level.
+static inline bool CheckVolume(const MipLevelInfo &mip_info,
+ const Volume &volume) {
+ return CheckDimension(volume.x, volume.width, mip_info.width,
+ mip_info.block_size_x) &&
+ CheckDimension(volume.y, volume.height, mip_info.height,
+ mip_info.block_size_y) &&
+ CheckDimension(volume.z, volume.depth, mip_info.depth, 1);
+}
+
+// Checks whether a volume fully maps a mip level.
+static inline bool IsFullVolume(const MipLevelInfo &mip_info,
+ const Volume &volume) {
+ return (volume.x == 0) && (volume.y == 0) && (volume.z == 0) &&
+ (volume.width == mip_info.width) &&
+ (volume.height == mip_info.height) &&
+ (volume.depth == mip_info.depth);
+}
+
+// Makes a transfer info from a mip level, a volume and row/slice pitches.
+void MakeTransferInfo(TransferInfo *transfer_info,
+ const MipLevelInfo &mip_level,
+ const Volume &volume,
+ unsigned int row_pitch,
+ unsigned int slice_pitch);
+
+// Makes a transfer info from a mip level and a volume, considering packed data.
+void MakePackedTransferInfo(TransferInfo *transfer_info,
+ const MipLevelInfo &mip_level,
+ const Volume &volume);
+
+// Transfers a volume of texels.
+void TransferVolume(const Volume &volume,
+ const MipLevelInfo &mip_level,
+ const TransferInfo &dst_transfer_info,
+ void *dst_data,
+ const TransferInfo &src_transfer_info,
+ const void *src_data);
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_
diff --git a/o3d/gpu/command_buffer/service/x_utils.cc b/o3d/gpu/command_buffer/service/x_utils.cc
new file mode 100644
index 0000000..b9eb9d9
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/x_utils.cc
@@ -0,0 +1,92 @@
+/*
+ * 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 class implements the XWindowWrapper class.
+
+#include "gpu/command_buffer/service/precompile.h"
+#include "gpu/command_buffer/common/cross/logging.h"
+#include "gpu/command_buffer/service/linux/x_utils.h"
+
+namespace command_buffer {
+
+bool XWindowWrapper::Initialize() {
+ XWindowAttributes attributes;
+ XGetWindowAttributes(display_, window_, &attributes);
+ XVisualInfo visual_info_template;
+ visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
+ int visual_info_count = 0;
+ XVisualInfo *visual_info_list = XGetVisualInfo(display_, VisualIDMask,
+ &visual_info_template,
+ &visual_info_count);
+ DCHECK(visual_info_list);
+ DCHECK_GT(visual_info_count, 0);
+ context_ = 0;
+ for (int i = 0; i < visual_info_count; ++i) {
+ context_ = glXCreateContext(display_, visual_info_list + i, 0,
+ True);
+ if (context_) break;
+ }
+ XFree(visual_info_list);
+ if (!context_) {
+ DLOG(ERROR) << "Couldn't create GL context.";
+ return false;
+ }
+ return true;
+}
+
+bool XWindowWrapper::MakeCurrent() {
+ if (glXMakeCurrent(display_, window_, context_) != True) {
+ glXDestroyContext(display_, context_);
+ context_ = 0;
+ DLOG(ERROR) << "Couldn't make context current.";
+ return false;
+ }
+ return true;
+}
+
+void XWindowWrapper::Destroy() {
+ Bool result = glXMakeCurrent(display_, 0, 0);
+ // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
+ // we have pending draws on an invalid window - which shouldn't be the case
+ // here.
+ DCHECK(result);
+ if (context_) {
+ glXDestroyContext(display_, context_);
+ context_ = 0;
+ }
+}
+
+void XWindowWrapper::SwapBuffers() {
+ glXSwapBuffers(display_, window_);
+}
+
+} // namespace command_buffer
diff --git a/o3d/gpu/command_buffer/service/x_utils.h b/o3d/gpu/command_buffer/service/x_utils.h
new file mode 100644
index 0000000..0d8c26a
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/x_utils.h
@@ -0,0 +1,76 @@
+/*
+ * 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 declares the XWindowWrapper class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_
+#define GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_
+
+#include <GL/glx.h>
+#include "base/basictypes.h"
+#include "gpu/command_buffer/common/cross/logging.h"
+
+namespace command_buffer {
+
+// This class is a wrapper around an X Window and associated GL context. It is
+// useful to isolate intrusive X headers, since it can be forward declared
+// (Window and GLXContext can't).
+class XWindowWrapper {
+ public:
+ XWindowWrapper(Display *display, Window window)
+ : display_(display),
+ window_(window) {
+ DCHECK(display_);
+ DCHECK(window_);
+ }
+ // Initializes the GL context.
+ bool Initialize();
+
+ // Destroys the GL context.
+ void Destroy();
+
+ // Makes the GL context current on the current thread.
+ bool MakeCurrent();
+
+ // Swaps front and back buffers.
+ void SwapBuffers();
+
+ private:
+ Display *display_;
+ Window window_;
+ GLXContext context_;
+ DISALLOW_COPY_AND_ASSIGN(XWindowWrapper);
+};
+
+} // namespace command_buffer
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_
diff --git a/o3d/gpu/gpu.gyp b/o3d/gpu/gpu.gyp
new file mode 100644
index 0000000..60b56b8
--- /dev/null
+++ b/o3d/gpu/gpu.gyp
@@ -0,0 +1,351 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ '../build/common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'command_buffer_common',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '..',
+ '../..',
+ ],
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ '../..',
+ ],
+ }, # 'all_dependent_settings'
+ 'sources': [
+ 'command_buffer/common/bitfield_helpers.h',
+ 'command_buffer/common/cmd_buffer_common.h',
+ 'command_buffer/common/cmd_buffer_common.cc',
+ 'command_buffer/common/o3d_cmd_format.h',
+ 'command_buffer/common/o3d_cmd_format.cc',
+ 'command_buffer/common/gapi_interface.h',
+ 'command_buffer/common/logging.h',
+ 'command_buffer/common/mocks.h',
+ 'command_buffer/common/resource.cc',
+ 'command_buffer/common/resource.h',
+ 'command_buffer/common/types.h',
+ ],
+ },
+ {
+ 'target_name': 'command_buffer_common_test',
+ 'type': 'none',
+ 'direct_dependent_settings': {
+ 'sources': [
+ 'command_buffer/common/bitfield_helpers_test.cc',
+ ],
+ },
+ },
+ {
+ 'target_name': 'command_buffer_client',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'command_buffer_common',
+ 'np_utils',
+ ],
+ 'sources': [
+ 'command_buffer/client/cmd_buffer_helper.cc',
+ 'command_buffer/client/cmd_buffer_helper.h',
+ 'command_buffer/client/effect_helper.cc',
+ 'command_buffer/client/effect_helper.h',
+ 'command_buffer/client/fenced_allocator.cc',
+ 'command_buffer/client/fenced_allocator.h',
+ 'command_buffer/client/id_allocator.cc',
+ 'command_buffer/client/id_allocator.h',
+ 'command_buffer/client/o3d_cmd_helper.cc',
+ 'command_buffer/client/o3d_cmd_helper.h',
+ ],
+ },
+ {
+ 'target_name': 'command_buffer_client_test',
+ 'type': 'none',
+ 'direct_dependent_settings': {
+ 'sources': [
+ 'command_buffer/client/cmd_buffer_helper_test.cc',
+ 'command_buffer/client/fenced_allocator_test.cc',
+ 'command_buffer/client/id_allocator_test.cc',
+ ],
+ },
+ },
+ {
+ 'target_name': 'command_buffer_service',
+ 'type': 'static_library',
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ 'conditions': [
+ ['OS == "win" and (renderer == "gl" or cb_service == "gl")',
+ {
+ 'include_dirs': [
+ '../../<(glewdir)/include',
+ '../../<(cgdir)/include',
+ ],
+ },
+ ],
+ ],
+ }, # 'all_dependent_settings'
+ 'dependencies': [
+ 'command_buffer_common',
+ ],
+ 'sources': [
+ 'command_buffer/service/common_decoder.cc',
+ 'command_buffer/service/common_decoder.h',
+ 'command_buffer/service/cmd_buffer_engine.h',
+ 'command_buffer/service/cmd_parser.cc',
+ 'command_buffer/service/cmd_parser.h',
+ 'command_buffer/service/effect_utils.cc',
+ 'command_buffer/service/effect_utils.h',
+ 'command_buffer/service/gapi_decoder.cc',
+ 'command_buffer/service/gapi_decoder.h',
+ 'command_buffer/service/mocks.h',
+ 'command_buffer/service/precompile.cc',
+ 'command_buffer/service/precompile.h',
+ 'command_buffer/service/resource.cc',
+ 'command_buffer/service/resource.h',
+ 'command_buffer/service/texture_utils.cc',
+ 'command_buffer/service/texture_utils.h',
+ ],
+ 'conditions': [
+ ['cb_service == "d3d9"',
+ {
+ 'include_dirs': [
+ '$(DXSDK_DIR)/Include',
+ ],
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '$(DXSDK_DIR)/Include',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '"$(DXSDK_DIR)/Lib/x86/DxErr.lib"',
+ ],
+ },
+ }, # 'all_dependent_settings'
+ 'sources': [
+ 'command_buffer/service/d3d9_utils.h',
+ 'command_buffer/service/effect_d3d9.cc',
+ 'command_buffer/service/effect_d3d9.h',
+ 'command_buffer/service/gapi_d3d9.cc',
+ 'command_buffer/service/gapi_d3d9.h',
+ 'command_buffer/service/geometry_d3d9.cc',
+ 'command_buffer/service/geometry_d3d9.h',
+ 'command_buffer/service/render_surface_d3d9.cc',
+ 'command_buffer/service/render_surface_d3d9.h',
+ 'command_buffer/service/sampler_d3d9.cc',
+ 'command_buffer/service/sampler_d3d9.h',
+ 'command_buffer/service/states_d3d9.cc',
+ 'command_buffer/service/texture_d3d9.cc',
+ 'command_buffer/service/texture_d3d9.h',
+ ], # 'sources'
+ },
+ ],
+ ['cb_service == "gl"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:gl_libs',
+ '../build/libs.gyp:cg_libs',
+ ],
+ 'sources': [
+ 'command_buffer/service/effect_gl.cc',
+ 'command_buffer/service/effect_gl.h',
+ 'command_buffer/service/gapi_gl.cc',
+ 'command_buffer/service/gapi_gl.h',
+ 'command_buffer/service/geometry_gl.cc',
+ 'command_buffer/service/geometry_gl.h',
+ 'command_buffer/service/gl_utils.h',
+ 'command_buffer/service/render_surface_gl.cc',
+ 'command_buffer/service/render_surface_gl.h',
+ 'command_buffer/service/sampler_gl.cc',
+ 'command_buffer/service/sampler_gl.h',
+ 'command_buffer/service/states_gl.cc',
+ 'command_buffer/service/texture_gl.cc',
+ 'command_buffer/service/texture_gl.h',
+ ], # 'sources'
+ },
+ ],
+ ['OS == "linux"',
+ {
+ 'sources': [
+ 'command_buffer/service/linux/x_utils.cc',
+ 'command_buffer/service/linux/x_utils.h',
+ ],
+ },
+ ],
+ ], # 'conditions'
+ },
+ {
+ 'target_name': 'command_buffer_service_test',
+ 'type': 'none',
+ 'direct_dependent_settings': {
+ 'sources': [
+ 'command_buffer/service/cmd_parser_test.cc',
+ 'command_buffer/service/resource_test.cc',
+ ],
+ },
+ },
+ {
+ 'target_name': 'np_utils',
+ 'type': '<(library)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../build/o3d_in_chrome.gyp:o3d_in_chrome',
+ ],
+ 'include_dirs': [
+ '..',
+ '../..',
+ '../../third_party/npapi',
+ ],
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ '../..',
+ '../../third_party/npapi',
+ ],
+ }, # 'all_dependent_settings'
+ 'sources': [
+ 'np_utils/default_np_object.h',
+ 'np_utils/dynamic_np_object.cc',
+ 'np_utils/dynamic_np_object.h',
+ 'np_utils/np_browser.cc',
+ 'np_utils/np_browser.h',
+ 'np_utils/np_browser_mock.h',
+ 'np_utils/np_browser_stub.cc',
+ 'np_utils/np_browser_stub.h',
+ 'np_utils/np_class.h',
+ 'np_utils/np_dispatcher.cc',
+ 'np_utils/np_dispatcher.h',
+ 'np_utils/np_dispatcher_specializations.h',
+ 'np_utils/np_headers.h',
+ 'np_utils/np_object_mock.h',
+ 'np_utils/np_object_pointer.h',
+ 'np_utils/np_plugin_object.h',
+ 'np_utils/np_plugin_object_mock.h',
+ 'np_utils/np_plugin_object_factory.cc',
+ 'np_utils/np_plugin_object_factory.h',
+ 'np_utils/np_plugin_object_factory_mock.h',
+ 'np_utils/np_utils.cc',
+ 'np_utils/np_utils.h',
+ 'np_utils/webkit_browser.h',
+ ],
+ },
+
+ # This is a standalone executable until O3D is fully moved over to using
+ # gyp. At that point these can become part of the regular O3D unit tests.
+ {
+ 'target_name': 'np_utils_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ 'np_utils',
+ '../../testing/gmock.gyp:gmock',
+ '../../testing/gmock.gyp:gmockmain',
+ '../../testing/gtest.gyp:gtest',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '../..',
+ ],
+ }, # 'all_dependent_settings'
+ 'sources': [
+ 'np_utils/dispatched_np_object_unittest.cc',
+ 'np_utils/dynamic_np_object_unittest.cc',
+ 'np_utils/np_class_unittest.cc',
+ 'np_utils/np_object_pointer_unittest.cc',
+ 'np_utils/np_utils_unittest.cc',
+ ],
+ },
+
+ # These can eventually be merged back into the gpu_plugin target. There
+ # separated for now so O3D can statically link against them and use command
+ # buffers in-process without the GPU plugin.
+ {
+ 'target_name': 'command_buffer',
+ 'type': '<(library)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ 'command_buffer_service',
+ 'np_utils',
+ ],
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '../..',
+ ],
+ }, # 'all_dependent_settings'
+ 'sources': [
+ 'gpu_plugin/command_buffer.cc',
+ 'gpu_plugin/command_buffer.h',
+ 'gpu_plugin/command_buffer_mock.h',
+ 'gpu_plugin/gpu_processor.h',
+ 'gpu_plugin/gpu_processor.cc',
+ 'gpu_plugin/gpu_processor_mock.h',
+ 'gpu_plugin/gpu_processor_win.cc',
+ ],
+ },
+
+ {
+ 'target_name': 'gpu_plugin',
+ 'type': '<(library)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ 'command_buffer',
+ 'np_utils',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'gpu_plugin/gpu_plugin.cc',
+ 'gpu_plugin/gpu_plugin.h',
+ 'gpu_plugin/gpu_plugin_object.cc',
+ 'gpu_plugin/gpu_plugin_object.h',
+ 'gpu_plugin/gpu_plugin_object_win.cc',
+ 'gpu_plugin/gpu_plugin_object_factory.cc',
+ 'gpu_plugin/gpu_plugin_object_factory.h',
+ ],
+ },
+
+ # This is a standalone executable until O3D is fully moved over to using
+ # gyp. At that point these can become part of the regular O3D unit tests.
+ {
+ 'target_name': 'gpu_plugin_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ 'command_buffer_service',
+ 'gpu_plugin',
+ 'np_utils',
+ '../../testing/gmock.gyp:gmock',
+ '../../testing/gmock.gyp:gmockmain',
+ '../../testing/gtest.gyp:gtest',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'gpu_plugin/command_buffer_unittest.cc',
+ 'gpu_plugin/gpu_plugin_unittest.cc',
+ 'gpu_plugin/gpu_plugin_object_unittest.cc',
+ 'gpu_plugin/gpu_plugin_object_factory_unittest.cc',
+ 'gpu_plugin/gpu_processor_unittest.cc',
+ ],
+ },
+ ]
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/o3d/gpu/gpu_plugin/command_buffer.cc b/o3d/gpu/gpu_plugin/command_buffer.cc
new file mode 100644
index 0000000..b293693
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/command_buffer.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/gpu_plugin/command_buffer.h"
+
+using ::base::SharedMemory;
+
+namespace gpu_plugin {
+
+CommandBuffer::CommandBuffer(NPP npp)
+ : npp_(npp),
+ size_(0),
+ get_offset_(0),
+ put_offset_(0),
+ token_(0),
+ parse_error_(0),
+ error_status_(false) {
+ // Element zero is always NULL.
+ registered_objects_.push_back(linked_ptr<SharedMemory>());
+}
+
+CommandBuffer::~CommandBuffer() {
+}
+
+bool CommandBuffer::Initialize(::base::SharedMemory* ring_buffer) {
+ DCHECK(ring_buffer);
+
+ // Fail if already initialized.
+ if (ring_buffer_.get())
+ return false;
+
+ size_t size_in_bytes = ring_buffer->max_size();
+ size_ = size_in_bytes / sizeof(int32);
+ ring_buffer_.reset(ring_buffer);
+
+ return true;
+}
+
+SharedMemory* CommandBuffer::GetRingBuffer() {
+ return ring_buffer_.get();
+}
+
+int32 CommandBuffer::GetSize() {
+ return size_;
+}
+
+int32 CommandBuffer::SyncOffsets(int32 put_offset) {
+ if (put_offset < 0 || put_offset >= size_)
+ return -1;
+
+ put_offset_ = put_offset;
+
+ if (put_offset_change_callback_.get()) {
+ put_offset_change_callback_->Run();
+ }
+
+ return get_offset_;
+}
+
+int32 CommandBuffer::GetGetOffset() {
+ return get_offset_;
+}
+
+void CommandBuffer::SetGetOffset(int32 get_offset) {
+ DCHECK(get_offset >= 0 && get_offset < size_);
+ get_offset_ = get_offset;
+}
+
+int32 CommandBuffer::GetPutOffset() {
+ return put_offset_;
+}
+
+void CommandBuffer::SetPutOffsetChangeCallback(Callback0::Type* callback) {
+ put_offset_change_callback_.reset(callback);
+}
+
+int32 CommandBuffer::CreateTransferBuffer(size_t size) {
+ linked_ptr<SharedMemory> buffer(new SharedMemory);
+ if (!buffer->Create(std::wstring(), false, false, size))
+ return -1;
+
+ if (unused_registered_object_elements_.empty()) {
+ // Check we haven't exceeded the range that fits in a 32-bit integer.
+ int32 handle = static_cast<int32>(registered_objects_.size());
+ if (handle != registered_objects_.size())
+ return -1;
+
+ registered_objects_.push_back(buffer);
+ return handle;
+ }
+
+ int32 handle = *unused_registered_object_elements_.begin();
+ unused_registered_object_elements_.erase(
+ unused_registered_object_elements_.begin());
+ DCHECK(!registered_objects_[handle].get());
+ registered_objects_[handle] = buffer;
+ return handle;
+}
+
+void CommandBuffer::DestroyTransferBuffer(int32 handle) {
+ if (handle <= 0)
+ return;
+
+ if (static_cast<size_t>(handle) >= registered_objects_.size())
+ return;
+
+ registered_objects_[handle].reset();
+ unused_registered_object_elements_.insert(handle);
+
+ // Remove all null objects from the end of the vector. This allows the vector
+ // to shrink when, for example, all objects are unregistered. Note that this
+ // loop never removes element zero, which is always NULL.
+ while (registered_objects_.size() > 1 && !registered_objects_.back().get()) {
+ registered_objects_.pop_back();
+ unused_registered_object_elements_.erase(
+ static_cast<int32>(registered_objects_.size()));
+ }
+}
+
+::base::SharedMemory* CommandBuffer::GetTransferBuffer(int32 handle) {
+ if (handle < 0)
+ return NULL;
+
+ if (static_cast<size_t>(handle) >= registered_objects_.size())
+ return NULL;
+
+ return registered_objects_[handle].get();
+}
+
+int32 CommandBuffer::ResetParseError() {
+ int32 last_error = parse_error_;
+ parse_error_ = 0;
+ return last_error;
+}
+
+void CommandBuffer::SetParseError(int32 parse_error) {
+ if (parse_error_ == 0) {
+ parse_error_ = parse_error;
+ }
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/command_buffer.h b/o3d/gpu/gpu_plugin/command_buffer.h
new file mode 100644
index 0000000..c92e0f3
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/command_buffer.h
@@ -0,0 +1,130 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_GPU_PLUGIN_COMMAND_BUFFER_H_
+#define GPU_GPU_PLUGIN_COMMAND_BUFFER_H_
+
+#include <set>
+#include <vector>
+
+#include "base/linked_ptr.h"
+#include "base/scoped_ptr.h"
+#include "base/shared_memory.h"
+#include "base/task.h"
+#include "gpu/np_utils/default_np_object.h"
+#include "gpu/np_utils/np_dispatcher.h"
+
+namespace gpu_plugin {
+
+// An NPObject that implements a shared memory command buffer and a synchronous
+// API to manage the put and get pointers.
+class CommandBuffer : public DefaultNPObject<NPObject> {
+ public:
+ explicit CommandBuffer(NPP npp);
+ virtual ~CommandBuffer();
+
+ // Initialize the command buffer with the given ring buffer. Takes ownership
+ // of ring buffer.
+ virtual bool Initialize(::base::SharedMemory* ring_buffer);
+
+ // Gets the shared memory ring buffer object for the command buffer.
+ virtual ::base::SharedMemory* GetRingBuffer();
+
+ virtual int32 GetSize();
+
+ // The writer calls this to update its put offset. This function returns the
+ // reader's most recent get offset. Does not return until after the put offset
+ // change callback has been invoked. Returns -1 if the put offset is invalid.
+ virtual int32 SyncOffsets(int32 put_offset);
+
+ // Returns the current get offset. This can be called from any thread.
+ virtual int32 GetGetOffset();
+
+ // Sets the current get offset. This can be called from any thread.
+ virtual void SetGetOffset(int32 get_offset);
+
+ // Returns the current put offset. This can be called from any thread.
+ virtual int32 GetPutOffset();
+
+ // Sets a callback that should be posted on another thread whenever the put
+ // offset is changed. The callback must not return until some progress has
+ // been made (unless the command buffer is empty), i.e. the
+ // get offset must have changed. It need not process the entire command
+ // buffer though. This allows concurrency between the writer and the reader
+ // while giving the writer a means of waiting for the reader to make some
+ // progress before attempting to write more to the command buffer. Avoiding
+ // the use of a synchronization primitive like a condition variable to
+ // synchronize reader and writer reduces the risk of deadlock.
+ // Takes ownership of callback. The callback is invoked on the plugin thread.
+ virtual void SetPutOffsetChangeCallback(Callback0::Type* callback);
+
+ // Create a shared memory transfer buffer and return a handle that uniquely
+ // identifies it or -1 on error.
+ virtual int32 CreateTransferBuffer(size_t size);
+
+ // Destroy a shared memory transfer buffer and recycle the handle.
+ virtual void DestroyTransferBuffer(int32 id);
+
+ // Get the shared memory associated with a handle.
+ virtual ::base::SharedMemory* GetTransferBuffer(int32 handle);
+
+ // Get the current token value. This is used for by the writer to defer
+ // changes to shared memory objects until the reader has reached a certain
+ // point in the command buffer. The reader is responsible for updating the
+ // token value, for example in response to an asynchronous set token command
+ // embedded in the command buffer. The default token value is zero.
+ int32 GetToken() {
+ return token_;
+ }
+
+ // Allows the reader to update the current token value.
+ void SetToken(int32 token) {
+ token_ = token;
+ }
+
+ // Get the current parse error and reset it to zero. Zero means no error. Non-
+ // zero means error. The default error status is zero.
+ int32 ResetParseError();
+
+ // Allows the reader to set the current parse error.
+ void SetParseError(int32 parse_error);
+
+ // Returns whether the command buffer is in the error state.
+ bool GetErrorStatus() {
+ return error_status_;
+ }
+
+ // Allows the reader to set the error status. Once in an error state, the
+ // command buffer cannot recover and ceases to process commands.
+ void RaiseErrorStatus() {
+ error_status_ = true;
+ }
+
+ NP_UTILS_BEGIN_DISPATCHER_CHAIN(CommandBuffer, DefaultNPObject<NPObject>)
+ NP_UTILS_DISPATCHER(GetSize, int32())
+ NP_UTILS_DISPATCHER(SyncOffsets, int32(int32 get_offset))
+ NP_UTILS_DISPATCHER(GetGetOffset, int32());
+ NP_UTILS_DISPATCHER(GetPutOffset, int32());
+ NP_UTILS_DISPATCHER(GetToken, int32());
+ NP_UTILS_DISPATCHER(ResetParseError, int32());
+ NP_UTILS_DISPATCHER(GetErrorStatus, bool());
+ NP_UTILS_END_DISPATCHER_CHAIN
+
+ private:
+ NPP npp_;
+ scoped_ptr< ::base::SharedMemory> ring_buffer_;
+ int32 size_;
+ int32 get_offset_;
+ int32 put_offset_;
+ scoped_ptr<Callback0::Type> put_offset_change_callback_;
+ std::vector<linked_ptr< ::base::SharedMemory> > registered_objects_;
+ std::set<int32> unused_registered_object_elements_;
+ int32 token_;
+ int32 parse_error_;
+ bool error_status_;
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_GPU_PLUGIN_COMMAND_BUFFER_H_
diff --git a/o3d/gpu/gpu_plugin/command_buffer_mock.h b/o3d/gpu/gpu_plugin/command_buffer_mock.h
new file mode 100644
index 0000000..bb55f52
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/command_buffer_mock.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_GPU_PLUGIN_COMMAND_BUFFER_MOCK_H_
+#define GPU_GPU_PLUGIN_COMMAND_BUFFER_MOCK_H_
+
+#include "gpu/gpu_plugin/command_buffer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu_plugin {
+
+// An NPObject that implements a shared memory command buffer and a synchronous
+// API to manage the put and get pointers.
+class MockCommandBuffer : public CommandBuffer {
+ public:
+ explicit MockCommandBuffer(NPP npp) : CommandBuffer(npp) {
+ ON_CALL(*this, GetRingBuffer())
+ .WillByDefault(testing::Return(static_cast<::base::SharedMemory*>(NULL)));
+ ON_CALL(*this, GetTransferBuffer(testing::_))
+ .WillByDefault(testing::Return(static_cast<::base::SharedMemory*>(NULL)));
+ }
+
+ MOCK_METHOD1(Initialize, bool(::base::SharedMemory* ring_buffer));
+ MOCK_METHOD0(GetRingBuffer, ::base::SharedMemory*());
+ MOCK_METHOD0(GetSize, int32());
+ MOCK_METHOD1(SyncOffsets, int32(int32 put_offset));
+ MOCK_METHOD0(GetGetOffset, int32());
+ MOCK_METHOD1(SetGetOffset, void(int32 get_offset));
+ MOCK_METHOD0(GetPutOffset, int32());
+ MOCK_METHOD1(SetPutOffsetChangeCallback, void(Callback0::Type* callback));
+ MOCK_METHOD1(CreateTransferBuffer, int32(size_t size));
+ MOCK_METHOD1(DestroyTransferBuffer, void(int32 handle));
+ MOCK_METHOD1(GetTransferBuffer, ::base::SharedMemory*(int32 handle));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCommandBuffer);
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_GPU_PLUGIN_COMMAND_BUFFER_MOCK_H_
diff --git a/o3d/gpu/gpu_plugin/command_buffer_unittest.cc b/o3d/gpu/gpu_plugin/command_buffer_unittest.cc
new file mode 100644
index 0000000..00e5640
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/command_buffer_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2006-2008 The Chromium 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 "base/thread.h"
+#include "gpu/gpu_plugin/command_buffer.h"
+#include "gpu/np_utils/np_browser_mock.h"
+#include "gpu/np_utils/dynamic_np_object.h"
+#include "gpu/np_utils/np_object_mock.h"
+#include "gpu/np_utils/np_object_pointer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using base::SharedMemory;
+using testing::_;
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+namespace gpu_plugin {
+
+class CommandBufferTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ command_buffer_ = NPCreateObject<CommandBuffer>(NULL);
+ }
+
+ MockNPBrowser mock_browser_;
+ NPObjectPointer<CommandBuffer> command_buffer_;
+};
+
+TEST_F(CommandBufferTest, NullRingBufferByDefault) {
+ EXPECT_TRUE(NULL == command_buffer_->GetRingBuffer());
+}
+
+TEST_F(CommandBufferTest, InitializesCommandBuffer) {
+ SharedMemory* ring_buffer = new SharedMemory;
+ EXPECT_TRUE(ring_buffer->Create(std::wstring(), false, false, 1024));
+ EXPECT_TRUE(command_buffer_->Initialize(ring_buffer));
+ EXPECT_TRUE(ring_buffer == command_buffer_->GetRingBuffer());
+ EXPECT_EQ(256, command_buffer_->GetSize());
+}
+
+TEST_F(CommandBufferTest, InitializeFailsSecondTime) {
+ SharedMemory* ring_buffer = new SharedMemory;
+ EXPECT_TRUE(command_buffer_->Initialize(ring_buffer));
+ EXPECT_FALSE(command_buffer_->Initialize(ring_buffer));
+}
+
+TEST_F(CommandBufferTest, GetAndPutOffsetsDefaultToZero) {
+ EXPECT_EQ(0, command_buffer_->GetGetOffset());
+ EXPECT_EQ(0, command_buffer_->GetPutOffset());
+}
+
+class MockCallback : public CallbackRunner<Tuple0> {
+ public:
+ MOCK_METHOD1(RunWithParams, void(const Tuple0&));
+};
+
+TEST_F(CommandBufferTest, CanSyncGetAndPutOffset) {
+ SharedMemory* ring_buffer = new SharedMemory;
+ ring_buffer->Create(std::wstring(), false, false, 1024);
+
+ EXPECT_TRUE(command_buffer_->Initialize(ring_buffer));
+
+ StrictMock<MockCallback>* put_offset_change_callback =
+ new StrictMock<MockCallback>;
+ command_buffer_->SetPutOffsetChangeCallback(put_offset_change_callback);
+
+ EXPECT_CALL(*put_offset_change_callback, RunWithParams(_));
+ EXPECT_EQ(0, command_buffer_->SyncOffsets(2));
+ EXPECT_EQ(2, command_buffer_->GetPutOffset());
+
+ EXPECT_CALL(*put_offset_change_callback, RunWithParams(_));
+ EXPECT_EQ(0, command_buffer_->SyncOffsets(4));
+ EXPECT_EQ(4, command_buffer_->GetPutOffset());
+
+ command_buffer_->SetGetOffset(2);
+ EXPECT_EQ(2, command_buffer_->GetGetOffset());
+ EXPECT_CALL(*put_offset_change_callback, RunWithParams(_));
+ EXPECT_EQ(2, command_buffer_->SyncOffsets(6));
+
+ EXPECT_EQ(-1, command_buffer_->SyncOffsets(-1));
+ EXPECT_EQ(-1, command_buffer_->SyncOffsets(1024));
+}
+
+TEST_F(CommandBufferTest, ZeroHandleMapsToNull) {
+ EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(0));
+}
+
+TEST_F(CommandBufferTest, NegativeHandleMapsToNull) {
+ EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(-1));
+}
+
+TEST_F(CommandBufferTest, OutOfRangeHandleMapsToNull) {
+ EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(1));
+}
+
+TEST_F(CommandBufferTest, CanCreateTransferBuffers) {
+ int32 handle = command_buffer_->CreateTransferBuffer(1024);
+ EXPECT_EQ(1, handle);
+ SharedMemory* buffer = command_buffer_->GetTransferBuffer(handle);
+ ASSERT_TRUE(NULL != buffer);
+ EXPECT_EQ(1024, buffer->max_size());
+}
+
+TEST_F(CommandBufferTest, CreateTransferBufferReturnsDistinctHandles) {
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+}
+
+TEST_F(CommandBufferTest, CreateTransferBufferReusesUnregisteredHandles) {
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+ EXPECT_EQ(2, command_buffer_->CreateTransferBuffer(1024));
+ command_buffer_->DestroyTransferBuffer(1);
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+ EXPECT_EQ(3, command_buffer_->CreateTransferBuffer(1024));
+}
+
+TEST_F(CommandBufferTest, CannotUnregisterHandleZero) {
+ command_buffer_->DestroyTransferBuffer(0);
+ EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(0));
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+}
+
+TEST_F(CommandBufferTest, CannotUnregisterNegativeHandles) {
+ command_buffer_->DestroyTransferBuffer(-1);
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+}
+
+TEST_F(CommandBufferTest, CannotUnregisterUnregisteredHandles) {
+ command_buffer_->DestroyTransferBuffer(1);
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+}
+
+// Testing this case specifically because there is an optimization that takes
+// a different code path in this case.
+TEST_F(CommandBufferTest, UnregistersLastRegisteredHandle) {
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+ command_buffer_->DestroyTransferBuffer(1);
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+}
+
+// Testing this case specifically because there is an optimization that takes
+// a different code path in this case.
+TEST_F(CommandBufferTest, UnregistersTwoLastRegisteredHandles) {
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+ EXPECT_EQ(2, command_buffer_->CreateTransferBuffer(1024));
+ command_buffer_->DestroyTransferBuffer(2);
+ command_buffer_->DestroyTransferBuffer(1);
+ EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024));
+}
+
+TEST_F(CommandBufferTest, DefaultTokenIsZero) {
+ EXPECT_EQ(0, command_buffer_->GetToken());
+}
+
+TEST_F(CommandBufferTest, CanSetToken) {
+ command_buffer_->SetToken(7);
+ EXPECT_EQ(7, command_buffer_->GetToken());
+}
+
+TEST_F(CommandBufferTest, DefaultParseErrorIsNoError) {
+ EXPECT_EQ(0, command_buffer_->ResetParseError());
+}
+
+TEST_F(CommandBufferTest, CanSetAndResetParseError) {
+ command_buffer_->SetParseError(1);
+ EXPECT_EQ(1, command_buffer_->ResetParseError());
+ EXPECT_EQ(0, command_buffer_->ResetParseError());
+}
+
+TEST_F(CommandBufferTest, DefaultErrorStatusIsFalse) {
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+}
+
+TEST_F(CommandBufferTest, CanRaiseErrorStatus) {
+ command_buffer_->RaiseErrorStatus();
+ EXPECT_TRUE(command_buffer_->GetErrorStatus());
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin.cc b/o3d/gpu/gpu_plugin/gpu_plugin.cc
new file mode 100644
index 0000000..d8cfb58
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/gpu_plugin/gpu_plugin.h"
+#include "gpu/gpu_plugin/gpu_plugin_object_factory.h"
+#include "gpu/np_utils/np_browser.h"
+#include "gpu/np_utils/np_plugin_object.h"
+#include "gpu/np_utils/np_plugin_object_factory.h"
+
+#if defined(O3D_IN_CHROME)
+#include "webkit/glue/plugins/nphostapi.h"
+#else
+#include "o3d/third_party/npapi/include/npfunctions.h"
+#endif
+
+namespace gpu_plugin {
+
+// Definitions of NPAPI plugin entry points.
+
+namespace {
+NPBrowser* g_browser;
+GPUPluginObjectFactory g_plugin_object_factory;
+
+NPError NPP_New(NPMIMEType plugin_type, NPP instance,
+ uint16 mode, int16 argc, char* argn[],
+ char* argv[], NPSavedData* saved) {
+ if (!instance)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ PluginObject* plugin_object =
+ NPPluginObjectFactory::get()->CreatePluginObject(instance, plugin_type);
+ if (!plugin_object)
+ return NPERR_GENERIC_ERROR;
+
+ instance->pdata = plugin_object;
+
+ NPError error = plugin_object->New(plugin_type, argc, argn, argv, saved);
+ if (error != NPERR_NO_ERROR) {
+ plugin_object->Release();
+ }
+
+ return error;
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData** saved) {
+ if (!instance)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ PluginObject* plugin_object = static_cast<PluginObject*>(instance->pdata);
+ NPError error = plugin_object->Destroy(saved);
+
+ if (error == NPERR_NO_ERROR) {
+ plugin_object->Release();
+ }
+
+ return error;
+}
+
+NPError NPP_SetWindow(NPP instance, NPWindow* window) {
+ if (!instance)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ PluginObject* plugin_object = static_cast<PluginObject*>(instance->pdata);
+ return plugin_object->SetWindow(window);
+}
+
+int16 NPP_HandleEvent(NPP instance, void* event) {
+ if (!instance)
+ return 0;
+
+ PluginObject* plugin_object = static_cast<PluginObject*>(instance->pdata);
+ return plugin_object->HandleEvent(static_cast<NPEvent*>(event));
+}
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
+ if (!instance)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ PluginObject* plugin_object = static_cast<PluginObject*>(instance->pdata);
+ switch (variable) {
+ case NPPVpluginScriptableNPObject:
+ *reinterpret_cast<NPObject**>(value) =
+ plugin_object->GetScriptableNPObject();
+ return NPERR_NO_ERROR;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
+ return NPERR_NO_ERROR;
+}
+}
+
+NPError NP_GetEntryPoints(NPPluginFuncs* funcs) {
+ funcs->newp = NPP_New;
+ funcs->destroy = NPP_Destroy;
+ funcs->setwindow = NPP_SetWindow;
+ funcs->event = NPP_HandleEvent;
+ funcs->getvalue = NPP_GetValue;
+ funcs->setvalue = NPP_SetValue;
+ return NPERR_NO_ERROR;
+}
+
+#if defined(OS_LINUX)
+NPError API_CALL NP_Initialize(NPNetscapeFuncs *browser_funcs,
+ NPPluginFuncs* plugin_funcs) {
+#else
+NPError NP_Initialize(NPNetscapeFuncs *browser_funcs) {
+#endif
+ if (!browser_funcs)
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ if (g_browser)
+ return NPERR_GENERIC_ERROR;
+
+#if defined(OS_LINUX)
+ NP_GetEntryPoints(plugin_funcs);
+#endif
+
+ g_browser = new NPBrowser(browser_funcs);
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NP_Shutdown() {
+ if (!g_browser)
+ return NPERR_GENERIC_ERROR;
+
+ delete g_browser;
+ g_browser = NULL;
+
+ return NPERR_NO_ERROR;
+}
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin.h b/o3d/gpu/gpu_plugin/gpu_plugin.h
new file mode 100644
index 0000000..0f90f77
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_GPU_PLUGIN_GPU_PLUGIN_H_
+#define GPU_GPU_PLUGIN_GPU_PLUGIN_H_
+
+#include "gpu/np_utils/np_headers.h"
+
+typedef struct _NPPluginFuncs NPPluginFuncs;
+typedef struct _NPNetscapeFuncs NPNetscapeFuncs;
+
+namespace gpu_plugin {
+
+// Declarations of NPAPI plugin entry points.
+
+NPError NP_GetEntryPoints(NPPluginFuncs* funcs);
+
+#if defined(OS_LINUX)
+NPError NP_Initialize(NPNetscapeFuncs *browser_funcs,
+ NPPluginFuncs* plugin_funcs);
+#else
+NPError NP_Initialize(NPNetscapeFuncs* browser_funcs);
+#endif
+
+NPError NP_Shutdown();
+
+} // namespace gpu_plugin
+
+#endif // GPU_GPU_PLUGIN_GPU_PLUGIN_H_
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin_object.cc b/o3d/gpu/gpu_plugin/gpu_plugin_object.cc
new file mode 100644
index 0000000..6a2bd6c
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin_object.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2006-2008 The Chromium 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 <stdlib.h>
+
+#include "base/logging.h"
+#include "gpu/np_utils/np_utils.h"
+#include "gpu/gpu_plugin/gpu_plugin_object.h"
+#include "gpu/gpu_plugin/gpu_processor.h"
+
+using ::base::SharedMemory;
+
+namespace gpu_plugin {
+
+const NPUTF8 GPUPluginObject::kPluginType[] =
+ "application/vnd.google.chrome.gpu-plugin";
+
+GPUPluginObject::GPUPluginObject(NPP npp)
+ : npp_(npp),
+ status_(kWaitingForNew),
+ command_buffer_(NPCreateObject<CommandBuffer>(npp)),
+ processor_(new GPUProcessor(npp, command_buffer_.Get())) {
+ memset(&window_, 0, sizeof(window_));
+}
+
+NPError GPUPluginObject::New(NPMIMEType plugin_type,
+ int16 argc,
+ char* argn[],
+ char* argv[],
+ NPSavedData* saved) {
+ if (status_ != kWaitingForNew)
+ return NPERR_GENERIC_ERROR;
+
+ status_ = kWaitingForSetWindow;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError GPUPluginObject::SetWindow(NPWindow* new_window) {
+ if (status_ == kWaitingForNew || status_ == kDestroyed)
+ return NPERR_GENERIC_ERROR;
+
+ // PlatformSpecificSetWindow advances the status depending on what happens.
+ NPError error = PlatformSpecificSetWindow(new_window);
+ if (error == NPERR_NO_ERROR) {
+ window_ = *new_window;
+
+ if (event_sync_.Get()) {
+ NPInvokeVoid(npp_,
+ event_sync_,
+ "resize",
+ static_cast<int32>(window_.width),
+ static_cast<int32>(window_.height));
+ }
+ } else {
+ memset(&window_, 0, sizeof(window_));
+ }
+
+ return error;
+}
+
+int16 GPUPluginObject::HandleEvent(NPEvent* event) {
+ return 0;
+}
+
+NPError GPUPluginObject::Destroy(NPSavedData** saved) {
+ if (status_ == kWaitingForNew || status_ == kDestroyed)
+ return NPERR_GENERIC_ERROR;
+
+ if (command_buffer_.Get()) {
+ command_buffer_->SetPutOffsetChangeCallback(NULL);
+ }
+
+ status_ = kDestroyed;
+
+ return NPERR_NO_ERROR;
+}
+
+void GPUPluginObject::Release() {
+ DCHECK(status_ == kWaitingForNew || status_ == kDestroyed);
+ NPBrowser::get()->ReleaseObject(this);
+}
+
+NPObject*GPUPluginObject::GetScriptableNPObject() {
+ NPBrowser::get()->RetainObject(this);
+ return this;
+}
+
+NPObjectPointer<NPObject> GPUPluginObject::OpenCommandBuffer() {
+ if (status_ == kInitializationSuccessful)
+ return command_buffer_;
+
+ // SetWindow must have been called before OpenCommandBuffer.
+ // PlatformSpecificSetWindow advances the status to
+ // kWaitingForOpenCommandBuffer.
+ if (status_ != kWaitingForOpenCommandBuffer)
+ return NPObjectPointer<NPObject>();
+
+ scoped_ptr<SharedMemory> ring_buffer(new SharedMemory);
+ if (!ring_buffer->Create(std::wstring(), false, false, kCommandBufferSize))
+ return NPObjectPointer<NPObject>();
+
+ if (command_buffer_->Initialize(ring_buffer.release())) {
+ if (processor_->Initialize(static_cast<HWND>(window_.window))) {
+ command_buffer_->SetPutOffsetChangeCallback(
+ NewCallback(processor_.get(),
+ &GPUProcessor::ProcessCommands));
+ status_ = kInitializationSuccessful;
+ return command_buffer_;
+ }
+ }
+
+ return NPObjectPointer<CommandBuffer>();
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin_object.h b/o3d/gpu/gpu_plugin/gpu_plugin_object.h
new file mode 100644
index 0000000..09f612d
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin_object.h
@@ -0,0 +1,132 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_GPU_PLUGIN_GPU_PLUGIN_OBJECT_H_
+#define GPU_GPU_PLUGIN_GPU_PLUGIN_OBJECT_H_
+
+#include <string>
+
+#include "base/ref_counted.h"
+#include "base/thread.h"
+#include "gpu/gpu_plugin/command_buffer.h"
+#include "gpu/gpu_plugin/gpu_processor.h"
+#include "gpu/np_utils/default_np_object.h"
+#include "gpu/np_utils/np_dispatcher.h"
+#include "gpu/np_utils/np_headers.h"
+#include "gpu/np_utils/np_plugin_object.h"
+#include "gpu/np_utils/np_utils.h"
+
+namespace gpu_plugin {
+
+// The scriptable object for the GPU plugin.
+class GPUPluginObject : public DefaultNPObject<NPObject>,
+ public PluginObject {
+ public:
+ static const int32 kCommandBufferSize = 1024 * 1024;
+
+ enum Status {
+ // In the state of waiting for the named function to be called to continue
+ // the initialization sequence.
+ kWaitingForNew,
+ kWaitingForSetWindow,
+ kWaitingForOpenCommandBuffer,
+
+ // Initialization either succeeded or failed.
+ kInitializationSuccessful,
+ kInitializationFailed,
+
+ // Destroy has now been called and the plugin object cannot be used.
+ kDestroyed,
+ };
+
+ static const NPUTF8 kPluginType[];
+
+ explicit GPUPluginObject(NPP npp);
+
+ virtual NPError New(NPMIMEType plugin_type,
+ int16 argc,
+ char* argn[],
+ char* argv[],
+ NPSavedData* saved);
+
+ virtual NPError SetWindow(NPWindow* new_window);
+ const NPWindow& GetWindow() { return window_; }
+
+ virtual int16 HandleEvent(NPEvent* event);
+
+ virtual NPError Destroy(NPSavedData** saved);
+
+ virtual void Release();
+
+ virtual NPObject* GetScriptableNPObject();
+
+ // Returns the current initialization status. See Status enum.
+ int32 GetStatus() {
+ return status_;
+ }
+
+ // Get the width of the plugin window.
+ int32 GetWidth() {
+ return window_.width;
+ }
+
+ // Get the height of the plugin window.
+ int32 GetHeight() {
+ return window_.height;
+ }
+
+ // Set the object that receives notifications of GPU plugin object events
+ // such as resize and keyboard and mouse input.
+ void SetEventSync(NPObjectPointer<NPObject> event_sync) {
+ event_sync_ = event_sync;
+ }
+
+ NPObjectPointer<NPObject> GetEventSync() {
+ return event_sync_;
+ }
+
+ // Initializes and returns the command buffer object. Returns NULL if the
+ // command buffer cannot be initialized, for example if the plugin does not
+ // yet have a window handle.
+ NPObjectPointer<NPObject> OpenCommandBuffer();
+
+ // Set the status for testing.
+ void set_status(Status status) {
+ status_ = status;
+ }
+
+ // Replace the default command buffer for testing.
+ void set_command_buffer(
+ const NPObjectPointer<CommandBuffer>& command_buffer) {
+ command_buffer_ = command_buffer;
+ }
+
+ // Replace the default GPU processor for testing.
+ void set_gpu_processor(const scoped_refptr<GPUProcessor>& processor) {
+ processor_ = processor;
+ }
+
+ NP_UTILS_BEGIN_DISPATCHER_CHAIN(GPUPluginObject, DefaultNPObject<NPObject>)
+ NP_UTILS_DISPATCHER(GetStatus, int32());
+ NP_UTILS_DISPATCHER(GetWidth, int32());
+ NP_UTILS_DISPATCHER(GetHeight, int32());
+ NP_UTILS_DISPATCHER(SetEventSync, void(NPObjectPointer<NPObject> sync));
+ NP_UTILS_DISPATCHER(GetEventSync, NPObjectPointer<NPObject>());
+ NP_UTILS_DISPATCHER(OpenCommandBuffer, NPObjectPointer<NPObject>())
+ NP_UTILS_END_DISPATCHER_CHAIN
+
+ private:
+ NPError PlatformSpecificSetWindow(NPWindow* new_window);
+
+ NPP npp_;
+ Status status_;
+ NPWindow window_;
+ NPObjectPointer<CommandBuffer> command_buffer_;
+ scoped_refptr<GPUProcessor> processor_;
+ NPObjectPointer<NPObject> event_sync_;
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_GPU_PLUGIN_GPU_PLUGIN_OBJECT_H_
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin_object_factory.cc b/o3d/gpu/gpu_plugin/gpu_plugin_object_factory.cc
new file mode 100644
index 0000000..cfdced8
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin_object_factory.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/gpu_plugin/gpu_plugin_object.h"
+#include "gpu/gpu_plugin/gpu_plugin_object_factory.h"
+#include "gpu/np_utils/np_utils.h"
+
+namespace gpu_plugin {
+
+GPUPluginObjectFactory::GPUPluginObjectFactory() {
+}
+
+GPUPluginObjectFactory::~GPUPluginObjectFactory() {
+}
+
+PluginObject* GPUPluginObjectFactory::CreatePluginObject(
+ NPP npp,
+ NPMIMEType plugin_type) {
+ if (strcmp(plugin_type, GPUPluginObject::kPluginType) == 0) {
+ return NPCreateObject<GPUPluginObject>(npp).ToReturned();
+ }
+
+ return NULL;
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin_object_factory.h b/o3d/gpu/gpu_plugin/gpu_plugin_object_factory.h
new file mode 100644
index 0000000..1a73baf
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin_object_factory.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_GPU_PLUGIN_GPU_PLUGIN_OBJECT_FACTORY_H_
+#define GPU_GPU_PLUGIN_GPU_PLUGIN_OBJECT_FACTORY_H_
+
+#include "gpu/np_utils/np_plugin_object_factory.h"
+
+namespace gpu_plugin {
+
+// Plugin object factory for creating the GPUPluginObject.
+class GPUPluginObjectFactory : public NPPluginObjectFactory {
+ public:
+ GPUPluginObjectFactory();
+ virtual ~GPUPluginObjectFactory();
+
+ virtual PluginObject* CreatePluginObject(NPP npp, NPMIMEType plugin_type);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GPUPluginObjectFactory);
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_GPU_PLUGIN_GPU_PLUGIN_OBJECT_FACTORY_H_
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin_object_factory_unittest.cc b/o3d/gpu/gpu_plugin/gpu_plugin_object_factory_unittest.cc
new file mode 100644
index 0000000..7b006c2
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin_object_factory_unittest.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/gpu_plugin/gpu_plugin_object.h"
+#include "gpu/gpu_plugin/gpu_plugin_object_factory.h"
+#include "gpu/np_utils/np_browser_stub.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu_plugin {
+
+class PluginObjectFactoryTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ factory_ = new GPUPluginObjectFactory;
+ }
+
+ virtual void TearDown() {
+ delete factory_;
+ }
+
+ StubNPBrowser stub_browser_;
+ GPUPluginObjectFactory* factory_;
+};
+
+TEST_F(PluginObjectFactoryTest, ReturnsNullForUnknownMimeType) {
+ PluginObject* plugin_object = factory_->CreatePluginObject(
+ NULL, "application/unknown");
+ EXPECT_TRUE(NULL == plugin_object);
+}
+
+TEST_F(PluginObjectFactoryTest, CreatesGPUPlugin) {
+ PluginObject* plugin_object = factory_->CreatePluginObject(
+ NULL, const_cast<NPMIMEType>(GPUPluginObject::kPluginType));
+ EXPECT_TRUE(NULL != plugin_object);
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin_object_unittest.cc b/o3d/gpu/gpu_plugin/gpu_plugin_object_unittest.cc
new file mode 100644
index 0000000..2f91225
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin_object_unittest.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/gpu_plugin/command_buffer_mock.h"
+#include "gpu/gpu_plugin/gpu_plugin_object.h"
+#include "gpu/gpu_plugin/gpu_processor_mock.h"
+#include "gpu/np_utils/np_browser_mock.h"
+#include "gpu/np_utils/dynamic_np_object.h"
+#include "gpu/np_utils/np_object_mock.h"
+#include "gpu/np_utils/np_object_pointer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+#if defined(O3D_IN_CHROME)
+#include "webkit/glue/plugins/nphostapi.h"
+#else
+#include "o3d/third_party/npapi/include/npfunctions.h"
+#endif
+
+using ::base::SharedMemory;
+
+using testing::_;
+using testing::DoAll;
+using testing::Invoke;
+using testing::NotNull;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+namespace gpu_plugin {
+
+class MockSystemNPObject : public DefaultNPObject<NPObject> {
+ public:
+ explicit MockSystemNPObject(NPP npp) {
+ }
+
+ MOCK_METHOD1(CreateSharedMemory, NPObjectPointer<NPObject>(int32 size));
+
+ NP_UTILS_BEGIN_DISPATCHER_CHAIN(MockSystemNPObject, DefaultNPObject<NPObject>)
+ NP_UTILS_DISPATCHER(CreateSharedMemory,
+ NPObjectPointer<NPObject>(int32 size))
+ NP_UTILS_END_DISPATCHER_CHAIN
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockSystemNPObject);
+};
+
+class GPUPluginObjectTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ plugin_object_ = NPCreateObject<GPUPluginObject>(NULL);
+
+ command_buffer_ = NPCreateObject<MockCommandBuffer>(NULL);
+ plugin_object_->set_command_buffer(command_buffer_);
+
+ processor_ = new MockGPUProcessor(NULL, command_buffer_.Get());
+ plugin_object_->set_gpu_processor(processor_.get());
+
+ window_object_ = NPCreateObject<DynamicNPObject>(NULL);
+ ON_CALL(mock_browser_, GetWindowNPObject(NULL))
+ .WillByDefault(Return(window_object_.ToReturned()));
+
+ chromium_object_ = NPCreateObject<DynamicNPObject>(NULL);
+ NPSetProperty(NULL, window_object_, "chromium", chromium_object_);
+
+ system_object_ = NPCreateObject<StrictMock<MockSystemNPObject> >(NULL);
+ NPSetProperty(NULL, chromium_object_, "system", system_object_);
+ }
+
+ MockNPBrowser mock_browser_;
+ NPObjectPointer<GPUPluginObject> plugin_object_;
+ NPObjectPointer<MockCommandBuffer> command_buffer_;
+ scoped_refptr<MockGPUProcessor> processor_;
+ NPObjectPointer<DynamicNPObject> window_object_;
+ NPObjectPointer<DynamicNPObject> chromium_object_;
+ NPObjectPointer<MockSystemNPObject> system_object_;
+};
+
+namespace {
+template <typename T>
+void DeleteObject(T* object) {
+ delete object;
+}
+} // namespace anonymous
+
+
+TEST_F(GPUPluginObjectTest, CanInstantiateAndDestroyPluginObject) {
+ EXPECT_EQ(GPUPluginObject::kWaitingForNew, plugin_object_->GetStatus());
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ EXPECT_EQ(GPUPluginObject::kWaitingForSetWindow, plugin_object_->GetStatus());
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL));
+
+ EXPECT_EQ(GPUPluginObject::kDestroyed, plugin_object_->GetStatus());
+}
+
+TEST_F(GPUPluginObjectTest, DestroyFailsIfNotInitialized) {
+ EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_object_->Destroy(NULL));
+}
+
+TEST_F(GPUPluginObjectTest, NewFailsIfAlreadyInitialized) {
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ EXPECT_EQ(GPUPluginObject::kWaitingForSetWindow, plugin_object_->GetStatus());
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL));
+
+ EXPECT_EQ(GPUPluginObject::kDestroyed, plugin_object_->GetStatus());
+}
+
+TEST_F(GPUPluginObjectTest, NewFailsIfObjectHasPreviouslyBeenDestroyed) {
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL));
+
+ EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ EXPECT_EQ(GPUPluginObject::kDestroyed, plugin_object_->GetStatus());
+}
+
+TEST_F(GPUPluginObjectTest, WindowIsNullBeforeSetWindowCalled) {
+ NPWindow window = plugin_object_->GetWindow();
+ EXPECT_EQ(NULL, window.window);
+}
+
+TEST_F(GPUPluginObjectTest, CanSetWindow) {
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ NPWindow window = {0};
+ window.window = &window;
+ window.x = 7;
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->SetWindow(&window));
+ EXPECT_EQ(0, memcmp(&window, &plugin_object_->GetWindow(), sizeof(window)));
+ EXPECT_EQ(GPUPluginObject::kWaitingForOpenCommandBuffer,
+ plugin_object_->GetStatus());
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL));
+}
+
+TEST_F(GPUPluginObjectTest, CanGetWindowSize) {
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ NPWindow window = {0};
+ window.window = &window;
+ window.x = 10;
+ window.y = 10;
+ window.width = 100;
+ window.height = 200;
+
+ EXPECT_EQ(0, plugin_object_->GetWidth());
+ EXPECT_EQ(0, plugin_object_->GetHeight());
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->SetWindow(&window));
+ EXPECT_EQ(100, plugin_object_->GetWidth());
+ EXPECT_EQ(200, plugin_object_->GetHeight());
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL));
+}
+
+TEST_F(GPUPluginObjectTest, SetWindowFailsIfNotInitialized) {
+ NPWindow window = {0};
+ EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_object_->SetWindow(&window));
+ EXPECT_EQ(GPUPluginObject::kWaitingForNew, plugin_object_->GetStatus());
+}
+
+TEST_F(GPUPluginObjectTest, CanGetScriptableNPObject) {
+ NPObject* scriptable_object = plugin_object_->GetScriptableNPObject();
+ EXPECT_EQ(plugin_object_.Get(), scriptable_object);
+ NPBrowser::get()->ReleaseObject(scriptable_object);
+}
+
+TEST_F(GPUPluginObjectTest, OpenCommandBufferReturnsInitializedCommandBuffer) {
+ EXPECT_CALL(*command_buffer_.Get(), Initialize(NotNull()))
+ .WillOnce(DoAll(Invoke(DeleteObject<SharedMemory>),
+ Return(true)));
+
+ EXPECT_CALL(*processor_.get(), Initialize(NULL))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(*command_buffer_.Get(), SetPutOffsetChangeCallback(NotNull()))
+ .WillOnce(Invoke(DeleteObject<Callback0::Type>));
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ // Set status as though SetWindow has been called. Avoids having to create a
+ // valid window handle to pass to SetWindow in tests.
+ plugin_object_->set_status(GPUPluginObject::kWaitingForOpenCommandBuffer);
+
+ EXPECT_EQ(command_buffer_, plugin_object_->OpenCommandBuffer());
+
+ // Calling OpenCommandBuffer again just returns the existing command buffer.
+ EXPECT_EQ(command_buffer_, plugin_object_->OpenCommandBuffer());
+
+ EXPECT_EQ(GPUPluginObject::kInitializationSuccessful,
+ plugin_object_->GetStatus());
+
+ EXPECT_CALL(*command_buffer_.Get(), SetPutOffsetChangeCallback(NULL));
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL));
+}
+
+TEST_F(GPUPluginObjectTest, OpenCommandBufferReturnsNullIfWindowNotReady) {
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ // Set status as though SetWindow has not been called.
+ plugin_object_->set_status(GPUPluginObject::kWaitingForSetWindow);
+
+ EXPECT_EQ(NPObjectPointer<NPObject>(), plugin_object_->OpenCommandBuffer());
+
+ EXPECT_EQ(GPUPluginObject::kWaitingForSetWindow, plugin_object_->GetStatus());
+}
+
+
+TEST_F(GPUPluginObjectTest,
+ OpenCommandBufferReturnsNullIfCommandBufferCannotInitialize) {
+ EXPECT_CALL(*command_buffer_.Get(), Initialize(NotNull()))
+ .WillOnce(DoAll(Invoke(DeleteObject<SharedMemory>),
+ Return(false)));
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ // Set status as though SetWindow has been called. Avoids having to create a
+ // valid window handle to pass to SetWindow in tests.
+ plugin_object_->set_status(GPUPluginObject::kWaitingForOpenCommandBuffer);
+
+ EXPECT_EQ(NPObjectPointer<NPObject>(), plugin_object_->OpenCommandBuffer());
+
+ EXPECT_EQ(GPUPluginObject::kWaitingForOpenCommandBuffer,
+ plugin_object_->GetStatus());
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL));
+}
+
+TEST_F(GPUPluginObjectTest,
+ OpenCommandBufferReturnsNullIGPUProcessorCannotInitialize) {
+ EXPECT_CALL(*command_buffer_.Get(), Initialize(NotNull()))
+ .WillOnce(DoAll(Invoke(DeleteObject<SharedMemory>),
+ Return(true)));
+
+ EXPECT_CALL(*processor_.get(), Initialize(NULL))
+ .WillOnce(Return(false));
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ // Set status as though SetWindow has been called. Avoids having to create a
+ // valid window handle to pass to SetWindow in tests.
+ plugin_object_->set_status(GPUPluginObject::kWaitingForOpenCommandBuffer);
+
+ EXPECT_EQ(NPObjectPointer<NPObject>(), plugin_object_->OpenCommandBuffer());
+
+ EXPECT_EQ(GPUPluginObject::kWaitingForOpenCommandBuffer,
+ plugin_object_->GetStatus());
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL));
+}
+
+class MockEventSync : public DefaultNPObject<NPObject> {
+ public:
+ explicit MockEventSync(NPP npp) {
+ }
+
+ MOCK_METHOD2(Resize, void(int32 width, int32 height));
+
+ NP_UTILS_BEGIN_DISPATCHER_CHAIN(MockEventSync, DefaultNPObject<NPObject>)
+ NP_UTILS_DISPATCHER(Resize, void(int32 width, int32 height))
+ NP_UTILS_END_DISPATCHER_CHAIN
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockEventSync);
+};
+
+TEST_F(GPUPluginObjectTest, SendsResizeEventOnSetWindow) {
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo",
+ 0,
+ NULL,
+ NULL,
+ NULL));
+
+ NPObjectPointer<MockEventSync> event_sync =
+ NPCreateObject<MockEventSync>(NULL);
+ plugin_object_->SetEventSync(event_sync);
+
+ EXPECT_CALL(*event_sync.Get(), Resize(100, 200));
+
+ NPWindow window = {0};
+ window.window = &window;
+ window.x = 10;
+ window.y = 10;
+ window.width = 100;
+ window.height = 200;
+
+ plugin_object_->SetWindow(&window);
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL));
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin_object_win.cc b/o3d/gpu/gpu_plugin/gpu_plugin_object_win.cc
new file mode 100644
index 0000000..7108a09
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin_object_win.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2006-2008 The Chromium 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 <windows.h>
+
+#include "gpu/gpu_plugin/gpu_plugin_object.h"
+#include "gpu/gpu_plugin/gpu_processor.h"
+
+namespace gpu_plugin {
+
+namespace {
+const LPCTSTR kPluginObjectProperty = TEXT("GPUPluginObject");
+const LPCTSTR kOriginalWindowProc = TEXT("GPUPluginObjectOriginalWindowProc");
+
+LRESULT CALLBACK WindowProc(HWND handle,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return ::DefWindowProc(handle, message, w_param, l_param);
+}
+} // namespace anonymous
+
+NPError GPUPluginObject::PlatformSpecificSetWindow(NPWindow* new_window) {
+ // Detach properties from old window and restore the original window proc.
+ if (window_.window) {
+ HWND handle = reinterpret_cast<HWND>(window_.window);
+ ::RemoveProp(handle, kPluginObjectProperty);
+
+ LONG original_window_proc = reinterpret_cast<LONG>(
+ ::GetProp(handle, kOriginalWindowProc));
+ ::SetWindowLong(handle, GWL_WNDPROC,
+ original_window_proc);
+ ::RemoveProp(handle, kOriginalWindowProc);
+ }
+
+ // Attach properties to new window and set a new window proc.
+ if (new_window->window) {
+ HWND handle = reinterpret_cast<HWND>(new_window->window);
+ ::SetProp(handle,
+ kPluginObjectProperty,
+ reinterpret_cast<HANDLE>(this));
+
+ LONG original_window_proc = ::GetWindowLong(handle, GWL_WNDPROC);
+ ::SetProp(handle,
+ kOriginalWindowProc,
+ reinterpret_cast<HANDLE>(original_window_proc));
+ ::SetWindowLong(handle, GWL_WNDPROC,
+ reinterpret_cast<LONG>(WindowProc));
+
+ status_ = kWaitingForOpenCommandBuffer;
+ } else {
+ status_ = kWaitingForSetWindow;
+ if (processor_) {
+ processor_->Destroy();
+ }
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/gpu_plugin_unittest.cc b/o3d/gpu/gpu_plugin/gpu_plugin_unittest.cc
new file mode 100644
index 0000000..7d9ae86
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_plugin_unittest.cc
@@ -0,0 +1,305 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/gpu_plugin/gpu_plugin.h"
+#include "gpu/gpu_plugin/gpu_plugin_object.h"
+#include "gpu/np_utils/np_object_mock.h"
+#include "gpu/np_utils/np_plugin_object_factory_mock.h"
+#include "gpu/np_utils/np_plugin_object_mock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(O3D_IN_CHROME)
+#include "webkit/glue/plugins/nphostapi.h"
+#else
+#include "o3d/third_party/npapi/include/npfunctions.h"
+#endif
+
+#if defined(OS_LINUX)
+#define INITIALIZE_PLUGIN_FUNCS , &plugin_funcs_
+#else
+#define INITIALIZE_PLUGIN_FUNCS
+#endif
+
+using testing::_;
+using testing::DoAll;
+using testing::NiceMock;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+namespace gpu_plugin {
+
+class GPUPluginTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ memset(&npp_, 0, sizeof(npp_));
+ memset(&browser_funcs_, 0, sizeof(browser_funcs_));
+ memset(&plugin_funcs_, 0, sizeof(plugin_funcs_));
+
+ plugin_object_factory_ = new StrictMock<MockPluginObjectFactory>;
+
+ np_class_ = NPGetClass<StrictMock<MockNPObject> >();
+ }
+
+ virtual void TearDown() {
+ delete plugin_object_factory_;
+ }
+
+ NPP_t npp_;
+ NPNetscapeFuncs browser_funcs_;
+ NPPluginFuncs plugin_funcs_;
+ MockPluginObjectFactory* plugin_object_factory_;
+ const NPClass* np_class_;
+};
+
+TEST_F(GPUPluginTest, GetEntryPointsSetsNeededFunctionPointers) {
+#if defined(OS_LINUX)
+ NPError error = gpu_plugin::NP_Initialize(&browser_funcs_,
+ &plugin_funcs_);
+ gpu_plugin::NP_Shutdown();
+#else
+ NPError error = gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+#endif
+
+ EXPECT_EQ(NPERR_NO_ERROR, error);
+ EXPECT_TRUE(NULL != plugin_funcs_.newp);
+ EXPECT_TRUE(NULL != plugin_funcs_.destroy);
+ EXPECT_TRUE(NULL != plugin_funcs_.setwindow);
+ EXPECT_TRUE(NULL != plugin_funcs_.event);
+ EXPECT_TRUE(NULL != plugin_funcs_.getvalue);
+ EXPECT_TRUE(NULL != plugin_funcs_.setvalue);
+}
+
+TEST_F(GPUPluginTest, CanInitializeAndShutdownPlugin) {
+ EXPECT_EQ(NPERR_NO_ERROR,
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS));
+ EXPECT_EQ(NPERR_NO_ERROR, gpu_plugin::NP_Shutdown());
+}
+
+TEST_F(GPUPluginTest, InitializeFailsIfBrowserFuncsIsNull) {
+ EXPECT_EQ(NPERR_INVALID_FUNCTABLE_ERROR,
+ gpu_plugin::NP_Initialize(NULL INITIALIZE_PLUGIN_FUNCS));
+}
+
+TEST_F(GPUPluginTest, InitializeFailsIfAlreadyInitialized) {
+ EXPECT_EQ(NPERR_NO_ERROR,
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS));
+ EXPECT_EQ(NPERR_GENERIC_ERROR,
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS));
+ EXPECT_EQ(NPERR_NO_ERROR, gpu_plugin::NP_Shutdown());
+}
+
+TEST_F(GPUPluginTest, ShutdownFailsIfNotInitialized) {
+ EXPECT_EQ(NPERR_GENERIC_ERROR, gpu_plugin::NP_Shutdown());
+}
+
+TEST_F(GPUPluginTest, NewReturnsErrorForInvalidInstance) {
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ EXPECT_EQ(NPERR_INVALID_INSTANCE_ERROR, plugin_funcs_.newp(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ NULL, 0, 0, NULL, NULL, NULL));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+TEST_F(GPUPluginTest, GetValueReturnsErrorForInvalidInstance) {
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ int* result = NULL;
+ EXPECT_EQ(NPERR_INVALID_INSTANCE_ERROR, plugin_funcs_.getvalue(
+ NULL, NPPVjavaClass, &result));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+TEST_F(GPUPluginTest, DestroyReturnsErrorForInvalidInstance) {
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ EXPECT_EQ(NPERR_INVALID_INSTANCE_ERROR, plugin_funcs_.destroy(NULL, NULL));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+TEST_F(GPUPluginTest, SetWindowReturnsErrorForInvalidInstance) {
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ EXPECT_EQ(NPERR_INVALID_INSTANCE_ERROR, plugin_funcs_.setwindow(NULL, NULL));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+TEST_F(GPUPluginTest, HandleEventReturnsFalseForInvalidInstance) {
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ EXPECT_EQ(0, plugin_funcs_.event(NULL, NULL));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+TEST_F(GPUPluginTest, NewCreatesAPluginObjectAndInitializesIt) {
+ StrictMock<MockPluginObject> plugin_object;
+
+ EXPECT_CALL(*plugin_object_factory_, CreatePluginObject(
+ &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType)))
+ .WillOnce(Return(&plugin_object));
+
+ NPObject scriptable_object;
+
+ EXPECT_CALL(plugin_object, New(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ 0, NULL, NULL, NULL))
+ .WillOnce(Return(NPERR_NO_ERROR));
+
+ EXPECT_CALL(plugin_object, GetScriptableNPObject())
+ .WillOnce(Return(&scriptable_object));
+
+ EXPECT_CALL(plugin_object, Destroy(static_cast<NPSavedData**>(NULL)))
+ .WillOnce(Return(NPERR_NO_ERROR));
+
+ EXPECT_CALL(plugin_object, Release());
+
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.newp(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ &npp_, 0, 0, NULL, NULL, NULL));
+
+ NPObject* result;
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.getvalue(
+ &npp_, NPPVpluginScriptableNPObject, &result));
+ EXPECT_EQ(&scriptable_object, result);
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.destroy(&npp_, NULL));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+TEST_F(GPUPluginTest, NewFailsIfPluginObjectFactoryFails) {
+ EXPECT_CALL(*plugin_object_factory_, CreatePluginObject(
+ &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType)))
+ .WillOnce(Return(static_cast<PluginObject*>(NULL)));
+
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_funcs_.newp(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ &npp_, 0, 0, NULL, NULL, NULL));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+TEST_F(GPUPluginTest, SetWindowForwardsToPluginObject) {
+ StrictMock<MockPluginObject> plugin_object;
+
+ EXPECT_CALL(*plugin_object_factory_, CreatePluginObject(
+ &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType)))
+ .WillOnce(Return(&plugin_object));
+
+ EXPECT_CALL(plugin_object, New(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ 0, NULL, NULL, NULL))
+ .WillOnce(Return(NPERR_NO_ERROR));
+
+ NPWindow window = {0};
+
+ EXPECT_CALL(plugin_object, SetWindow(&window))
+ .WillOnce(Return(NPERR_NO_ERROR));
+
+ EXPECT_CALL(plugin_object, Destroy(static_cast<NPSavedData**>(NULL)))
+ .WillOnce(Return(NPERR_NO_ERROR));
+
+ EXPECT_CALL(plugin_object, Release());
+
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.newp(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ &npp_, 0, 0, NULL, NULL, NULL));
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.setwindow(&npp_, &window));
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.destroy(&npp_, NULL));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+TEST_F(GPUPluginTest, HandleEventForwardsToPluginObject) {
+ StrictMock<MockPluginObject> plugin_object;
+
+ EXPECT_CALL(*plugin_object_factory_, CreatePluginObject(
+ &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType)))
+ .WillOnce(Return(&plugin_object));
+
+ EXPECT_CALL(plugin_object, New(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ 0, NULL, NULL, NULL))
+ .WillOnce(Return(NPERR_NO_ERROR));
+
+ NPEvent event = {0};
+
+ EXPECT_CALL(plugin_object, HandleEvent(&event))
+ .WillOnce(Return(7));
+
+ EXPECT_CALL(plugin_object, Destroy(static_cast<NPSavedData**>(NULL)))
+ .WillOnce(Return(NPERR_NO_ERROR));
+
+ EXPECT_CALL(plugin_object, Release());
+
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.newp(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ &npp_, 0, 0, NULL, NULL, NULL));
+
+ EXPECT_EQ(7, plugin_funcs_.event(&npp_, &event));
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.destroy(&npp_, NULL));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+TEST_F(GPUPluginTest, GetValueReturnsErrorForUnknownVariable) {
+ StrictMock<MockPluginObject> plugin_object;
+
+ EXPECT_CALL(*plugin_object_factory_, CreatePluginObject(
+ &npp_, const_cast<NPMIMEType>(GPUPluginObject::kPluginType)))
+ .WillOnce(Return(&plugin_object));
+
+ EXPECT_CALL(plugin_object, New(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ 0, NULL, NULL, NULL))
+ .WillOnce(Return(NPERR_NO_ERROR));
+
+ EXPECT_CALL(plugin_object, Destroy(static_cast<NPSavedData**>(NULL)))
+ .WillOnce(Return(NPERR_NO_ERROR));
+
+ EXPECT_CALL(plugin_object, Release());
+
+ gpu_plugin::NP_GetEntryPoints(&plugin_funcs_);
+ gpu_plugin::NP_Initialize(&browser_funcs_ INITIALIZE_PLUGIN_FUNCS);
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.newp(
+ const_cast<NPMIMEType>(GPUPluginObject::kPluginType),
+ &npp_, 0, 0, NULL, NULL, NULL));
+
+ int* result = NULL;
+ EXPECT_EQ(NPERR_GENERIC_ERROR, plugin_funcs_.getvalue(
+ &npp_, NPPVjavaClass, &result));
+
+ EXPECT_EQ(NPERR_NO_ERROR, plugin_funcs_.destroy(&npp_, NULL));
+
+ gpu_plugin::NP_Shutdown();
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/gpu_processor.cc b/o3d/gpu/gpu_plugin/gpu_processor.cc
new file mode 100644
index 0000000..7b97917
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_processor.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/gpu_plugin/gpu_processor.h"
+
+using ::base::SharedMemory;
+
+namespace gpu_plugin {
+
+GPUProcessor::~GPUProcessor() {
+}
+
+namespace {
+void InvokeProcessCommands(void* data) {
+ static_cast<GPUProcessor*>(data)->ProcessCommands();
+}
+} // namespace anonymous
+
+void GPUProcessor::ProcessCommands() {
+ if (command_buffer_->GetErrorStatus())
+ return;
+
+ parser_->set_put(command_buffer_->GetPutOffset());
+
+ int commands_processed = 0;
+ while (commands_processed < commands_per_update_ && !parser_->IsEmpty()) {
+ command_buffer::parse_error::ParseError parse_error =
+ parser_->ProcessCommand();
+ switch (parse_error) {
+ case command_buffer::parse_error::kParseUnknownCommand:
+ case command_buffer::parse_error::kParseInvalidArguments:
+ command_buffer_->SetParseError(parse_error);
+ break;
+
+ case command_buffer::parse_error::kParseInvalidSize:
+ case command_buffer::parse_error::kParseOutOfBounds:
+ command_buffer_->SetParseError(parse_error);
+ command_buffer_->RaiseErrorStatus();
+ return;
+ }
+
+ ++commands_processed;
+ }
+
+ command_buffer_->SetGetOffset(static_cast<int32>(parser_->get()));
+
+ if (!parser_->IsEmpty()) {
+ NPBrowser::get()->PluginThreadAsyncCall(npp_, InvokeProcessCommands, this);
+ }
+}
+
+void *GPUProcessor::GetSharedMemoryAddress(int32 shm_id) {
+ SharedMemory* shared_memory = command_buffer_->GetTransferBuffer(shm_id);
+ if (!shared_memory)
+ return NULL;
+
+ if (!shared_memory->memory()) {
+ if (!shared_memory->Map(shared_memory->max_size()))
+ return NULL;
+ }
+
+ return shared_memory->memory();
+}
+
+// TODO(apatrick): Consolidate this with the above and return both the address
+// and size.
+size_t GPUProcessor::GetSharedMemorySize(int32 shm_id) {
+ SharedMemory* shared_memory = command_buffer_->GetTransferBuffer(shm_id);
+ if (!shared_memory)
+ return 0;
+
+ return shared_memory->max_size();
+}
+
+void GPUProcessor::set_token(int32 token) {
+ command_buffer_->SetToken(token);
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/gpu_plugin/gpu_processor.h b/o3d/gpu/gpu_plugin/gpu_processor.h
new file mode 100644
index 0000000..31617b0
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_processor.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_GPU_PLUGIN_GPU_PROCESSOR_H_
+#define GPU_GPU_PLUGIN_GPU_PROCESSOR_H_
+
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/shared_memory.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/cmd_parser.h"
+#include "gpu/command_buffer/service/gapi_decoder.h"
+#include "gpu/gpu_plugin/command_buffer.h"
+#include "gpu/np_utils/np_object_pointer.h"
+
+#if defined(CB_SERVICE_D3D9)
+#include "gpu/command_buffer/service/gapi_d3d9.h"
+#elif defined(CB_SERVICE_GL)
+#include "gpu/command_buffer/service/gapi_gl.h"
+#else
+#error command buffer service not defined
+#endif
+
+namespace gpu_plugin {
+
+// This class processes commands in a command buffer. It is event driven and
+// posts tasks to the current message loop to do additional work.
+class GPUProcessor : public ::base::RefCounted<GPUProcessor>,
+ public command_buffer::CommandBufferEngine {
+ public:
+#if defined(CB_SERVICE_D3D9)
+ typedef command_buffer::o3d::GAPID3D9 GPUGAPIInterface;
+#elif defined(CB_SERVICE_GL)
+ typedef command_buffer::o3d::GAPIGL GPUGAPIInterface;
+#else
+#error command buffer service not defined
+#endif
+
+ GPUProcessor(NPP npp,
+ CommandBuffer* command_buffer);
+
+ // This constructor is for unit tests.
+ GPUProcessor(NPP npp,
+ CommandBuffer* command_buffer,
+ GPUGAPIInterface* gapi,
+ command_buffer::o3d::GAPIDecoder* decoder,
+ command_buffer::CommandParser* parser,
+ int commands_per_update);
+
+ virtual bool Initialize(HWND hwnd);
+
+ virtual ~GPUProcessor();
+
+ virtual void Destroy();
+
+ virtual void ProcessCommands();
+
+#if defined(OS_WIN)
+ virtual bool SetWindow(HWND handle, int width, int height);
+#endif
+
+ // Implementation of CommandBufferEngine.
+
+ // Gets the base address of a registered shared memory buffer.
+ // Parameters:
+ // shm_id: the identifier for the shared memory buffer.
+ virtual void *GetSharedMemoryAddress(int32 shm_id);
+
+ // Gets the size of a registered shared memory buffer.
+ // Parameters:
+ // shm_id: the identifier for the shared memory buffer.
+ virtual size_t GetSharedMemorySize(int32 shm_id);
+
+ // Sets the token value.
+ virtual void set_token(int32 token);
+
+ private:
+ NPP npp_;
+
+ // The GPUProcessor holds a weak reference to the CommandBuffer. The
+ // CommandBuffer owns the GPUProcessor and holds a strong reference to it
+ // through the ProcessCommands callback.
+ CommandBuffer* command_buffer_;
+
+ scoped_ptr< ::base::SharedMemory> mapped_ring_buffer_;
+ int commands_per_update_;
+
+ scoped_ptr<GPUGAPIInterface> gapi_;
+ scoped_ptr<command_buffer::o3d::GAPIDecoder> decoder_;
+ scoped_ptr<command_buffer::CommandParser> parser_;
+};
+
+} // namespace gpu_plugin
+
+// Callbacks to the GPUProcessor hold a reference count.
+template <typename Method>
+class CallbackStorage<gpu_plugin::GPUProcessor, Method> {
+ public:
+ CallbackStorage(gpu_plugin::GPUProcessor* obj, Method method)
+ : obj_(obj),
+ meth_(method) {
+ DCHECK(obj_);
+ obj_->AddRef();
+ }
+
+ ~CallbackStorage() {
+ obj_->Release();
+ }
+
+ protected:
+ gpu_plugin::GPUProcessor* obj_;
+ Method meth_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CallbackStorage);
+};
+
+#endif // GPU_GPU_PLUGIN_GPU_PROCESSOR_H_
diff --git a/o3d/gpu/gpu_plugin/gpu_processor_mock.h b/o3d/gpu/gpu_plugin/gpu_processor_mock.h
new file mode 100644
index 0000000..e93c155
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_processor_mock.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_GPU_PLUGIN_GPU_PROCESSOR_MOCK_H_
+#define GPU_GPU_PLUGIN_GPU_PROCESSOR_MOCK_H_
+
+#include "gpu/gpu_plugin/gpu_processor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu_plugin {
+
+class MockGPUProcessor : public GPUProcessor {
+ public:
+ MockGPUProcessor(NPP npp,
+ CommandBuffer* command_buffer)
+ : GPUProcessor(npp, command_buffer) {
+ }
+
+#if defined(OS_WIN)
+ MOCK_METHOD1(Initialize, bool(HWND handle));
+#endif
+
+ MOCK_METHOD0(Destroy, void());
+ MOCK_METHOD0(ProcessCommands, void());
+
+#if defined(OS_WIN)
+ MOCK_METHOD3(SetWindow, bool(HWND handle, int width, int height));
+#endif
+
+ MOCK_METHOD1(GetSharedMemoryAddress, void*(int32 shm_id));
+ MOCK_METHOD1(GetSharedMemorySize, size_t(int32 shm_id));
+ MOCK_METHOD1(set_token, void(int32 token));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockGPUProcessor);
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_GPU_PLUGIN_GPU_PROCESSOR_MOCK_H_
diff --git a/o3d/gpu/gpu_plugin/gpu_processor_unittest.cc b/o3d/gpu/gpu_plugin/gpu_processor_unittest.cc
new file mode 100644
index 0000000..97c44b9
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_processor_unittest.cc
@@ -0,0 +1,309 @@
+// Copyright (c) 2006-2008 The Chromium 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 "base/at_exit.h"
+#include "base/message_loop.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/gpu_plugin/command_buffer_mock.h"
+#include "gpu/gpu_plugin/gpu_processor.h"
+#include "gpu/np_utils/np_browser_mock.h"
+#include "gpu/np_utils/np_object_pointer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::base::SharedMemory;
+
+using testing::_;
+using testing::DoAll;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+namespace gpu_plugin {
+
+const size_t kRingBufferSize = 1024;
+const size_t kRingBufferEntries = kRingBufferSize / sizeof(int32);
+
+class GPUProcessorTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ shared_memory_.reset(new SharedMemory);
+ shared_memory_->Create(std::wstring(), false, false, kRingBufferSize);
+ shared_memory_->Map(kRingBufferSize);
+ buffer_ = static_cast<int32*>(shared_memory_->memory());
+
+ memset(buffer_, 0, kRingBufferSize);
+
+ // Don't mock PluginThreadAsyncCall. Have it schedule the task.
+ ON_CALL(mock_browser_, PluginThreadAsyncCall(_, _, _))
+ .WillByDefault(Invoke(&mock_browser_,
+ &MockNPBrowser::ConcretePluginThreadAsyncCall));
+
+ command_buffer_ = NPCreateObject<MockCommandBuffer>(NULL);
+ ON_CALL(*command_buffer_.Get(), GetRingBuffer())
+ .WillByDefault(Return(shared_memory_.get()));
+ ON_CALL(*command_buffer_.Get(), GetSize())
+ .WillByDefault(Return(kRingBufferEntries));
+
+#if defined(OS_WIN)
+ gapi_ = new GPUProcessor::GPUGAPIInterface;
+#endif
+
+ async_api_.reset(new StrictMock<command_buffer::AsyncAPIMock>);
+
+ decoder_ = new command_buffer::o3d::GAPIDecoder(gapi_);
+
+ parser_ = new command_buffer::CommandParser(buffer_,
+ kRingBufferEntries,
+ 0,
+ kRingBufferEntries,
+ 0,
+ async_api_.get());
+
+ processor_ = new GPUProcessor(NULL,
+ command_buffer_.Get(),
+ gapi_,
+ decoder_,
+ parser_,
+ 2);
+ }
+
+ virtual void TearDown() {
+ // Ensure that any unexpected tasks posted by the GPU processor are executed
+ // in order to fail the test.
+ MessageLoop::current()->RunAllPending();
+ }
+
+ base::AtExitManager at_exit_manager;
+ MessageLoop message_loop;
+ MockNPBrowser mock_browser_;
+ NPObjectPointer<MockCommandBuffer> command_buffer_;
+ scoped_ptr<SharedMemory> shared_memory_;
+ int32* buffer_;
+ command_buffer::o3d::GAPIDecoder* decoder_;
+ command_buffer::CommandParser* parser_;
+ scoped_ptr<command_buffer::AsyncAPIMock> async_api_;
+ scoped_refptr<GPUProcessor> processor_;
+
+#if defined(OS_WIN)
+ GPUProcessor::GPUGAPIInterface* gapi_;
+#endif
+};
+
+TEST_F(GPUProcessorTest, ProcessorDoesNothingIfRingBufferIsEmpty) {
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(0));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(0));
+
+ processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::parse_error::kParseNoError,
+ command_buffer_->ResetParseError());
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+}
+
+TEST_F(GPUProcessorTest, ProcessesOneCommand) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 2;
+ buffer_[1] = 123;
+
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(2));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(2));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
+ .WillOnce(Return(command_buffer::parse_error::kParseNoError));
+
+ processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::parse_error::kParseNoError,
+ command_buffer_->ResetParseError());
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+}
+
+TEST_F(GPUProcessorTest, ProcessesTwoCommands) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 2;
+ buffer_[1] = 123;
+ header[2].command = 8;
+ header[2].size = 1;
+
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(3));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(3));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
+ .WillOnce(Return(command_buffer::parse_error::kParseNoError));
+
+ EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2]))
+ .WillOnce(Return(command_buffer::parse_error::kParseNoError));
+
+ processor_->ProcessCommands();
+}
+
+TEST_F(GPUProcessorTest, PostsTaskToFinishRemainingCommands) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 2;
+ buffer_[1] = 123;
+ header[2].command = 8;
+ header[2].size = 1;
+ header[3].command = 9;
+ header[3].size = 1;
+
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(4));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
+ .WillOnce(Return(command_buffer::parse_error::kParseNoError));
+
+ EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2]))
+ .WillOnce(Return(command_buffer::parse_error::kParseNoError));
+
+ EXPECT_CALL(*command_buffer_, SetGetOffset(3));
+
+ processor_->ProcessCommands();
+
+ // ProcessCommands is called a second time when the pending task is run.
+
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(4));
+
+ EXPECT_CALL(*async_api_, DoCommand(9, 0, &buffer_[3]))
+ .WillOnce(Return(command_buffer::parse_error::kParseNoError));
+
+ EXPECT_CALL(*command_buffer_, SetGetOffset(4));
+
+ MessageLoop::current()->RunAllPending();
+}
+
+TEST_F(GPUProcessorTest, SetsErrorCodeOnCommandBuffer) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 1;
+
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(1));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(1));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
+ .WillOnce(Return(
+ command_buffer::parse_error::kParseUnknownCommand));
+
+ processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::parse_error::kParseUnknownCommand,
+ command_buffer_->ResetParseError());
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+}
+
+TEST_F(GPUProcessorTest,
+ RecoverableParseErrorsAreNotClearedByFollowingSuccessfulCommands) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 1;
+ header[1].command = 8;
+ header[1].size = 1;
+
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(2));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(2));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
+ .WillOnce(Return(
+ command_buffer::parse_error::kParseUnknownCommand));
+
+ EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[1]))
+ .WillOnce(Return(command_buffer::parse_error::kParseNoError));
+
+ processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::parse_error::kParseUnknownCommand,
+ command_buffer_->ResetParseError());
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
+}
+
+TEST_F(GPUProcessorTest, UnrecoverableParseErrorsRaiseTheErrorStatus) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 1;
+ header[1].command = 8;
+ header[1].size = 1;
+
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(2));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
+ .WillOnce(Return(command_buffer::parse_error::kParseInvalidSize));
+
+ processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::parse_error::kParseInvalidSize,
+ command_buffer_->ResetParseError());
+ EXPECT_TRUE(command_buffer_->GetErrorStatus());
+}
+
+TEST_F(GPUProcessorTest, ProcessCommandsDoesNothingAfterUnrecoverableError) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 1;
+ header[1].command = 8;
+ header[1].size = 1;
+
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(2));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
+ .WillOnce(Return(command_buffer::parse_error::kParseInvalidSize));
+
+ processor_->ProcessCommands();
+ processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::parse_error::kParseInvalidSize,
+ command_buffer_->ResetParseError());
+ EXPECT_TRUE(command_buffer_->GetErrorStatus());
+}
+
+TEST_F(GPUProcessorTest, CanGetAddressOfSharedMemory) {
+ EXPECT_CALL(*command_buffer_.Get(), GetTransferBuffer(7))
+ .WillOnce(Return(shared_memory_.get()));
+
+ EXPECT_EQ(&buffer_[0], processor_->GetSharedMemoryAddress(7));
+}
+
+ACTION_P2(SetPointee, address, value) {
+ *address = value;
+}
+
+TEST_F(GPUProcessorTest, GetAddressOfSharedMemoryMapsMemoryIfUnmapped) {
+ EXPECT_CALL(*command_buffer_.Get(), GetTransferBuffer(7))
+ .WillOnce(Return(shared_memory_.get()));
+
+ EXPECT_EQ(&buffer_[0], processor_->GetSharedMemoryAddress(7));
+}
+
+TEST_F(GPUProcessorTest, CanGetSizeOfSharedMemory) {
+ EXPECT_CALL(*command_buffer_.Get(), GetTransferBuffer(7))
+ .WillOnce(Return(shared_memory_.get()));
+
+ EXPECT_EQ(kRingBufferSize, processor_->GetSharedMemorySize(7));
+}
+
+TEST_F(GPUProcessorTest, SetTokenForwardsToCommandBuffer) {
+ processor_->set_token(7);
+ EXPECT_EQ(7, command_buffer_->GetToken());
+}
+
+} // namespace gpu_plugin \ No newline at end of file
diff --git a/o3d/gpu/gpu_plugin/gpu_processor_win.cc b/o3d/gpu/gpu_plugin/gpu_processor_win.cc
new file mode 100644
index 0000000..4c62098
--- /dev/null
+++ b/o3d/gpu/gpu_plugin/gpu_processor_win.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2006-2008 The Chromium 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 <windows.h>
+
+#include "gpu/gpu_plugin/gpu_processor.h"
+
+using ::base::SharedMemory;
+
+namespace gpu_plugin {
+
+GPUProcessor::GPUProcessor(NPP npp,
+ CommandBuffer* command_buffer)
+ : npp_(npp),
+ command_buffer_(command_buffer),
+ commands_per_update_(100) {
+ DCHECK(command_buffer);
+ gapi_.reset(new GPUGAPIInterface);
+ decoder_.reset(new command_buffer::o3d::GAPIDecoder(gapi_.get()));
+ decoder_->set_engine(this);
+}
+
+GPUProcessor::GPUProcessor(NPP npp,
+ CommandBuffer* command_buffer,
+ GPUGAPIInterface* gapi,
+ command_buffer::o3d::GAPIDecoder* decoder,
+ command_buffer::CommandParser* parser,
+ int commands_per_update)
+ : npp_(npp),
+ command_buffer_(command_buffer),
+ commands_per_update_(commands_per_update) {
+ DCHECK(command_buffer);
+ gapi_.reset(gapi);
+ decoder_.reset(decoder);
+ parser_.reset(parser);
+}
+
+bool GPUProcessor::Initialize(HWND handle) {
+ DCHECK(handle);
+
+ // Cannot reinitialize.
+ if (gapi_->hwnd() != NULL)
+ return false;
+
+ // Map the ring buffer and create the parser.
+ SharedMemory* ring_buffer = command_buffer_->GetRingBuffer();
+ if (ring_buffer) {
+ size_t size = ring_buffer->max_size();
+ if (!ring_buffer->Map(size)) {
+ return false;
+ }
+
+ void* ptr = ring_buffer->memory();
+ parser_.reset(new command_buffer::CommandParser(ptr, size, 0, size, 0,
+ decoder_.get()));
+ } else {
+ parser_.reset(new command_buffer::CommandParser(NULL, 0, 0, 0, 0,
+ decoder_.get()));
+ }
+
+ // Initialize GAPI immediately if the window handle is valid.
+ gapi_->set_hwnd(handle);
+ return gapi_->Initialize();
+}
+
+void GPUProcessor::Destroy() {
+ // Destroy GAPI if window handle has not already become invalid.
+ if (gapi_->hwnd()) {
+ gapi_->Destroy();
+ gapi_->set_hwnd(NULL);
+ }
+}
+
+bool GPUProcessor::SetWindow(HWND handle, int width, int height) {
+ if (handle == NULL) {
+ // Destroy GAPI when the window handle becomes invalid.
+ Destroy();
+ return true;
+ } else {
+ return Initialize(handle);
+ }
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/default_np_object.h b/o3d/gpu/np_utils/default_np_object.h
new file mode 100644
index 0000000..575dabc
--- /dev/null
+++ b/o3d/gpu/np_utils/default_np_object.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_DEFAULT_NP_OBJECT_H_
+#define GPU_NP_UTILS_DEFAULT_NP_OBJECT_H_
+
+#include "base/basictypes.h"
+#include "gpu/np_utils/np_headers.h"
+
+namespace gpu_plugin {
+
+class BaseNPDispatcher;
+
+// This class implements each of the functions in the NPClass interface. They
+// all return error by default. Note that these are not virtual functions and
+// this is not an interface. This class can be used as a mixin so that an
+// NPObject class does not need to implement every NPClass function but rather
+// inherits a default from DefaultNPObject.
+template <typename RootClass>
+class DefaultNPObject : public RootClass {
+ public:
+ void Invalidate() {}
+
+ bool HasMethod(NPIdentifier name) {
+ return false;
+ }
+
+ bool Invoke(NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ return false;
+ }
+
+ bool InvokeDefault(const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ return false;
+ }
+
+ bool HasProperty(NPIdentifier name) {
+ return false;
+ }
+
+ bool GetProperty(NPIdentifier name, NPVariant* result) {
+ return false;
+ }
+
+ bool SetProperty(NPIdentifier name, const NPVariant* value) {
+ return false;
+ }
+
+ bool RemoveProperty(NPIdentifier name) {
+ return false;
+ }
+
+ bool Enumerate(NPIdentifier** names,
+ uint32_t* count) {
+ *names = NULL;
+ *count = 0;
+ return true;
+ }
+
+ bool Construct(const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ return false;
+ }
+
+ static BaseNPDispatcher* GetDispatcherChain() {
+ return NULL;
+ }
+
+ protected:
+ DefaultNPObject() {}
+ virtual ~DefaultNPObject() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DefaultNPObject);
+};
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_DEFAULT_NP_OBJECT_H_
diff --git a/o3d/gpu/np_utils/dispatched_np_object_unittest.cc b/o3d/gpu/np_utils/dispatched_np_object_unittest.cc
new file mode 100644
index 0000000..d4b2f96
--- /dev/null
+++ b/o3d/gpu/np_utils/dispatched_np_object_unittest.cc
@@ -0,0 +1,403 @@
+// Copyright (c) 2006-2008 The Chromium 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 <string>
+
+#include "gpu/np_utils/default_np_object.h"
+#include "gpu/np_utils/np_browser_stub.h"
+#include "gpu/np_utils/np_dispatcher.h"
+#include "gpu/np_utils/np_object_mock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+using testing::StrictMock;
+
+namespace gpu_plugin {
+
+// This mock class has a dispatcher chain with an entry for each mocked
+// function. The tests that follow that invoking an NPAPI method calls the
+// corresponding mocked member function.
+class MockDispatchedNPObject : public DefaultNPObject<NPObject> {
+ public:
+ explicit MockDispatchedNPObject(NPP npp) {
+ }
+
+ MOCK_METHOD0(VoidReturnNoParams, void());
+ MOCK_METHOD1(VoidReturnBoolParam, void(bool));
+ MOCK_METHOD1(VoidReturnIntParam, void(int));
+ MOCK_METHOD1(VoidReturnFloatParam, void(float));
+ MOCK_METHOD1(VoidReturnDoubleParam, void(double));
+ MOCK_METHOD1(VoidReturnStringParam, void(std::string));
+ MOCK_METHOD1(VoidReturnObjectParam, void(NPObjectPointer<NPObject>));
+ MOCK_METHOD2(VoidReturnTwoParams, void(bool, int));
+ MOCK_METHOD0(Overloaded, void());
+ MOCK_METHOD1(Overloaded, void(bool));
+ MOCK_METHOD1(Overloaded, void(std::string));
+ MOCK_METHOD0(BoolReturn, bool());
+ MOCK_METHOD0(IntReturn, int());
+ MOCK_METHOD0(FloatReturn, float());
+ MOCK_METHOD0(DoubleReturn, double());
+ MOCK_METHOD0(StringReturn, std::string());
+ MOCK_METHOD0(ObjectReturn, NPObjectPointer<NPObject>());
+
+ NP_UTILS_BEGIN_DISPATCHER_CHAIN(MockDispatchedNPObject, DefaultNPObject<NPObject>)
+ NP_UTILS_DISPATCHER(VoidReturnNoParams, void())
+ NP_UTILS_DISPATCHER(VoidReturnBoolParam, void(bool))
+ NP_UTILS_DISPATCHER(VoidReturnIntParam, void(int))
+ NP_UTILS_DISPATCHER(VoidReturnFloatParam, void(float))
+ NP_UTILS_DISPATCHER(VoidReturnDoubleParam, void(double))
+ NP_UTILS_DISPATCHER(VoidReturnStringParam, void(std::string))
+ NP_UTILS_DISPATCHER(VoidReturnObjectParam, void(NPObjectPointer<NPObject>))
+ NP_UTILS_DISPATCHER(VoidReturnTwoParams, void(bool, int))
+ NP_UTILS_DISPATCHER(Overloaded, void())
+ NP_UTILS_DISPATCHER(Overloaded, void(bool))
+ NP_UTILS_DISPATCHER(Overloaded, void(std::string))
+ NP_UTILS_DISPATCHER(BoolReturn, bool())
+ NP_UTILS_DISPATCHER(IntReturn, int())
+ NP_UTILS_DISPATCHER(FloatReturn, float())
+ NP_UTILS_DISPATCHER(DoubleReturn, double())
+ NP_UTILS_DISPATCHER(StringReturn, std::string())
+ NP_UTILS_DISPATCHER(ObjectReturn, NPObjectPointer<NPObject>());
+ NP_UTILS_END_DISPATCHER_CHAIN
+};
+
+class DispatchedNPObjectTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ object_ = NPCreateObject<StrictMock<MockDispatchedNPObject> >(NULL);
+ passed_object_ = NPCreateObject<MockNPObject>(NULL);
+
+ for (int i = 0; i != arraysize(args_); ++i) {
+ NULL_TO_NPVARIANT(args_[i]);
+ }
+ NULL_TO_NPVARIANT(result_);
+ }
+
+ StubNPBrowser stub_browser_;
+ NPVariant args_[3];
+ NPVariant result_;
+ NPObjectPointer<MockDispatchedNPObject> object_;
+ NPObjectPointer<NPObject> passed_object_;
+};
+
+TEST_F(DispatchedNPObjectTest, CannotInvokeMissingFunction) {
+ EXPECT_FALSE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("missing"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnNoParams) {
+ EXPECT_CALL(*object_, VoidReturnNoParams());
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnNoParams"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest,
+ CannotInvokeVoidReturnNoParamsWithTooManyParams) {
+ EXPECT_FALSE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnNoParams"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnIntParam) {
+ EXPECT_CALL(*object_, VoidReturnIntParam(7));
+
+ INT32_TO_NPVARIANT(7, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnIntParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnBoolParam) {
+ EXPECT_CALL(*object_, VoidReturnBoolParam(true));
+
+ BOOLEAN_TO_NPVARIANT(true, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnBoolParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnFloatParamWithDoubleParam) {
+ EXPECT_CALL(*object_, VoidReturnFloatParam(7.0f));
+
+ DOUBLE_TO_NPVARIANT(7.0, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnFloatParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnFloatParamWithIntParam) {
+ EXPECT_CALL(*object_, VoidReturnFloatParam(7.0f));
+
+ INT32_TO_NPVARIANT(7, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnFloatParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnDoubleParamWithDoubleParam) {
+ EXPECT_CALL(*object_, VoidReturnDoubleParam(7.0));
+
+ DOUBLE_TO_NPVARIANT(7.0, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnDoubleParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnDoubleParamWithIntParam) {
+ EXPECT_CALL(*object_, VoidReturnDoubleParam(7.0f));
+
+ INT32_TO_NPVARIANT(7, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnDoubleParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnStringParam) {
+ EXPECT_CALL(*object_, VoidReturnStringParam(std::string("hello")));
+
+ STRINGZ_TO_NPVARIANT("hello", args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnStringParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnObjectParamWithObject) {
+ EXPECT_CALL(*object_, VoidReturnObjectParam(passed_object_));
+
+ OBJECT_TO_NPVARIANT(passed_object_.Get(), args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnObjectParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnObjectParamWithNull) {
+ EXPECT_CALL(
+ *object_,
+ VoidReturnObjectParam(NPObjectPointer<NPObject>()));
+
+ NULL_TO_NPVARIANT(args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnObjectParam"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeVoidReturnTwoParams) {
+ EXPECT_CALL(*object_, VoidReturnTwoParams(false, 7));
+
+ BOOLEAN_TO_NPVARIANT(false, args_[0]);
+ INT32_TO_NPVARIANT(7, args_[1]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("voidReturnTwoParams"),
+ args_,
+ 2,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeOverloadedWithNoParams) {
+ EXPECT_CALL(*object_, Overloaded());
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("overloaded"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeOverloadedWithOneStringParam) {
+ EXPECT_CALL(*object_, Overloaded(std::string("hello")));
+
+ STRINGZ_TO_NPVARIANT("hello", args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("overloaded"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeOverloadedWithOneBoolParam) {
+ EXPECT_CALL(*object_, Overloaded(true));
+
+ BOOLEAN_TO_NPVARIANT(true, args_[0]);
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("overloaded"),
+ args_,
+ 1,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_VOID(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeBoolReturn) {
+ EXPECT_CALL(*object_, BoolReturn()).WillOnce(Return(true));
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("boolReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_BOOLEAN(result_));
+ EXPECT_TRUE(NPVARIANT_TO_BOOLEAN(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeIntReturn) {
+ EXPECT_CALL(*object_, IntReturn()).WillOnce(Return(7));
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("intReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_INT32(result_));
+ EXPECT_EQ(7, NPVARIANT_TO_INT32(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeFloatReturn) {
+ EXPECT_CALL(*object_, FloatReturn()).WillOnce(Return(7.0f));
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("floatReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_DOUBLE(result_));
+ EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeDoubleReturn) {
+ EXPECT_CALL(*object_, DoubleReturn()).WillOnce(Return(7.0));
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("doubleReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_DOUBLE(result_));
+ EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeStringReturn) {
+ EXPECT_CALL(*object_, StringReturn()).WillOnce(Return(std::string("hello")));
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("stringReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_STRING(result_));
+
+ NPString& str = NPVARIANT_TO_STRING(result_);
+ EXPECT_EQ(std::string("hello"),
+ std::string(str.UTF8Characters, str.UTF8Length));
+
+ // Callee is responsible for releasing string.
+ NPBrowser::get()->ReleaseVariantValue(&result_);
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeObjectReturnWithObject) {
+ EXPECT_CALL(*object_, ObjectReturn()).WillOnce(Return(passed_object_));
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("objectReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_OBJECT(result_));
+ EXPECT_EQ(passed_object_.Get(), NPVARIANT_TO_OBJECT(result_));
+
+ NPBrowser::get()->ReleaseVariantValue(&result_);
+}
+
+TEST_F(DispatchedNPObjectTest, CanInvokeObjectReturnWithNull) {
+ EXPECT_CALL(*object_, ObjectReturn())
+ .WillOnce(Return(NPObjectPointer<NPObject>()));
+
+ EXPECT_TRUE(object_->Invoke(
+ NPBrowser::get()->GetStringIdentifier("objectReturn"),
+ NULL,
+ 0,
+ &result_));
+ EXPECT_TRUE(NPVARIANT_IS_NULL(result_));
+}
+
+TEST_F(DispatchedNPObjectTest, HasMethodReturnsTrueIfMatchingMemberVariable) {
+ EXPECT_TRUE(object_->HasMethod(
+ NPBrowser::get()->GetStringIdentifier("objectReturn")));
+}
+
+TEST_F(DispatchedNPObjectTest, HasMethodReturnsTrueIfNoMatchingMemberVariable) {
+ EXPECT_FALSE(object_->HasMethod(
+ NPBrowser::get()->GetStringIdentifier("missing")));
+}
+
+TEST_F(DispatchedNPObjectTest, EnumeratesAllAvailableMethods) {
+ NPIdentifier* names;
+ uint32_t num_names;
+ ASSERT_TRUE(object_->Enumerate(&names, &num_names));
+
+ // Don't compare all of them; this test would need to change every time new
+ // dispatchers were added to the test NPObject class. Just compare the first
+ // registered (last in the dispatcher chain) and that more than one is
+ // returned.
+ EXPECT_GT(num_names, 1u);
+ EXPECT_EQ(NPBrowser::get()->GetStringIdentifier("voidReturnNoParams"),
+ names[num_names - 1]);
+
+ NPBrowser::get()->MemFree(names);
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/dynamic_np_object.cc b/o3d/gpu/np_utils/dynamic_np_object.cc
new file mode 100644
index 0000000..153c189
--- /dev/null
+++ b/o3d/gpu/np_utils/dynamic_np_object.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/np_utils/dynamic_np_object.h"
+
+namespace gpu_plugin {
+
+DynamicNPObject::DynamicNPObject(NPP npp) {
+}
+
+void DynamicNPObject::Invalidate() {
+ for (PropertyMap::iterator it = properties_.begin();
+ it != properties_.end();
+ ++it) {
+ it->second.Invalidate();
+ }
+}
+
+bool DynamicNPObject::HasProperty(NPIdentifier name) {
+ PropertyMap::iterator it = properties_.find(name);
+ return it != properties_.end();
+}
+
+bool DynamicNPObject::GetProperty(NPIdentifier name, NPVariant* result) {
+ PropertyMap::iterator it = properties_.find(name);
+ if (it == properties_.end())
+ return false;
+
+ it->second.CopyTo(result);
+ return true;
+}
+
+bool DynamicNPObject::SetProperty(NPIdentifier name, const NPVariant* value) {
+ properties_[name] = *value;
+ return true;
+}
+
+bool DynamicNPObject::RemoveProperty(NPIdentifier name) {
+ properties_.erase(name);
+ return false;
+}
+
+bool DynamicNPObject::Enumerate(NPIdentifier** names, uint32_t* count) {
+ *names = static_cast<NPIdentifier*>(
+ NPBrowser::get()->MemAlloc(properties_.size() * sizeof(*names)));
+ *count = properties_.size();
+
+ int i = 0;
+ for (PropertyMap::iterator it = properties_.begin();
+ it != properties_.end();
+ ++it) {
+ (*names)[i] = it->first;
+ ++i;
+ }
+
+ return true;
+}
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/dynamic_np_object.h b/o3d/gpu/np_utils/dynamic_np_object.h
new file mode 100644
index 0000000..8dd4892
--- /dev/null
+++ b/o3d/gpu/np_utils/dynamic_np_object.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_DYNAMIC_NP_OBJECT_H_
+#define GPU_NP_UTILS_DYNAMIC_NP_OBJECT_H_
+
+#include <map>
+
+#include "gpu/np_utils/default_np_object.h"
+#include "gpu/np_utils/np_utils.h"
+
+namespace gpu_plugin {
+
+// NPObjects of this type have a dictionary of property name / variant pairs
+// that can be changed at runtime through NPAPI.
+class DynamicNPObject : public DefaultNPObject<NPObject> {
+ public:
+ explicit DynamicNPObject(NPP npp);
+
+ void Invalidate();
+ bool HasProperty(NPIdentifier name);
+ bool GetProperty(NPIdentifier name, NPVariant* result);
+ bool SetProperty(NPIdentifier name, const NPVariant* value);
+ bool RemoveProperty(NPIdentifier name);
+ bool Enumerate(NPIdentifier** names, uint32_t* count);
+
+ private:
+ typedef std::map<NPIdentifier, SmartNPVariant> PropertyMap;
+ PropertyMap properties_;
+ DISALLOW_COPY_AND_ASSIGN(DynamicNPObject);
+};
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_DYNAMIC_NP_OBJECT_H_
diff --git a/o3d/gpu/np_utils/dynamic_np_object_unittest.cc b/o3d/gpu/np_utils/dynamic_np_object_unittest.cc
new file mode 100644
index 0000000..56fcff7
--- /dev/null
+++ b/o3d/gpu/np_utils/dynamic_np_object_unittest.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2006-2008 The Chromium 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 <string>
+
+#include "gpu/np_utils/dynamic_np_object.h"
+#include "gpu/np_utils/np_browser_stub.h"
+#include "gpu/np_utils/np_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+using testing::StrictMock;
+
+namespace gpu_plugin {
+
+class NPDynamicNPObjectTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ object_ = NPCreateObject<DynamicNPObject>(NULL);
+ }
+
+ StubNPBrowser stub_browser_;
+ NPObjectPointer<DynamicNPObject> object_;
+};
+
+TEST_F(NPDynamicNPObjectTest, HasPropertyReturnsFalseForMissingProperty) {
+ EXPECT_FALSE(NPHasProperty(NULL, object_, "missing"));
+}
+
+TEST_F(NPDynamicNPObjectTest, GetPropertyReturnsFalseForMissingProperty) {
+ int32 r;
+ EXPECT_FALSE(NPGetProperty(NULL, object_, "missing", &r));
+}
+
+TEST_F(NPDynamicNPObjectTest, CanSetProperty) {
+ EXPECT_TRUE(NPSetProperty(NULL, object_, "foo", 7));
+ int32 r;
+ EXPECT_TRUE(NPHasProperty(NULL, object_, "foo"));
+ EXPECT_TRUE(NPGetProperty(NULL, object_, "foo", &r));
+ EXPECT_EQ(7, r);
+}
+
+TEST_F(NPDynamicNPObjectTest, CanRemoveProperty) {
+ EXPECT_TRUE(NPSetProperty(NULL, object_, "foo", 7));
+ EXPECT_TRUE(NPHasProperty(NULL, object_, "foo"));
+ EXPECT_FALSE(NPRemoveProperty(NULL, object_, "foo"));
+ EXPECT_FALSE(NPHasProperty(NULL, object_, "foo"));
+ int32 r;
+ EXPECT_FALSE(NPGetProperty(NULL, object_, "foo", &r));
+}
+
+TEST_F(NPDynamicNPObjectTest, CanEnumerateProperties) {
+ EXPECT_TRUE(NPSetProperty(NULL, object_, "foo", 7));
+
+ NPIdentifier* names;
+ uint32 num_names;
+ EXPECT_TRUE(object_->_class->enumerate(object_.Get(), &names, &num_names));
+
+ EXPECT_EQ(1, num_names);
+ EXPECT_EQ(NPBrowser::get()->GetStringIdentifier("foo"), names[0]);
+
+ NPBrowser::get()->MemFree(names);
+}
+
+// Properties should not be
+TEST_F(NPDynamicNPObjectTest, InvalidateNullsObjectProperties) {
+ EXPECT_EQ(1, object_->referenceCount);
+ {
+ EXPECT_TRUE(NPSetProperty(NULL, object_, "foo", object_));
+ EXPECT_TRUE(NPHasProperty(NULL, object_, "foo"));
+ object_->_class->invalidate(object_.Get());
+ EXPECT_TRUE(NPHasProperty(NULL, object_, "foo"));
+ NPObjectPointer<DynamicNPObject> r;
+ EXPECT_TRUE(NPGetProperty(NULL, object_, "foo", &r));
+ EXPECT_TRUE(NULL == r.Get());
+ }
+ // Invalidate did not release object
+ EXPECT_EQ(2, object_->referenceCount);
+ NPBrowser::get()->ReleaseObject(object_.Get());
+}
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/np_browser.cc b/o3d/gpu/np_utils/np_browser.cc
new file mode 100644
index 0000000..3754d3b
--- /dev/null
+++ b/o3d/gpu/np_utils/np_browser.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/np_utils/np_browser.h"
+#include "base/logging.h"
+
+#if defined(O3D_IN_CHROME)
+#include "webkit/glue/plugins/nphostapi.h"
+#else
+#include "o3d/third_party/npapi/include/npfunctions.h"
+#endif
+
+namespace gpu_plugin {
+
+NPBrowser* NPBrowser::browser_;
+
+NPBrowser::NPBrowser(NPNetscapeFuncs* funcs)
+ : netscape_funcs_(funcs) {
+ // Make this the first browser in the linked list.
+ previous_browser_ = browser_;
+ browser_ = this;
+}
+
+NPBrowser::~NPBrowser() {
+ // Remove this browser from the linked list.
+ DCHECK(browser_ == this);
+ browser_ = previous_browser_;
+}
+
+NPIdentifier NPBrowser::GetStringIdentifier(const NPUTF8* name) {
+ return netscape_funcs_->getstringidentifier(name);
+}
+
+void* NPBrowser::MemAlloc(size_t size) {
+ return netscape_funcs_->memalloc(size);
+}
+
+void NPBrowser::MemFree(void* p) {
+ netscape_funcs_->memfree(p);
+}
+
+NPObject* NPBrowser::CreateObject(NPP npp, const NPClass* cl) {
+ return netscape_funcs_->createobject(npp, const_cast<NPClass*>(cl));
+}
+
+NPObject* NPBrowser::RetainObject(NPObject* object) {
+ return netscape_funcs_->retainobject(object);
+}
+
+void NPBrowser::ReleaseObject(NPObject* object) {
+ netscape_funcs_->releaseobject(object);
+}
+
+void NPBrowser::ReleaseVariantValue(NPVariant* variant) {
+ netscape_funcs_->releasevariantvalue(variant);
+}
+
+bool NPBrowser::HasProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name) {
+ return netscape_funcs_->hasproperty(npp, object, name);
+}
+
+bool NPBrowser::GetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ NPVariant* result) {
+ return netscape_funcs_->getproperty(npp, object, name, result);
+}
+
+bool NPBrowser::SetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* result) {
+ return netscape_funcs_->setproperty(npp, object, name, result);
+}
+
+bool NPBrowser::RemoveProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name) {
+ return netscape_funcs_->removeproperty(npp, object, name);
+}
+
+bool NPBrowser::HasMethod(NPP npp,
+ NPObject* object,
+ NPIdentifier name) {
+ return netscape_funcs_->hasmethod(npp, object, name);
+}
+
+bool NPBrowser::Invoke(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ return netscape_funcs_->invoke(npp, object, name, args, num_args, result);
+}
+
+NPObject* NPBrowser::GetWindowNPObject(NPP npp) {
+ NPObject* window;
+ if (NPERR_NO_ERROR == netscape_funcs_->getvalue(npp,
+ NPNVWindowNPObject,
+ &window)) {
+ return window;
+ } else {
+ return NULL;
+ }
+}
+
+void NPBrowser::PluginThreadAsyncCall(NPP npp,
+ PluginThreadAsyncCallProc callback,
+ void* data) {
+ netscape_funcs_->pluginthreadasynccall(npp, callback, data);
+}
+
+uint32 NPBrowser::ScheduleTimer(NPP npp,
+ uint32 interval,
+ bool repeat,
+ TimerProc callback) {
+ return netscape_funcs_->scheduletimer(npp, interval, repeat, callback);
+}
+
+void NPBrowser::UnscheduleTimer(NPP npp, uint32 timer_id) {
+ netscape_funcs_->unscheduletimer(npp, timer_id);
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/np_browser.h b/o3d/gpu/np_utils/np_browser.h
new file mode 100644
index 0000000..d792316
--- /dev/null
+++ b/o3d/gpu/np_utils/np_browser.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_BROWSER_H_
+#define GPU_NP_UTILS_NP_BROWSER_H_
+
+#include "base/basictypes.h"
+#include "gpu/np_utils/np_headers.h"
+
+typedef struct _NPNetscapeFuncs NPNetscapeFuncs;
+
+namespace gpu_plugin {
+
+// This class exposes the functions provided by the browser to a plugin (the
+// ones prefixed NPN_).
+class NPBrowser {
+ public:
+ explicit NPBrowser(NPNetscapeFuncs* funcs);
+ virtual ~NPBrowser();
+
+ static NPBrowser* get() {
+ return browser_;
+ }
+
+ // Standard functions from NPNetscapeFuncs.
+
+ virtual NPIdentifier GetStringIdentifier(const NPUTF8* name);
+
+ virtual void* MemAlloc(size_t size);
+
+ virtual void MemFree(void* p);
+
+ virtual NPObject* CreateObject(NPP npp, const NPClass* cl);
+
+ virtual NPObject* RetainObject(NPObject* object);
+
+ virtual void ReleaseObject(NPObject* object);
+
+ virtual void ReleaseVariantValue(NPVariant* variant);
+
+ virtual bool HasProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name);
+
+ virtual bool GetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ NPVariant* result);
+
+ virtual bool SetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* result);
+
+ virtual bool RemoveProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name);
+
+ virtual bool HasMethod(NPP npp,
+ NPObject* object,
+ NPIdentifier name);
+
+ virtual bool Invoke(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result);
+
+ virtual NPObject* GetWindowNPObject(NPP npp);
+
+ typedef void (*PluginThreadAsyncCallProc)(void* data);
+ virtual void PluginThreadAsyncCall(NPP npp,
+ PluginThreadAsyncCallProc callback,
+ void* data);
+
+ typedef void (*TimerProc)(NPP npp, uint32 timer_id);
+ virtual uint32 ScheduleTimer(NPP npp,
+ uint32 interval,
+ bool repeat,
+ TimerProc callback);
+
+ virtual void UnscheduleTimer(NPP npp, uint32 timer_id);
+
+ private:
+ static NPBrowser* browser_;
+ NPBrowser* previous_browser_;
+ NPNetscapeFuncs* netscape_funcs_;
+ DISALLOW_COPY_AND_ASSIGN(NPBrowser);
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_BROWSER_H_
diff --git a/o3d/gpu/np_utils/np_browser_mock.h b/o3d/gpu/np_utils/np_browser_mock.h
new file mode 100644
index 0000000..1ef574e
--- /dev/null
+++ b/o3d/gpu/np_utils/np_browser_mock.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_BROWSER_MOCK_H_
+#define GPU_NP_UTILS_NP_BROWSER_MOCK_H_
+
+#include "gpu/np_utils/np_browser_stub.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu_plugin {
+
+// This mocks certain member functions of the stub browser. Those relating
+// to identifiers, memory management, reference counting and forwarding to
+// NPObjects are deliberately not mocked so the mock browser can be used as
+// normal for these calls.
+class MockNPBrowser : public StubNPBrowser {
+ public:
+ NPObject* ConcreteCreateObject(NPP npp, const NPClass* cl) {
+ return StubNPBrowser::CreateObject(npp, cl);
+ }
+
+ MockNPBrowser() {
+ // Do not mock CreateObject by default but allow it to be mocked so object
+ // creation can be intercepted.
+ ON_CALL(*this, CreateObject(testing::_, testing::_))
+ .WillByDefault(testing::Invoke(this,
+ &MockNPBrowser::ConcreteCreateObject));
+ }
+
+ void ConcretePluginThreadAsyncCall(NPP npp,
+ PluginThreadAsyncCallProc callback,
+ void* data) {
+ return StubNPBrowser::PluginThreadAsyncCall(npp, callback, data);
+ }
+
+ MOCK_METHOD2(CreateObject, NPObject*(NPP npp, const NPClass* cl));
+ MOCK_METHOD1(GetWindowNPObject, NPObject*(NPP cpp));
+ MOCK_METHOD3(PluginThreadAsyncCall,
+ void(NPP npp, PluginThreadAsyncCallProc callback, void* data));
+ MOCK_METHOD4(ScheduleTimer, uint32(NPP npp,
+ uint32 interval,
+ bool repeat,
+ TimerProc callback));
+ MOCK_METHOD2(UnscheduleTimer, void(NPP npp, uint32 timer_id));
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_BROWSER_MOCK_H_
diff --git a/o3d/gpu/np_utils/np_browser_stub.cc b/o3d/gpu/np_utils/np_browser_stub.cc
new file mode 100644
index 0000000..2bc1c6a
--- /dev/null
+++ b/o3d/gpu/np_utils/np_browser_stub.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/np_utils/np_browser_stub.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+
+namespace gpu_plugin {
+
+StubNPBrowser::StubNPBrowser() : NPBrowser(NULL) {
+}
+
+StubNPBrowser::~StubNPBrowser() {
+}
+
+NPIdentifier StubNPBrowser::GetStringIdentifier(const NPUTF8* name) {
+ static std::set<std::string> names;
+ std::set<std::string>::iterator it = names.find(name);
+ if (it == names.end()) {
+ it = names.insert(name).first;
+ }
+ return const_cast<NPUTF8*>((*it).c_str());
+}
+
+void* StubNPBrowser::MemAlloc(size_t size) {
+ return malloc(size);
+}
+
+void StubNPBrowser::MemFree(void* p) {
+ free(p);
+}
+
+NPObject* StubNPBrowser::CreateObject(NPP npp, const NPClass* cl) {
+ NPObject* object = cl->allocate(npp, const_cast<NPClass*>(cl));
+ object->referenceCount = 1;
+ object->_class = const_cast<NPClass*>(cl);
+ return object;
+}
+
+NPObject* StubNPBrowser::RetainObject(NPObject* object) {
+ ++object->referenceCount;
+ return object;
+}
+
+void StubNPBrowser::ReleaseObject(NPObject* object) {
+ DCHECK_GE(object->referenceCount, 0u);
+ --object->referenceCount;
+ if (object->referenceCount == 0) {
+ object->_class->deallocate(object);
+ }
+}
+
+void StubNPBrowser::ReleaseVariantValue(NPVariant* variant) {
+ if (NPVARIANT_IS_STRING(*variant)) {
+ MemFree(const_cast<NPUTF8*>(variant->value.stringValue.UTF8Characters));
+ } else if (NPVARIANT_IS_OBJECT(*variant)) {
+ ReleaseObject(NPVARIANT_TO_OBJECT(*variant));
+ }
+}
+
+bool StubNPBrowser::HasProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name) {
+ return object->_class->hasProperty(object, name);
+}
+
+bool StubNPBrowser::GetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ NPVariant* result) {
+ return object->_class->getProperty(object, name, result);
+}
+
+bool StubNPBrowser::SetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* result) {
+ return object->_class->setProperty(object, name, result);
+}
+
+bool StubNPBrowser::RemoveProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name) {
+ return object->_class->removeProperty(object, name);
+}
+
+bool StubNPBrowser::HasMethod(NPP npp,
+ NPObject* object,
+ NPIdentifier name) {
+ return object->_class->hasMethod(object, name);
+}
+
+bool StubNPBrowser::Invoke(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ return object->_class->invoke(object, name, args, num_args, result);
+}
+
+NPObject* StubNPBrowser::GetWindowNPObject(NPP npp) {
+ return NULL;
+}
+
+void StubNPBrowser::PluginThreadAsyncCall(
+ NPP npp,
+ PluginThreadAsyncCallProc callback,
+ void* data) {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ NewRunnableFunction(callback, data));
+}
+
+uint32 StubNPBrowser::ScheduleTimer(NPP npp,
+ uint32 interval,
+ bool repeat,
+ TimerProc callback) {
+ return 0;
+}
+
+void StubNPBrowser::UnscheduleTimer(NPP npp, uint32 timer_id) {
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/np_browser_stub.h b/o3d/gpu/np_utils/np_browser_stub.h
new file mode 100644
index 0000000..b18d52d
--- /dev/null
+++ b/o3d/gpu/np_utils/np_browser_stub.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_BROWSER_STUB_H_
+#define GPU_NP_UTILS_NP_BROWSER_STUB_H_
+
+#include <set>
+#include <string>
+
+#include "gpu/np_utils/np_browser.h"
+
+namespace gpu_plugin {
+
+// Simple implementation of subset of the NPN functions for testing.
+class StubNPBrowser : public NPBrowser {
+ public:
+ StubNPBrowser();
+ virtual ~StubNPBrowser();
+
+ // Standard functions from NPNetscapeFuncs.
+
+ virtual NPIdentifier GetStringIdentifier(const NPUTF8* name);
+
+ virtual void* MemAlloc(size_t size);
+
+ virtual void MemFree(void* p);
+
+ virtual NPObject* CreateObject(NPP npp, const NPClass* cl);
+
+ virtual NPObject* RetainObject(NPObject* object);
+
+ virtual void ReleaseObject(NPObject* object);
+
+ virtual void ReleaseVariantValue(NPVariant* variant);
+
+ virtual bool HasProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name);
+
+ virtual bool GetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ NPVariant* result);
+
+ virtual bool SetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* result);
+
+ virtual bool RemoveProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name);
+
+ virtual bool HasMethod(NPP npp,
+ NPObject* object,
+ NPIdentifier name);
+ virtual bool Invoke(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result);
+
+ virtual NPObject* GetWindowNPObject(NPP npp);
+
+ virtual void PluginThreadAsyncCall(NPP npp,
+ PluginThreadAsyncCallProc callback,
+ void* data);
+
+ virtual uint32 ScheduleTimer(NPP npp,
+ uint32 interval,
+ bool repeat,
+ TimerProc callback);
+
+ virtual void UnscheduleTimer(NPP npp, uint32 timer_id);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StubNPBrowser);
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_BROWSER_STUB_H_
diff --git a/o3d/gpu/np_utils/np_class.h b/o3d/gpu/np_utils/np_class.h
new file mode 100644
index 0000000..113f493
--- /dev/null
+++ b/o3d/gpu/np_utils/np_class.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_CLASS_H_
+#define GPU_NP_UTILS_NP_CLASS_H_
+
+#include "gpu/np_utils/np_object_pointer.h"
+#include "gpu/np_utils/np_headers.h"
+
+// This file implements NPGetClass<T>. This function returns an NPClass
+// that can be used to instantiate an NPObject subclass T. The NPClass
+// function pointers will invoke the most derived corresponding member
+// functions in T.
+
+namespace gpu_plugin {
+
+namespace np_class_impl {
+ // This template version of the NPClass allocate function creates a subclass
+ // of BaseNPObject.
+ template <typename NPObjectType>
+ static NPObject* Allocate(NPP npp, NPClass*) {
+ return new NPObjectType(npp);
+ }
+
+ // These implementations of the NPClass functions forward to the virtual
+ // functions in DefaultNPObject.
+ template <typename NPObjectType>
+ static void Deallocate(NPObject* object) {
+ delete static_cast<NPObjectType*>(object);
+ }
+
+ template <typename NPObjectType>
+ static void Invalidate(NPObject* object) {
+ return static_cast<NPObjectType*>(object)->Invalidate();
+ }
+
+ template <typename NPObjectType>
+ static bool HasMethod(NPObject* object, NPIdentifier name) {
+ return static_cast<NPObjectType*>(object)->HasMethod(name);
+ }
+
+ template <typename NPObjectType>
+ static bool Invoke(NPObject* object,
+ NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ return static_cast<NPObjectType*>(object)->Invoke(
+ name, args, num_args, result);
+ }
+
+ template <typename NPObjectType>
+ static bool InvokeDefault(NPObject* object,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ return static_cast<NPObjectType*>(object)->InvokeDefault(
+ args, num_args, result);
+ }
+
+ template <typename NPObjectType>
+ static bool HasProperty(NPObject* object, NPIdentifier name) {
+ return static_cast<NPObjectType*>(object)->HasProperty(name);
+ }
+
+ template <typename NPObjectType>
+ static bool GetProperty(NPObject* object,
+ NPIdentifier name,
+ NPVariant* result) {
+ return static_cast<NPObjectType*>(object)->GetProperty(name, result);
+ }
+
+ template <typename NPObjectType>
+ static bool SetProperty(NPObject* object,
+ NPIdentifier name,
+ const NPVariant* value) {
+ return static_cast<NPObjectType*>(object)->SetProperty(name, value);
+ }
+
+ template <typename NPObjectType>
+ static bool RemoveProperty(NPObject* object, NPIdentifier name) {
+ return static_cast<NPObjectType*>(object)->RemoveProperty(name);
+ }
+
+ template <typename NPObjectType>
+ static bool Enumerate(NPObject* object,
+ NPIdentifier** names,
+ uint32_t* count) {
+ return static_cast<NPObjectType*>(object)->Enumerate(names, count);
+ };
+
+ template <typename NPObjectType>
+ static bool Construct(NPObject* object,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ return static_cast<NPObjectType*>(object)->Construct(
+ args, num_args, result);
+ }
+} // namespace np_class_impl;
+
+template <typename NPObjectType>
+const NPClass* NPGetClass() {
+ static const NPClass np_class = {
+ NP_CLASS_STRUCT_VERSION,
+ np_class_impl::Allocate<NPObjectType>,
+ np_class_impl::Deallocate<NPObjectType>,
+ np_class_impl::Invalidate<NPObjectType>,
+ np_class_impl::HasMethod<NPObjectType>,
+ np_class_impl::Invoke<NPObjectType>,
+ np_class_impl::InvokeDefault<NPObjectType>,
+ np_class_impl::HasProperty<NPObjectType>,
+ np_class_impl::GetProperty<NPObjectType>,
+ np_class_impl::SetProperty<NPObjectType>,
+ np_class_impl::RemoveProperty<NPObjectType>,
+ np_class_impl::Enumerate<NPObjectType>,
+ np_class_impl::Construct<NPObjectType>,
+ };
+ return &np_class;
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_CLASS_H_
diff --git a/o3d/gpu/np_utils/np_class_unittest.cc b/o3d/gpu/np_utils/np_class_unittest.cc
new file mode 100644
index 0000000..0db632b
--- /dev/null
+++ b/o3d/gpu/np_utils/np_class_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/np_utils/np_class.h"
+#include "gpu/np_utils/np_object_mock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::StrictMock;
+
+namespace gpu_plugin {
+
+class NPClassTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ np_class = NPGetClass<StrictMock<MockNPObject> >();
+
+ // Dummy identifier is never used with real NPAPI so it can point to
+ // anything.
+ identifier = this;
+ }
+
+ virtual void TearDown() {
+ }
+
+ NPP_t npp_;
+ const NPClass* np_class;
+ NPIdentifier identifier;
+ NPVariant args[3];
+ NPVariant result;
+};
+
+TEST_F(NPClassTest, AllocateAndDeallocateObject) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+ EXPECT_TRUE(NULL != object);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, InvalidateForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ EXPECT_CALL(*object, Invalidate());
+ np_class->invalidate(object);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, HasMethodForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ EXPECT_CALL(*object, HasMethod(identifier));
+ np_class->hasMethod(object, identifier);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, InvokeForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ EXPECT_CALL(*object, Invoke(identifier, args, 3, &result));
+ np_class->invoke(object, identifier, args, 3, &result);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, InvokeDefaultForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ EXPECT_CALL(*object, InvokeDefault(args, 3, &result));
+ np_class->invokeDefault(object, args, 3, &result);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, HasPropertyForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ EXPECT_CALL(*object, HasProperty(identifier));
+ np_class->hasProperty(object, identifier);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, GetPropertyForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ EXPECT_CALL(*object, GetProperty(identifier, &result));
+ np_class->getProperty(object, identifier, &result);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, SetPropertyForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ EXPECT_CALL(*object, SetProperty(identifier, &result));
+ np_class->setProperty(object, identifier, &result);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, RemovePropertyForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ EXPECT_CALL(*object, RemoveProperty(identifier));
+ np_class->removeProperty(object, identifier);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, EnumerateForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ NPIdentifier* identifier = NULL;
+ uint32_t count;
+ EXPECT_CALL(*object, Enumerate(&identifier, &count));
+ np_class->enumerate(object, &identifier, &count);
+
+ np_class->deallocate(object);
+}
+
+TEST_F(NPClassTest, ConstructForwards) {
+ MockNPObject* object = static_cast<MockNPObject*>(
+ np_class->allocate(&npp_, const_cast<NPClass*>(np_class)));
+
+ EXPECT_CALL(*object, Construct(args, 3, &result));
+ np_class->construct(object, args, 3, &result);
+
+ np_class->deallocate(object);
+}
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/np_dispatcher.cc b/o3d/gpu/np_utils/np_dispatcher.cc
new file mode 100644
index 0000000..7859f8b
--- /dev/null
+++ b/o3d/gpu/np_utils/np_dispatcher.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/np_utils/np_dispatcher.h"
+
+namespace gpu_plugin {
+
+bool DispatcherHasMethodHelper(BaseNPDispatcher* chain,
+ NPObject* object,
+ NPIdentifier name) {
+ for (BaseNPDispatcher* dispatcher = chain;
+ dispatcher;
+ dispatcher = dispatcher->next()) {
+ if (dispatcher->name() == name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DispatcherInvokeHelper(BaseNPDispatcher* chain,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ VOID_TO_NPVARIANT(*result);
+
+ for (BaseNPDispatcher* dispatcher = chain;
+ dispatcher;
+ dispatcher = dispatcher->next()) {
+ if (dispatcher->name() == name &&
+ dispatcher->num_args() == static_cast<int>(num_args)) {
+ if (dispatcher->Invoke(object, args, num_args, result))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DispatcherEnumerateHelper(BaseNPDispatcher* chain,
+ NPObject* object,
+ NPIdentifier** names,
+ uint32_t* num_names) {
+ // Count the number of names.
+ *num_names = 0;
+ for (BaseNPDispatcher* dispatcher = chain;
+ dispatcher;
+ dispatcher = dispatcher->next()) {
+ ++(*num_names);
+ }
+
+ // Copy names into the array.
+ *names = static_cast<NPIdentifier*>(
+ NPBrowser::get()->MemAlloc((*num_names) * sizeof(**names)));
+ int i = 0;
+ for (BaseNPDispatcher* dispatcher = chain;
+ dispatcher;
+ dispatcher = dispatcher->next()) {
+ (*names)[i] = dispatcher->name();
+ ++i;
+ }
+
+ return true;
+}
+
+BaseNPDispatcher::BaseNPDispatcher(BaseNPDispatcher* next, const NPUTF8* name)
+ : next_(next) {
+ // Convert first character to lower case if it is the ASCII range.
+ // TODO(apatrick): do this correctly for non-ASCII characters.
+ std::string java_script_style_name(name);
+ if (isupper(java_script_style_name[0])) {
+ java_script_style_name[0] = tolower(java_script_style_name[0]);
+ }
+
+ name_ = NPBrowser::get()->GetStringIdentifier(
+ java_script_style_name.c_str());
+}
+
+BaseNPDispatcher::~BaseNPDispatcher() {
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/np_dispatcher.h b/o3d/gpu/np_utils/np_dispatcher.h
new file mode 100644
index 0000000..5b84f86
--- /dev/null
+++ b/o3d/gpu/np_utils/np_dispatcher.h
@@ -0,0 +1,222 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_DISPATCHER_H_
+#define GPU_NP_UTILS_NP_DISPATCHER_H_
+
+#include <string>
+
+#include "gpu/np_utils/np_utils.h"
+#include "gpu/np_utils/np_headers.h"
+
+// Dispatchers make regular member functions available as NPObject methods.
+// Usage:
+//
+// class MyNPObject : public DefaultNPObject<NPObject> {
+// public:
+// int MyMethod(bool a, float b);
+// NP_UTILS_BEGIN_DISPATCHER_CHAIN(MyNPObject, DispatchedNPObject)
+// NP_UTILS_DISPATCHER(MyMethod, int(bool, float))
+// NP_UTILS_END_DISPATCHER_CHAIN
+// };
+//
+// Multiple member functions may be listed in the dispatcher chain. Inheritance
+// is supported. The following types are supported as return types and parameter
+// types:
+// * bool
+// * int
+// * float
+// * double
+// * std::string
+// * NPObject*
+//
+
+// These macros are used to make dispatcher chains.
+#define NP_UTILS_NP_UTILS_DISPATCHER_JOIN2(a, b) a ## b
+#define NP_UTILS_DISPATCHER_JOIN(a, b) NP_UTILS_NP_UTILS_DISPATCHER_JOIN2(a, b)
+#define NP_UTILS_DISPATCHER_UNIQUE \
+ NP_UTILS_DISPATCHER_JOIN(dispatcher, __LINE__)
+
+#define NP_UTILS_BEGIN_DISPATCHER_CHAIN(Class, BaseClass) \
+ static BaseNPDispatcher* GetDispatcherChain() { \
+ typedef Class ThisClass; \
+ BaseNPDispatcher* top_dispatcher = BaseClass::GetDispatcherChain(); \
+
+#define NP_UTILS_DISPATCHER(name, Signature) \
+ static NPDispatcher<ThisClass, Signature> \
+ NP_UTILS_DISPATCHER_UNIQUE( \
+ top_dispatcher, \
+ #name, \
+ &ThisClass::name); \
+ top_dispatcher = &NP_UTILS_DISPATCHER_UNIQUE; \
+
+#define NP_UTILS_END_DISPATCHER_CHAIN \
+ return top_dispatcher; \
+ } \
+ bool HasMethod(NPIdentifier name) { \
+ return DispatcherHasMethodHelper(GetDispatcherChain(), this, name); \
+ } \
+ bool Invoke(NPIdentifier name, \
+ const NPVariant* args, \
+ uint32_t num_args, \
+ NPVariant* result) { \
+ return DispatcherInvokeHelper(GetDispatcherChain(), \
+ this, \
+ name, \
+ args, \
+ num_args, \
+ result); \
+ } \
+ bool Enumerate(NPIdentifier** names, uint32_t* num_names) { \
+ return DispatcherEnumerateHelper(GetDispatcherChain(), \
+ this, \
+ names, \
+ num_names); \
+ } \
+
+namespace gpu_plugin {
+
+class BaseNPDispatcher {
+ public:
+ BaseNPDispatcher(BaseNPDispatcher* next, const NPUTF8* name);
+
+ virtual ~BaseNPDispatcher();
+
+ BaseNPDispatcher* next() const {
+ return next_;
+ }
+
+ NPIdentifier name() const {
+ return name_;
+ }
+
+ virtual int num_args() const = 0;
+
+ virtual bool Invoke(NPObject* object,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) = 0;
+
+ private:
+ BaseNPDispatcher* next_;
+ NPIdentifier name_;
+ DISALLOW_COPY_AND_ASSIGN(BaseNPDispatcher);
+};
+
+bool DispatcherHasMethodHelper(BaseNPDispatcher* chain,
+ NPObject* object,
+ NPIdentifier name);
+
+bool DispatcherInvokeHelper(BaseNPDispatcher* chain,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result);
+
+bool DispatcherEnumerateHelper(BaseNPDispatcher* chain,
+ NPObject* object,
+ NPIdentifier** names,
+ uint32_t* num_names);
+
+// This class should never be instantiated. It is always specialized. Attempting
+// to instantiate it results in a compilation error. This might mean an
+// attempt to instantiate a dispatcher with more parameters than have been
+// specialized for. See the specialization code below.
+template <typename NPObjectType, typename FunctionType>
+struct NPDispatcher {
+};
+
+#define TO_NPVARIANT(index) \
+ T##index n##index; \
+ if (!NPVariantToValue(&n##index, args[index])) \
+ return false; \
+
+#define NUM_PARAMS 0
+#define PARAM_TYPENAMES
+#define PARAM_TYPES
+#define PARAM_NAMES
+#define PARAM_DECLS // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+
+#include "gpu/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 1
+#define PARAM_TYPENAMES , typename T0
+#define PARAM_TYPES T0
+#define PARAM_NAMES n0
+#define PARAM_DECLS T0 n0; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+
+#include "gpu/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 2
+#define PARAM_TYPENAMES , typename T0, typename T1
+#define PARAM_TYPES T0, T1
+#define PARAM_NAMES n0, n1
+#define PARAM_DECLS T0 n0; T1 n1; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+ TO_NPVARIANT(1); \
+
+#include "gpu/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 3
+#define PARAM_TYPENAMES , typename T0, typename T1, typename T2
+#define PARAM_TYPES T0, T1, T2
+#define PARAM_NAMES n0, n1, n2
+#define PARAM_DECLS T0 n0; T1 n1; T2 n2; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+ TO_NPVARIANT(1); \
+ TO_NPVARIANT(2); \
+
+#include "gpu/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 4
+#define PARAM_TYPENAMES , typename T0, typename T1, typename T2, typename T3
+#define PARAM_TYPES T0, T1, T2, T3
+#define PARAM_NAMES n0, n1, n2, n3
+#define PARAM_DECLS T0 n0; T1 n1; T2 n2; T3 n3; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+ TO_NPVARIANT(1); \
+ TO_NPVARIANT(2); \
+ TO_NPVARIANT(3); \
+
+#include "gpu/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#define NUM_PARAMS 5
+#define PARAM_TYPENAMES , typename T0, typename T1, typename T2, typename T3, \
+ typename T4
+#define PARAM_TYPES T0, T1, T2, T3, T4
+#define PARAM_NAMES n0, n1, n2, n3, n4
+#define PARAM_DECLS T0 n0; T1 n1; T2 n2; T3 n3; T4 n4; // NOLINT
+
+#define PARAM_TO_NVPARIANT_CONVERSIONS \
+ TO_NPVARIANT(0); \
+ TO_NPVARIANT(1); \
+ TO_NPVARIANT(2); \
+ TO_NPVARIANT(3); \
+ TO_NPVARIANT(4); \
+
+#include "gpu/np_utils/np_dispatcher_specializations.h" // NOLINT
+
+
+#undef TO_NPVARIANT
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_DISPATCHER_H_
diff --git a/o3d/gpu/np_utils/np_dispatcher_specializations.h b/o3d/gpu/np_utils/np_dispatcher_specializations.h
new file mode 100644
index 0000000..62fb8c4
--- /dev/null
+++ b/o3d/gpu/np_utils/np_dispatcher_specializations.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// There is deliberately no header guard here. This file is included multiple
+// times, once for each dispatcher specialiation arity. Do not include this
+// file directly. Include np_dispatcher.h instead.
+
+template <typename NPObjectType PARAM_TYPENAMES>
+class NPDispatcher<NPObjectType, void(PARAM_TYPES)>
+ : public BaseNPDispatcher {
+ typedef void (NPObjectType::*FunctionType)(PARAM_TYPES);
+ public:
+ NPDispatcher(BaseNPDispatcher* next,
+ const NPUTF8* name,
+ FunctionType function)
+ : BaseNPDispatcher(next, name),
+ function_(function) {
+ }
+
+ virtual bool Invoke(NPObject* object,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ VOID_TO_NPVARIANT(*result);
+
+ if (num_args != NUM_PARAMS)
+ return false;
+
+ PARAM_TO_NVPARIANT_CONVERSIONS
+
+ (static_cast<NPObjectType*>(object)->*function_)(PARAM_NAMES);
+ return true;
+ }
+
+ virtual int num_args() const {
+ return NUM_PARAMS;
+ }
+
+ private:
+ FunctionType function_;
+};
+
+template <typename NPObjectType, typename R PARAM_TYPENAMES>
+class NPDispatcher<NPObjectType, R(PARAM_TYPES)>
+ : public BaseNPDispatcher {
+ typedef R (NPObjectType::*FunctionType)(PARAM_TYPES);
+ public:
+ NPDispatcher(BaseNPDispatcher* next,
+ const NPUTF8* name,
+ FunctionType function)
+ : BaseNPDispatcher(next, name),
+ function_(function) {
+ }
+
+ virtual bool Invoke(NPObject* object,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ VOID_TO_NPVARIANT(*result);
+
+ if (num_args != NUM_PARAMS)
+ return false;
+
+ PARAM_TO_NVPARIANT_CONVERSIONS
+
+ ValueToNPVariant(
+ (static_cast<NPObjectType*>(object)->*function_)(PARAM_NAMES), result);
+ return true;
+ }
+
+ virtual int num_args() const {
+ return NUM_PARAMS;
+ }
+
+ private:
+ FunctionType function_;
+};
+
+#undef NUM_PARAMS
+#undef PARAM_TYPENAMES
+#undef PARAM_TYPES
+#undef PARAM_NAMES
+#undef PARAM_DECLS
+#undef PARAM_TO_NVPARIANT_CONVERSIONS
diff --git a/o3d/gpu/np_utils/np_headers.h b/o3d/gpu/np_utils/np_headers.h
new file mode 100644
index 0000000..5f60d8e
--- /dev/null
+++ b/o3d/gpu/np_utils/np_headers.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_HEADERS_H_
+#define GPU_NP_UTILS_NP_HEADERS_H_
+
+#if defined(O3D_IN_CHROME)
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+#else
+#include "o3d/third_party/npapi/include/npapi.h"
+#include "o3d/third_party/npapi/include/npruntime.h"
+#endif
+
+#endif // GPU_NP_UTILS_NP_HEADERS_H_
diff --git a/o3d/gpu/np_utils/np_object_mock.h b/o3d/gpu/np_utils/np_object_mock.h
new file mode 100644
index 0000000..8c3d0e7
--- /dev/null
+++ b/o3d/gpu/np_utils/np_object_mock.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_OBJECT_MOCK_H_
+#define GPU_NP_UTILS_NP_OBJECT_MOCK_H_
+
+#include "gpu/np_utils/np_browser.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu_plugin {
+
+class MockNPObject : public NPObject {
+ public:
+ explicit MockNPObject(NPP npp) {
+ }
+
+ MOCK_METHOD0(Invalidate, void());
+ MOCK_METHOD1(HasMethod, bool(NPIdentifier));
+ MOCK_METHOD4(Invoke,
+ bool(NPIdentifier, const NPVariant*, uint32_t, NPVariant*));
+ MOCK_METHOD3(InvokeDefault, bool(const NPVariant*, uint32_t, NPVariant*));
+ MOCK_METHOD1(HasProperty, bool(NPIdentifier));
+ MOCK_METHOD2(GetProperty, bool(NPIdentifier, NPVariant*));
+ MOCK_METHOD2(SetProperty, bool(NPIdentifier, const NPVariant*));
+ MOCK_METHOD1(RemoveProperty, bool(NPIdentifier));
+ MOCK_METHOD2(Enumerate, bool(NPIdentifier**, uint32_t*));
+ MOCK_METHOD3(Construct, bool(const NPVariant*, uint32_t, NPVariant*));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockNPObject);
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_OBJECT_MOCK_H_
diff --git a/o3d/gpu/np_utils/np_object_pointer.h b/o3d/gpu/np_utils/np_object_pointer.h
new file mode 100644
index 0000000..a8987be
--- /dev/null
+++ b/o3d/gpu/np_utils/np_object_pointer.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_OBJECT_POINTER_H_
+#define GPU_NP_UTILS_NP_OBJECT_POINTER_H_
+
+#include "base/logging.h"
+#include "gpu/np_utils/np_browser.h"
+#include "gpu/np_utils/np_headers.h"
+
+namespace gpu_plugin {
+
+// Smart pointer for NPObjects that automatically handles reference counting.
+template <typename NPObjectType>
+class NPObjectPointer {
+ public:
+ NPObjectPointer() : object_(NULL) {}
+
+ NPObjectPointer(const NPObjectPointer& rhs) : object_(rhs.object_) {
+ Retain();
+ }
+
+ explicit NPObjectPointer(NPObjectType* p) : object_(p) {
+ Retain();
+ }
+
+ template <typename RHS>
+ NPObjectPointer(const NPObjectPointer<RHS>& rhs) : object_(rhs.Get()) {
+ Retain();
+ }
+
+ ~NPObjectPointer() {
+ Release();
+ }
+
+ NPObjectPointer& operator=(const NPObjectPointer& rhs) {
+ if (object_ == rhs.Get())
+ return *this;
+
+ Release();
+ object_ = rhs.object_;
+ Retain();
+ return *this;
+ }
+
+ template <typename RHS>
+ NPObjectPointer& operator=(const NPObjectPointer<RHS>& rhs) {
+ if (object_ == rhs.Get())
+ return *this;
+
+ Release();
+ object_ = rhs.Get();
+ Retain();
+ return *this;
+ }
+
+ template <class RHS>
+ bool operator==(const NPObjectPointer<RHS>& rhs) const {
+ return object_ == rhs.Get();
+ }
+
+ template <class RHS>
+ bool operator!=(const NPObjectPointer<RHS>& rhs) const {
+ return object_ != rhs.Get();
+ }
+
+ // The NPObject convention for returning an NPObject pointer from a function
+ // is that the caller is responsible for releasing the reference count.
+ static NPObjectPointer FromReturned(NPObjectType* p) {
+ NPObjectPointer pointer(p);
+ pointer.Release();
+ return pointer;
+ }
+
+ // The NPObject convention for returning an NPObject pointer from a function
+ // is that the caller is responsible for releasing the reference count.
+ NPObjectType* ToReturned() const {
+ Retain();
+ return object_;
+ }
+
+ NPObjectType* Get() const {
+ return object_;
+ }
+
+ NPObjectType* operator->() const {
+ return object_;
+ }
+
+ NPObjectType& operator*() const {
+ return *object_;
+ }
+
+ private:
+ void Retain() const {
+ if (object_) {
+ NPBrowser::get()->RetainObject(object_);
+ }
+ }
+
+ void Release() const {
+ if (object_) {
+ NPBrowser::get()->ReleaseObject(object_);
+ }
+ }
+
+ NPObjectType* object_;
+};
+
+// For test diagnostics.
+template <typename NPObjectType>
+std::ostream& operator<<(std::ostream& stream,
+ const NPObjectPointer<NPObjectType>& pointer) {
+ return stream << pointer.Get();
+}
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_OBJECT_POINTER_H_
diff --git a/o3d/gpu/np_utils/np_object_pointer_unittest.cc b/o3d/gpu/np_utils/np_object_pointer_unittest.cc
new file mode 100644
index 0000000..c14f6ed
--- /dev/null
+++ b/o3d/gpu/np_utils/np_object_pointer_unittest.cc
@@ -0,0 +1,220 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/np_utils/np_class.h"
+#include "gpu/np_utils/np_object_mock.h"
+#include "gpu/np_utils/np_browser_stub.h"
+#include "gpu/np_utils/np_object_pointer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+using testing::StrictMock;
+
+namespace gpu_plugin {
+
+class DerivedNPObject : public MockNPObject {
+ public:
+ explicit DerivedNPObject(NPP npp) : MockNPObject(npp) {
+ }
+};
+
+class NPObjectPointerTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ np_class_ = NPGetClass<StrictMock<MockNPObject> >();
+
+ raw_pointer_ = static_cast<MockNPObject*>(
+ NPBrowser::get()->CreateObject(NULL, np_class_));
+
+ raw_derived_pointer_ = static_cast<DerivedNPObject*>(
+ NPBrowser::get()->CreateObject(NULL, np_class_));
+ }
+
+ virtual void TearDown() {
+ NPBrowser::get()->ReleaseObject(raw_pointer_);
+ NPBrowser::get()->ReleaseObject(raw_derived_pointer_);
+ }
+
+ StubNPBrowser stub_browser_;
+ const NPClass* np_class_;
+ MockNPObject* raw_pointer_;
+ DerivedNPObject* raw_derived_pointer_;
+};
+
+TEST_F(NPObjectPointerTest, PointerIsNullByDefault) {
+ NPObjectPointer<MockNPObject> p;
+ ASSERT_TRUE(NULL == p.Get());
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeExplicitlyConstructedFromRawPointer) {
+ EXPECT_EQ(1, raw_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockNPObject> p(raw_pointer_);
+ ASSERT_TRUE(raw_pointer_ == p.Get());
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ }
+ EXPECT_EQ(1, raw_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest,
+ PointerCanBeExplicitlyConstructedFromNullRawPointer) {
+ NPObjectPointer<MockNPObject> p(NULL);
+ ASSERT_TRUE(NULL == p.Get());
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeCopyConstructed) {
+ NPObjectPointer<MockNPObject> p1(raw_pointer_);
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockNPObject> p2(p1);
+ ASSERT_TRUE(raw_pointer_ == p2.Get());
+ EXPECT_EQ(3, raw_pointer_->referenceCount);
+ }
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeConstructedFromDerived) {
+ NPObjectPointer<DerivedNPObject> p1(raw_derived_pointer_);
+ EXPECT_EQ(2, raw_derived_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockNPObject> p2(p1);
+ ASSERT_TRUE(raw_derived_pointer_ == p2.Get());
+ EXPECT_EQ(3, raw_derived_pointer_->referenceCount);
+ }
+ EXPECT_EQ(2, raw_derived_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest,
+ PointerCanBeCopyConstructedFromNull) {
+ NPObjectPointer<MockNPObject> p(NULL);
+ ASSERT_TRUE(NULL == p.Get());
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeAssigned) {
+ NPObjectPointer<MockNPObject> p1(raw_pointer_);
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockNPObject> p2;
+ p2 = p1;
+ ASSERT_TRUE(raw_pointer_ == p2.Get());
+ EXPECT_EQ(3, raw_pointer_->referenceCount);
+
+ p2 = NPObjectPointer<MockNPObject>();
+ ASSERT_TRUE(NULL == p2.Get());
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+
+ p2 = p1;
+ ASSERT_TRUE(raw_pointer_ == p2.Get());
+ EXPECT_EQ(3, raw_pointer_->referenceCount);
+ }
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeAssignedToSelf) {
+ NPObjectPointer<MockNPObject> p(raw_pointer_);
+ NPBrowser::get()->ReleaseObject(raw_pointer_);
+ EXPECT_EQ(1, raw_pointer_->referenceCount);
+ p = p;
+ EXPECT_EQ(1, raw_pointer_->referenceCount);
+ NPBrowser::get()->RetainObject(raw_pointer_);
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeAssignedDerived) {
+ NPObjectPointer<DerivedNPObject> p1(raw_derived_pointer_);
+ EXPECT_EQ(2, raw_derived_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockNPObject> p2;
+ p2 = p1;
+ ASSERT_TRUE(raw_derived_pointer_ == p2.Get());
+ EXPECT_EQ(3, raw_derived_pointer_->referenceCount);
+
+ p2 = NPObjectPointer<MockNPObject>();
+ ASSERT_TRUE(NULL == p2.Get());
+ EXPECT_EQ(2, raw_derived_pointer_->referenceCount);
+
+ p2 = p1;
+ ASSERT_TRUE(raw_derived_pointer_ == p2.Get());
+ EXPECT_EQ(3, raw_derived_pointer_->referenceCount);
+ }
+ EXPECT_EQ(2, raw_derived_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest, DerivedPointerCanBeAssignedToSelf) {
+ NPObjectPointer<MockNPObject> p1(raw_derived_pointer_);
+ NPObjectPointer<DerivedNPObject> p2(raw_derived_pointer_);
+ NPBrowser::get()->ReleaseObject(raw_derived_pointer_);
+ NPBrowser::get()->ReleaseObject(raw_derived_pointer_);
+ EXPECT_EQ(1, raw_derived_pointer_->referenceCount);
+ p1 = p2;
+ EXPECT_EQ(1, raw_derived_pointer_->referenceCount);
+ NPBrowser::get()->RetainObject(raw_derived_pointer_);
+ NPBrowser::get()->RetainObject(raw_derived_pointer_);
+}
+
+TEST_F(NPObjectPointerTest, CanComparePointersForEqual) {
+ NPObjectPointer<MockNPObject> p1(raw_pointer_);
+ NPObjectPointer<DerivedNPObject> p2(raw_derived_pointer_);
+ EXPECT_TRUE(p1 == p1);
+ EXPECT_FALSE(p1 == p2);
+ EXPECT_FALSE(p2 == p1);
+ EXPECT_FALSE(p1 == NPObjectPointer<MockNPObject>());
+}
+
+TEST_F(NPObjectPointerTest, CanComparePointersForNotEqual) {
+ NPObjectPointer<MockNPObject> p1(raw_pointer_);
+ NPObjectPointer<DerivedNPObject> p2(raw_derived_pointer_);
+ EXPECT_FALSE(p1 != p1);
+ EXPECT_TRUE(p1 != p2);
+ EXPECT_TRUE(p2 != p1);
+ EXPECT_TRUE(p1 != NPObjectPointer<MockNPObject>());
+}
+
+TEST_F(NPObjectPointerTest, ArrowOperatorCanBeUsedToAccessNPObjectMembers) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("hello");
+
+ EXPECT_CALL(*raw_pointer_, HasProperty(name)).WillOnce(Return(true));
+
+ NPObjectPointer<MockNPObject> p(raw_pointer_);
+ EXPECT_TRUE(p->HasProperty(name));
+}
+
+TEST_F(NPObjectPointerTest, StarOperatorReturnsNPObjectReference) {
+ NPObjectPointer<MockNPObject> p(raw_pointer_);
+ EXPECT_EQ(raw_pointer_, &*p);
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeConstructedFromReturnedNPObject) {
+ NPBrowser::get()->RetainObject(raw_pointer_);
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ {
+ NPObjectPointer<MockNPObject> p(
+ NPObjectPointer<MockNPObject>::FromReturned(raw_pointer_));
+ EXPECT_EQ(2, raw_pointer_->referenceCount);
+ }
+ EXPECT_EQ(1, raw_pointer_->referenceCount);
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeConstructedFromReturnedNullNPObject) {
+ NPObjectPointer<MockNPObject> p(
+ NPObjectPointer<MockNPObject>::FromReturned(NULL));
+ EXPECT_TRUE(NULL == p.Get());
+}
+
+TEST_F(NPObjectPointerTest, PointerCanBeReturnedAsARawNPObject) {
+ NPObjectPointer<MockNPObject> p(raw_pointer_);
+ EXPECT_EQ(raw_pointer_, p.ToReturned());
+
+ // Check reference count is incremented before return for caller.
+ EXPECT_EQ(3, raw_pointer_->referenceCount);
+
+ NPBrowser::get()->ReleaseObject(raw_pointer_);
+}
+
+TEST_F(NPObjectPointerTest, NULLPointerCanBeReturnedAsARawNPObject) {
+ NPObjectPointer<MockNPObject> p;
+ EXPECT_TRUE(NULL == p.ToReturned());
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/np_plugin_object.h b/o3d/gpu/np_utils/np_plugin_object.h
new file mode 100644
index 0000000..063079f
--- /dev/null
+++ b/o3d/gpu/np_utils/np_plugin_object.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_PLUGIN_OBJECT_H_
+#define GPU_NP_UTILS_NP_PLUGIN_OBJECT_H_
+
+#include "gpu/np_utils/np_object_pointer.h"
+#include "gpu/np_utils/np_headers.h"
+
+namespace gpu_plugin {
+
+// Interface for a plugin instance. The NPP plugin calls forwards to an instance
+// of this interface.
+class PluginObject {
+ public:
+ // Initialize this object.
+ virtual NPError New(NPMIMEType plugin_type,
+ int16 argc,
+ char* argn[],
+ char* argv[],
+ NPSavedData* saved) = 0;
+
+ virtual NPError SetWindow(NPWindow* new_window) = 0;
+
+ virtual int16 HandleEvent(NPEvent* event) = 0;
+
+ // Uninitialize but do not deallocate the object. Release will be called to
+ // deallocate if Destroy succeeds.
+ virtual NPError Destroy(NPSavedData** saved) = 0;
+
+ // Deallocate this object. This object is invalid after this returns.
+ virtual void Release() = 0;
+
+ virtual NPObject* GetScriptableNPObject() = 0;
+
+ protected:
+ PluginObject() {
+ }
+
+ virtual ~PluginObject() {
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PluginObject);
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_PLUGIN_OBJECT_H_
diff --git a/o3d/gpu/np_utils/np_plugin_object_factory.cc b/o3d/gpu/np_utils/np_plugin_object_factory.cc
new file mode 100644
index 0000000..831a4bd
--- /dev/null
+++ b/o3d/gpu/np_utils/np_plugin_object_factory.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/gpu_plugin/gpu_plugin_object_factory.h"
+#include "base/logging.h"
+
+namespace gpu_plugin {
+
+NPPluginObjectFactory* NPPluginObjectFactory::factory_;
+
+PluginObject* NPPluginObjectFactory::CreatePluginObject(
+ NPP npp,
+ NPMIMEType plugin_type) {
+ return NULL;
+}
+
+NPPluginObjectFactory::NPPluginObjectFactory() {
+ // Make this the first factory in the linked list.
+ previous_factory_ = factory_;
+ factory_ = this;
+}
+
+NPPluginObjectFactory::~NPPluginObjectFactory() {
+ // Remove this factory from the linked list.
+ DCHECK(factory_ == this);
+ factory_ = previous_factory_;
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/np_plugin_object_factory.h b/o3d/gpu/np_utils/np_plugin_object_factory.h
new file mode 100644
index 0000000..403d8d5
--- /dev/null
+++ b/o3d/gpu/np_utils/np_plugin_object_factory.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_H_
+#define GPU_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_H_
+
+#include "base/basictypes.h"
+#include "gpu/np_utils/np_headers.h"
+
+namespace gpu_plugin {
+
+class PluginObject;
+
+// Mockable factory base class used to create instances of PluginObject based on
+// plugin mime type.
+class NPPluginObjectFactory {
+ public:
+ virtual PluginObject* CreatePluginObject(NPP npp, NPMIMEType plugin_type);
+
+ static NPPluginObjectFactory* get() {
+ return factory_;
+ }
+
+ protected:
+ NPPluginObjectFactory();
+ virtual ~NPPluginObjectFactory();
+
+ private:
+ static NPPluginObjectFactory* factory_;
+ NPPluginObjectFactory* previous_factory_;
+ DISALLOW_COPY_AND_ASSIGN(NPPluginObjectFactory);
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_H_
diff --git a/o3d/gpu/np_utils/np_plugin_object_factory_mock.h b/o3d/gpu/np_utils/np_plugin_object_factory_mock.h
new file mode 100644
index 0000000..e15447a
--- /dev/null
+++ b/o3d/gpu/np_utils/np_plugin_object_factory_mock.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_MOCK_H_
+#define GPU_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_MOCK_H_
+
+#include "gpu/np_utils/np_plugin_object_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu_plugin {
+
+// Mockable factory used to create instances of PluginObject based on plugin
+// mime type.
+class MockPluginObjectFactory : public NPPluginObjectFactory {
+ public:
+ MOCK_METHOD2(CreatePluginObject, PluginObject*(NPP, NPMIMEType));
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_PLUGIN_OBJECT_FACTORY_MOCK_H_
diff --git a/o3d/gpu/np_utils/np_plugin_object_mock.h b/o3d/gpu/np_utils/np_plugin_object_mock.h
new file mode 100644
index 0000000..e67861b
--- /dev/null
+++ b/o3d/gpu/np_utils/np_plugin_object_mock.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_PLUGIN_OBJECT_MOCK_H_
+#define GPU_NP_UTILS_NP_PLUGIN_OBJECT_MOCK_H_
+
+#include "gpu/np_utils/np_plugin_object.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu_plugin {
+
+class MockPluginObject : public PluginObject {
+ public:
+ MOCK_METHOD5(New, NPError(NPMIMEType, int16, char*[], char*[], NPSavedData*));
+ MOCK_METHOD1(SetWindow, NPError(NPWindow*));
+ MOCK_METHOD1(HandleEvent, int16(NPEvent*));
+ MOCK_METHOD1(Destroy, NPError(NPSavedData**));
+ MOCK_METHOD0(Release, void());
+ MOCK_METHOD0(GetScriptableNPObject, NPObject*());
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_PLUGIN_OBJECT_MOCK_H_
diff --git a/o3d/gpu/np_utils/np_utils.cc b/o3d/gpu/np_utils/np_utils.cc
new file mode 100644
index 0000000..03c4a20
--- /dev/null
+++ b/o3d/gpu/np_utils/np_utils.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/np_utils/np_utils.h"
+
+namespace gpu_plugin {
+
+bool NPVariantToValue(bool* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_BOOLEAN(variant)) {
+ *value = NPVARIANT_TO_BOOLEAN(variant);
+ return true;
+ }
+
+ return false;
+}
+
+bool NPVariantToValue(int32* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_INT32(variant)) {
+ *value = NPVARIANT_TO_INT32(variant);
+ return true;
+ }
+
+ return false;
+}
+
+bool NPVariantToValue(float* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_DOUBLE(variant)) {
+ *value = static_cast<float>(NPVARIANT_TO_DOUBLE(variant));
+ return true;
+ } else if (NPVARIANT_IS_INT32(variant)) {
+ *value = static_cast<float>(NPVARIANT_TO_INT32(variant));
+ return true;
+ }
+
+ return false;
+}
+
+bool NPVariantToValue(double* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_DOUBLE(variant)) {
+ *value = NPVARIANT_TO_DOUBLE(variant);
+ return true;
+ } else if (NPVARIANT_IS_INT32(variant)) {
+ *value = NPVARIANT_TO_INT32(variant);
+ return true;
+ }
+
+ return false;
+}
+
+bool NPVariantToValue(std::string* value, const NPVariant& variant) {
+ if (NPVARIANT_IS_STRING(variant)) {
+ const NPString& str = NPVARIANT_TO_STRING(variant);
+ *value = std::string(str.UTF8Characters, str.UTF8Length);
+ return true;
+ }
+
+ return false;
+}
+
+void ValueToNPVariant(bool value, NPVariant* variant) {
+ BOOLEAN_TO_NPVARIANT(value, *variant);
+}
+
+void ValueToNPVariant(int32 value, NPVariant* variant) {
+ INT32_TO_NPVARIANT(value, *variant);
+}
+
+void ValueToNPVariant(float value, NPVariant* variant) {
+ DOUBLE_TO_NPVARIANT(value, *variant);
+}
+
+void ValueToNPVariant(double value, NPVariant* variant) {
+ DOUBLE_TO_NPVARIANT(value, *variant);
+}
+
+void ValueToNPVariant(const std::string& value, NPVariant* variant) {
+ NPUTF8* p = static_cast<NPUTF8*>(NPBrowser::get()->MemAlloc(value.length()));
+ memcpy(p, value.c_str(), value.length());
+ STRINGN_TO_NPVARIANT(p, value.length(), *variant);
+}
+
+SmartNPVariant::SmartNPVariant() {
+ VOID_TO_NPVARIANT(*this);
+}
+
+SmartNPVariant::SmartNPVariant(const SmartNPVariant& rhs) {
+ rhs.CopyTo(this);
+}
+
+SmartNPVariant::SmartNPVariant(const NPVariant& rhs) {
+ static_cast<const SmartNPVariant&>(rhs).CopyTo(this);
+}
+
+SmartNPVariant::~SmartNPVariant() {
+ Release();
+}
+
+SmartNPVariant& SmartNPVariant::operator=(const SmartNPVariant& rhs) {
+ Release();
+ rhs.CopyTo(this);
+ return *this;
+}
+
+SmartNPVariant& SmartNPVariant::operator=(const NPVariant& rhs) {
+ Release();
+ static_cast<const SmartNPVariant&>(rhs).CopyTo(this);
+ return *this;
+}
+
+bool SmartNPVariant::IsVoid() const {
+ return NPVARIANT_IS_VOID(*this);
+}
+
+void SmartNPVariant::Release() {
+ NPBrowser::get()->ReleaseVariantValue(this);
+ VOID_TO_NPVARIANT(*this);
+}
+
+void SmartNPVariant::Invalidate() {
+ if (NPVARIANT_IS_OBJECT(*this)) {
+ NULL_TO_NPVARIANT(*this);
+ }
+}
+
+void SmartNPVariant::CopyTo(NPVariant* rhs) const {
+ if (NPVARIANT_IS_OBJECT(*this)) {
+ NPObject* object = NPVARIANT_TO_OBJECT(*this);
+ OBJECT_TO_NPVARIANT(object, *rhs);
+ NPBrowser::get()->RetainObject(object);
+ } else if (NPVARIANT_IS_STRING(*this)) {
+ NPUTF8* copy = static_cast<NPUTF8*>(NPBrowser::get()->MemAlloc(
+ value.stringValue.UTF8Length));
+ memcpy(copy,
+ value.stringValue.UTF8Characters,
+ value.stringValue.UTF8Length);
+ STRINGN_TO_NPVARIANT(copy, value.stringValue.UTF8Length, *rhs);
+ } else {
+ memcpy(rhs, this, sizeof(*rhs));
+ }
+}
+
+bool NPHasMethod(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name) {
+ return NPBrowser::get()->HasMethod(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name));
+}
+
+bool NPHasProperty(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name) {
+ return NPBrowser::get()->HasProperty(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name));
+}
+
+bool NPRemoveProperty(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name) {
+ return NPBrowser::get()->RemoveProperty(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name));
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/np_utils.h b/o3d/gpu/np_utils/np_utils.h
new file mode 100644
index 0000000..2ab9384
--- /dev/null
+++ b/o3d/gpu/np_utils/np_utils.h
@@ -0,0 +1,271 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_NP_UTILS_H_
+#define GPU_NP_UTILS_NP_UTILS_H_
+
+#include <string>
+
+#include "gpu/np_utils/np_browser.h"
+#include "gpu/np_utils/np_class.h"
+#include "gpu/np_utils/np_object_pointer.h"
+#include "gpu/np_utils/np_headers.h"
+
+namespace gpu_plugin {
+
+// Convert NPVariant to C++ type. Returns whether the conversion was successful.
+bool NPVariantToValue(bool* value, const NPVariant& variant);
+bool NPVariantToValue(int32* value, const NPVariant& variant);
+bool NPVariantToValue(float* value, const NPVariant& variant);
+bool NPVariantToValue(double* value, const NPVariant& variant);
+bool NPVariantToValue(std::string* value, const NPVariant& variant);
+
+template <typename T>
+bool NPVariantToValue(NPObjectPointer<T>* value,
+ const NPVariant& variant) {
+ if (NPVARIANT_IS_NULL(variant)) {
+ *value = NPObjectPointer<T>();
+ return true;
+ } else if (NPVARIANT_IS_OBJECT(variant)) {
+ NPObject* object = NPVARIANT_TO_OBJECT(variant);
+ if (object->_class == NPGetClass<T>()) {
+ *value = NPObjectPointer<T>(static_cast<T*>(
+ NPVARIANT_TO_OBJECT(variant)));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Specialization for NPObject does not check for mismatched NPClass.
+template <>
+inline bool NPVariantToValue(NPObjectPointer<NPObject>* value,
+ const NPVariant& variant) {
+ if (NPVARIANT_IS_NULL(variant)) {
+ *value = NPObjectPointer<NPObject>();
+ return true;
+ } else if (NPVARIANT_IS_OBJECT(variant)) {
+ *value = NPObjectPointer<NPObject>(NPVARIANT_TO_OBJECT(variant));
+ return true;
+ }
+
+ return false;
+}
+
+// Convert C++ type to NPVariant.
+void ValueToNPVariant(bool value, NPVariant* variant);
+void ValueToNPVariant(int32 value, NPVariant* variant);
+void ValueToNPVariant(float value, NPVariant* variant);
+void ValueToNPVariant(double value, NPVariant* variant);
+void ValueToNPVariant(const std::string& value, NPVariant* variant);
+
+template <typename T>
+void ValueToNPVariant(const NPObjectPointer<T>& value,
+ NPVariant* variant) {
+ if (value.Get()) {
+ NPBrowser::get()->RetainObject(value.Get());
+ OBJECT_TO_NPVARIANT(value.Get(), *variant);
+ } else {
+ NULL_TO_NPVARIANT(*variant);
+ }
+}
+
+// NPVariant that automatically manages lifetime of string and object variants.
+class SmartNPVariant : public NPVariant {
+ public:
+ SmartNPVariant();
+ SmartNPVariant(const SmartNPVariant& rhs);
+ explicit SmartNPVariant(const NPVariant& rhs);
+
+ template <typename T>
+ explicit SmartNPVariant(const T& v) {
+ ValueToNPVariant(v, this);
+ }
+
+ ~SmartNPVariant();
+
+ SmartNPVariant& operator=(const SmartNPVariant& rhs);
+ SmartNPVariant& operator=(const NPVariant& rhs);
+
+ template <typename T>
+ bool GetValue(T* v) const {
+ return NPVariantToValue(v, *this);
+ }
+
+ bool IsVoid() const;
+
+ template <typename T>
+ void SetValue(const T& v) {
+ Release();
+ ValueToNPVariant(v, this);
+ }
+
+ void CopyTo(NPVariant* target) const;
+
+ // Sets the variant to void.
+ void Release();
+
+ // Called when an NPObject is invalidated to clear any references to other
+ // NPObjects. Does not release the object as it might no longer be valid.
+ void Invalidate();
+};
+
+// These allow a method to be invoked with automatic conversion of C++
+// types to variants for arguments and return values.
+
+bool NPHasMethod(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name);
+
+inline bool NPInvokeVoid(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name) {
+ SmartNPVariant result;
+ return NPBrowser::get()->Invoke(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name),
+ NULL, 0,
+ &result);
+}
+
+template<typename R>
+bool NPInvoke(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name,
+ R* r) {
+ SmartNPVariant result;
+ if (NPBrowser::get()->Invoke(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name),
+ NULL, 0,
+ &result)) {
+ return result.GetValue(r);
+ }
+ return false;
+}
+
+template<typename P0>
+bool NPInvokeVoid(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name,
+ P0 p0) {
+ SmartNPVariant args[1];
+ args[0].SetValue(p0);
+ SmartNPVariant result;
+ return NPBrowser::get()->Invoke(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name),
+ &args[0], 1,
+ &result);
+}
+
+template<typename R, typename P0>
+bool NPInvoke(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name,
+ P0 p0,
+ R* r) {
+ SmartNPVariant args[1];
+ args[0].SetValue(p0);
+ SmartNPVariant result;
+ if (NPBrowser::get()->Invoke(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name),
+ &args[0], 1,
+ &result)) {
+ return result.GetValue(r);
+ }
+ return false;
+}
+
+template<typename P0, typename P1>
+bool NPInvokeVoid(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name,
+ P0 p0, P1 p1) {
+ SmartNPVariant args[2];
+ args[0].SetValue(p0);
+ args[1].SetValue(p1);
+ SmartNPVariant result;
+ return NPBrowser::get()->Invoke(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name),
+ &args[0], 2,
+ &result);
+}
+
+template<typename R, typename P0, typename P1>
+bool NPInvoke(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name,
+ P0 p0, P1 p1,
+ R* r) {
+ SmartNPVariant args[2];
+ args[0].SetValue(p0);
+ args[1].SetValue(p1);
+ SmartNPVariant result;
+ if (NPBrowser::get()->Invoke(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name),
+ &args[0], 2,
+ &result)) {
+ return result.GetValue(r);
+ }
+ return false;
+}
+
+bool NPHasProperty(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name);
+
+template <typename T>
+bool NPGetProperty(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name,
+ T* value) {
+ SmartNPVariant result;
+ if (NPBrowser::get()->GetProperty(npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name),
+ &result)) {
+ return result.GetValue(value);
+ }
+ return false;
+}
+
+template <typename T>
+bool NPSetProperty(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name,
+ const T& value) {
+ SmartNPVariant variant(value);
+ return NPBrowser::get()->SetProperty(
+ npp,
+ object.Get(),
+ NPBrowser::get()->GetStringIdentifier(name),
+ &variant);
+}
+
+bool NPRemoveProperty(NPP npp,
+ const NPObjectPointer<NPObject>& object,
+ const NPUTF8* name);
+
+template <typename NPObjectType>
+NPObjectPointer<NPObjectType> NPCreateObject(NPP npp) {
+ const NPClass* np_class = NPGetClass<NPObjectType>();
+ NPObjectType* object = static_cast<NPObjectType*>(
+ NPBrowser::get()->CreateObject(npp, np_class));
+ return NPObjectPointer<NPObjectType>::FromReturned(object);
+}
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_NP_UTILS_H_
diff --git a/o3d/gpu/np_utils/np_utils_unittest.cc b/o3d/gpu/np_utils/np_utils_unittest.cc
new file mode 100644
index 0000000..e481187
--- /dev/null
+++ b/o3d/gpu/np_utils/np_utils_unittest.cc
@@ -0,0 +1,424 @@
+// Copyright (c) 2006-2008 The Chromium 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 "gpu/np_utils/np_object_mock.h"
+#include "gpu/np_utils/np_browser_stub.h"
+#include "gpu/np_utils/np_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::DoAll;
+using testing::MakeMatcher;
+using testing::Matcher;
+using testing::Pointee;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+namespace gpu_plugin {
+
+class NPUtilsTest : public testing::Test {
+ protected:
+ StubNPBrowser stub_browser_;
+ NPP_t npp_;
+ NPVariant variant_;
+};
+
+TEST_F(NPUtilsTest, TestBoolNPVariantToValue) {
+ bool v;
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_FALSE(v);
+
+ BOOLEAN_TO_NPVARIANT(true, variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_TRUE(v);
+
+ INT32_TO_NPVARIANT(7, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPUtilsTest, TestIntNPVariantToValue) {
+ INT32_TO_NPVARIANT(7, variant_);
+
+ int v1;
+ EXPECT_TRUE(NPVariantToValue(&v1, variant_));
+ EXPECT_EQ(7, v1);
+
+ float v2;
+ EXPECT_TRUE(NPVariantToValue(&v2, variant_));
+ EXPECT_EQ(7.0f, v2);
+
+ double v3;
+ EXPECT_TRUE(NPVariantToValue(&v3, variant_));
+ EXPECT_EQ(7.0, v3);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v1, variant_));
+}
+
+TEST_F(NPUtilsTest, TestFloatNPVariantToValue) {
+ float v;
+
+ DOUBLE_TO_NPVARIANT(7.0, variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_EQ(7.0f, v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPUtilsTest, TestDoubleNPVariantToValue) {
+ double v;
+
+ DOUBLE_TO_NPVARIANT(7.0, variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_EQ(7.0, v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPUtilsTest, TestStringNPVariantToValue) {
+ std::string v;
+
+ STRINGZ_TO_NPVARIANT("hello", variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_EQ(std::string("hello"), v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPUtilsTest, TestObjectNPVariantToValue) {
+ NPObjectPointer<NPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+ NPObjectPointer<NPObject> v;
+
+ OBJECT_TO_NPVARIANT(object.Get(), variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_EQ(object, v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPUtilsTest, TestNullNPVariantToValue) {
+ NPObjectPointer<NPObject> v;
+
+ NULL_TO_NPVARIANT(variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_TRUE(NPObjectPointer<NPObject>() == v);
+
+ BOOLEAN_TO_NPVARIANT(false, variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPUtilsTest, TestDerivedObjectNPVariantToValue) {
+ NPObjectPointer<NPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+ NPObjectPointer<StrictMock<MockNPObject> > v;
+
+ OBJECT_TO_NPVARIANT(object.Get(), variant_);
+ EXPECT_TRUE(NPVariantToValue(&v, variant_));
+ EXPECT_EQ(object, v);
+}
+
+TEST_F(NPUtilsTest,
+ TestDerivedObjectNPVariantToValueFailsIfValueHasDifferentType) {
+ NPObjectPointer<NPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+ NPObjectPointer<MockNPObject> v;
+
+ OBJECT_TO_NPVARIANT(object.Get(), variant_);
+ EXPECT_FALSE(NPVariantToValue(&v, variant_));
+}
+
+TEST_F(NPUtilsTest, TestBoolValueToNPVariant) {
+ ValueToNPVariant(true, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_BOOLEAN(variant_));
+ EXPECT_TRUE(NPVARIANT_TO_BOOLEAN(variant_));
+
+ ValueToNPVariant(false, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_BOOLEAN(variant_));
+ EXPECT_FALSE(NPVARIANT_TO_BOOLEAN(variant_));
+}
+
+TEST_F(NPUtilsTest, TestIntValueToNPVariant) {
+ ValueToNPVariant(7, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_INT32(variant_));
+ EXPECT_EQ(7, NPVARIANT_TO_INT32(variant_));
+}
+
+TEST_F(NPUtilsTest, TestFloatValueToNPVariant) {
+ ValueToNPVariant(7.0f, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_DOUBLE(variant_));
+ EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(variant_));
+}
+
+TEST_F(NPUtilsTest, TestDoubleValueToNPVariant) {
+ ValueToNPVariant(7.0, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_DOUBLE(variant_));
+ EXPECT_EQ(7.0, NPVARIANT_TO_DOUBLE(variant_));
+}
+
+TEST_F(NPUtilsTest, TestStringValueToNPVariant) {
+ ValueToNPVariant(std::string("hello"), &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_STRING(variant_));
+ EXPECT_EQ(std::string("hello"),
+ std::string(variant_.value.stringValue.UTF8Characters,
+ variant_.value.stringValue.UTF8Length));
+}
+
+TEST_F(NPUtilsTest, TestObjectValueToNPVariant) {
+ NPObjectPointer<NPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ ValueToNPVariant(object, &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_OBJECT(variant_));
+ EXPECT_EQ(object.Get(), NPVARIANT_TO_OBJECT(variant_));
+
+ NPBrowser::get()->ReleaseVariantValue(&variant_);
+}
+
+TEST_F(NPUtilsTest, TestNullValueToNPVariant) {
+ ValueToNPVariant(NPObjectPointer<NPObject>(), &variant_);
+ EXPECT_TRUE(NPVARIANT_IS_NULL(variant_));
+}
+
+TEST_F(NPUtilsTest, CanCopyObjectSmartVariant) {
+ NPObjectPointer<NPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+ EXPECT_EQ(1, object->referenceCount);
+ {
+ SmartNPVariant v1(object);
+ EXPECT_EQ(2, object->referenceCount);
+ {
+ SmartNPVariant v2(v1);
+ EXPECT_EQ(3, object->referenceCount);
+ }
+ EXPECT_EQ(2, object->referenceCount);
+ }
+ EXPECT_EQ(1, object->referenceCount);
+}
+
+TEST_F(NPUtilsTest, CanCopyStringSmartVariant) {
+ SmartNPVariant v1(std::string("hello"));
+ SmartNPVariant v2(v1);
+ std::string r;
+ EXPECT_TRUE(NPVariantToValue(&r, v2));
+ EXPECT_EQ(std::string("hello"), r);
+ EXPECT_NE(v1.value.stringValue.UTF8Characters,
+ v2.value.stringValue.UTF8Characters);
+}
+
+TEST_F(NPUtilsTest, CanReleaseSmartVariant) {
+ SmartNPVariant variant(std::string("hello"));
+ EXPECT_FALSE(variant.IsVoid());
+ variant.Release();
+ EXPECT_TRUE(variant.IsVoid());
+}
+
+template <typename T>
+class VariantMatcher : public testing::MatcherInterface<const NPVariant&> {
+ public:
+ explicit VariantMatcher(const T& value) : value_(value) {
+ }
+
+ virtual bool Matches(const NPVariant& variant) const {
+ T other_value;
+ return NPVariantToValue(&other_value, variant) && other_value == value_;
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "equals " << value_;
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "does not equal " << value_;
+ }
+
+ private:
+ T value_;
+};
+
+template <typename T>
+Matcher<const NPVariant&> VariantMatches(const T& value) {
+ return MakeMatcher(new VariantMatcher<T>(value));
+}
+
+TEST_F(NPUtilsTest, CanDetermineIfObjectHasMethod) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ EXPECT_CALL(*object, HasMethod(name))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(NPHasMethod(NULL, object, "foo"));
+}
+
+TEST_F(NPUtilsTest, CanInvokeVoidMethodWithNativeTypes) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ VOID_TO_NPVARIANT(variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(true)));
+
+ EXPECT_TRUE(NPInvokeVoid(NULL, object, "foo", 7));
+}
+
+TEST_F(NPUtilsTest, InvokeVoidMethodCanFail) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ VOID_TO_NPVARIANT(variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(false)));
+
+ EXPECT_FALSE(NPInvokeVoid(NULL, object, "foo", 7));
+}
+
+TEST_F(NPUtilsTest, CanInvokeNonVoidMethodWithNativeTypes) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ DOUBLE_TO_NPVARIANT(1.5, variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(true)));
+
+ double r;
+ EXPECT_TRUE(NPInvoke(NULL, object, "foo", 7, &r));
+ EXPECT_EQ(1.5, r);
+}
+
+TEST_F(NPUtilsTest, InvokeNonVoidMethodCanFail) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ DOUBLE_TO_NPVARIANT(1.5, variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(false)));
+
+ double r;
+ EXPECT_FALSE(NPInvoke(NULL, object, "foo", 7, &r));
+}
+
+TEST_F(NPUtilsTest, InvokeNonVoidMethodFailsIfResultIsIncompatible) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ DOUBLE_TO_NPVARIANT(1.5, variant_);
+
+ EXPECT_CALL(*object, Invoke(name, Pointee(VariantMatches<int32>(7)), 1, _))
+ .WillOnce(DoAll(SetArgumentPointee<3>(variant_),
+ Return(true)));
+
+ int r;
+ EXPECT_FALSE(NPInvoke(NULL, object, "foo", 7, &r));
+}
+
+TEST_F(NPUtilsTest, CanDetermineIfObjectHasProperty) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ EXPECT_CALL(*object, HasProperty(name))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(NPHasProperty(NULL, object, "foo"));
+}
+
+TEST_F(NPUtilsTest, CanGetPropertyValue) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ DOUBLE_TO_NPVARIANT(1.5, variant_);
+
+ EXPECT_CALL(*object, GetProperty(name, _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(variant_),
+ Return(true)));
+
+ double r;
+ EXPECT_TRUE(NPGetProperty(NULL, object, "foo", &r));
+}
+
+TEST_F(NPUtilsTest, NPGetPropertyReportsFailureIfResultTypeIsDifferent) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ DOUBLE_TO_NPVARIANT(1.5, variant_);
+
+ EXPECT_CALL(*object, GetProperty(name, _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(variant_),
+ Return(true)));
+
+ bool r;
+ EXPECT_FALSE(NPGetProperty(NULL, object, "foo", &r));
+}
+
+TEST_F(NPUtilsTest, NPGetPropertyReportsFailureFromGetProperty) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ EXPECT_CALL(*object, GetProperty(name, _))
+ .WillOnce(Return(false));
+
+ double r;
+ EXPECT_FALSE(NPGetProperty(NULL, object, "foo", &r));
+}
+
+TEST_F(NPUtilsTest, CanSetPropertyValue) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ EXPECT_CALL(*object, SetProperty(name, Pointee(VariantMatches(1.5))))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(NPSetProperty(NULL, object, "foo", 1.5));
+}
+
+TEST_F(NPUtilsTest, NPSetPropertyReportsFailureFromSetProperty) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ EXPECT_CALL(*object, SetProperty(name, Pointee(VariantMatches(1.5))))
+ .WillOnce(Return(false));
+
+ EXPECT_FALSE(NPSetProperty(NULL, object, "foo", 1.5));
+}
+
+TEST_F(NPUtilsTest, CanRemovePropertyValue) {
+ NPIdentifier name = NPBrowser::get()->GetStringIdentifier("foo");
+ NPObjectPointer<MockNPObject> object =
+ NPCreateObject<StrictMock<MockNPObject> >(NULL);
+
+ EXPECT_CALL(*object, RemoveProperty(name))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(NPRemoveProperty(NULL, object, "foo"));
+}
+
+} // namespace gpu_plugin
diff --git a/o3d/gpu/np_utils/webkit_browser.h b/o3d/gpu/np_utils/webkit_browser.h
new file mode 100644
index 0000000..8afc167
--- /dev/null
+++ b/o3d/gpu/np_utils/webkit_browser.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2006-2008 The Chromium 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 GPU_NP_UTILS_WEBKIT_BROWSER_H_
+#define GPU_NP_UTILS_WEBKIT_BROWSER_H_
+
+// TODO(apatrick): This does not belong in np_utils. np_utils should not be
+// dependent on WebKit (and it isn't - that's why the member functions are
+// inline).
+
+#include <stdlib.h>
+
+#include "gpu/np_utils/np_browser.h"
+#include "WebKit/api/public/WebBindings.h"
+
+typedef struct _NPNetscapeFuncs NPNetscapeFuncs;
+typedef struct _NPChromiumFuncs NPChromiumFuncs;
+
+namespace gpu_plugin {
+
+// This class implements NPBrowser for the WebKit WebBindings.
+class WebKitBrowser : public NPBrowser {
+ public:
+ WebKitBrowser(): NPBrowser(NULL) {
+ }
+
+ // Standard functions from NPNetscapeFuncs.
+
+ virtual NPIdentifier GetStringIdentifier(const NPUTF8* name) {
+ return WebKit::WebBindings::getStringIdentifier(name);
+ }
+
+ virtual void* MemAlloc(size_t size) {
+ return malloc(size);
+ }
+
+ virtual void MemFree(void* p) {
+ free(p);
+ }
+
+ virtual NPObject* CreateObject(NPP npp, const NPClass* cl) {
+ return WebKit::WebBindings::createObject(npp, const_cast<NPClass*>(cl));
+ }
+
+ virtual NPObject* RetainObject(NPObject* object) {
+ return WebKit::WebBindings::retainObject(object);
+ }
+
+ virtual void ReleaseObject(NPObject* object) {
+ WebKit::WebBindings::releaseObject(object);
+ }
+
+ virtual void ReleaseVariantValue(NPVariant* variant) {
+ WebKit::WebBindings::releaseVariantValue(variant);
+ }
+
+ virtual bool HasProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name) {
+ return WebKit::WebBindings::hasProperty(npp, object, name);
+ }
+
+ virtual bool GetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ NPVariant* result) {
+ return WebKit::WebBindings::getProperty(npp, object, name, result);
+ }
+
+ virtual bool SetProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* result) {
+ return WebKit::WebBindings::setProperty(npp, object, name, result);
+ }
+
+ virtual bool RemoveProperty(NPP npp,
+ NPObject* object,
+ NPIdentifier name) {
+ return WebKit::WebBindings::removeProperty(npp, object, name);
+ }
+
+ virtual bool HasMethod(NPP npp,
+ NPObject* object,
+ NPIdentifier name) {
+ return WebKit::WebBindings::hasMethod(npp, object, name);
+ }
+
+ virtual bool Invoke(NPP npp,
+ NPObject* object,
+ NPIdentifier name,
+ const NPVariant* args,
+ uint32_t num_args,
+ NPVariant* result) {
+ return WebKit::WebBindings::invoke(npp, object, name, args, num_args,
+ result);
+ }
+
+ virtual NPObject* GetWindowNPObject(NPP npp) {
+ NPObject* window;
+ if (NPERR_NO_ERROR == NPN_GetValue(npp,
+ NPNVWindowNPObject,
+ &window)) {
+ return window;
+ } else {
+ return NULL;
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebKitBrowser);
+};
+
+} // namespace gpu_plugin
+
+#endif // GPU_NP_UTILS_WEBKIT_BROWSER_H_