summaryrefslogtreecommitdiffstats
path: root/o3d/core/win
diff options
context:
space:
mode:
authorgspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-27 23:15:42 +0000
committergspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-27 23:15:42 +0000
commit05b47f7a8c5451f858dc220df0e3a97542edace6 (patch)
treea2273d619f0625c9d44d40842845ccce2eac1045 /o3d/core/win
parent5cdc8bdb4c847cefe7f4542bd10c9880c2c557a0 (diff)
downloadchromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.zip
chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.gz
chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.bz2
This is the O3D source tree's initial commit to the Chromium tree. It
is not built or referenced at all by the chrome build yet, and doesn't yet build in it's new home. We'll change that shortly. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17035 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/core/win')
-rw-r--r--o3d/core/win/command_buffer/win32_cb_server.cc116
-rw-r--r--o3d/core/win/command_buffer/win32_cb_server.h71
-rw-r--r--o3d/core/win/core_unittests.sln39
-rw-r--r--o3d/core/win/d3d9/buffer_d3d9.cc221
-rw-r--r--o3d/core/win/d3d9/buffer_d3d9.h122
-rw-r--r--o3d/core/win/d3d9/d3d_entry_points.h140
-rw-r--r--o3d/core/win/d3d9/draw_element_d3d9.cc48
-rw-r--r--o3d/core/win/d3d9/draw_element_d3d9.h53
-rw-r--r--o3d/core/win/d3d9/effect_d3d9.cc869
-rw-r--r--o3d/core/win/d3d9/effect_d3d9.h203
-rw-r--r--o3d/core/win/d3d9/install_check.cc255
-rw-r--r--o3d/core/win/d3d9/param_cache_d3d9.cc83
-rw-r--r--o3d/core/win/d3d9/param_cache_d3d9.h74
-rw-r--r--o3d/core/win/d3d9/primitive_d3d9.cc239
-rw-r--r--o3d/core/win/d3d9/primitive_d3d9.h67
-rw-r--r--o3d/core/win/d3d9/render_surface_d3d9.cc101
-rw-r--r--o3d/core/win/d3d9/render_surface_d3d9.h116
-rw-r--r--o3d/core/win/d3d9/renderer_d3d9.cc1691
-rw-r--r--o3d/core/win/d3d9/renderer_d3d9.h281
-rw-r--r--o3d/core/win/d3d9/sampler_d3d9.cc194
-rw-r--r--o3d/core/win/d3d9/sampler_d3d9.h72
-rw-r--r--o3d/core/win/d3d9/stream_bank_d3d9.cc184
-rw-r--r--o3d/core/win/d3d9/stream_bank_d3d9.h81
-rw-r--r--o3d/core/win/d3d9/texture_d3d9.cc747
-rw-r--r--o3d/core/win/d3d9/texture_d3d9.h188
-rw-r--r--o3d/core/win/d3d9/utils_d3d9.cc119
-rw-r--r--o3d/core/win/d3d9/utils_d3d9.h72
-rw-r--r--o3d/core/win/display_window_win.h58
-rw-r--r--o3d/core/win/performance_timer.cc79
29 files changed, 6583 insertions, 0 deletions
diff --git a/o3d/core/win/command_buffer/win32_cb_server.cc b/o3d/core/win/command_buffer/win32_cb_server.cc
new file mode 100644
index 0000000..01bfd26
--- /dev/null
+++ b/o3d/core/win/command_buffer/win32_cb_server.cc
@@ -0,0 +1,116 @@
+/*
+ * 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 Win32CBServer class.
+
+#include "core/cross/precompile.h"
+#include "core/win/command_buffer/win32_cb_server.h"
+#include "command_buffer/service/cross/buffer_rpc.h"
+#include "command_buffer/service/cross/cmd_buffer_engine.h"
+#include "command_buffer/service/cross/gapi_decoder.h"
+
+namespace o3d {
+
+using command_buffer::GAPIDecoder;
+using command_buffer::IMCSender;
+using command_buffer::IMCMessageProcessor;
+using command_buffer::BufferSyncProxy;
+using command_buffer::CommandBufferEngine;
+
+Win32CBServer::Win32CBServer(HWND window)
+ : gapi_(),
+ proxy_(NULL),
+ imc_sender_(NULL),
+ thread_(NULL) {
+ gapi_.set_hwnd(window);
+
+ nacl::Handle handles[2];
+ nacl::SocketPair(handles);
+
+ socket_pair_[0] = nacl::CreateImcDesc(handles[0]);
+ socket_pair_[1] = nacl::CreateImcDesc(handles[1]);
+ imc_sender_.reset(new IMCSender(socket_pair_[0]));
+ proxy_.reset(new BufferSyncProxy(imc_sender_.get()));
+
+ thread_ = ::CreateThread(NULL, 0, ThreadMain, this, 0, NULL);
+}
+
+Win32CBServer::~Win32CBServer() {
+ imc_sender_->SendCall(command_buffer::POISONED_MESSAGE_ID, NULL, 0, NULL,
+ 0);
+ ::WaitForSingleObject(thread_, INFINITE);
+ ::CloseHandle(thread_);
+
+ nacl::Close(socket_pair_[0]);
+ nacl::Close(socket_pair_[1]);
+}
+
+DWORD WINAPI Win32CBServer::ThreadMain(LPVOID param) {
+ Win32CBServer *server = static_cast<Win32CBServer *>(param);
+
+ scoped_ptr<GAPIDecoder> decoder(new GAPIDecoder(&server->gapi_));
+ scoped_ptr<CommandBufferEngine> engine(
+ new CommandBufferEngine(decoder.get()));
+ decoder->set_engine(engine.get());
+
+ IMCMessageProcessor processor(server->socket_pair_[1], engine->rpc_impl());
+ engine->set_process_interface(&processor);
+ IMCSender sender(server->socket_pair_[1]);
+ engine->set_client_rpc(&sender);
+
+ server->gapi_.Initialize();
+ bool running = true;
+ while (running) {
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ if (msg.message == WM_QUIT) {
+ running = false;
+ break;
+ }
+ }
+ if (!running) break;
+ // DoWork() will block if there is nothing to be done, meaning we are only
+ // going to handle message after commands are sent. It should happen at
+ // least once a frame, so it's OK.
+ // TODO: figure out a way to wait on the socket OR messages with
+ // MsgWaitForMultipleObjects. Asynchronous ("overlapped") read on the
+ // socket may let us do that.
+ running = engine->DoWork();
+ }
+ server->gapi_.Destroy();
+
+ return 0;
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/command_buffer/win32_cb_server.h b/o3d/core/win/command_buffer/win32_cb_server.h
new file mode 100644
index 0000000..8d34e8d1
--- /dev/null
+++ b/o3d/core/win/command_buffer/win32_cb_server.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.
+ */
+
+
+// This file declares the Win32CBServer class, helper class that runs a command
+// buffer server in a separate win32 thread.
+
+#ifndef O3D_CORE_WIN_COMMAND_BUFFER_WIN32_CB_SERVER_H_
+#define O3D_CORE_WIN_COMMAND_BUFFER_WIN32_CB_SERVER_H_
+
+#include "core/cross/precompile.h"
+#include "command_buffer/common/cross/rpc_imc.h"
+#include "command_buffer/client/cross/buffer_sync_proxy.h"
+#include "command_buffer/service/win/d3d9/gapi_d3d9.h"
+
+namespace o3d {
+
+// The current Renderer API assumes we connect directly to the window. This
+// class creates a command buffer server in a separate thread, and sets up the
+// communication socket.
+// This code will go away once we fix the API, and provide a separate mechanism
+// to connect to the service.
+class Win32CBServer {
+ public:
+ explicit Win32CBServer(HWND window);
+ ~Win32CBServer();
+
+ // Gets the (client-side) command buffer interface.
+ command_buffer::BufferSyncInterface *GetInterface() { return proxy_.get(); }
+
+ private:
+ static DWORD WINAPI ThreadMain(LPVOID param);
+
+ command_buffer::GAPID3D9 gapi_;
+ nacl::HtpHandle socket_pair_[2];
+ scoped_ptr<command_buffer::IMCSender> imc_sender_;
+ scoped_ptr<command_buffer::BufferSyncProxy> proxy_;
+ HANDLE thread_;
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_WIN_COMMAND_BUFFER_WIN32_CB_SERVER_H_
diff --git a/o3d/core/win/core_unittests.sln b/o3d/core/win/core_unittests.sln
new file mode 100644
index 0000000..d72ca8d6
--- /dev/null
+++ b/o3d/core/win/core_unittests.sln
@@ -0,0 +1,39 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_unittests", "core_unittests.vcproj", "{A330B4F2-1340-41F9-AE61-BF5471772624}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B} = {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "o3dCore", "core_win.vcproj", "{B57C4010-AE66-47A2-8B1F-F839B6E6A67B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ DebugD3D9|Win32 = DebugD3D9|Win32
+ DebugGL|Win32 = DebugGL|Win32
+ ReleaseD3D9|Win32 = ReleaseD3D9|Win32
+ ReleaseGL|Win32 = ReleaseGL|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A330B4F2-1340-41F9-AE61-BF5471772624}.DebugD3D9|Win32.ActiveCfg = DebugD3D9|Win32
+ {A330B4F2-1340-41F9-AE61-BF5471772624}.DebugD3D9|Win32.Build.0 = DebugD3D9|Win32
+ {A330B4F2-1340-41F9-AE61-BF5471772624}.DebugGL|Win32.ActiveCfg = DebugGL|Win32
+ {A330B4F2-1340-41F9-AE61-BF5471772624}.DebugGL|Win32.Build.0 = DebugGL|Win32
+ {A330B4F2-1340-41F9-AE61-BF5471772624}.ReleaseD3D9|Win32.ActiveCfg = ReleaseD3D9|Win32
+ {A330B4F2-1340-41F9-AE61-BF5471772624}.ReleaseD3D9|Win32.Build.0 = ReleaseD3D9|Win32
+ {A330B4F2-1340-41F9-AE61-BF5471772624}.ReleaseGL|Win32.ActiveCfg = ReleaseGL|Win32
+ {A330B4F2-1340-41F9-AE61-BF5471772624}.ReleaseGL|Win32.Build.0 = ReleaseGL|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.DebugD3D9|Win32.ActiveCfg = DebugD3D9|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.DebugD3D9|Win32.Build.0 = DebugD3D9|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.DebugGL|Win32.ActiveCfg = DebugGL|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.DebugGL|Win32.Build.0 = DebugGL|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.ReleaseD3D9|Win32.ActiveCfg = ReleaseD3D9|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.ReleaseD3D9|Win32.Build.0 = ReleaseD3D9|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.ReleaseGL|Win32.ActiveCfg = ReleaseGL|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.ReleaseGL|Win32.Build.0 = ReleaseGL|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/o3d/core/win/d3d9/buffer_d3d9.cc b/o3d/core/win/d3d9/buffer_d3d9.cc
new file mode 100644
index 0000000..0633208
--- /dev/null
+++ b/o3d/core/win/d3d9/buffer_d3d9.cc
@@ -0,0 +1,221 @@
+/*
+ * 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 definitions of VertexBufferD3D9 and IndexBufferD3D9.
+
+#include "core/cross/precompile.h"
+#include "core/win/d3d9/buffer_d3d9.h"
+#include "core/win/d3d9/utils_d3d9.h"
+
+namespace o3d {
+
+namespace {
+
+DWORD BufferAccessModeToD3DLock(Buffer::AccessMode access_mode) {
+ switch (access_mode) {
+ case Buffer::READ_ONLY:
+ return D3DLOCK_READONLY;
+ break;
+ case Buffer::WRITE_ONLY:
+ return 0;
+ case Buffer::READ_WRITE:
+ return 0;
+ }
+ DCHECK(false);
+ return 0;
+}
+
+} // anonymous namespace
+
+// Initializes the O3D VertexBuffer object but does not create a DX9 buffer
+// yet.
+VertexBufferD3D9::VertexBufferD3D9(ServiceLocator* service_locator,
+ LPDIRECT3DDEVICE9 d3d_device)
+ : VertexBuffer(service_locator),
+ d3d_device_(d3d_device) {
+ DCHECK(d3d_device);
+}
+
+VertexBufferD3D9::~VertexBufferD3D9() {
+}
+
+// Creates a DX9 vertex buffer of the requested size.
+bool VertexBufferD3D9::ConcreteAllocate(unsigned int size_in_bytes) {
+ d3d_buffer_ = NULL;
+ return HR(d3d_device_->CreateVertexBuffer(
+ size_in_bytes,
+ 0,
+ 0,
+ D3DPOOL_MANAGED,
+ &d3d_buffer_,
+ NULL));
+}
+
+void VertexBufferD3D9::ConcreteFree() {
+ d3d_buffer_ = NULL;
+}
+
+// Calls Lock on the DX9 buffer to get the address in memory of where the
+// buffer data is currently stored.
+bool VertexBufferD3D9::ConcreteLock(AccessMode access_mode,
+ void **buffer_data) {
+ *buffer_data = NULL;
+
+ if (GetSizeInBytes() == 0)
+ return true;
+
+ if (!d3d_buffer_)
+ return false;
+
+ if (!HR(d3d_buffer_->Lock(0, GetSizeInBytes(), buffer_data,
+ BufferAccessModeToD3DLock(access_mode)))) {
+ return false;
+ }
+
+ // Yes, this really happens sometimes.
+ if (NULL == *buffer_data) {
+ HR(d3d_buffer_->Unlock());
+ return false;
+ }
+
+ return true;
+}
+
+// Calls Unlock on the DX9 buffer to notify that the contents of the buffer
+// are now ready for use.
+bool VertexBufferD3D9::ConcreteUnlock() {
+ if (!d3d_buffer_) return false;
+ return HR(d3d_buffer_->Unlock());
+}
+
+// Initializes the O3D IndexBuffer object but does not create a DX9 buffer
+// yet.
+IndexBufferD3D9::IndexBufferD3D9(ServiceLocator* service_locator,
+ LPDIRECT3DDEVICE9 d3d_device,
+ bool small_buffer)
+ : IndexBuffer(service_locator),
+ d3d_device_(d3d_device),
+ shadow_buffer_(NULL),
+ dirty_(false),
+ small_(small_buffer) {
+ DCHECK(d3d_device);
+}
+
+IndexBufferD3D9::~IndexBufferD3D9() {
+}
+
+// Creates a DX9 index buffer of the requested size.
+bool IndexBufferD3D9::ConcreteAllocate(unsigned int size_in_bytes) {
+ d3d_buffer_ = NULL;
+ if (small_) {
+ shadow_buffer_.reset(new uint8[size_in_bytes]);
+ }
+ return HR(d3d_device_->CreateIndexBuffer(
+ size_in_bytes / (small_ ? 2 : 1),
+ 0,
+ small_ ? D3DFMT_INDEX16 : D3DFMT_INDEX32,
+ D3DPOOL_MANAGED,
+ &d3d_buffer_,
+ NULL));
+}
+
+void IndexBufferD3D9::ConcreteFree() {
+ d3d_buffer_ = NULL;
+ shadow_buffer_.reset();
+}
+
+// Calls Lock on the DX9 buffer to get the address in memory of where the
+// buffer data is currently stored.
+bool IndexBufferD3D9::ConcreteLock(AccessMode access_mode, void **buffer_data) {
+ *buffer_data = NULL;
+
+ if (GetSizeInBytes() == 0)
+ return true;
+
+ if (!d3d_buffer_)
+ return false;
+
+ if (small_) {
+ *buffer_data = shadow_buffer_.get();
+ if (access_mode == Buffer::READ_WRITE ||
+ access_mode == Buffer::WRITE_ONLY) {
+ dirty_ = true;
+ }
+ return true;
+ }
+
+ if (!HR(d3d_buffer_->Lock(0, GetSizeInBytes(), buffer_data,
+ BufferAccessModeToD3DLock(access_mode)))) {
+ return false;
+ }
+
+ // Yes, this really happens sometimes.
+ // WTF is this? If this fails the app fails!
+ if (NULL == *buffer_data) {
+ HR(d3d_buffer_->Unlock());
+ return false;
+ }
+
+ return true;
+}
+
+// Calls Unlock on the DX9 buffer to notify that the contents of the buffer
+// are now ready for use.
+bool IndexBufferD3D9::ConcreteUnlock() {
+ if (GetSizeInBytes() == 0) return true;
+ if (!d3d_buffer_) return false;
+ if (small_) {
+ // TODO: Move this to just before rendering.
+ if (dirty_) {
+ void* data;
+ bool locked = HR(d3d_buffer_->Lock(0, GetSizeInBytes() / 2, &data,
+ Buffer::WRITE_ONLY));
+ if (locked) {
+ uint16* destination = reinterpret_cast<uint16*>(data);
+ uint32* source = reinterpret_cast<uint32*>(shadow_buffer_.get());
+ uint32* end = source + num_elements();
+ for (; source < end; ++source, ++destination) {
+ *destination = *source;
+ }
+ d3d_buffer_->Unlock();
+ dirty_ = false;
+ return true;
+ }
+ return false;
+ }
+ return true;
+ } else {
+ return HR(d3d_buffer_->Unlock());
+ }
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/buffer_d3d9.h b/o3d/core/win/d3d9/buffer_d3d9.h
new file mode 100644
index 0000000..dfce1bf
--- /dev/null
+++ b/o3d/core/win/d3d9/buffer_d3d9.h
@@ -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.
+ */
+
+
+// This file contains the declaration of VertexBufferD3D9 and IndexBufferD3D9.
+
+#ifndef O3D_CORE_WIN_D3D9_BUFFER_D3D9_H_
+#define O3D_CORE_WIN_D3D9_BUFFER_D3D9_H_
+
+#include <d3d9.h>
+#include <atlbase.h>
+#include "core/cross/buffer.h"
+
+namespace o3d {
+
+// VertexBufferD3D9 is a wrapper around the DX9 vertex buffer.
+// The buffer starts out empty. Calling Allocate will reserve video memory
+// for the buffer. Buffer contents are are updated by calling Lock() to get a
+// pointer to the memory allocated for the buffer, updating that data in place
+// and calling Unlock() to notify DX that the edits are done.
+class VertexBufferD3D9 : public VertexBuffer {
+ public:
+ VertexBufferD3D9(ServiceLocator* service_locator,
+ IDirect3DDevice9* d3d_device);
+ ~VertexBufferD3D9();
+
+ // Returns the DX9 vertex buffer handle.
+ LPDIRECT3DVERTEXBUFFER9 d3d_buffer() const { return d3d_buffer_; }
+
+ protected:
+ // Creates a DX9 vertex buffer of the specified size.
+ virtual bool ConcreteAllocate(size_t size_in_bytes);
+
+ // Frees the buffer.
+ virtual void ConcreteFree();
+
+ // Returns a pointer to the current contents of the buffer. A matching
+ // call to Unlock is necessary to update the contents of the buffer.
+ virtual bool ConcreteLock(AccessMode access_mode, void** buffer_data);
+
+ // Notifies DX9 that the buffer data has been updated. Unlock is only valid
+ // if it follows a Lock operation.
+ virtual bool ConcreteUnlock();
+
+ private:
+ // The D3D Device interface used to create this object.
+ CComPtr<IDirect3DDevice9> d3d_device_;
+ // Pointer to the internal D3D9 Vertex Buffer object.
+ CComPtr<IDirect3DVertexBuffer9> d3d_buffer_;
+};
+
+// IndexBufferD3D9 is a wrapper around the DX9 index buffer object. The buffer
+// starts out empty. A call to Allocate will create a DX9 index buffer of the
+// requested size. Updates the to the contents of the buffer are done via
+// the Lock/Unlock calls.
+class IndexBufferD3D9 : public IndexBuffer {
+ public:
+ IndexBufferD3D9(ServiceLocator* service_locator,
+ IDirect3DDevice9* d3d_device,
+ bool small_buffer);
+ ~IndexBufferD3D9();
+
+ // Returns the DX9 index buffer handle.
+ inline LPDIRECT3DINDEXBUFFER9 d3d_buffer() const { return d3d_buffer_; }
+
+ protected:
+ // Creates a DX9 index buffer of the specified size.
+ virtual bool ConcreteAllocate(size_t size_in_bytes);
+
+ // Frees the buffer.
+ virtual void ConcreteFree();
+
+ // Returns a pointer to the current contents of the buffer. After calling
+ // Lock, the contents of the buffer can be updated in place.
+ virtual bool ConcreteLock(AccessMode access_mode, void** buffer_data);
+
+ // Notifies DX9 that the buffer data has been updated. Unlock is only
+ // valid if it follows a Lock operation.
+ virtual bool ConcreteUnlock();
+
+ private:
+ bool dirty_;
+ bool small_; // 16 or 32 bit. True = 16bit.
+ scoped_array<uint8> shadow_buffer_; // shadow buffer if this buffer is small
+ // The D3D Device interface used to create this object.
+ CComPtr<IDirect3DDevice9> d3d_device_;
+ // Pointer to the internal D3D9 Index Buffer object.
+ CComPtr<IDirect3DIndexBuffer9> d3d_buffer_;
+};
+
+} // namespace o3d
+
+
+#endif // O3D_CORE_WIN_D3D9_BUFFER_D3D9_H_
diff --git a/o3d/core/win/d3d9/d3d_entry_points.h b/o3d/core/win/d3d9/d3d_entry_points.h
new file mode 100644
index 0000000..2153ceb
--- /dev/null
+++ b/o3d/core/win/d3d9/d3d_entry_points.h
@@ -0,0 +1,140 @@
+/*
+ * 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_CORE_WIN_D3D9_D3D_ENTRY_POINTS_H_
+#define O3D_CORE_WIN_D3D9_D3D_ENTRY_POINTS_H_
+
+#include <Windows.h>
+#include <d3d9.h>
+#include <d3dx9.h>
+
+namespace o3d {
+typedef HRESULT (__stdcall *D3DXCreateEffect_Ptr)(
+ LPDIRECT3DDEVICE9,
+ LPCVOID,
+ UINT,
+ CONST D3DXMACRO *,
+ LPD3DXINCLUDE,
+ DWORD,
+ LPD3DXEFFECTPOOL,
+ LPD3DXEFFECT *,
+ LPD3DXBUFFER *);
+
+typedef HRESULT (__stdcall *D3DXGetShaderInputSemantics_Ptr)(
+ CONST DWORD *,
+ D3DXSEMANTIC *,
+ UINT* pCount);
+
+typedef HRESULT (__stdcall *D3DXCreateEffectCompilerFromFileA_Ptr)(
+ LPCSTR,
+ CONST D3DXMACRO*,
+ LPD3DXINCLUDE,
+ DWORD,
+ LPD3DXEFFECTCOMPILER*,
+ LPD3DXBUFFER*);
+
+typedef HRESULT (__stdcall *D3DXCreateEffectCompilerFromFileW_Ptr)(
+ LPCWSTR,
+ CONST D3DXMACRO*,
+ LPD3DXINCLUDE,
+ DWORD,
+ LPD3DXEFFECTCOMPILER*,
+ LPD3DXBUFFER*);
+
+typedef HRESULT (__stdcall *D3DXSaveSurfaceToFileA_Ptr)(
+ LPCSTR,
+ D3DXIMAGE_FILEFORMAT,
+ LPDIRECT3DSURFACE9,
+ CONST PALETTEENTRY*,
+ CONST RECT*);
+
+typedef HRESULT (__stdcall *D3DXSaveSurfaceToFileW_Ptr)(
+ LPCWSTR,
+ D3DXIMAGE_FILEFORMAT,
+ LPDIRECT3DSURFACE9,
+ CONST PALETTEENTRY*,
+ CONST RECT*);
+
+typedef HRESULT (__stdcall *D3DXGetShaderConstantTable_Ptr)(
+ CONST DWORD*,
+ LPD3DXCONSTANTTABLE*);
+
+typedef HRESULT (__stdcall *D3DXCreateFontW_Ptr)(
+ LPDIRECT3DDEVICE9 pDevice,
+ INT Height,
+ UINT Width,
+ UINT Weight,
+ UINT MipLevels,
+ BOOL Italic,
+ DWORD CharSet,
+ DWORD OutputPrecision,
+ DWORD Quality,
+ DWORD PitchAndFamily,
+ LPCTSTR pFacename,
+ LPD3DXFONT * ppFont);
+
+typedef HRESULT (__stdcall *D3DXCreateFontA_Ptr)(
+ LPDIRECT3DDEVICE9 pDevice,
+ INT Height,
+ UINT Width,
+ UINT Weight,
+ UINT MipLevels,
+ BOOL Italic,
+ DWORD CharSet,
+ DWORD OutputPrecision,
+ DWORD Quality,
+ DWORD PitchAndFamily,
+ LPCTSTR pFacename,
+ LPD3DXFONT * ppFont);
+
+typedef HRESULT (__stdcall *D3DXCreateLine_Ptr)(
+ LPDIRECT3DDEVICE9 pDevice,
+ LPD3DXLINE * ppLine);
+
+typedef IDirect3D9* (__stdcall *Direct3DCreate9_Ptr)(
+ UINT SDKVersion);
+
+extern D3DXCreateEffect_Ptr D3DXCreateEffect;
+extern D3DXGetShaderInputSemantics_Ptr D3DXGetShaderInputSemantics;
+extern D3DXCreateEffectCompilerFromFileW_Ptr D3DXCreateEffectCompilerFromFileW;
+extern D3DXCreateEffectCompilerFromFileA_Ptr D3DXCreateEffectCompilerFromFileA;
+extern D3DXSaveSurfaceToFileW_Ptr D3DXSaveSurfaceToFileW;
+extern D3DXSaveSurfaceToFileA_Ptr D3DXSaveSurfaceToFileA;
+extern D3DXGetShaderConstantTable_Ptr D3DXGetShaderConstantTable;
+extern D3DXCreateFontW_Ptr D3DXCreateFontW;
+extern D3DXCreateFontA_Ptr D3DXCreateFontA;
+extern D3DXCreateLine_Ptr D3DXCreateLine;
+extern Direct3DCreate9_Ptr Direct3DCreate9Software;
+
+} // namespace o3d
+
+#endif // O3D_CORE_WIN_D3D9_D3D_ENTRY_POINTS_H_
diff --git a/o3d/core/win/d3d9/draw_element_d3d9.cc b/o3d/core/win/d3d9/draw_element_d3d9.cc
new file mode 100644
index 0000000..709fbaa
--- /dev/null
+++ b/o3d/core/win/d3d9/draw_element_d3d9.cc
@@ -0,0 +1,48 @@
+/*
+ * 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 DrawElementD3D9 class.
+
+#include "core/cross/precompile.h"
+#include "core/win/d3d9/draw_element_d3d9.h"
+
+namespace o3d {
+
+DrawElementD3D9::DrawElementD3D9(ServiceLocator* service_locator)
+ : DrawElement(service_locator) {
+}
+
+DrawElementD3D9::~DrawElementD3D9() {
+}
+
+} // namespace o3d
+
diff --git a/o3d/core/win/d3d9/draw_element_d3d9.h b/o3d/core/win/d3d9/draw_element_d3d9.h
new file mode 100644
index 0000000..2d8a295
--- /dev/null
+++ b/o3d/core/win/d3d9/draw_element_d3d9.h
@@ -0,0 +1,53 @@
+/*
+ * 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 DrawElementD3D9 class.
+
+#ifndef O3D_CORE_WIN_D3D9_DRAW_ELEMENT_D3D9_H_
+#define O3D_CORE_WIN_D3D9_DRAW_ELEMENT_D3D9_H_
+
+#include "core/cross/draw_element.h"
+
+namespace o3d {
+
+// DrawElementD3D9 is the DX9 implementation of the DrawElement. It provides
+// a place for the renderer to store platform specific cache information.
+class DrawElementD3D9 : public DrawElement {
+ public:
+ explicit DrawElementD3D9(ServiceLocator* service_locator);
+ ~DrawElementD3D9();
+
+ private:
+};
+} // o3d
+
+#endif // O3D_CORE_WIN_D3D9_DRAW_ELEMENT_D3D9_H_
diff --git a/o3d/core/win/d3d9/effect_d3d9.cc b/o3d/core/win/d3d9/effect_d3d9.cc
new file mode 100644
index 0000000..216e6b9
--- /dev/null
+++ b/o3d/core/win/d3d9/effect_d3d9.cc
@@ -0,0 +1,869 @@
+/*
+ * 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 EffectD3D9.
+
+#include "core/cross/precompile.h"
+
+#include "core/win/d3d9/effect_d3d9.h"
+
+#include "base/scoped_ptr.h"
+#include "core/cross/core_metrics.h"
+#include "core/cross/error.h"
+#include "core/cross/material.h"
+#include "core/cross/renderer_platform.h"
+#include "core/cross/semantic_manager.h"
+#include "core/cross/standard_param.h"
+#include "core/cross/transform.h"
+#include "core/win/d3d9/d3d_entry_points.h"
+#include "core/win/d3d9/primitive_d3d9.h"
+#include "core/win/d3d9/sampler_d3d9.h"
+#include "core/win/d3d9/texture_d3d9.h"
+#include "core/win/d3d9/utils_d3d9.h"
+#include "core/cross/param_array.h"
+
+namespace o3d {
+
+// A 'mostly' typesafe class to set an effect parameter from an O3D
+// Param. The phandle must match the type of Param to be typesafe. That is
+// handled when these are created.
+template<typename ParamType, D3DXPARAMETER_CLASS d3d_parameter_class>
+class TypedEffectParamHandlerD3D9 : public EffectParamHandlerD3D9 {
+ public:
+ TypedEffectParamHandlerD3D9(ParamType* param, D3DXHANDLE phandle)
+ : param_(param),
+ phandle_(phandle) {
+ }
+ virtual void SetEffectParam(RendererD3D9* renderer, ID3DXEffect* d3d_effect);
+ private:
+ ParamType* param_;
+ D3DXHANDLE phandle_;
+};
+
+class EffectParamFloatArrayHandlerD3D9 : public EffectParamHandlerD3D9 {
+ public:
+ EffectParamFloatArrayHandlerD3D9(ParamParamArray* param, D3DXHANDLE phandle)
+ : param_(param),
+ phandle_(phandle) {
+ }
+ virtual void SetEffectParam(RendererD3D9* renderer, ID3DXEffect* d3d_effect);
+ private:
+ ParamParamArray* param_;
+ D3DXHANDLE phandle_;
+};
+
+// Number of h/w sampler units in the same shader using a single sampler.
+// Eight should be enough!
+static const int kMaxUnitsPerSampler = 8;
+
+// A class for setting the the appropriate d3d sampler states from a
+// o3d Sampler object.
+class EffectParamHandlerForSamplersD3D9 : public EffectParamHandlerD3D9 {
+ public:
+ EffectParamHandlerForSamplersD3D9(ParamSampler* sampler_param,
+ const D3DXPARAMETER_DESC& pdesc,
+ LPD3DXCONSTANTTABLE fs_constant_table,
+ LPDIRECT3DDEVICE9 d3d_device);
+
+ virtual void SetEffectParam(RendererD3D9* renderer, ID3DXEffect* d3d_effect);
+
+ // Resets the value of the parameter to default. Currently this is used
+ // to unbind textures contained in Sampler params.
+ virtual void ResetEffectParam(RendererD3D9* renderer,
+ ID3DXEffect* d3d_effect);
+ private:
+ ParamSampler* sampler_param_;
+ // The number of sampler units using this sampler parameter.
+ int number_sampler_units_;
+ // An array of sampler unit indices.
+ int sampler_unit_index_array_[kMaxUnitsPerSampler];
+};
+
+// Converts a given D3DX parameter description to an O3D Param type,
+// or Param::INVALID if no corresponding type is found.
+static const ObjectBase::Class* D3DXPDescToParamType(
+ const D3DXPARAMETER_DESC& pdesc) {
+ // Matrix4 Param
+ if (pdesc.Type == D3DXPT_FLOAT &&
+ pdesc.Columns == 4 &&
+ pdesc.Rows == 4) {
+ return ParamMatrix4::GetApparentClass();
+ // Float Param
+ } else if (pdesc.Type == D3DXPT_FLOAT &&
+ pdesc.Class == D3DXPC_SCALAR) {
+ return ParamFloat::GetApparentClass();
+ // Float2 Param
+ } else if (pdesc.Type == D3DXPT_FLOAT &&
+ pdesc.Class == D3DXPC_VECTOR) {
+ if (pdesc.Columns == 1) {
+ return ParamFloat::GetApparentClass();
+ } else if (pdesc.Columns == 2) {
+ return ParamFloat2::GetApparentClass();
+ } else if (pdesc.Columns == 3) {
+ return ParamFloat3::GetApparentClass();
+ } else if (pdesc.Columns == 4) {
+ return ParamFloat4::GetApparentClass();
+ }
+ // Integer param
+ } else if (pdesc.Type == D3DXPT_INT &&
+ pdesc.Class == D3DXPC_SCALAR &&
+ pdesc.Columns == 1) {
+ return ParamInteger::GetApparentClass();
+ // Boolean param
+ } else if (pdesc.Type == D3DXPT_BOOL &&
+ pdesc.Class == D3DXPC_SCALAR &&
+ pdesc.Columns == 1) {
+ return ParamBoolean::GetApparentClass();
+ // Texture param
+ // TODO Texture params should be removed once we switch over to
+ // using samplers only.
+ } else if (pdesc.Type == D3DXPT_TEXTURE &&
+ pdesc.Class == D3DXPC_OBJECT) {
+ return ParamTexture::GetApparentClass();
+ // Sampler param
+ } else if (pdesc.Class == D3DXPC_OBJECT &&
+ (pdesc.Type == D3DXPT_SAMPLER ||
+ pdesc.Type == D3DXPT_SAMPLER2D ||
+ pdesc.Type == D3DXPT_SAMPLERCUBE)) {
+ return ParamSampler::GetApparentClass();
+ }
+ return NULL;
+}
+
+EffectD3D9::EffectD3D9(ServiceLocator* service_locator,
+ IDirect3DDevice9* d3d_device)
+ : Effect(service_locator),
+ semantic_manager_(service_locator->GetService<SemanticManager>()),
+ renderer_(static_cast<RendererD3D9*>(
+ service_locator->GetService<Renderer>())),
+ d3d_device_(d3d_device) {
+ DCHECK(d3d_device);
+}
+
+EffectD3D9::~EffectD3D9() {
+}
+
+bool EffectD3D9::PrepareFX(const String& effect,
+ String* prepared_effect) {
+ String vertex_shader_entry_point;
+ String fragment_shader_entry_point;
+ MatrixLoadOrder matrix_load_order;
+
+ // TODO: Temporary fix to make GL and D3D match until the shader parser
+ // is written.
+ if (!ValidateFX(effect,
+ &vertex_shader_entry_point,
+ &fragment_shader_entry_point,
+ &matrix_load_order)) {
+ // TODO: Remove this but for now just let bad ones pass so collada
+ // importer works.
+ *prepared_effect = effect;
+ return false;
+ }
+
+ *prepared_effect = effect +
+ "technique Shaders { "
+ " pass p0 { "
+ " VertexShader = compile vs_2_0 " + vertex_shader_entry_point + "();"
+ " PixelShader = compile ps_2_0 " + fragment_shader_entry_point + "();"
+ " }"
+ "};";
+
+ set_matrix_load_order(matrix_load_order);
+
+ return true;
+}
+
+void EffectD3D9::ClearD3D9Effect() {
+ set_source("");
+ d3d_vertex_shader_ = NULL;
+ d3d_fragment_shader_ = NULL;
+ fs_constant_table_ = NULL;
+ d3dx_effect_ = NULL;
+}
+
+// Initializes the Effect object using the shaders found in an FX formatted
+// string.
+bool EffectD3D9::LoadFromFXString(const String& effect) {
+ ClearD3D9Effect();
+
+ LPD3DXBUFFER error_buffer;
+
+ String prepared_effect;
+ // TODO: Check for failure once shader parser is in.
+ PrepareFX(effect, &prepared_effect);
+
+ if (!HR(o3d::D3DXCreateEffect(d3d_device_,
+ prepared_effect.c_str(),
+ (UINT)prepared_effect.size(),
+ NULL,
+ NULL,
+ D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
+ NULL,
+ &d3dx_effect_,
+ &error_buffer))) {
+ DisplayFXError("FX from String", error_buffer);
+ return false;
+ }
+ if (!InitializeFX()) {
+ return false;
+ }
+
+ // Get metrics for the length of the shader
+ UINT data_size = 0;
+ if (d3d_vertex_shader_) {
+ d3d_vertex_shader_->GetFunction(NULL, &data_size);
+ metric_vertex_shader_instruction_count.AddSample(data_size);
+ }
+ if (d3d_fragment_shader_) {
+ d3d_fragment_shader_->GetFunction(NULL, &data_size);
+ metric_pixel_shader_instruction_count.AddSample(data_size);
+ }
+
+ set_source(effect);
+ return true;
+}
+
+// Parses a DX9 error buffer and displays a nicely formatted error string
+// in a MessageBox.
+void EffectD3D9::DisplayFXError(const String &header,
+ LPD3DXBUFFER error_buffer) {
+ String compile_errors_string;
+ if (error_buffer) {
+ LPVOID compile_errors = error_buffer->GetBufferPointer();
+ compile_errors_string = (reinterpret_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));
+ std::wstring msg_utf16(msg);
+ String msg_utf8 = WideToUTF8(msg_utf16);
+
+ compile_errors_string = header + ": " + msg_utf8.c_str();
+ LocalFree(hLocal);
+ }
+ O3D_ERROR(service_locator()) << "Effect Compile Error::"
+ << compile_errors_string.c_str();
+}
+
+// Creates the vertex and fragment shaders based on the programs found in the
+// DX9 effect.
+bool EffectD3D9::InitializeFX() {
+ bool rc = false;
+
+ // we only handle the first technique, for now
+ D3DXHANDLE technique = d3dx_effect_->GetTechnique(0);
+ if (!technique) {
+ DLOG(ERROR) << "Failed to get technique";
+ return false;
+ }
+
+ D3DXTECHNIQUE_DESC desc;
+ if (!HR(d3dx_effect_->GetTechniqueDesc(technique, &desc))) {
+ DLOG(ERROR) << "Failed to get technique description";
+ return false;
+ }
+
+ if (desc.Passes != 1) {
+ O3D_ERROR(service_locator())
+ << "Effect Compile Error: "
+ << "Multi-pass shaders are unsupported.";
+ return false;
+ }
+
+ D3DXHANDLE pass = d3dx_effect_->GetPass(technique, 0);
+ if (!pass) {
+ DLOG(ERROR) << "Failed to get pass";
+ return false;
+ }
+
+ D3DXPASS_DESC pass_desc;
+ if (!HR(d3dx_effect_->GetPassDesc(pass, &pass_desc))) {
+ DLOG(ERROR) << "Failed to get pass description";
+ return false;
+ }
+
+ if (!HR(d3d_device_->CreateVertexShader(
+ pass_desc.pVertexShaderFunction, &d3d_vertex_shader_))) {
+ DLOG(ERROR) << "Failed to create vertex shader";
+ return false;
+ }
+
+ if (!HR(d3d_device_->CreatePixelShader(
+ pass_desc.pPixelShaderFunction, &d3d_fragment_shader_))) {
+ DLOG(ERROR) << "Failed to create pixel shader";
+ return false;
+ }
+
+ // Get the Fragment Shader constant table.
+ if (!HR(o3d::D3DXGetShaderConstantTable(
+ pass_desc.pPixelShaderFunction,
+ &fs_constant_table_))) {
+ DLOG(ERROR) << "Failed to get fragment shader constant table";
+ return false;
+ }
+
+ return true;
+}
+
+// Adds a Parameter Mapping from an O3D param to a d3d parameter if they
+// match in type.
+// Parameters:
+// param: Param we are attempting to map.
+// pdesc: d3d parameter description.
+// phandle: Handle to d3d parameter.
+// effect_param_cache: Cache to add mapping to.
+// Returns:
+// true if a mapping was added.
+bool EffectD3D9::AddParameterMapping(
+ Param* param,
+ const D3DXPARAMETER_DESC& pdesc,
+ D3DXHANDLE phandle,
+ EffectParamHandlerCacheD3D9* effect_param_cache) {
+ // Array param
+ if (param->IsA(ParamParamArray::GetApparentClass()) &&
+ pdesc.Elements > 1) {
+ if (pdesc.Class == D3DXPC_SCALAR && pdesc.Type == D3DXPT_FLOAT) {
+ effect_param_cache->AddElement(
+ new EffectParamFloatArrayHandlerD3D9(
+ down_cast<ParamParamArray*>(param), phandle));
+ }
+ // Matrix4 Param
+ } else if (param->IsA(ParamMatrix4::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_MATRIX_COLUMNS) {
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamMatrix4,
+ D3DXPC_MATRIX_COLUMNS>(
+ down_cast<ParamMatrix4*>(param), phandle));
+ } else if (param->IsA(ParamMatrix4::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_MATRIX_ROWS) {
+ if (matrix_load_order() == COLUMN_MAJOR) {
+ // D3D has already created a uniform of type MATRIX_ROWS, but the
+ // effect wants column major matrices, so we create a handler
+ // for MATRIX_COLUMNS. This will cause the matrix to be tranposed
+ // on load.
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamMatrix4,
+ D3DXPC_MATRIX_COLUMNS>(
+ down_cast<ParamMatrix4*>(param), phandle));
+ } else {
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamMatrix4,
+ D3DXPC_MATRIX_ROWS>(
+ down_cast<ParamMatrix4*>(param), phandle));
+ }
+ // Float Param
+ } else if (param->IsA(ParamFloat::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_SCALAR &&
+ pdesc.Type == D3DXPT_FLOAT) {
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamFloat,
+ D3DXPC_SCALAR>(
+ down_cast<ParamFloat*>(param), phandle));
+ // Float2 Param
+ } else if (param->IsA(ParamFloat2::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_VECTOR &&
+ pdesc.Type == D3DXPT_FLOAT &&
+ pdesc.Columns == 2) {
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamFloat2,
+ D3DXPC_VECTOR>(
+ down_cast<ParamFloat2*>(param), phandle));
+ // Float3 Param
+ } else if (param->IsA(ParamFloat3::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_VECTOR &&
+ pdesc.Type == D3DXPT_FLOAT &&
+ pdesc.Columns == 3) {
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamFloat3,
+ D3DXPC_VECTOR>(
+ down_cast<ParamFloat3*>(param), phandle));
+ // Float4 Param
+ } else if (param->IsA(ParamFloat4::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_VECTOR &&
+ pdesc.Type == D3DXPT_FLOAT &&
+ pdesc.Columns == 4) {
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamFloat4,
+ D3DXPC_VECTOR>(
+ down_cast<ParamFloat4*>(param), phandle));
+ // Integer param
+ } else if (param->IsA(ParamInteger::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_SCALAR &&
+ pdesc.Type == D3DXPT_INT &&
+ pdesc.Columns == 1) {
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamInteger,
+ D3DXPC_SCALAR>(
+ down_cast<ParamInteger*>(param), phandle));
+ // Boolean param
+ } else if (param->IsA(ParamBoolean::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_SCALAR &&
+ pdesc.Type == D3DXPT_BOOL &&
+ pdesc.Columns == 1) {
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamBoolean,
+ D3DXPC_SCALAR>(
+ down_cast<ParamBoolean*>(param), phandle));
+ // Texture param
+ // TODO The texture param block should be removed once we start
+ // using samplers only. In the meantime, we need to create a texture param
+ // to be able to handle collada files referencing external fx .
+ } else if (param->IsA(ParamTexture::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_OBJECT &&
+ pdesc.Type == D3DXPT_TEXTURE) {
+ effect_param_cache->AddElement(
+ new TypedEffectParamHandlerD3D9<ParamTexture,
+ D3DXPC_OBJECT>(
+ down_cast<ParamTexture*>(param), phandle));
+ // Sampler param
+ } else if (param->IsA(ParamSampler::GetApparentClass()) &&
+ pdesc.Class == D3DXPC_OBJECT &&
+ (pdesc.Type == D3DXPT_SAMPLER ||
+ pdesc.Type == D3DXPT_SAMPLER2D ||
+ pdesc.Type == D3DXPT_SAMPLERCUBE)) {
+ effect_param_cache->AddElement(
+ new EffectParamHandlerForSamplersD3D9(down_cast<ParamSampler*>(param),
+ pdesc,
+ fs_constant_table_,
+ d3d_device_));
+ } else {
+ return false;
+ }
+ return true;
+}
+
+// Loops through all the parameters in the d3dx effect and tries to
+// find matches (by name and type) first in the Transform (param_object1)
+// DrawPrimitive Params (param_object2), then in the Primitive Param
+// (param_object3) then in the Material params and finally in the Effect params.
+// If there exists a Param with the same name as the d3dx effect parameter and a
+// compatible type then a handler is created to update the d3d parameter with
+// the Param.
+void EffectD3D9::UpdateParameterMappings(
+ const std::vector<ParamObject*>& param_object_list,
+ EffectParamHandlerCacheD3D9* effect_param_cache) {
+ // Clear the old ones.
+ effect_param_cache->Clear();
+ if (d3dx_effect_) {
+ // Update all the parameter handles from the effect desc
+ D3DXEFFECT_DESC desc;
+ d3dx_effect_->GetDesc(&desc);
+ for (UINT i = 0; i < desc.Parameters; ++i) {
+ D3DXPARAMETER_DESC pdesc;
+ D3DXHANDLE phandle = d3dx_effect_->GetParameter(NULL, i);
+ d3dx_effect_->GetParameterDesc(phandle, &pdesc);
+ Param *param;
+ String constant_name(pdesc.Name);
+ const ObjectBase::Class* sem_type = NULL;
+ if (pdesc.Semantic) {
+ sem_type = semantic_manager_->LookupSemantic(pdesc.Semantic);
+ }
+ bool mapped = false;
+ for (unsigned ii = 0; !mapped && ii < param_object_list.size(); ++ii) {
+ ParamObject* param_object = param_object_list[ii];
+ param = param_object->GetUntypedParam(constant_name);
+ if (!param && sem_type) {
+ param = param_object->GetUntypedParam(sem_type->name());
+ }
+ if (param) {
+ mapped = AddParameterMapping(param,
+ pdesc,
+ phandle,
+ effect_param_cache);
+ }
+ }
+
+ // If it's still not mapped attempt to map it to the error sampler param.
+ // It will fail if it's not a sampler.
+ if (!mapped) {
+ param = renderer_->error_param_sampler();
+ mapped = AddParameterMapping(param,
+ pdesc,
+ phandle,
+ effect_param_cache);
+ }
+ }
+ }
+}
+
+void EffectD3D9::GetParameterInfo(EffectParameterInfoArray* info_array) {
+ DCHECK(info_array);
+ info_array->clear();
+ if (d3dx_effect_) {
+ // Add parameters to the Shape for all parameters in the effect
+ D3DXEFFECT_DESC desc;
+ d3dx_effect_->GetDesc(&desc);
+ for (UINT i = 0; i < desc.Parameters; ++i) {
+ D3DXPARAMETER_DESC pdesc;
+ D3DXHANDLE phandle = d3dx_effect_->GetParameter(NULL, i);
+ const ObjectBase::Class* sas_class_type = NULL;
+ if (d3dx_effect_->GetParameterDesc(phandle, &pdesc) == S_OK) {
+ const ObjectBase::Class* type = D3DXPDescToParamType(pdesc);
+ if (type != NULL) {
+ if (pdesc.Semantic != NULL &&
+ type == ParamMatrix4::GetApparentClass()) {
+ sas_class_type = semantic_manager_->LookupSemantic(pdesc.Semantic);
+ }
+ String semantic((pdesc.Semantic != NULL) ? pdesc.Semantic : "");
+ info_array->push_back(EffectParameterInfo(
+ pdesc.Name,
+ type,
+ pdesc.Elements,
+ semantic,
+ sas_class_type));
+ }
+ }
+ }
+ }
+}
+
+void EffectD3D9::GetStreamInfo(EffectStreamInfoArray* info_array) {
+ DCHECK(info_array);
+ info_array->clear();
+ if (d3d_vertex_shader_) {
+ 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(o3d::D3DXGetShaderInputSemantics(function.get(),
+ NULL,
+ &num_semantics));
+ scoped_array<D3DXSEMANTIC> semantics(new D3DXSEMANTIC[num_semantics]);
+ HR(o3d::D3DXGetShaderInputSemantics(function.get(),
+ semantics.get(),
+ &num_semantics));
+
+ info_array->resize(num_semantics);
+ for (UINT i = 0; i < num_semantics; ++i) {
+ (*info_array)[i] = EffectStreamInfo(
+ SemanticFromDX9UsageType(static_cast<D3DDECLUSAGE>(
+ semantics[i].Usage)),
+ static_cast<int>(semantics[i].UsageIndex));
+ }
+ }
+}
+
+template<>
+void TypedEffectParamHandlerD3D9<ParamMatrix4,
+ D3DXPC_MATRIX_COLUMNS>::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ Matrix4 param_matrix = transpose(param_->value());
+ HR(d3dx_effect->SetMatrix(
+ phandle_,
+ reinterpret_cast<D3DXMATRIX*>(&param_matrix[0][0])));
+}
+
+template<>
+void TypedEffectParamHandlerD3D9<ParamMatrix4,
+ D3DXPC_MATRIX_ROWS>::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ Matrix4 param_matrix = param_->value();
+ HR(d3dx_effect->SetMatrix(
+ phandle_,
+ reinterpret_cast<D3DXMATRIX*>(&param_matrix[0][0])));
+}
+
+template<>
+void TypedEffectParamHandlerD3D9<ParamFloat,
+ D3DXPC_SCALAR>::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ HR(d3dx_effect->SetFloat(phandle_, param_->value()));
+}
+
+template<>
+void TypedEffectParamHandlerD3D9<ParamFloat2,
+ D3DXPC_VECTOR>::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ Float2 param_float2 = param_->value();
+ HR(d3dx_effect->SetFloatArray(
+ phandle_,
+ param_float2.GetFloatArray(),
+ 2));
+}
+
+template<>
+void TypedEffectParamHandlerD3D9<ParamFloat3,
+ D3DXPC_VECTOR>::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ Float3 param_float3 = param_->value();
+ HR(d3dx_effect->SetFloatArray(
+ phandle_,
+ param_float3.GetFloatArray(),
+ 3));
+}
+
+template<>
+void TypedEffectParamHandlerD3D9<ParamFloat4,
+ D3DXPC_VECTOR>::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ Float4 param_float4 = param_->value();
+ HR(d3dx_effect->SetFloatArray(
+ phandle_,
+ param_float4.GetFloatArray(),
+ 4));
+}
+
+template<>
+void TypedEffectParamHandlerD3D9<ParamInteger,
+ D3DXPC_SCALAR>::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ HR(d3dx_effect->SetInt(phandle_, param_->value()));
+}
+
+template<>
+void TypedEffectParamHandlerD3D9<ParamBoolean,
+ D3DXPC_SCALAR>::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ HR(d3dx_effect->SetBool(phandle_, param_->value()));
+}
+
+// TODO: The following handler should be removed once we switch to
+// using Samplers exclusively.
+template<>
+void TypedEffectParamHandlerD3D9<ParamTexture,
+ D3DXPC_OBJECT>::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ Texture* texture = param_->value();
+ // TODO: If texture is NULL then we don't set the texture on the
+ // effect to avoid clobbering texture set by the corresponding sampler in
+ // the cases where we use samplers. The side-effect of this is that if
+ // the texture is not set, we could end up using whatever texture was used
+ // by the unit before (instead of black). This handler will be removed
+ // once we add support for ColladaFX and samplers so it should be ok.
+ if (texture != NULL) {
+ IDirect3DBaseTexture9 *d3d_texture = NULL;
+ if (!renderer->SafeToBindTexture(texture)) {
+ O3D_ERROR(renderer->service_locator())
+ << "Attempt to bind texture, " << texture->name() << " when drawing "
+ << "to an owned RenderSurface";
+ d3d_texture = static_cast<IDirect3DBaseTexture9*>(
+ renderer->error_texture()->GetTextureHandle());
+ } else {
+ d3d_texture =
+ static_cast<IDirect3DBaseTexture9*>(texture->GetTextureHandle());
+ }
+ HR(d3dx_effect->SetTexture(phandle_, d3d_texture));
+ }
+}
+
+void EffectParamFloatArrayHandlerD3D9::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ ParamArray* param = param_->value();
+ if (param) {
+ int size = param->size();
+ for (int i = 0; i < size; ++i) {
+ ParamFloat* element = param->GetParam<ParamFloat>(i);
+ D3DXHANDLE dx_element = d3dx_effect->GetParameterElement(phandle_, i);
+ if (element) {
+ d3dx_effect->SetFloat(dx_element, element->value());
+ } else {
+ d3dx_effect->SetFloat(dx_element, 0.0);
+ }
+ }
+ }
+}
+
+void EffectParamHandlerForSamplersD3D9::SetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ // Find the texture associated with the sampler first.
+ Sampler* sampler = sampler_param_->value();
+ if (!sampler) {
+ sampler = renderer->error_sampler();
+ if (!renderer->error_texture()) {
+ O3D_ERROR(sampler_param_->service_locator())
+ << "Missing Sampler for ParamSampler " << sampler_param_->name();
+ }
+ }
+
+ SamplerD3D9* d3d_sampler = down_cast<SamplerD3D9*>(sampler);
+ for (int stage = 0; stage < number_sampler_units_; stage++) {
+ d3d_sampler->SetTextureAndStates(sampler_unit_index_array_[stage]);
+ }
+}
+
+void EffectParamHandlerForSamplersD3D9::ResetEffectParam(
+ RendererD3D9* renderer,
+ ID3DXEffect* d3dx_effect) {
+ Sampler* sampler = sampler_param_->value();
+ if (sampler) {
+ SamplerD3D9* d3d_sampler = down_cast<SamplerD3D9*>(sampler);
+ for (int stage = 0; stage < number_sampler_units_; stage++) {
+ d3d_sampler->ResetTexture(sampler_unit_index_array_[stage]);
+ }
+ }
+}
+
+// Creates a handler for setting up the d3d9 sampler states based on the values
+// on Sampler object pointed to by the sampler_param. It does a lookup
+// (by name) in the fragment shader constants to determine the index of the
+// texture stage the sampler has been mapped to in hardware. This index
+// will be used when making calls to set the texture and various sampler
+// states at render time.
+EffectParamHandlerForSamplersD3D9::EffectParamHandlerForSamplersD3D9(
+ ParamSampler* sampler_param,
+ const D3DXPARAMETER_DESC& pdesc,
+ LPD3DXCONSTANTTABLE fs_constant_table,
+ LPDIRECT3DDEVICE9 d3d_device)
+ : sampler_param_(sampler_param),
+ number_sampler_units_(0) {
+ if (!fs_constant_table) {
+ DLOG(ERROR) << "Fragment shader constant table is NULL";
+ return;
+ }
+ D3DXHANDLE sampler_handle = fs_constant_table->GetConstantByName(
+ NULL,
+ pdesc.Name);
+ if (!sampler_handle) {
+ DLOG(ERROR) << "Sampler " << pdesc.Name <<
+ " not found in fragment shader";
+ return;
+ }
+ D3DXCONSTANT_DESC desc_array[kMaxUnitsPerSampler];
+ UINT num_desc = kMaxUnitsPerSampler;
+ fs_constant_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 kMaxUnitsPerSampler (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 == kMaxUnitsPerSampler) {
+ DLOG(WARNING) << "Number of constant descriptions might have exceeded "
+ << "the maximum of " << kMaxUnitsPerSampler;
+ }
+ for (UINT 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_SAMPLERCUBE)) {
+ sampler_unit_index_array_[number_sampler_units_++] =
+ constant_desc.RegisterIndex;
+ }
+ }
+ if (number_sampler_units_ == 0) {
+ DLOG(ERROR) << "No matching sampler units found for " <<
+ pdesc.Name;
+ }
+}
+
+// Loops through all the parameters needed by the effect and updates the
+// corresponding uniforms in the d3d Effect
+void EffectD3D9::UpdateShaderConstantsFromEffect(
+ const EffectParamHandlerCacheD3D9& effect_param_cache) {
+
+ const EffectParamHandlerCacheD3D9::ElementArray& effect_params =
+ effect_param_cache.GetElements();
+
+ EffectParamHandlerCacheD3D9::ElementArray::size_type end =
+ effect_params.size();
+ for (EffectParamHandlerCacheD3D9::ElementArray::size_type ii = 0;
+ ii != end;
+ ++ii) {
+ effect_params[ii]->SetEffectParam(renderer_, d3dx_effect_);
+ }
+}
+
+// Updates the values of the vertex and fragment shader parameters using the
+// current values of the corresponding Shape Param's and sets the various
+// render states if they are different from the default value.
+void EffectD3D9::PrepareForDraw(
+ const EffectParamHandlerCacheD3D9& effect_param_cache) {
+ // Patch in the vertex and fragment shader constants using
+ // values from the matching Params of the Shape
+ if (d3dx_effect_) {
+ UpdateShaderConstantsFromEffect(effect_param_cache);
+ UINT numpasses;
+ d3dx_effect_->SetTechnique(d3dx_effect_->GetTechnique(0));
+ HR(d3dx_effect_->Begin(&numpasses, 0));
+ HR(d3dx_effect_->BeginPass(0));
+ }
+}
+
+// Resets the render states back to their default value.
+void EffectD3D9::PostDraw(
+ ParamObject* param_object,
+ const EffectParamHandlerCacheD3D9& effect_param_cache) {
+ if (d3dx_effect_) {
+ HR(d3dx_effect_->EndPass());
+ HR(d3dx_effect_->End());
+
+ const EffectParamHandlerCacheD3D9::ElementArray& effect_params =
+ effect_param_cache.GetElements();
+
+ EffectParamHandlerCacheD3D9::ElementArray::size_type end =
+ effect_params.size();
+ for (EffectParamHandlerCacheD3D9::ElementArray::size_type ii = 0;
+ ii != end;
+ ++ii) {
+ effect_params[ii]->ResetEffectParam(renderer_, d3dx_effect_);
+ }
+ }
+}
+
+// Handler for lost device. This invalidates the effect for a device reset.
+// Returns true on success.
+bool EffectD3D9::OnLostDevice() {
+ if (d3dx_effect_)
+ return HR(d3dx_effect_->OnLostDevice());
+ else
+ return true;
+}
+
+// Handler for reset device. This restores the effect after a device reset.
+// Returns true on success.
+bool EffectD3D9::OnResetDevice() {
+ if (d3dx_effect_)
+ return HR(d3dx_effect_->OnResetDevice());
+ else
+ return true;
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/effect_d3d9.h b/o3d/core/win/d3d9/effect_d3d9.h
new file mode 100644
index 0000000..46d1bbc
--- /dev/null
+++ b/o3d/core/win/d3d9/effect_d3d9.h
@@ -0,0 +1,203 @@
+/*
+ * 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 EffectD3D9 class.
+
+#ifndef O3D_CORE_WIN_D3D9_EFFECT_D3D9_H_
+#define O3D_CORE_WIN_D3D9_EFFECT_D3D9_H_
+
+#include <d3d9.h>
+#include <d3dx9.h>
+#include <atlbase.h>
+#include <vector>
+#include "core/cross/effect.h"
+
+interface ID3DXEffect;
+
+namespace o3d {
+
+class Material;
+class ParamObject;
+class RendererD3D9;
+class SemanticManager;
+class ShapeDataD3D9;
+
+// A class to set an effect parameter from an O3D parameter.
+class EffectParamHandlerD3D9 {
+ public:
+ virtual ~EffectParamHandlerD3D9() { }
+
+ // Sets a D3D9 Effect Parameter by an O3D Param.
+ virtual void SetEffectParam(RendererD3D9* renderer,
+ ID3DXEffect* d3d_effect) = 0;
+
+ // Resets a D3D9 Effect parameter to default value. This is currently
+ // used to unbind textures contained in Sampler parameters.
+ virtual void ResetEffectParam(RendererD3D9* renderer,
+ ID3DXEffect* d3d_effect) {}
+};
+
+// This class creates a use limited array of pointers to instances of a certain
+// class. It will destroy this instances when Clear() is called or on
+// destruction. You can only add to the array and clear it. No other operations
+// are supported.
+template <typename T>
+class ClassPointerArray {
+ public:
+ // Public declaration of the type used to store the array.
+ typedef std::vector<T*> ElementArray;
+
+ ~ClassPointerArray() {
+ Clear();
+ }
+
+ // Clears the array and delete all the elements it points to.
+ void Clear() {
+ for (ElementArray::size_type ii = 0; ii < elements_.size(); ++ii) {
+ delete elements_[ii];
+ }
+ elements_.clear();
+ }
+
+ // Adds an element to the array.
+ // Parameters:
+ // element: Element to add.
+ void AddElement(T* element) {
+ elements_.push_back(element);
+ }
+
+ // Gets a const reference to the elements currently in the array
+ // as a const stl::vector& so you can use the array with standard stl
+ // operations.
+ // Returns:
+ // const references to the elements.
+ const ElementArray& GetElements() const {
+ return elements_;
+ }
+ private:
+ ElementArray elements_;
+};
+
+typedef ClassPointerArray<EffectParamHandlerD3D9> EffectParamHandlerCacheD3D9;
+
+// EffectD3D9 is an implementation of the Effect object for DX9. It provides
+// the API for setting the vertex and framgent shaders for the Effect in HLSL.
+// Currently the two shaders can either be provided separately as HLSL code
+// or together in the DX9 FX format.
+class EffectD3D9 : public Effect {
+ public:
+ EffectD3D9(ServiceLocator* service_locator, IDirect3DDevice9* d3d_device);
+ ~EffectD3D9();
+
+ // Reads the vertex and fragment shaders from string in the DX9 FX format.
+ // It returns true if the shaders were successfully compiled.
+ bool LoadFromFXString(const String& effect);
+
+ // Binds the shaders to the device and sets up all the shader parameters using
+ // the values from the matching Param's of the ParamObject.
+ void PrepareForDraw(const EffectParamHandlerCacheD3D9& effect_param_cache);
+
+ // Removes any pipeline state-changes installed during a draw.
+ void PostDraw(ParamObject* param_object,
+ const EffectParamHandlerCacheD3D9& effect_param_cache);
+
+ // Gets info about the parameters this effect needs.
+ // Overriden from Effect.
+ virtual void GetParameterInfo(EffectParameterInfoArray* info_array);
+
+ // Gets info about the parameters this effect needs.
+ // Overriden from Effect.
+ virtual void GetStreamInfo(EffectStreamInfoArray* info_array);
+
+ // Returns a pointer to the DX9 vertex shader.
+ IDirect3DVertexShader9* d3d_vertex_shader() const {
+ return d3d_vertex_shader_;
+ }
+
+ // Returns a pointer to the DX9 fragment shader.
+ IDirect3DPixelShader9* d3d_fragment_shader() const {
+ return d3d_fragment_shader_;
+ }
+
+ // Updates the binds between the params in the list of param objecst and the
+ // shader parameters. The two are matched using their names.
+ void UpdateParameterMappings(
+ const std::vector<ParamObject*>& param_object_list,
+ EffectParamHandlerCacheD3D9* effect_param_cache);
+
+ // Handler for lost device. This invalidates the effect for a device reset.
+ bool OnLostDevice();
+
+ // Handler for reset device. This restores the effect after a device reset.
+ bool OnResetDevice();
+
+ private:
+ void UpdateShaderConstantsFromEffect(
+ const EffectParamHandlerCacheD3D9& effect_param_cache);
+
+ // Adds a Parameter Mapping from an O3D param to a d3d parameter if they
+ // match in type.
+ // Parameters:
+ // param: Param we are attempting to map.
+ // pdesc: d3d parameter description.
+ // phandle: Handle to d3d parameter.
+ // effect_param_cache: Cache to add mapping to.
+ // Returns:
+ // true if a mapping was added.
+ bool AddParameterMapping(Param* param,
+ const D3DXPARAMETER_DESC& pdesc,
+ D3DXHANDLE phandle,
+ EffectParamHandlerCacheD3D9* effect_param_cache);
+
+ bool InitializeFX();
+ void DisplayFXError(const String &header, LPD3DXBUFFER error_buffer);
+
+ // Prepares o3d effect string by converting to platform specific effect
+ // string.
+ bool PrepareFX(const String& effect, String* prepared_effect);
+
+ // Clears, Frees the D3D9 parts of this effect.
+ void ClearD3D9Effect();
+
+ SemanticManager* semantic_manager_;
+ RendererD3D9* renderer_;
+
+ CComPtr<IDirect3DVertexShader9> d3d_vertex_shader_;
+ CComPtr<IDirect3DPixelShader9> d3d_fragment_shader_;
+ CComPtr<ID3DXConstantTable> fs_constant_table_;
+ CComPtr<IDirect3DDevice9> d3d_device_;
+ CComPtr<ID3DXEffect> d3dx_effect_;
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_WIN_D3D9_EFFECT_D3D9_H_
diff --git a/o3d/core/win/d3d9/install_check.cc b/o3d/core/win/d3d9/install_check.cc
new file mode 100644
index 0000000..cf4d584
--- /dev/null
+++ b/o3d/core/win/d3d9/install_check.cc
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+
+
+// The precompiled header must appear before anything else.
+#include "core/cross/precompile.h"
+
+#include "core/cross/install_check.h"
+
+#include <Windows.h>
+#include <Shlwapi.h>
+#include <tchar.h>
+
+#include <sstream>
+
+#include "base/scoped_ptr.h"
+#include "core/win/d3d9/d3d_entry_points.h"
+
+EXTERN_C IMAGE_DOS_HEADER __ImageBase;
+namespace o3d {
+
+D3DXCreateEffect_Ptr D3DXCreateEffect = NULL;
+D3DXGetShaderInputSemantics_Ptr D3DXGetShaderInputSemantics = NULL;
+D3DXCreateEffectCompilerFromFileW_Ptr D3DXCreateEffectCompilerFromFileW = NULL;
+D3DXCreateEffectCompilerFromFileA_Ptr D3DXCreateEffectCompilerFromFileA = NULL;
+D3DXSaveSurfaceToFileW_Ptr D3DXSaveSurfaceToFileW = NULL;
+D3DXSaveSurfaceToFileA_Ptr D3DXSaveSurfaceToFileA = NULL;
+D3DXGetShaderConstantTable_Ptr D3DXGetShaderConstantTable = NULL;
+D3DXCreateFontA_Ptr D3DXCreateFontA = NULL;
+D3DXCreateFontW_Ptr D3DXCreateFontW = NULL;
+D3DXCreateLine_Ptr D3DXCreateLine = NULL;
+Direct3DCreate9_Ptr Direct3DCreate9Software = NULL;
+
+static HINSTANCE g_d3dx = NULL;
+static HINSTANCE g_d3d9_software = NULL;
+
+namespace {
+
+void RendererCleanupAllVariables() {
+ D3DXCreateEffect = NULL;
+ D3DXGetShaderInputSemantics = NULL;
+ D3DXCreateEffectCompilerFromFileW = NULL;
+ D3DXCreateEffectCompilerFromFileA = NULL;
+ D3DXSaveSurfaceToFileW = NULL;
+ D3DXSaveSurfaceToFileA = NULL;
+ D3DXGetShaderConstantTable = NULL;
+ D3DXCreateFontW = NULL;
+ D3DXCreateFontA = NULL;
+ D3DXCreateLine = NULL;
+
+ if (g_d3dx) {
+ FreeLibrary(g_d3dx);
+ g_d3dx = NULL;
+ }
+
+ if (g_d3d9_software) {
+ FreeLibrary(g_d3d9_software);
+ g_d3d9_software = NULL;
+ }
+}
+
+bool GetModuleDirectory(TCHAR* path, std::string* error) {
+ ::GetModuleFileName((HINSTANCE)&__ImageBase, path, _MAX_PATH);
+ // Trim off the module filename, leaving the path to the directory containing
+ // the module.
+ if (!PathRemoveFileSpec(path)) {
+ *error = "Failed to compute plugin directory base.";
+ return false;
+ }
+
+ return true;
+}
+
+bool D3DX9InstallCheck(std::string* error) {
+ scoped_array<TCHAR> dll_path(new TCHAR[_MAX_PATH]);
+ if (!GetModuleDirectory(dll_path.get(), error)) {
+ return false;
+ }
+
+ if (!PathAppend(dll_path.get(), _T("O3DExtras\\d3dx9_36.dll"))) {
+ *error = "Failed to compute location of d3dx9_36.dll.";
+ return false;
+ }
+ g_d3dx = LoadLibrary(dll_path.get());
+ if (!g_d3dx) { // Last-ditch "Is this anywhere?" check.
+ g_d3dx = LoadLibrary(_T("d3dx9_36.dll"));
+ }
+ if (!g_d3dx) {
+ std::stringstream error_code_str;
+ error_code_str << GetLastError();
+ *error = "Got error " + error_code_str.str() + " loading d3dx9 library.";
+ return false;
+ }
+
+ D3DXCreateEffect = reinterpret_cast<D3DXCreateEffect_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXCreateEffect"));
+ if (D3DXCreateEffect == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXCreateEffect.";
+ return false;
+ }
+
+ D3DXGetShaderInputSemantics =
+ reinterpret_cast<D3DXGetShaderInputSemantics_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXGetShaderInputSemantics"));
+ if (D3DXGetShaderInputSemantics == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXGetShaderInputSemantics.";
+ return false;
+ }
+
+ D3DXCreateEffectCompilerFromFileW =
+ reinterpret_cast<D3DXCreateEffectCompilerFromFileW_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXCreateEffectCompilerFromFileW"));
+ if (D3DXCreateEffectCompilerFromFileW == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXCreateEffectCompilerFromFileW.";
+ return false;
+ }
+
+ D3DXCreateEffectCompilerFromFileA =
+ reinterpret_cast<D3DXCreateEffectCompilerFromFileA_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXCreateEffectCompilerFromFileA"));
+ if (D3DXCreateEffectCompilerFromFileA == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXCreateEffectCompilerFromFileA.";
+ return false;
+ }
+
+ D3DXSaveSurfaceToFileW =
+ reinterpret_cast<D3DXSaveSurfaceToFileW_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXSaveSurfaceToFileW"));
+ if (D3DXSaveSurfaceToFileW == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXSaveSurfaceToFileW.";
+ return false;
+ }
+
+ D3DXSaveSurfaceToFileA =
+ reinterpret_cast<D3DXSaveSurfaceToFileA_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXSaveSurfaceToFileA"));
+ if (D3DXSaveSurfaceToFileA == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXSaveSurfaceToFileA.";
+ return false;
+ }
+
+ D3DXGetShaderConstantTable =
+ reinterpret_cast<D3DXGetShaderConstantTable_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXGetShaderConstantTable"));
+ if (D3DXGetShaderConstantTable == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXGetShaderConstantTable.";
+ return false;
+ }
+
+ D3DXCreateFontW = reinterpret_cast<D3DXCreateFontW_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXCreateFontW"));
+ if (D3DXCreateFontW == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXCreateFontW.";
+ return false;
+ }
+
+ D3DXCreateFontA = reinterpret_cast<D3DXCreateFontW_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXCreateFontA"));
+ if (D3DXCreateFontA == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXCreateFontA.";
+ return false;
+ }
+
+ D3DXCreateLine = reinterpret_cast<D3DXCreateLine_Ptr>(
+ GetProcAddress(g_d3dx, "D3DXCreateLine"));
+ if (D3DXCreateLine == NULL) {
+ RendererCleanupAllVariables();
+ *error = "Failed to load D3DXCreateLine.";
+ return false;
+ }
+
+ return true;
+}
+
+bool D3D9SoftwareInstallCheck(std::string* error) {
+ scoped_array<TCHAR> dll_path(new TCHAR[_MAX_PATH]);
+ if (!GetModuleDirectory(dll_path.get(), error)) {
+ return false;
+ }
+
+ if (!PathAppend(dll_path.get(), _T("O3DExtras\\swrend\\d3d9.dll"))) {
+ *error = "Failed to compute new plugin location.";
+ return false;
+ }
+
+ g_d3d9_software = LoadLibrary(dll_path.get());
+ if (!g_d3d9_software) {
+ *error = "Failed to load software renderer.";
+ return false;
+ }
+
+ Direct3DCreate9Software = reinterpret_cast<Direct3DCreate9_Ptr>(
+ GetProcAddress(g_d3d9_software, "Direct3DCreate9"));
+ if (Direct3DCreate9Software == NULL) {
+ *error = "Failed to locate Direct3DCreate9 in software renderer.";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace anonymous
+
+bool RendererInstallCheck(std::string *error) {
+ if (g_d3dx) {
+ return true; // Already done.
+ }
+ if (!D3DX9InstallCheck(error)) {
+ return false;
+ }
+
+ // Failure to find the software renderer is not an error at this point.
+ D3D9SoftwareInstallCheck(error);
+
+ return true;
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/param_cache_d3d9.cc b/o3d/core/win/d3d9/param_cache_d3d9.cc
new file mode 100644
index 0000000..2610a02
--- /dev/null
+++ b/o3d/core/win/d3d9/param_cache_d3d9.cc
@@ -0,0 +1,83 @@
+/*
+ * 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 ParamCacheD3D9 class.
+
+#include "core/cross/precompile.h"
+#include "core/win/d3d9/param_cache_d3d9.h"
+#include "core/win/d3d9/effect_d3d9.h"
+#include "core/cross/element.h"
+#include "core/cross/draw_element.h"
+
+namespace o3d {
+
+ParamCacheD3D9::ParamCacheD3D9(ServiceLocator* service_locator)
+ : semantic_manager_(service_locator->GetService<SemanticManager>()),
+ last_vertex_shader_(NULL),
+ last_fragment_shader_(NULL) {
+}
+
+bool ParamCacheD3D9::ValidateEffect(Effect* effect) {
+ DLOG_ASSERT(effect);
+
+ EffectD3D9* effect_d3d9 = down_cast<EffectD3D9*>(effect);
+ IDirect3DVertexShader9* vertex_shader = effect_d3d9->d3d_vertex_shader();
+ IDirect3DPixelShader9* fragment_shader = effect_d3d9->d3d_fragment_shader();
+
+ return (last_fragment_shader_ == fragment_shader ||
+ last_vertex_shader_ == vertex_shader);
+}
+
+void ParamCacheD3D9::UpdateCache(Effect* effect,
+ DrawElement* draw_element,
+ Element* element,
+ Material* material,
+ ParamObject* override) {
+ DLOG_ASSERT(effect);
+ EffectD3D9* effect_d3d9 = down_cast<EffectD3D9*>(effect);
+
+ std::vector<ParamObject*> param_object_list;
+ param_object_list.push_back(override);
+ param_object_list.push_back(draw_element);
+ param_object_list.push_back(element);
+ param_object_list.push_back(material);
+ param_object_list.push_back(effect);
+ param_object_list.push_back(semantic_manager_->sas_param_object());
+
+ effect_d3d9->UpdateParameterMappings(param_object_list,
+ &cached_effect_params_);
+
+ last_vertex_shader_ = effect_d3d9->d3d_vertex_shader();
+ last_fragment_shader_ = effect_d3d9->d3d_fragment_shader();}
+
+} // namespace o3d
+
diff --git a/o3d/core/win/d3d9/param_cache_d3d9.h b/o3d/core/win/d3d9/param_cache_d3d9.h
new file mode 100644
index 0000000..d1e710d
--- /dev/null
+++ b/o3d/core/win/d3d9/param_cache_d3d9.h
@@ -0,0 +1,74 @@
+/*
+ * 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 ParamCacheD3D9 class.
+
+#ifndef O3D_CORE_WIN_D3D9_PARAM_CACHE_D3D9_H_
+#define O3D_CORE_WIN_D3D9_PARAM_CACHE_D3D9_H_
+
+#include <d3d9.h>
+#include <atlbase.h>
+#include "core/cross/param_cache.h"
+#include "core/win/d3d9/effect_d3d9.h"
+#include "core/cross/semantic_manager.h"
+
+namespace o3d {
+
+class ParamCacheD3D9 : public ParamCache {
+ public:
+ explicit ParamCacheD3D9(ServiceLocator* service_locator);
+
+ // Overridden from ParamCache.
+ virtual void UpdateCache(Effect* effect,
+ DrawElement* draw_element,
+ Element* element,
+ Material* material,
+ ParamObject* override);
+
+ const EffectParamHandlerCacheD3D9& cached_effect_params() {
+ return cached_effect_params_;
+ };
+ protected:
+ // Overridden from ParamCache
+ // Validates platform specific information about the effect.
+ virtual bool ValidateEffect(Effect* effect);
+
+ private:
+ EffectParamHandlerCacheD3D9 cached_effect_params_;
+ SemanticManager* semantic_manager_;
+
+ CComPtr<IDirect3DVertexShader9> last_vertex_shader_;
+ CComPtr<IDirect3DPixelShader9> last_fragment_shader_;
+};
+} // o3d
+
+#endif // O3D_CORE_WIN_D3D9_PARAM_CACHE_D3D9_H_
diff --git a/o3d/core/win/d3d9/primitive_d3d9.cc b/o3d/core/win/d3d9/primitive_d3d9.cc
new file mode 100644
index 0000000..5d0a026
--- /dev/null
+++ b/o3d/core/win/d3d9/primitive_d3d9.cc
@@ -0,0 +1,239 @@
+/*
+ * 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 PrimitiveD3D9.
+
+#include "core/cross/precompile.h"
+
+#include "core/win/d3d9/primitive_d3d9.h"
+
+#include "core/cross/buffer.h"
+#include "core/cross/param_cache.h"
+#include "core/cross/renderer.h"
+#include "core/cross/error.h"
+#include "core/win/d3d9/buffer_d3d9.h"
+#include "core/win/d3d9/d3d_entry_points.h"
+#include "core/win/d3d9/draw_element_d3d9.h"
+#include "core/win/d3d9/effect_d3d9.h"
+#include "core/win/d3d9/param_cache_d3d9.h"
+#include "core/win/d3d9/stream_bank_d3d9.h"
+#include "core/win/d3d9/utils_d3d9.h"
+
+// Someone defines min, conflicting with std::min
+#ifdef min
+#undef min
+#endif
+
+namespace o3d {
+
+PrimitiveD3D9::PrimitiveD3D9(ServiceLocator* service_locator,
+ IDirect3DDevice9* d3d_device)
+ : Primitive(service_locator),
+ d3d_device_(d3d_device) {
+ DCHECK(d3d_device);
+}
+
+PrimitiveD3D9::~PrimitiveD3D9() {
+}
+
+// Binds the vertex and index streams required to draw the shape. If the
+// vertex or fragment programs have changed since the last time this method
+// was called (or it's the first time it's getting called) then it forces
+// an update of the mapping between the Material's Params and the shader
+// parameters and also fills in for any missing streams.
+void PrimitiveD3D9::Render(Renderer* renderer,
+ DrawElement* draw_element,
+ Material* material,
+ ParamObject* override,
+ ParamCache* param_cache) {
+ DLOG_ASSERT(param_cache != NULL);
+ ParamCacheD3D9* param_cache_d3d9 = down_cast<ParamCacheD3D9*>(param_cache);
+
+ if (!material) {
+ O3D_ERROR(service_locator())
+ << "No material on Primitive '" << name() << "'";
+ return;
+ }
+
+ EffectD3D9* effect_d3d9 = down_cast<EffectD3D9*>(material->effect());
+ if (!effect_d3d9) {
+ O3D_ERROR(service_locator())
+ << "No effect on material '" << material->name() << "'";
+ return;
+ }
+
+ StreamBankD3D9* stream_bank_d3d9 = down_cast<StreamBankD3D9*>(stream_bank());
+ if (!stream_bank_d3d9) {
+ O3D_ERROR(service_locator())
+ << "No stream bank on Primitive '" << name() << "'";
+ return;
+ }
+
+ DrawElementD3D9* draw_element_d3d9 = down_cast<DrawElementD3D9*>(
+ draw_element);
+
+ IDirect3DVertexShader9* vshader = effect_d3d9->d3d_vertex_shader();
+ IDirect3DPixelShader9* fshader = effect_d3d9->d3d_fragment_shader();
+
+ if (!param_cache_d3d9->ValidateAndCacheParams(effect_d3d9,
+ draw_element_d3d9,
+ this,
+ stream_bank_d3d9,
+ material,
+ override)) {
+ Stream::Semantic missing_semantic;
+ int missing_semnatic_index;
+ if (!stream_bank_d3d9->CheckForMissingVertexStreams(
+ effect_d3d9,
+ &missing_semantic,
+ &missing_semnatic_index)) {
+ param_cache_d3d9->ClearParamCache();
+ O3D_ERROR(service_locator())
+ << "Required Stream "
+ << Stream::GetSemanticDescription(missing_semantic) << ":"
+ << missing_semnatic_index << " missing on Primitive '" << name()
+ << "' using Material '" << material->name()
+ << "' with Effect '" << effect_d3d9->name() << "'";
+ return;
+ }
+ }
+
+ if (indexed()) {
+ // Set the index stream
+ IndexBufferD3D9* index_buffer_d3d9 =
+ down_cast<IndexBufferD3D9*>(index_buffer());
+ unsigned int max_indices = index_buffer_d3d9->num_elements();
+ unsigned int index_count;
+
+ if (!Primitive::GetIndexCount(primitive_type_,
+ number_primitives_,
+ &index_count)) {
+ O3D_ERROR(service_locator())
+ << "Unknown Primitive Type in GetIndexCount: "
+ << primitive_type_ << ". Skipping primitive "
+ << name();
+ return;
+ }
+ if (index_count > max_indices) {
+ O3D_ERROR(service_locator())
+ << "Trying to draw with " << index_count
+ << " indices when only " << max_indices
+ << " are available in the buffer. Skipping primitive " << name();
+ return;
+ }
+ // TODO: Also check that indices in the index buffer are less than
+ // max_vertices_. Needs support from the index buffer (scan indices on
+ // Unlock).
+ HR(d3d_device_->SetIndices(index_buffer_d3d9->d3d_buffer()));
+ }
+
+ // Make sure our streams are up to date (skinned, etc..)
+ stream_bank_d3d9->UpdateStreams();
+
+ // Get all the vertex streams associated with the shape
+ unsigned int max_vertices;
+ if (!stream_bank_d3d9->BindStreamsForRendering(&max_vertices)) {
+ return;
+ }
+
+ // TODO: move these checks at 'set' time instead of draw time.
+
+ // Check the max number of vertices. Do this after InsertMissingVertexStreams
+ // happenned because it may modify the list of streams, thus max_vertices_.
+ if (number_vertices_ > max_vertices) {
+ O3D_ERROR(service_locator())
+ << "Trying to draw with " << number_vertices_
+ << " vertices when there are only " << max_vertices
+ << " available in the buffers. Skipping primitive " << name();
+ return;
+ }
+
+ // Setup the shaders in the effect
+ if (effect_d3d9) {
+ effect_d3d9->PrepareForDraw(param_cache_d3d9->cached_effect_params());
+ }
+
+ // Draw the appropriate primitive
+ D3DPRIMITIVETYPE d3d_primitive_type;
+ switch (primitive_type()) {
+ case Primitive::POINTLIST:
+ if (indexed()) {
+ O3D_ERROR(service_locator())
+ << "POINTLIST unsupported for indexed primitives for primitive "
+ << name();
+ return;
+ } else {
+ d3d_primitive_type = D3DPT_POINTLIST;
+ break;
+ }
+ case Primitive::LINELIST:
+ d3d_primitive_type = D3DPT_LINELIST;
+ break;
+ case Primitive::LINESTRIP:
+ d3d_primitive_type = D3DPT_LINESTRIP;
+ break;
+ case Primitive::TRIANGLELIST:
+ d3d_primitive_type = D3DPT_TRIANGLELIST;
+ break;
+ case Primitive::TRIANGLESTRIP:
+ d3d_primitive_type = D3DPT_TRIANGLESTRIP;
+ break;
+ case Primitive::TRIANGLEFAN:
+ d3d_primitive_type = D3DPT_TRIANGLEFAN;
+ break;
+ default:
+ O3D_ERROR(service_locator())
+ << "Unknown Primitive Type in Primitive: "
+ << primitive_type() << " for primitive "
+ << name();
+ return;
+ }
+ renderer->AddPrimitivesRendered(number_primitives_);
+
+ if (indexed()) {
+ d3d_device_->DrawIndexedPrimitive(d3d_primitive_type,
+ 0,
+ 0,
+ number_vertices_,
+ start_index_,
+ number_primitives_);
+ } else {
+ d3d_device_->DrawPrimitive(
+ d3d_primitive_type, start_index_, number_primitives_);
+ }
+
+ if (effect_d3d9) {
+ effect_d3d9->PostDraw(this, param_cache_d3d9->cached_effect_params());
+ }
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/primitive_d3d9.h b/o3d/core/win/d3d9/primitive_d3d9.h
new file mode 100644
index 0000000..2c03178
--- /dev/null
+++ b/o3d/core/win/d3d9/primitive_d3d9.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 contains the declaration of the PrimitiveD3D9 class.
+
+#ifndef O3D_CORE_WIN_D3D9_PRIMITIVE_D3D9_H_
+#define O3D_CORE_WIN_D3D9_PRIMITIVE_D3D9_H_
+
+#include <d3d9.h>
+#include <atlbase.h>
+#include "core/cross/primitive.h"
+#include "core/win/d3d9/effect_d3d9.h"
+
+namespace o3d {
+
+// PrimitiveD3D9 is the DX9 implementation of the Primitive. It provides the
+// necessary interfaces for setting the geometry streams on the Primitive.
+class PrimitiveD3D9 : public Primitive {
+ public:
+ explicit PrimitiveD3D9(ServiceLocator* service_locator,
+ IDirect3DDevice9* d3d_device);
+ ~PrimitiveD3D9();
+
+ // Overridden from Primitive Render this Primitive using the parameters from
+ // override first, followed by the draw_element, followed by params on this
+ // Primitive and material.
+ virtual void Render(Renderer* renderer,
+ DrawElement* draw_element,
+ Material* material,
+ ParamObject* override,
+ ParamCache* param_cache);
+
+ private:
+ CComPtr<IDirect3DDevice9> d3d_device_;
+};
+} // o3d
+
+#endif // O3D_CORE_WIN_D3D9_PRIMITIVE_D3D9_H_
diff --git a/o3d/core/win/d3d9/render_surface_d3d9.cc b/o3d/core/win/d3d9/render_surface_d3d9.cc
new file mode 100644
index 0000000..7548584
--- /dev/null
+++ b/o3d/core/win/d3d9/render_surface_d3d9.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.
+ */
+
+
+#include "core/cross/precompile.h"
+#include "core/win/d3d9/render_surface_d3d9.h"
+#include "core/win/d3d9/utils_d3d9.h"
+#include "core/win/d3d9/renderer_d3d9.h"
+
+namespace o3d {
+
+RenderSurfaceD3D9::RenderSurfaceD3D9(ServiceLocator *service_locator,
+ int width,
+ int height,
+ Texture *texture,
+ SurfaceConstructor *surface_constructor)
+ : RenderSurface(service_locator, width, height, texture),
+ direct3d_surface_(NULL),
+ surface_constructor_(surface_constructor) {
+ DCHECK(surface_constructor);
+ DCHECK(texture);
+ // TODO: Won't this crash if it can not create the surface?
+ HR(surface_constructor_->ConstructSurface(&direct3d_surface_));
+ Clear();
+}
+
+bool RenderSurfaceD3D9::OnLostDevice() {
+ direct3d_surface_ = NULL;
+ return true;
+}
+
+bool RenderSurfaceD3D9::OnResetDevice() {
+ // Reconstruct the surface from the construction object provided by the
+ // owning texture.
+ HR(surface_constructor_->ConstructSurface(&direct3d_surface_));
+ Clear();
+ return direct3d_surface_ != NULL;
+}
+
+void RenderSurfaceD3D9::Clear() {
+ RendererD3D9* renderer =
+ down_cast<RendererD3D9*>(service_locator()->GetService<Renderer>());
+ if (direct3d_surface_) {
+ renderer->d3d_device()->ColorFill(
+ direct3d_surface_, NULL, D3DCOLOR_RGBA(0, 0, 0, 0));
+ }
+}
+
+RenderDepthStencilSurfaceD3D9::RenderDepthStencilSurfaceD3D9(
+ ServiceLocator *service_locator,
+ int width,
+ int height,
+ SurfaceConstructor *surface_constructor)
+ : RenderDepthStencilSurface(service_locator, width, height),
+ direct3d_surface_(NULL),
+ surface_constructor_(surface_constructor) {
+ DCHECK(surface_constructor);
+ HR(surface_constructor_->ConstructSurface(&direct3d_surface_));
+}
+
+bool RenderDepthStencilSurfaceD3D9::OnLostDevice() {
+ direct3d_surface_ = NULL;
+ return true;
+}
+
+bool RenderDepthStencilSurfaceD3D9::OnResetDevice() {
+ // Reconstruct the surface from the construction object provided by the
+ // owning texture.
+ HR(surface_constructor_->ConstructSurface(&direct3d_surface_));
+ return direct3d_surface_ != NULL;
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/render_surface_d3d9.h b/o3d/core/win/d3d9/render_surface_d3d9.h
new file mode 100644
index 0000000..d375ec1
--- /dev/null
+++ b/o3d/core/win/d3d9/render_surface_d3d9.h
@@ -0,0 +1,116 @@
+/*
+ * 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_CORE_WIN_D3D9_RENDER_SURFACE_D3D9_H_
+#define O3D_CORE_WIN_D3D9_RENDER_SURFACE_D3D9_H_
+
+#include <d3d9.h>
+#include <atlbase.h>
+#include "core/cross/render_surface.h"
+
+namespace o3d {
+
+// A memento class that is capable of constructing and returning
+// a DirectX surface. It maintains all of the parameters relevant to the
+// construction internally.
+class SurfaceConstructor {
+ public:
+ SurfaceConstructor() {}
+ virtual ~SurfaceConstructor() {}
+ virtual HRESULT ConstructSurface(IDirect3DSurface9** surface) = 0;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SurfaceConstructor);
+};
+
+class RenderSurfaceD3D9 : public RenderSurface {
+ public:
+ typedef SmartPointer<RenderSurfaceD3D9> Ref;
+
+ RenderSurfaceD3D9(ServiceLocator *service_locator,
+ int width,
+ int height,
+ Texture *texture,
+ SurfaceConstructor *surface_constructor);
+
+ IDirect3DSurface9* GetSurfaceHandle() const {
+ return direct3d_surface_;
+ }
+
+ // Handler for lost device. This invalidates the render surface for a
+ // device reset.
+ bool OnLostDevice();
+
+ // Handler for reset device. This restores the render surface after a
+ // device reset.
+ bool OnResetDevice();
+
+ // Clears the surface to 0, 0, 0, 0.
+ // TODO: Move this to texture, expose it to JavaScript and let
+ // the user supply an RGBA color.
+ void Clear();
+
+ private:
+ CComPtr<IDirect3DSurface9> direct3d_surface_;
+ scoped_ptr<SurfaceConstructor> surface_constructor_;
+ DISALLOW_COPY_AND_ASSIGN(RenderSurfaceD3D9);
+};
+
+class RenderDepthStencilSurfaceD3D9 : public RenderDepthStencilSurface {
+ public:
+ typedef SmartPointer<RenderDepthStencilSurfaceD3D9> Ref;
+
+ RenderDepthStencilSurfaceD3D9(ServiceLocator *service_locator,
+ int width,
+ int height,
+ SurfaceConstructor *surface_constructor);
+
+ IDirect3DSurface9* GetSurfaceHandle() const {
+ return direct3d_surface_;
+ }
+
+ // Handler for lost device. This invalidates the render surface for a
+ // device reset.
+ bool OnLostDevice();
+
+ // Handler for reset device. This restores the render surface after a
+ // device reset.
+ bool OnResetDevice();
+
+ private:
+ CComPtr<IDirect3DSurface9> direct3d_surface_;
+ scoped_ptr<SurfaceConstructor> surface_constructor_;
+ DISALLOW_COPY_AND_ASSIGN(RenderDepthStencilSurfaceD3D9);
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_WIN_D3D9_RENDER_SURFACE_D3D9_H_
diff --git a/o3d/core/win/d3d9/renderer_d3d9.cc b/o3d/core/win/d3d9/renderer_d3d9.cc
new file mode 100644
index 0000000..b81bf47
--- /dev/null
+++ b/o3d/core/win/d3d9/renderer_d3d9.cc
@@ -0,0 +1,1691 @@
+/*
+ * 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 RendererD3D9 class.
+
+#include "core/cross/precompile.h"
+#include "core/win/d3d9/renderer_d3d9.h"
+
+#include <vector>
+#include <d3dx9core.h>
+
+#include "core/cross/ierror_status.h"
+#include "core/cross/object_manager.h"
+#include "core/cross/renderer_platform.h"
+#include "core/cross/semantic_manager.h"
+#include "core/cross/service_dependency.h"
+#include "core/cross/shape.h"
+#include "core/cross/features.h"
+#include "core/cross/types.h"
+#include "core/win/d3d9/buffer_d3d9.h"
+#include "core/win/d3d9/d3d_entry_points.h"
+#include "core/win/d3d9/draw_element_d3d9.h"
+#include "core/win/d3d9/effect_d3d9.h"
+#include "core/win/d3d9/param_cache_d3d9.h"
+#include "core/win/d3d9/primitive_d3d9.h"
+#include "core/win/d3d9/render_surface_d3d9.h"
+#include "core/win/d3d9/sampler_d3d9.h"
+#include "core/win/d3d9/stream_bank_d3d9.h"
+#include "core/win/d3d9/texture_d3d9.h"
+#include "core/win/d3d9/utils_d3d9.h"
+
+namespace o3d {
+
+typedef std::vector<Effect*> EffectArray;
+typedef std::vector<RenderSurfaceBase*> RenderSurfaceBaseArray;
+typedef std::vector<State*> StateArray;
+typedef std::vector<Texture*> TextureArray;
+
+namespace {
+
+D3DCMPFUNC ConvertCmpFunc(State::Comparison cmp) {
+ switch (cmp) {
+ case State::CMP_ALWAYS:
+ return D3DCMP_ALWAYS;
+ case State::CMP_NEVER:
+ return D3DCMP_NEVER;
+ case State::CMP_LESS:
+ return D3DCMP_LESS;
+ case State::CMP_GREATER:
+ return D3DCMP_GREATER;
+ case State::CMP_LEQUAL:
+ return D3DCMP_LESSEQUAL;
+ case State::CMP_GEQUAL:
+ return D3DCMP_GREATEREQUAL;
+ case State::CMP_EQUAL:
+ return D3DCMP_EQUAL;
+ case State::CMP_NOTEQUAL:
+ return D3DCMP_NOTEQUAL;
+ default:
+ break;
+ }
+ return D3DCMP_ALWAYS;
+}
+
+D3DFILLMODE ConvertFillMode(State::Fill mode) {
+ switch (mode) {
+ case State::POINT:
+ return D3DFILL_POINT;
+ case State::WIREFRAME:
+ return D3DFILL_WIREFRAME;
+ case State::SOLID:
+ return D3DFILL_SOLID;
+ default:
+ break;
+ }
+ return D3DFILL_SOLID;
+}
+
+D3DBLEND ConvertBlendFunc(State::BlendingFunction blend_func) {
+ switch (blend_func) {
+ case State::BLENDFUNC_ZERO:
+ return D3DBLEND_ZERO;
+ case State::BLENDFUNC_ONE:
+ return D3DBLEND_ONE;
+ case State::BLENDFUNC_SOURCE_COLOR:
+ return D3DBLEND_SRCCOLOR;
+ case State::BLENDFUNC_INVERSE_SOURCE_COLOR:
+ return D3DBLEND_INVSRCCOLOR;
+ case State::BLENDFUNC_SOURCE_ALPHA:
+ return D3DBLEND_SRCALPHA;
+ case State::BLENDFUNC_INVERSE_SOURCE_ALPHA:
+ return D3DBLEND_INVSRCALPHA;
+ case State::BLENDFUNC_DESTINATION_ALPHA:
+ return D3DBLEND_DESTALPHA;
+ case State::BLENDFUNC_INVERSE_DESTINATION_ALPHA:
+ return D3DBLEND_INVDESTALPHA;
+ case State::BLENDFUNC_DESTINATION_COLOR:
+ return D3DBLEND_DESTCOLOR;
+ case State::BLENDFUNC_INVERSE_DESTINATION_COLOR:
+ return D3DBLEND_INVDESTCOLOR;
+ case State::BLENDFUNC_SOURCE_ALPHA_SATUTRATE:
+ return D3DBLEND_SRCALPHASAT;
+ default:
+ break;
+ }
+ return D3DBLEND_ONE;
+}
+
+D3DBLENDOP ConvertBlendEquation(State::BlendingEquation blend_equation) {
+ switch (blend_equation) {
+ case State::BLEND_ADD:
+ return D3DBLENDOP_ADD;
+ case State::BLEND_SUBTRACT:
+ return D3DBLENDOP_SUBTRACT;
+ case State::BLEND_REVERSE_SUBTRACT:
+ return D3DBLENDOP_REVSUBTRACT;
+ case State::BLEND_MIN:
+ return D3DBLENDOP_MIN;
+ case State::BLEND_MAX:
+ return D3DBLENDOP_MAX;
+ default:
+ break;
+ }
+ return D3DBLENDOP_ADD;
+}
+
+D3DSTENCILOP ConvertStencilOp(State::StencilOperation stencil_func) {
+ switch (stencil_func) {
+ case State::STENCIL_KEEP:
+ return D3DSTENCILOP_KEEP;
+ case State::STENCIL_ZERO:
+ return D3DSTENCILOP_ZERO;
+ case State::STENCIL_REPLACE:
+ return D3DSTENCILOP_REPLACE;
+ case State::STENCIL_INCREMENT_SATURATE:
+ return D3DSTENCILOP_INCRSAT;
+ case State::STENCIL_DECREMENT_SATURATE:
+ return D3DSTENCILOP_DECRSAT;
+ case State::STENCIL_INVERT:
+ return D3DSTENCILOP_INVERT;
+ case State::STENCIL_INCREMENT:
+ return D3DSTENCILOP_INCR;
+ case State::STENCIL_DECREMENT:
+ return D3DSTENCILOP_DECR;
+ default:
+ break;
+ }
+ return D3DSTENCILOP_KEEP;
+}
+
+// Checks that a device will be able to support the given texture formats.
+bool CheckTextureFormatsSupported(LPDIRECT3D9 d3d,
+ D3DFORMAT display_format,
+ const D3DFORMAT* formats,
+ int num_formats) {
+ for (int i = 0; i < num_formats; ++i) {
+ if (!SUCCEEDED(d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ display_format,
+ 0,
+ D3DRTYPE_TEXTURE,
+ formats[i]))) {
+ LOG(ERROR) << "Device does not support all required texture formats.";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Checks that the graphics device meets the necessary minimum requirements.
+// Note that in the current implementation we're being very lenient with the
+// capabilities we require.
+bool CheckDeviceCaps(LPDIRECT3D9 d3d, Features* features) {
+ D3DCAPS9 d3d_caps;
+ if (!HR(d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3d_caps))) {
+ LOG(ERROR) << "Failed to get device capabilities.";
+ return false;
+ }
+
+ // Check the version of the pixel and vertex shader programs supported.
+ DWORD pixel_shader_version = d3d_caps.PixelShaderVersion;
+ if (pixel_shader_version < D3DPS_VERSION(2, 0)) {
+ LOG(ERROR) << "Device only supports up to pixel shader version "
+ << D3DSHADER_VERSION_MAJOR(pixel_shader_version) << "."
+ << D3DSHADER_VERSION_MINOR(pixel_shader_version)
+ << ". Version 2.0 is required.";
+ return false;
+ }
+
+ // Check that the device can support textures that are at least 2048x2048.
+ DWORD max_texture_height = d3d_caps.MaxTextureHeight;
+ DWORD max_texture_width = d3d_caps.MaxTextureWidth;
+ DWORD required_texture_size = 2048;
+ if (max_texture_height < required_texture_size ||
+ max_texture_width < required_texture_size) {
+ LOG(ERROR) << "Device only supports up to " << max_texture_height << "x"
+ << max_texture_width << " textures. " << required_texture_size << "x"
+ << required_texture_size << " is required.";
+ return false;
+ }
+
+ D3DDISPLAYMODE d3d_display_mode;
+ if (!HR(d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3d_display_mode)))
+ return false;
+
+ // Check that the device supports all the texture formats needed.
+ D3DFORMAT texture_formats[] = {
+ D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_DXT1,
+ D3DFMT_DXT3, D3DFMT_DXT5
+ };
+ if (!CheckTextureFormatsSupported(
+ d3d,
+ d3d_display_mode.Format,
+ texture_formats,
+ sizeof(texture_formats) / sizeof(texture_formats[0]))) {
+ return false;
+ }
+ if (features->floating_point_textures()) {
+ D3DFORMAT float_texture_formats[] = {
+ D3DFMT_R32F, D3DFMT_A16B16G16R16F, D3DFMT_A32B32G32R32F
+ };
+ if (!CheckTextureFormatsSupported(
+ d3d,
+ d3d_display_mode.Format,
+ float_texture_formats,
+ sizeof(float_texture_formats) / sizeof(float_texture_formats[0]))) {
+ return false;
+ }
+ }
+
+ // Check the device supports the needed indices
+ if (features->large_geometry()) {
+ if (d3d_caps.MaxVertexIndex < Buffer::MAX_LARGE_INDEX) {
+ return false;
+ }
+ }
+
+ // Check render target formats.
+ D3DFORMAT render_target_formats[] = { D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 };
+ const int kNumRenderTargetFormats = sizeof(render_target_formats) /
+ sizeof(render_target_formats[0]);
+ for (int i = 0; i < kNumRenderTargetFormats; ++i) {
+ if (!SUCCEEDED(d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ d3d_display_mode.Format,
+ D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_TEXTURE,
+ render_target_formats[i]))) {
+ LOG(ERROR) << "Device does not support all required texture formats"
+ << " for render targets.";
+ return false;
+ }
+ }
+
+ // Check depth stencil formats.
+ D3DFORMAT depth_stencil_formats[] = { D3DFMT_D24S8 };
+ const int kNumDepthStencilFormats = sizeof(depth_stencil_formats) /
+ sizeof(depth_stencil_formats[0]);
+ for (int i = 0; i < kNumDepthStencilFormats; ++i) {
+ if (!SUCCEEDED(d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ d3d_display_mode.Format,
+ D3DUSAGE_DEPTHSTENCIL,
+ D3DRTYPE_SURFACE,
+ depth_stencil_formats[i]))) {
+ LOG(ERROR) << "Device does not support all required texture formats"
+ << " for depth/stencil buffers.";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Attempt to create a Direct3D9 object supporting the required caps. Return
+// NULL if the object cannot be created or if it does not support the caps.
+Renderer::InitStatus CreateDirect3D(Direct3DCreate9_Ptr d3d_create_function,
+ LPDIRECT3D9* d3d,
+ Features* features) {
+ if (!d3d_create_function) {
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ *d3d = d3d_create_function(D3D_SDK_VERSION);
+ if (NULL == *d3d) {
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ // Check that the graphics device meets the minimum capabilities.
+ if (!CheckDeviceCaps(*d3d, features)) {
+ (*d3d)->Release();
+ *d3d = NULL;
+ return Renderer::GPU_NOT_UP_TO_SPEC;
+ }
+
+ return Renderer::SUCCESS;
+}
+
+// Helper function that gets the D3D Interface, checks the available
+// multisampling modes and selects the most advanced one available to create
+// a D3D Device with a back buffer containing depth and stencil buffers that
+// match the current display device.
+Renderer::InitStatus InitializeD3D9Context(
+ HWND window,
+ LPDIRECT3D9* d3d,
+ LPDIRECT3DDEVICE9* d3d_device,
+ D3DPRESENT_PARAMETERS* d3d_present_parameters,
+ bool fullscreen,
+ Features* features,
+ int* out_width,
+ int* out_height) {
+
+ // Try the hardware renderer first.
+ Renderer::InitStatus status_hardware = CreateDirect3D(
+ Direct3DCreate9, d3d, features);
+ if (status_hardware != Renderer::SUCCESS) {
+ Renderer::InitStatus status_software = CreateDirect3D(
+ Direct3DCreate9Software, d3d, features);
+
+ // We should not be requiring caps that are not supported by the software
+ // renderer.
+ DCHECK(status_software != Renderer::GPU_NOT_UP_TO_SPEC);
+
+ if (status_software != Renderer::SUCCESS) {
+ // Report the hardware error. An error with the software renderer should
+ // only mean that it is not available, which is normal.
+ if (status_hardware == Renderer::INITIALIZATION_ERROR) {
+ LOG(ERROR) << "Failed to create the initial D3D9 Interface";
+ }
+ return status_hardware;
+ }
+ }
+
+ D3DDISPLAYMODE d3ddm;
+ if (!HR((*d3d)->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
+ return Renderer::GPU_NOT_UP_TO_SPEC;
+
+ // NOTE: make sure the backbuffer matches this format, as it is
+ // currently currently assumed to be 32-bit 8X8R8G8B
+
+ ZeroMemory(d3d_present_parameters, sizeof(*d3d_present_parameters));
+ d3d_present_parameters->Windowed = !fullscreen;
+ d3d_present_parameters->SwapEffect = D3DSWAPEFFECT_DISCARD;
+ d3d_present_parameters->BackBufferFormat = d3ddm.Format;
+ d3d_present_parameters->EnableAutoDepthStencil = FALSE;
+ d3d_present_parameters->AutoDepthStencilFormat = D3DFMT_UNKNOWN;
+ // wait for vsync
+ d3d_present_parameters->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+
+ // Note: SwapEffect=DISCARD is req. for multisample to function
+ // Note: AutoDepthStencilFormat is 16-bit (not the usual 8-bit)
+ D3DFORMAT depth_stencil_formats[] = { D3DFMT_D24S8, };
+ const int kNumFormats = sizeof(depth_stencil_formats) /
+ sizeof(depth_stencil_formats[0]);
+ for (int i = 0; i < kNumFormats; ++i) {
+ // Check if this depth/stencil combination is supported.
+ if (SUCCEEDED((*d3d)->CheckDeviceFormat(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ d3ddm.Format,
+ D3DUSAGE_DEPTHSTENCIL,
+ D3DRTYPE_SURFACE,
+ depth_stencil_formats[i]))) {
+ // Now check that it's compatible with the given backbuffer format.
+ if (SUCCEEDED((*d3d)->CheckDepthStencilMatch(
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ d3ddm.Format,
+ d3d_present_parameters->BackBufferFormat,
+ depth_stencil_formats[i]))) {
+ d3d_present_parameters->AutoDepthStencilFormat =
+ depth_stencil_formats[i];
+ d3d_present_parameters->EnableAutoDepthStencil = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (features->not_anti_aliased()) {
+ d3d_present_parameters->MultiSampleType = D3DMULTISAMPLE_NONE;
+ d3d_present_parameters->MultiSampleQuality = 0;
+ } else {
+ // query multisampling
+ D3DMULTISAMPLE_TYPE multisample_types[] = {
+ D3DMULTISAMPLE_5_SAMPLES,
+ D3DMULTISAMPLE_4_SAMPLES,
+ D3DMULTISAMPLE_2_SAMPLES,
+ D3DMULTISAMPLE_NONE
+ };
+
+ DWORD multisample_quality = 0;
+ for (int i = 0; i < arraysize(multisample_types); ++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))) {
+ d3d_present_parameters->MultiSampleType = multisample_types[i];
+ d3d_present_parameters->MultiSampleQuality = multisample_quality - 1;
+ break;
+ }
+ }
+ }
+ }
+
+ // Check if the window size is zero. Some drivers will fail because of that
+ // so we'll force a small size in that case.
+ {
+ RECT windowRect;
+ ::GetWindowRect(window, &windowRect);
+ int width = windowRect.right - windowRect.left;
+ int height = windowRect.bottom - windowRect.top;
+
+ *out_width = width;
+ *out_height = height;
+
+ if (width == 0 || height == 0) {
+ d3d_present_parameters->BackBufferWidth = 16;
+ d3d_present_parameters->BackBufferHeight = 16;
+ *out_width = 16;
+ *out_height = 16;
+ }
+ }
+
+ // create the D3D device
+ DWORD d3d_behavior_flags = 0;
+
+ // Check the device capabilities.
+ D3DCAPS9 d3d_caps;
+ HRESULT caps_result = (*d3d)->GetDeviceCaps(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ &d3d_caps);
+ if (!HR(caps_result)) {
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ // Check if the device supports HW vertex processing.
+ if (d3d_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
+ d3d_behavior_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
+ else
+ d3d_behavior_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
+
+ // D3DCREATE_FPU_PRESERVE is there because Firefox 3 relies on specific FPU
+ // flags for its UI rendering. Apparently Firefox 2 is 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.
+ d3d_behavior_flags |= D3DCREATE_FPU_PRESERVE;
+ if (!HR((*d3d)->CreateDevice(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ window,
+ d3d_behavior_flags,
+ d3d_present_parameters,
+ d3d_device))) {
+ return Renderer::OUT_OF_RESOURCES;
+ }
+
+ return Renderer::SUCCESS;
+}
+
+// Helper function that constructs an off-screen surface based on the
+// current state of the d3d_device argument.
+Renderer::InitStatus InitOffscreenSurface(
+ LPDIRECT3DDEVICE9 d3d_device,
+ IDirect3DSurface9** off_screen_surface) {
+ CComPtr<IDirect3DSurface9> current_surface;
+ if (!HR(d3d_device->GetRenderTarget(0, &current_surface))) {
+ DLOG(ERROR) << "Failed to get offscreen render target.";
+ return Renderer::OUT_OF_RESOURCES;
+ }
+
+ D3DSURFACE_DESC surface_description;
+ if (!HR(current_surface->GetDesc(&surface_description))) {
+ DLOG(ERROR) << "Failed to get offscreen surface description.";
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ CComPtr<IDirect3DSurface9> depth_stencil_surface;
+ if (!HR(d3d_device->GetDepthStencilSurface(&depth_stencil_surface)))
+ return Renderer::OUT_OF_RESOURCES;
+
+ D3DSURFACE_DESC depth_stencil_description;
+ if (!HR(depth_stencil_surface->GetDesc(
+ &depth_stencil_description))) {
+ DLOG(ERROR) << "Failed to get offscreen depth stencil.";
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ // create our surface as render target
+ if (!HR(d3d_device->CreateRenderTarget(
+ surface_description.Width,
+ surface_description.Height,
+ surface_description.Format,
+ surface_description.MultiSampleType,
+ surface_description.MultiSampleQuality,
+ false,
+ off_screen_surface,
+ NULL))) {
+ DLOG(ERROR) << "Failed to create offscreen renderer.";
+ return Renderer::OUT_OF_RESOURCES;
+ }
+
+ return Renderer::SUCCESS;
+}
+
+namespace {
+template <typename T>
+T LocalMinMax(T value, T min_value, T max_value) {
+ return (value < min_value) ? min_value :
+ ((value > max_value) ? max_value : value);
+}
+} // namespace anonymous
+
+// Callback class used to construct depth-stencil RenderSurface objects during
+// lost device events. See usage in CreateDepthStencilSurface(...).
+class DepthStencilSurfaceConstructor : public SurfaceConstructor {
+ public:
+ DepthStencilSurfaceConstructor(ServiceLocator* service_locator,
+ int width,
+ int height)
+ : width_(width),
+ height_(height),
+ renderer_(service_locator) {}
+
+ virtual HRESULT ConstructSurface(IDirect3DSurface9** surface) {
+ if (!renderer_.IsAvailable()) {
+ return E_FAIL;
+ }
+
+ RendererD3D9* renderer_d3d9 = static_cast<RendererD3D9*>(renderer_.Get());
+ return renderer_d3d9->d3d_device()->CreateDepthStencilSurface(
+ width_,
+ height_,
+ D3DFMT_D24S8,
+ D3DMULTISAMPLE_NONE,
+ 0,
+ FALSE,
+ surface,
+ NULL);
+ }
+
+ private:
+ // The width and height of the surface to create, respectively.
+ int width_;
+ int height_;
+
+ ServiceDependency<Renderer> renderer_;
+ DISALLOW_COPY_AND_ASSIGN(DepthStencilSurfaceConstructor);
+};
+
+} // unnamed namespace
+
+// This class wraps StateHandler to make it typesafe.
+template <typename T>
+class TypedStateHandler : public RendererD3D9::StateHandler {
+ public:
+ typedef typename T ParamType;
+ // Override this function to set a specific state.
+ // Parameters:
+ // renderer: The platform specific renderer.
+ // param: A concrete param with state data.
+ virtual void SetStateFromTypedParam(
+ RendererD3D9* renderer, T* param) const = 0;
+
+ // Gets Class of State's Parameter
+ virtual const ObjectBase::Class* GetClass() const {
+ return T::GetApparentClass();
+ }
+
+ private:
+ // Calls SetStateFromTypedParam after casting the param to the correct type.
+ // The State object guarntees that bad mis-matches do not happe,.
+ // Parameters:
+ // renderer: The platform specific renderer.
+ // param: A param with state data.
+ virtual void SetState(Renderer* renderer, Param* param) const {
+ RendererD3D9 *renderer_d3d = down_cast<RendererD3D9 *>(renderer);
+ // This is safe because State guarntees Params match by type.
+ DCHECK(param->IsA(T::GetApparentClass()));
+ SetStateFromTypedParam(renderer_d3d, down_cast<T*>(param));
+ }
+};
+
+// A template the generates a handler for enable/disable states.
+// Parameters:
+// state_constant: D3DRENDERSTATETYPE of state we want to enable/disable
+template <D3DRENDERSTATETYPE state_constant>
+class StateEnableHandler : public TypedStateHandler<ParamBoolean> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamBoolean* param) const {
+ HR(renderer->d3d_device()->SetRenderState(state_constant,
+ param->value()));
+ }
+};
+
+// A template that generates a handler for stencil operation states.
+// Parameters:
+// state_constant: D3DRENDERSTATETYPE of state we want to set.
+template <D3DRENDERSTATETYPE state_constant>
+class StencilOperationHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamInteger* param) const {
+ HR(renderer->d3d_device()->SetRenderState(
+ state_constant,
+ ConvertStencilOp(static_cast<State::StencilOperation>(
+ param->value()))));
+ }
+};
+
+// A template that generates a handler for blend function states.
+// Parameters:
+// state_constant: D3DRENDERSTATETYPE of state we want to set.
+template <D3DRENDERSTATETYPE state_constant>
+class BlendFunctionHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamInteger* param) const {
+ HR(renderer->d3d_device()->SetRenderState(
+ state_constant,
+ ConvertBlendFunc(static_cast<State::BlendingFunction>(
+ param->value()))));
+ }
+};
+
+// A template that generates a handler for blend equation states.
+// Parameters:
+// state_constant: D3DRENDERSTATETYPE of state we want to set.
+template <D3DRENDERSTATETYPE state_constant>
+class BlendEquationHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamInteger* param) const {
+ HR(renderer->d3d_device()->SetRenderState(
+ state_constant,
+ ConvertBlendEquation(
+ static_cast<State::BlendingEquation>(param->value()))));
+ }
+};
+
+// A template that generates a handler for comparison function states.
+// Parameters:
+// state_constant: D3DRENDERSTATETYPE of state we want to set.
+template <D3DRENDERSTATETYPE state_constant>
+class ComparisonFunctionHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamInteger* param) const {
+ HR(renderer->d3d_device()->SetRenderState(
+ state_constant,
+ ConvertCmpFunc(static_cast<State::Comparison>(param->value()))));
+ }
+};
+
+// A template that generates a handler for integer function states.
+// Parameters:
+// state_constant: D3DRENDERSTATETYPE of state we want to set.
+template <D3DRENDERSTATETYPE state_constant>
+class IntegerStateHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamInteger* param) const {
+ HR(renderer->d3d_device()->SetRenderState(state_constant,
+ param->value()));
+ }
+};
+
+class AlphaReferenceHandler : public TypedStateHandler<ParamFloat> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamFloat* param) const {
+ float refFloat = LocalMinMax(param->value(), 0.0f, 1.0f);
+ int ref = static_cast<int>(refFloat * 255.0f);
+
+ HR(renderer->d3d_device()->SetRenderState(D3DRS_ALPHAREF, ref));
+ }
+};
+
+class CullModeHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamInteger* param) const {
+ State::Cull cull = static_cast<State::Cull>(param->value());
+ switch (cull) {
+ case State::CULL_NONE:
+ HR(renderer->d3d_device()->SetRenderState(D3DRS_CULLMODE,
+ D3DCULL_NONE));
+ break;
+ case State::CULL_CW:
+ HR(renderer->d3d_device()->SetRenderState(D3DRS_CULLMODE,
+ D3DCULL_CW));
+ break;
+ case State::CULL_CCW:
+ HR(renderer->d3d_device()->SetRenderState(D3DRS_CULLMODE,
+ D3DCULL_CCW));
+ break;
+ }
+ }
+};
+
+class PointSizeHandler : public TypedStateHandler<ParamFloat> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamFloat* param) const {
+ Float2DWord offset;
+ offset.my_float = param->value();
+
+ HR(renderer->d3d_device()->SetRenderState(D3DRS_POINTSIZE,
+ offset.my_dword));
+ }
+};
+
+class PolygonOffset1Handler : public TypedStateHandler<ParamFloat> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamFloat* param) const {
+ Float2DWord offset;
+ offset.my_float = param->value();
+
+ HR(renderer->d3d_device()->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS,
+ offset.my_dword));
+ }
+};
+
+class PolygonOffset2Handler : public TypedStateHandler<ParamFloat> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamFloat* param) const {
+ // TODO: this value is hard-coded currently because we only create a
+ // 24-bit depth buffer. Move this to a member of RendererD3D9 if it changes.
+ const float kUnitScale = 1.f / (1 << 24);
+ Float2DWord offset;
+ offset.my_float = param->value() * kUnitScale;
+
+ HR(renderer->d3d_device()->SetRenderState(D3DRS_DEPTHBIAS,
+ offset.my_dword));
+ }
+};
+
+class FillModeHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererD3D9* renderer,
+ ParamInteger* param) const {
+ HR(renderer->d3d_device()->SetRenderState(
+ D3DRS_FILLMODE,
+ ConvertFillMode(static_cast<State::Fill>(param->value()))));
+ }
+};
+
+RendererD3D9* RendererD3D9::CreateDefault(ServiceLocator* service_locator) {
+ return new RendererD3D9(service_locator);
+}
+
+RendererD3D9::RendererD3D9(ServiceLocator* service_locator)
+ : Renderer(service_locator),
+ object_manager_(service_locator),
+ semantic_manager_(service_locator),
+ d3d_(NULL),
+ d3d_device_(NULL),
+ use_small_index_buffers_(false),
+ off_screen_surface_(NULL),
+ back_buffer_surface_(NULL),
+ back_buffer_depth_surface_(NULL),
+ have_device_(false),
+ fullscreen_(false),
+ fullscreen_message_font_(NULL),
+ fullscreen_message_line_(NULL),
+ showing_fullscreen_message_(false) {
+ // Setup state handlers
+ AddStateHandler(State::kAlphaTestEnableParamName,
+ new StateEnableHandler<D3DRS_ALPHATESTENABLE>);
+ AddStateHandler(State::kAlphaReferenceParamName,
+ new AlphaReferenceHandler);
+ AddStateHandler(State::kAlphaComparisonFunctionParamName,
+ new ComparisonFunctionHandler<D3DRS_ALPHAFUNC>);
+ AddStateHandler(State::kCullModeParamName,
+ new CullModeHandler);
+ AddStateHandler(State::kDitherEnableParamName,
+ new StateEnableHandler<D3DRS_DITHERENABLE>);
+ AddStateHandler(State::kLineSmoothEnableParamName,
+ new StateEnableHandler<D3DRS_ANTIALIASEDLINEENABLE>);
+ AddStateHandler(State::kPointSpriteEnableParamName,
+ new StateEnableHandler<D3DRS_POINTSPRITEENABLE>);
+ AddStateHandler(State::kPointSizeParamName,
+ new PointSizeHandler);
+ AddStateHandler(State::kPolygonOffset1ParamName,
+ new PolygonOffset1Handler);
+ AddStateHandler(State::kPolygonOffset2ParamName,
+ new PolygonOffset2Handler);
+ AddStateHandler(State::kFillModeParamName,
+ new FillModeHandler);
+ AddStateHandler(State::kZEnableParamName,
+ new StateEnableHandler<D3DRS_ZENABLE>);
+ AddStateHandler(State::kZWriteEnableParamName,
+ new StateEnableHandler<D3DRS_ZWRITEENABLE>);
+ AddStateHandler(State::kZComparisonFunctionParamName,
+ new ComparisonFunctionHandler<D3DRS_ZFUNC>);
+ AddStateHandler(State::kAlphaBlendEnableParamName,
+ new StateEnableHandler<D3DRS_ALPHABLENDENABLE>);
+ AddStateHandler(State::kSourceBlendFunctionParamName,
+ new BlendFunctionHandler<D3DRS_SRCBLEND>);
+ AddStateHandler(State::kDestinationBlendFunctionParamName,
+ new BlendFunctionHandler<D3DRS_DESTBLEND>);
+ AddStateHandler(State::kStencilEnableParamName,
+ new StateEnableHandler<D3DRS_STENCILENABLE>);
+ AddStateHandler(State::kStencilFailOperationParamName,
+ new StencilOperationHandler<D3DRS_STENCILFAIL>);
+ AddStateHandler(State::kStencilZFailOperationParamName,
+ new StencilOperationHandler<D3DRS_STENCILZFAIL>);
+ AddStateHandler(State::kStencilPassOperationParamName,
+ new StencilOperationHandler<D3DRS_STENCILPASS>);
+ AddStateHandler(State::kStencilComparisonFunctionParamName,
+ new ComparisonFunctionHandler<D3DRS_STENCILFUNC>);
+ AddStateHandler(State::kStencilReferenceParamName,
+ new IntegerStateHandler<D3DRS_STENCILREF>);
+ AddStateHandler(State::kStencilMaskParamName,
+ new IntegerStateHandler<D3DRS_STENCILMASK>);
+ AddStateHandler(State::kStencilWriteMaskParamName,
+ new IntegerStateHandler<D3DRS_STENCILWRITEMASK>);
+ AddStateHandler(State::kColorWriteEnableParamName,
+ new IntegerStateHandler<D3DRS_COLORWRITEENABLE>);
+ AddStateHandler(State::kBlendEquationParamName,
+ new BlendEquationHandler<D3DRS_BLENDOP>);
+ AddStateHandler(State::kTwoSidedStencilEnableParamName,
+ new StateEnableHandler<D3DRS_TWOSIDEDSTENCILMODE>);
+ AddStateHandler(State::kCCWStencilFailOperationParamName,
+ new StencilOperationHandler<D3DRS_CCW_STENCILFAIL>);
+ AddStateHandler(State::kCCWStencilZFailOperationParamName,
+ new StencilOperationHandler<D3DRS_CCW_STENCILZFAIL>);
+ AddStateHandler(State::kCCWStencilPassOperationParamName,
+ new StencilOperationHandler<D3DRS_CCW_STENCILPASS>);
+ AddStateHandler(State::kCCWStencilComparisonFunctionParamName,
+ new ComparisonFunctionHandler<D3DRS_CCW_STENCILFUNC>);
+ AddStateHandler(State::kSeparateAlphaBlendEnableParamName,
+ new StateEnableHandler<D3DRS_SEPARATEALPHABLENDENABLE>);
+ AddStateHandler(State::kSourceBlendAlphaFunctionParamName,
+ new BlendFunctionHandler<D3DRS_SRCBLENDALPHA>);
+ AddStateHandler(State::kDestinationBlendAlphaFunctionParamName,
+ new BlendFunctionHandler<D3DRS_DESTBLENDALPHA>);
+ AddStateHandler(State::kBlendAlphaEquationParamName,
+ new BlendEquationHandler<D3DRS_BLENDOPALPHA>);
+}
+
+RendererD3D9::~RendererD3D9() {
+ Destroy();
+}
+
+Renderer::InitStatus RendererD3D9::InitPlatformSpecific(
+ const DisplayWindow& display,
+ bool off_screen) {
+ const DisplayWindowWindows& platform_display =
+ static_cast<const DisplayWindowWindows&>(display);
+ HWND window = platform_display.hwnd();
+ int width;
+ int height;
+ d3d_ = NULL;
+ d3d_device_ = NULL;
+ InitStatus init_status = InitializeD3D9Context(
+ window,
+ &d3d_,
+ &d3d_device_,
+ &d3d_present_parameters_,
+ fullscreen_,
+ features(),
+ &width,
+ &height);
+ if (init_status != SUCCESS) {
+ DLOG(ERROR) << "Failed to initialize D3D9.";
+ return init_status;
+ }
+
+ D3DCAPS9 d3d_caps;
+ if (!HR(d3d_->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3d_caps))) {
+ DLOG(ERROR) << "Failed to get device capabilities.";
+ return INITIALIZATION_ERROR;
+ }
+
+ // Do we require small index buffers?
+ use_small_index_buffers_ = d3d_caps.MaxVertexIndex < 0x10000;
+ DCHECK(!use_small_index_buffers_ || !features()->large_geometry());
+
+ const unsigned int kNpotFlags =
+ D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_CUBEMAP_POW2;
+ supports_npot_ = ((d3d_caps.TextureCaps & kNpotFlags) == 0);
+
+ SetClientSize(width, height);
+ have_device_ = true;
+
+ if (!HR(d3d_->CheckDeviceFormat(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ d3d_present_parameters_.BackBufferFormat,
+ D3DUSAGE_DEPTHSTENCIL,
+ D3DRTYPE_SURFACE,
+ D3DFMT_D24S8))) {
+ DLOG(ERROR) << "Failed to find compatible depth surface format.";
+ Destroy();
+ return GPU_NOT_UP_TO_SPEC;
+ }
+
+ if (off_screen) {
+ init_status = InitOffscreenSurface(d3d_device_, &off_screen_surface_);
+ if (init_status != SUCCESS) {
+ Destroy();
+ return init_status;
+ }
+ }
+
+ if (S_OK !=
+ D3DXCreateFont(d3d_device_,
+ 27 /* font_height */,
+ 0 /* font width--0 appears to be "don't care" */,
+ FW_DONTCARE,
+ 1 /* MIP levels */,
+ FALSE,
+ DEFAULT_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ DEFAULT_PITCH | FF_DONTCARE /* pitch and font family */,
+ L"Arial",
+ &fullscreen_message_font_)) {
+ DLOG(ERROR) << "Failed to initialize font.";
+ return INITIALIZATION_ERROR;
+ }
+
+ if (S_OK !=
+ D3DXCreateLine(d3d_device_,
+ &fullscreen_message_line_)) {
+ DLOG(ERROR) << "Failed to initialize line for message background.";
+ return INITIALIZATION_ERROR;
+ }
+
+ return SUCCESS;
+}
+
+// Deletes the D3D9 Device and releases the D3D interface.
+void RendererD3D9::Destroy() {
+ off_screen_surface_ = NULL;
+ d3d_device_ = NULL;
+ d3d_ = NULL;
+}
+
+void RendererD3D9::Clear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag) {
+ // is this safe to call inside BeginScene/EndScene?
+ CComPtr<IDirect3DSurface9> current_surface;
+ if (!HR(d3d_device()->GetRenderTarget(0, &current_surface)))
+ return;
+
+ CComPtr<IDirect3DSurface9> current_depth_surface;
+ if (!HR(d3d_device()->GetDepthStencilSurface(&current_depth_surface)))
+ return;
+
+ // Conditionally clear the properties of the back buffer based on the
+ // argument flags, and the existence of currently bound buffers.
+ HR(d3d_device_->Clear(
+ 0,
+ NULL,
+ ((color_flag && current_surface) ? D3DCLEAR_TARGET : 0) |
+ ((depth_flag && current_depth_surface) ? D3DCLEAR_ZBUFFER : 0) |
+ ((stencil_flag && current_depth_surface) ? D3DCLEAR_STENCIL : 0),
+ D3DCOLOR_COLORVALUE(color[0],
+ color[1],
+ color[2],
+ color[3]),
+ depth,
+ stencil));
+}
+
+void RendererD3D9::SetViewportInPixels(int left,
+ int top,
+ int width,
+ int height,
+ float min_z,
+ float max_z) {
+ D3DVIEWPORT9 viewport;
+
+ viewport.X = left;
+ viewport.Y = top;
+ viewport.Width = width;
+ viewport.Height = height;
+ viewport.MinZ = min_z;
+ viewport.MaxZ = max_z;
+
+ HR(d3d_device_->SetViewport(&viewport));
+}
+
+// Resource allocation methods ------------------------------------------------
+
+// Invalidates all resources which are in D3DPOOL_DEFAULT.
+// Used before we try to reset the device, when the device is lost.
+// (ie when suspending the computer, locking it, etc.)
+// Returns true on success and false on failure.
+bool RendererD3D9::InvalidateDeviceObjects() {
+ back_buffer_surface_ = NULL;
+ back_buffer_depth_surface_ = NULL;
+
+ // Invalidate all effect objects.
+ const EffectArray effect_array(object_manager_->GetByClass<Effect>());
+ EffectArray::const_iterator p, end(effect_array.end());
+ for (p = effect_array.begin(); p != end; ++p) {
+ EffectD3D9* effect = down_cast<EffectD3D9*>(*p);
+ if (!HR(effect->OnLostDevice()))
+ return false;
+ }
+
+ // Invalidate all Texture and RenderSurface objects.
+ const RenderSurfaceBaseArray surface_array(
+ object_manager_->GetByClass<RenderSurfaceBase>());
+ RenderSurfaceBaseArray::const_iterator surface_iter(surface_array.begin()),
+ surface_end(surface_array.end());
+ for (;surface_iter != surface_end; ++surface_iter) {
+ if ((*surface_iter)->IsA(RenderSurface::GetApparentClass())) {
+ RenderSurfaceD3D9* render_surface_d3d9 =
+ down_cast<RenderSurfaceD3D9*>(*surface_iter);
+ if (!HR(render_surface_d3d9 ->OnLostDevice())) {
+ return false;
+ }
+ } else if ((*surface_iter)->IsA(
+ RenderDepthStencilSurface::GetApparentClass())) {
+ RenderDepthStencilSurfaceD3D9* render_depth_surface_d3d9 =
+ down_cast<RenderDepthStencilSurfaceD3D9*>(*surface_iter);
+ if (!HR(render_depth_surface_d3d9 ->OnLostDevice())) {
+ return false;
+ }
+ }
+ }
+
+ const TextureArray texture_array(object_manager_->GetByClass<Texture>());
+ TextureArray::const_iterator texture_iter(texture_array.begin()),
+ texture_end(texture_array.end());
+ for (;texture_iter != texture_end; ++texture_iter) {
+ if ((*texture_iter)->IsA(Texture2D::GetApparentClass())) {
+ Texture2DD3D9* texture2d_d3d9 = down_cast<Texture2DD3D9*>(*texture_iter);
+ if (!HR(texture2d_d3d9->OnLostDevice())) {
+ return false;
+ }
+ } else if ((*texture_iter)->IsA(TextureCUBE::GetApparentClass())) {
+ TextureCUBED3D9* texture_cube_d3d9 =
+ down_cast<TextureCUBED3D9*>(*texture_iter);
+ if (!HR(texture_cube_d3d9->OnLostDevice())) {
+ return false;
+ }
+ }
+ }
+
+ if (fullscreen_message_font_ &&
+ S_OK != fullscreen_message_font_->OnLostDevice()) {
+ return false;
+ }
+ if (fullscreen_message_line_ &&
+ S_OK != fullscreen_message_line_->OnLostDevice()) {
+ return false;
+ }
+ return true;
+}
+
+// Restore all resources which are in D3DPOOL_DEFAULT.
+// Used after we reset the direct3d device to restore these resources.
+// Returns true on success and false on failure.
+bool RendererD3D9::RestoreDeviceObjects() {
+ // Restore all Effect objects.
+ const EffectArray effect_array(object_manager_->GetByClass<Effect>());
+ EffectArray::const_iterator p, end(effect_array.end());
+ for (p = effect_array.begin(); p != end; ++p) {
+ EffectD3D9* effect = down_cast<EffectD3D9*>(*p);
+ if (!HR(effect->OnResetDevice()))
+ return false;
+ }
+
+ // Restore all Texture objects.
+ const TextureArray texture_array(object_manager_->GetByClass<Texture>());
+ TextureArray::const_iterator texture_iter(texture_array.begin()),
+ texture_end(texture_array.end());
+ for (;texture_iter != texture_end; ++texture_iter) {
+ if ((*texture_iter)->IsA(Texture2D::GetApparentClass())) {
+ Texture2DD3D9* texture2d_d3d9 = down_cast<Texture2DD3D9*>(*texture_iter);
+ if (!HR(texture2d_d3d9->OnResetDevice())) {
+ return false;
+ }
+ } else if ((*texture_iter)->IsA(TextureCUBE::GetApparentClass())) {
+ TextureCUBED3D9* texture_cube_d3d9 =
+ down_cast<TextureCUBED3D9*>(*texture_iter);
+ if (!HR(texture_cube_d3d9->OnResetDevice())) {
+ return false;
+ }
+ }
+ }
+
+ // Restore all RenderSurface objects. Note that this pass must happen
+ // after the Textures have been restored.
+ RenderSurfaceBaseArray surface_array(
+ object_manager_->GetByClass<RenderSurfaceBase>());
+ RenderSurfaceBaseArray::const_iterator surface_iter(surface_array.begin()),
+ surface_end(surface_array.end());
+ for (; surface_iter != surface_end; ++surface_iter) {
+ if ((*surface_iter)->IsA(RenderSurface::GetApparentClass())) {
+ RenderSurfaceD3D9* render_surface_d3d9 =
+ down_cast<RenderSurfaceD3D9*>(*surface_iter);
+ if (!HR(render_surface_d3d9->OnResetDevice())) {
+ return false;
+ }
+ } else if ((*surface_iter)->IsA(
+ RenderDepthStencilSurface::GetApparentClass())) {
+ RenderDepthStencilSurfaceD3D9* render_depth_stencil_surface_d3d9 =
+ down_cast<RenderDepthStencilSurfaceD3D9*>(*surface_iter);
+ if (!HR(render_depth_stencil_surface_d3d9->OnResetDevice())) {
+ return false;
+ }
+ }
+ }
+ if (fullscreen_message_font_ &&
+ S_OK != fullscreen_message_font_->OnResetDevice()) {
+ return false;
+ }
+ if (fullscreen_message_line_ &&
+ S_OK != fullscreen_message_line_->OnResetDevice()) {
+ return false;
+ }
+
+ return true;
+}
+
+// Resets the d3d device properly and returns true on success.
+bool RendererD3D9::ResetDevice() {
+ // First update the flag if it hasn't been set yet.
+ have_device_ = false;
+
+ // Try to release all resources
+ if (!InvalidateDeviceObjects())
+ return false;
+
+ // Attempt to reset the device
+ if (!HR(d3d_device_->Reset(&d3d_present_parameters_)))
+ return false;
+
+ // Now try to restore our resources
+ if (!RestoreDeviceObjects())
+ return false;
+
+ // If everything goes well, reset render states.
+ SetInitialStates();
+
+ // successful
+ return true;
+}
+
+// This function tests if the device is lost and sets the have_device_ flag
+// appropriately.
+// It attempts to reset the device if it is lost.
+void RendererD3D9::TestLostDevice() {
+ HRESULT hr = 0;
+
+ // We poll for the state of the device using TestCooperativeLevel().
+ hr = d3d_device_->TestCooperativeLevel();
+
+ // When hr == D3DERR_DEVICELOST, it means that we have lost the device
+ // ie. a screensaver, or the computer is locked etc.
+ // and there is nothing we can do to get back the device,
+ // and display stuff normally.
+ // In this case, we set the have_device_ flag to false to disable
+ // all render calls and calls involving the device.
+
+ // When hr == D3DERR_DEVICENOTRESET, we have lost the device BUT we can
+ // reset it and restore our original display.
+ // (ie. user has come out of his screensaver)
+ // In this case, we attempt to invalidate all resources in D3DPOOL_DEFAULT,
+ // reset the device, and then restore the resources.
+ // This should succeed and we set the have_device_ flag to true.
+ // If it fails, we do not set the flag to true so as
+
+ if (hr == D3DERR_DEVICELOST) {
+ // We've lost the device, update the flag so that render calls don't
+ // get called.
+ have_device_ = false;
+ return;
+ } else if (hr == D3DERR_DEVICENOTRESET) {
+ // Direct3d tells us it is possible to reset the device now..
+ // So let's attempt a reset!
+ ResetDevice();
+ }
+
+ // TestCooperativeLevel doesn't give us a device lost error or variant
+ // or the device has been successfully reset and reinitialized.
+ // We can safely set our have_device_ flag to true.
+ have_device_ = true;
+}
+
+// The window has been resized; change the size of our back buffer
+// and do a reset.
+void RendererD3D9::Resize(int width, int height) {
+ if (width > 0 && height > 0) {
+ // New size of back buffer
+ d3d_present_parameters_.BackBufferWidth = width;
+ d3d_present_parameters_.BackBufferHeight = height;
+
+ // Attempt to do a reset if possible
+ HRESULT hr = d3d_device_->TestCooperativeLevel();
+ if (hr == D3DERR_DEVICENOTRESET || hr == D3D_OK) {
+ // Reset device
+ ResetDevice();
+ }
+
+ // Save this off.
+ SetClientSize(width, height);
+ }
+}
+
+void RendererD3D9::GetDisplayModes(std::vector<DisplayMode> *modes) {
+ int num_modes =
+ d3d_->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8);
+ std::vector<DisplayMode> modes_found;
+ for (int i = 0; i < num_modes; ++i) {
+ D3DDISPLAYMODE mode;
+ if (FAILED(d3d_->EnumAdapterModes(D3DADAPTER_DEFAULT,
+ D3DFMT_X8R8G8B8,
+ i,
+ &mode))) {
+ LOG(ERROR) << "Failed to enumerate adapter display modes.";
+ } else {
+ DCHECK(mode.Format == D3DFMT_X8R8G8B8);
+ modes_found.push_back(
+ DisplayMode(mode.Width, mode.Height, mode.RefreshRate, i));
+ }
+ }
+ modes->swap(modes_found);
+}
+
+bool RendererD3D9::GetDisplayMode(int id, DisplayMode *mode) {
+ D3DDISPLAYMODE d3d_mode;
+ bool success = SUCCEEDED(d3d_->EnumAdapterModes(D3DADAPTER_DEFAULT,
+ D3DFMT_X8R8G8B8,
+ id,
+ &d3d_mode));
+ if (success) {
+ mode->Set(d3d_mode.Width, d3d_mode.Height, d3d_mode.RefreshRate, id);
+ }
+ return success;
+}
+
+bool RendererD3D9::SetFullscreen(bool fullscreen,
+ const DisplayWindow& display,
+ int mode_id) {
+ if (fullscreen != fullscreen_) {
+ if (d3d_device_) { // Have we been initialized yet?
+ const DisplayWindowWindows& platform_display =
+ static_cast<const DisplayWindowWindows&>(display);
+ HWND window = platform_display.hwnd();
+ int refresh_rate = 0;
+ if (fullscreen) {
+ // Look up the refresh rate.
+ D3DDISPLAYMODE mode;
+ if (FAILED(d3d_->EnumAdapterModes(D3DADAPTER_DEFAULT,
+ D3DFMT_X8R8G8B8,
+ mode_id,
+ &mode))) {
+ LOG(ERROR) << "Failed to EnumAdapterModes";
+ return false;
+ }
+ refresh_rate = mode.RefreshRate;
+ showing_fullscreen_message_ = true;
+ fullscreen_message_timer_.GetElapsedTimeAndReset(); // Reset the timer.
+ } else {
+ showing_fullscreen_message_ = false;
+ }
+ d3d_present_parameters_.FullScreen_RefreshRateInHz = refresh_rate;
+ d3d_present_parameters_.hDeviceWindow = window;
+ d3d_present_parameters_.Windowed = !fullscreen;
+
+ // Check if the window size is zero. Some drivers will fail because of
+ // that so we'll force a small size in that case.
+ RECT windowRect;
+ ::GetWindowRect(window, &windowRect);
+ int width = windowRect.right - windowRect.left;
+ int height = windowRect.bottom - windowRect.top;
+
+ if (width == 0 || height == 0) {
+ width = 16;
+ height = 16;
+ }
+ fullscreen_ = fullscreen;
+ Resize(width, height);
+ }
+ }
+ return true;
+}
+
+// Resets the rendering stats and
+bool RendererD3D9::StartRendering() {
+ ++render_frame_count_;
+ transforms_culled_ = 0;
+ transforms_processed_ = 0;
+ draw_elements_culled_ = 0;
+ draw_elements_processed_ = 0;
+ draw_elements_rendered_ = 0;
+ primitives_rendered_ = 0;
+
+ // Attempt to reset the device if it is lost.
+ if (!have_device_)
+ TestLostDevice();
+
+ // Only perform ops with the device if we have it.
+ if (have_device_) {
+ // Clear the client if we need to.
+ if (clear_client_) {
+ clear_client_ = false;
+ Clear(Float4(0.5f, 0.5f, 0.5f, 1.0f), true, 1.0f, true, 0, true);
+ }
+ return true;
+ } else {
+ // Return false if we have lost the device.
+ return false;
+ }
+}
+
+// prepares DX9 for rendering the frame. Returns true on success.
+bool RendererD3D9::BeginDraw() {
+ // Only perform ops with the device if we have it.
+ if (have_device_) {
+ if (!HR(d3d_device_->GetRenderTarget(0, &back_buffer_surface_)))
+ return false;
+ if (!HR(d3d_device_->GetDepthStencilSurface(&back_buffer_depth_surface_)))
+ return false;
+ if (!HR(d3d_device_->BeginScene()))
+ return false;
+ // Reset the viewport.
+ SetViewport(Float4(0.0f, 0.0f, 1.0f, 1.0f), Float2(0.0f, 1.0f));
+ return true;
+ } else {
+ back_buffer_surface_ = NULL;
+ back_buffer_depth_surface_ = NULL;
+
+ // Return false if we have lost the device.
+ return false;
+ }
+}
+
+void RendererD3D9::ShowFullscreenMessage() {
+ RECT rect;
+ const float curve_radius = 16.0f;
+ const float curve_radius_squared = curve_radius * curve_radius;
+ const float line_height = 80.0f;
+ const float line_base_height = line_height - 2.0f * curve_radius;
+ const float line_base_height_offset = line_base_height / 2.0f;
+ const float midline_height = height() / 2.0f;
+ const float midline_width = width() / 2.0f;
+ const D3DXCOLOR background_color(0.0f, 0.0f, 0.0f, 0.5f);
+ SetRect(&rect, 0, 0, width(), height());
+ // Drawing the message before the background puts it on top.
+ HR(fullscreen_message_font_->DrawText(NULL,
+ L"Press ESC to exit full screen mode.", -1, &rect,
+ DT_CENTER | DT_VCENTER, D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f)));
+ D3DXVECTOR2 line_vertices[2];
+ HR(fullscreen_message_line_->SetWidth(line_base_height));
+ line_vertices[0].x = midline_width - 400.0f - curve_radius;
+ line_vertices[0].y = midline_height;
+ line_vertices[1].x = midline_width + 400.0f + curve_radius;
+ line_vertices[1].y = midline_height;
+ HR(fullscreen_message_line_->Draw(line_vertices, 2, background_color));
+ HR(fullscreen_message_line_->SetWidth(1));
+ HR(fullscreen_message_line_->Begin());
+ for (int i = 0; i <= curve_radius; ++i) {
+ const float dx = sqrt(curve_radius_squared - i * i);
+ const float dy = i + line_base_height_offset;
+ line_vertices[0].x = midline_width - 400.0f - dx;
+ line_vertices[0].y = midline_height + dy;
+ line_vertices[1].x = midline_width + 400.0f + dx;
+ line_vertices[1].y = midline_height + dy;
+ HR(fullscreen_message_line_->Draw(line_vertices, 2, background_color));
+ line_vertices[0].y = midline_height - dy;
+ line_vertices[1].y = midline_height - dy;
+ HR(fullscreen_message_line_->Draw(line_vertices, 2, background_color));
+ }
+ HR(fullscreen_message_line_->End());
+}
+
+// Notifies DX9 that rendering of the frame is complete and swaps the buffers.
+void RendererD3D9::EndDraw() {
+ if (have_device_) {
+ if (showing_fullscreen_message_) {
+ // Message should display for 3 seconds after transition to fullscreen.
+ if (fullscreen_message_timer_.GetElapsedTimeWithoutClearing() > 3.0f) {
+ showing_fullscreen_message_ = false;
+ } else {
+ ShowFullscreenMessage();
+ }
+ }
+ HR(d3d_device_->EndScene());
+
+ // Release the back-buffer references.
+ back_buffer_surface_ = NULL;
+ back_buffer_depth_surface_ = NULL;
+ }
+}
+
+void RendererD3D9::FinishRendering() {
+ // No need to call Present(...) if we are rendering to an off-screen
+ // target.
+ if (!off_screen_surface_) {
+ HRESULT hr = d3d_device_->Present(NULL, NULL, NULL, NULL);
+ // Test for lost device if Present fails.
+ if (hr != D3D_OK) {
+ TestLostDevice();
+ // TODO: This should only be called if some resources were
+ // actually lost. In other words if there are no RenderSurfaces
+ // then there is no reason to call this.
+ lost_resources_callback_manager_.Run();
+ }
+ }
+}
+
+// Asks the primitive to draw itself.
+void RendererD3D9::RenderElement(Element* element,
+ DrawElement* draw_element,
+ Material* material,
+ ParamObject* override,
+ ParamCache* param_cache) {
+ ++draw_elements_rendered_;
+ // If this a new state then reset the old state.
+ State *current_state = material ? material->state() : NULL;
+ PushRenderStates(current_state);
+ element->Render(this, draw_element, material, override, param_cache);
+ PopRenderStates();
+}
+
+void RendererD3D9::SetRenderSurfacesPlatformSpecific(
+ RenderSurface* surface,
+ RenderDepthStencilSurface* surface_depth) {
+ RenderSurfaceD3D9 *d3d_render_surface =
+ down_cast<RenderSurfaceD3D9*>(surface);
+ RenderDepthStencilSurfaceD3D9 *d3d_render_depth_surface =
+ down_cast<RenderDepthStencilSurfaceD3D9*>(surface_depth);
+
+ IDirect3DSurface9 *d3d_surface =
+ d3d_render_surface ? d3d_render_surface->GetSurfaceHandle() : NULL;
+ IDirect3DSurface9 *d3d_depth_surface = d3d_render_depth_surface ?
+ d3d_render_depth_surface->GetSurfaceHandle() : NULL;
+
+ // At least one of the surfaces must be non-null.
+ DCHECK(d3d_surface || d3d_depth_surface);
+
+ HR(d3d_device()->SetRenderTarget(0, d3d_surface));
+ HR(d3d_device()->SetDepthStencilSurface(d3d_depth_surface));
+}
+
+void RendererD3D9::SetBackBufferPlatformSpecific() {
+ HR(d3d_device()->SetRenderTarget(0, back_buffer_surface_));
+ HR(d3d_device()->SetDepthStencilSurface(back_buffer_depth_surface_));
+}
+
+StreamBank::Ref RendererD3D9::CreateStreamBank() {
+ return StreamBank::Ref(new StreamBankD3D9(service_locator(), d3d_device()));
+}
+
+Primitive::Ref RendererD3D9::CreatePrimitive() {
+ return Primitive::Ref(new PrimitiveD3D9(service_locator(), d3d_device()));
+}
+
+DrawElement::Ref RendererD3D9::CreateDrawElement() {
+ return DrawElement::Ref(new DrawElementD3D9(service_locator()));
+}
+
+VertexBuffer::Ref RendererD3D9::CreateVertexBuffer() {
+ return VertexBuffer::Ref(new VertexBufferD3D9(service_locator(),
+ d3d_device()));
+}
+
+// Creates and returns a D3D9 specific integer buffer.
+IndexBuffer::Ref RendererD3D9::CreateIndexBuffer() {
+ return IndexBuffer::Ref(new IndexBufferD3D9(service_locator(),
+ d3d_device(),
+ use_small_index_buffers_));
+}
+
+Effect::Ref RendererD3D9::CreateEffect() {
+ return Effect::Ref(new EffectD3D9(service_locator(), d3d_device()));
+}
+
+Sampler::Ref RendererD3D9::CreateSampler() {
+ return Sampler::Ref(new SamplerD3D9(service_locator(), d3d_device()));
+}
+
+ParamCache* RendererD3D9::CreatePlatformSpecificParamCache() {
+ return new ParamCacheD3D9(service_locator());
+}
+
+// Attempts to create a Texture with the given bitmap, automatically
+// determining whether the to create a 2D texture, cube texture, etc. If
+// creation fails the method returns NULL.
+// Parameters:
+// bitmap: The bitmap specifying the dimensions, format and content of the
+// new texture. The created texture takes ownership of the bitmap
+// data.
+// Returns:
+// A ref-counted pointer to the texture or NULL if it did not load.
+Texture::Ref RendererD3D9::CreatePlatformSpecificTextureFromBitmap(
+ Bitmap* bitmap) {
+ if (bitmap->is_cubemap()) {
+ return Texture::Ref(TextureCUBED3D9::Create(service_locator(),
+ bitmap,
+ this,
+ false));
+ } else {
+ return Texture::Ref(Texture2DD3D9::Create(service_locator(),
+ bitmap,
+ this,
+ false));
+ }
+}
+
+// Attempts to create a Texture2D with the given specs. If creation fails
+// then the method returns NULL.
+Texture2D::Ref RendererD3D9::CreatePlatformSpecificTexture2D(
+ int width,
+ int height,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces) {
+ Bitmap bitmap;
+ bitmap.set_format(format);
+ bitmap.set_width(width);
+ bitmap.set_height(height);
+ bitmap.set_num_mipmaps(levels);
+ return Texture2D::Ref(Texture2DD3D9::Create(service_locator(),
+ &bitmap,
+ this,
+ enable_render_surfaces));
+}
+
+// Attempts to create a Texture2D with the given specs. If creation fails
+// then the method returns NULL.
+TextureCUBE::Ref RendererD3D9::CreatePlatformSpecificTextureCUBE(
+ int edge_length,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces) {
+ Bitmap bitmap;
+ bitmap.set_format(format);
+ bitmap.set_width(edge_length);
+ bitmap.set_height(edge_length);
+ bitmap.set_num_mipmaps(levels);
+ bitmap.set_is_cubemap(true);
+ return TextureCUBE::Ref(TextureCUBED3D9::Create(service_locator(),
+ &bitmap,
+ this,
+ enable_render_surfaces));
+}
+
+RenderDepthStencilSurface::Ref RendererD3D9::CreateDepthStencilSurface(
+ int width,
+ int height) {
+ DepthStencilSurfaceConstructor *depth_constructor =
+ new DepthStencilSurfaceConstructor(service_locator(), width, height);
+
+ // Note that since the returned surface is not associated with a Texture
+ // mip-level, NULL is passed for the texture argument.
+ return RenderDepthStencilSurface::Ref(
+ new RenderDepthStencilSurfaceD3D9(service_locator(),
+ width,
+ height,
+ depth_constructor));
+}
+
+// Saves a png screenshot 'filename.png'.
+// Returns true on success and false on failure.
+bool RendererD3D9::SaveScreen(const String& file_name) {
+#ifdef TESTING
+ LPDIRECT3DDEVICE9 device = d3d_device();
+ CComPtr<IDirect3DSurface9> system_surface;
+ CComPtr<IDirect3DSurface9> current_surface;
+
+ if (!HR(device->GetRenderTarget(0, &current_surface)))
+ return false;
+
+ D3DSURFACE_DESC surface_description;
+ if (!HR(current_surface->GetDesc(&surface_description)))
+ return false;
+
+ // Construct an intermediate surface with multi-sampling disabled.
+ // This surface is required because GetRenderTargetData(...) will fail
+ // for multi-sampled targets. One must first down-sample to a
+ // non-multi-sample buffer, and then copy from that intermediate buffer
+ // to a main memory surface.
+ CComPtr<IDirect3DSurface9> intermediate_target;
+ if (!HR(device->CreateRenderTarget(surface_description.Width,
+ surface_description.Height,
+ surface_description.Format,
+ D3DMULTISAMPLE_NONE,
+ 0,
+ FALSE,
+ &intermediate_target,
+ NULL))) {
+ return false;
+ }
+
+ if (!HR(device->StretchRect(current_surface,
+ NULL,
+ intermediate_target,
+ NULL,
+ D3DTEXF_NONE))) {
+ return false;
+ }
+
+ if (!HR(device->CreateOffscreenPlainSurface(surface_description.Width,
+ surface_description.Height,
+ surface_description.Format,
+ D3DPOOL_SYSTEMMEM,
+ &system_surface,
+ NULL))) {
+ return false;
+ }
+
+ if (!HR(device->GetRenderTargetData(intermediate_target, system_surface)))
+ return false;
+
+ // append .png to the end of file_name
+ String png_file_name = file_name;
+ png_file_name.append(String(".png"));
+ // convert file name to utf16
+ std::wstring file_name_utf16 = UTF8ToWide(png_file_name);
+
+ return HR(o3d::D3DXSaveSurfaceToFile(file_name_utf16.c_str(),
+ D3DXIFF_PNG,
+ system_surface,
+ NULL,
+ NULL));
+#else
+ // Not a test build, always return false.
+ return false;
+#endif
+}
+
+const int* RendererD3D9::GetRGBAUByteNSwizzleTable() {
+ static int swizzle_table[] = { 2, 1, 0, 3, };
+ return swizzle_table;
+}
+
+// This is a factory function for creating Renderer objects. Since
+// we're implementing D3D9, we only ever return a D3D9 renderer.
+Renderer* Renderer::CreateDefaultRenderer(ServiceLocator* service_locator) {
+ return RendererD3D9::CreateDefault(service_locator);
+}
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/renderer_d3d9.h b/o3d/core/win/d3d9/renderer_d3d9.h
new file mode 100644
index 0000000..747f001
--- /dev/null
+++ b/o3d/core/win/d3d9/renderer_d3d9.h
@@ -0,0 +1,281 @@
+/*
+ * 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 RendererD3D9 class.
+
+#ifndef O3D_CORE_WIN_D3D9_RENDERER_D3D9_H_
+#define O3D_CORE_WIN_D3D9_RENDERER_D3D9_H_
+
+#include <atlbase.h>
+#include <d3d9.h>
+
+#include <vector>
+
+#include "core/cross/display_mode.h"
+#include "core/cross/display_window.h"
+#include "core/cross/renderer.h"
+#include "core/cross/state.h"
+#include "core/cross/texture.h"
+#include "core/cross/timer.h"
+#include "core/cross/types.h"
+
+interface ID3DXFont;
+interface ID3DXLine;
+
+namespace o3d {
+
+class Material;
+class Texture2D;
+class ObjectManager;
+class ParamCache;
+class SemanticManager;
+
+// The RenderedD9D9 class implements the genereric Renderer interface using
+// DirectX9.
+class RendererD3D9 : public Renderer {
+ public:
+ // Creates a default Renderer.
+ static RendererD3D9* CreateDefault(ServiceLocator* service_locator);
+ virtual ~RendererD3D9();
+
+ // Initialises the renderer for use, claiming hardware resources.
+ virtual InitStatus InitPlatformSpecific(const DisplayWindow& display,
+ bool off_screen);
+
+ // Released all hardware resources.
+ virtual void Destroy();
+
+ // This method should be called before any draw calls take place in a
+ // frame. It clears the back buffer, stencil and depth buffers.
+ virtual bool BeginDraw();
+
+ // Finalizes the drawing of the frame.
+ virtual void EndDraw();
+
+ // Does any pre-rendering preparation
+ virtual bool StartRendering();
+
+ // Presents the results of the draw calls for this frame.
+ virtual void FinishRendering();
+
+ // Attempts to reset the back buffer to its new dimensions.
+ virtual void Resize(int width, int height);
+
+ // Turns fullscreen display on or off.
+ // Parameters:
+ // fullscreen: true for fullscreen, false for in-plugin display
+ // display: a platform-specific display identifier
+ // mode_id: a mode returned by GetDisplayModes, for fullscreen use. Ignored
+ // in non-fullscreen mode.
+ // Returns true on success, false on failure.
+ virtual bool SetFullscreen(bool fullscreen, const DisplayWindow& display,
+ int mode_id);
+
+ // Tells whether we're currently displayed fullscreen or not.
+ virtual bool fullscreen() const {
+ return fullscreen_;
+ }
+
+ // Get a vector of the available fullscreen display modes.
+ // Clears *modes on error.
+ virtual void GetDisplayModes(std::vector<DisplayMode> *modes);
+
+ // Get a single fullscreen display mode by id.
+ // Returns true on success, false on error.
+ virtual bool GetDisplayMode(int id, DisplayMode *mode);
+
+ // clears the current buffers
+ virtual void Clear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag);
+
+ // Draws a Element.
+ virtual void RenderElement(Element* element,
+ DrawElement* draw_element,
+ Material* material,
+ ParamObject* override,
+ ParamCache* param_cache);
+
+ // Creates a StreamBank, returning a platform specific implementation class.
+ virtual StreamBank::Ref CreateStreamBank();
+
+ // Creates a Primitive, returning a platform specific implementation class.
+ virtual Primitive::Ref CreatePrimitive();
+
+ // Creates a DrawElement, returning a platform specific implementation
+ // class.
+ virtual DrawElement::Ref CreateDrawElement();
+
+ // Creates and returns a D3D9 specific float buffer.
+ virtual VertexBuffer::Ref CreateVertexBuffer();
+
+ // Creates and returns a D3D9 specific integer buffer.
+ virtual IndexBuffer::Ref CreateIndexBuffer();
+
+ // Creates and returns a D3D9 specific Effect object.
+ virtual Effect::Ref CreateEffect();
+
+ // Creates and returns a D3D9 specific Sampler object.
+ virtual Sampler::Ref CreateSampler();
+
+ // Creates and returns a platform-specific RenderDepthStencilSurface object
+ // for use as a depth-stencil render target.
+ virtual RenderDepthStencilSurface::Ref CreateDepthStencilSurface(
+ int width,
+ int height);
+
+ // Saves a png screenshot 'file_name.png'.
+ // Returns true on success and false on failure.
+ virtual bool SaveScreen(const String& file_name);
+
+ inline LPDIRECT3DDEVICE9 d3d_device() const { return d3d_device_; }
+ inline LPDIRECT3D9 d3d() const { return d3d_; }
+
+ inline DWORD supported_depth_format() const {
+ return supported_depth_format_;
+ }
+
+ // Overridden from Renderer.
+ virtual const int* GetRGBAUByteNSwizzleTable();
+
+ protected:
+ // Keep the constructor protected so only factory methods can create
+ // renderers.
+ explicit RendererD3D9(ServiceLocator* service_locator);
+
+ // Overridden from Renderer.
+ virtual ParamCache* CreatePlatformSpecificParamCache();
+
+ // Overridden from Renderer.
+ virtual void SetBackBufferPlatformSpecific();
+
+ // Overridden from Renderer.
+ virtual void SetRenderSurfacesPlatformSpecific(
+ RenderSurface* surface,
+ RenderDepthStencilSurface* depth_surface);
+
+ // Sets the viewport. This is the platform specific version.
+ void SetViewportInPixels(int left,
+ int top,
+ int width,
+ int height,
+ float min_z,
+ float max_z);
+
+ // Overridden from Renderer.
+ virtual Texture::Ref CreatePlatformSpecificTextureFromBitmap(Bitmap* bitmap);
+
+ // Overridden from Renderer.
+ virtual Texture2D::Ref CreatePlatformSpecificTexture2D(
+ int width,
+ int height,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces);
+
+ // Overridden from Renderer.
+ virtual TextureCUBE::Ref CreatePlatformSpecificTextureCUBE(
+ int edge_length,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces);
+
+ private:
+ ServiceDependency<ObjectManager> object_manager_;
+ ServiceDependency<SemanticManager> semantic_manager_;
+
+ // Instance of the D3D9 interface.
+ CComPtr<IDirect3D9> d3d_;
+
+ // Instance of the D3DDevice9 interface.
+ CComPtr<IDirect3DDevice9> d3d_device_;
+
+ // D3DFORMAT value of the depth surface type supported.
+ DWORD supported_depth_format_;
+
+ // Pointer to interface of the off-screen-surface used for off-screen
+ // rendering. Is non-null when off-screen rendering is enabled.
+ CComPtr<IDirect3DSurface9> off_screen_surface_;
+
+ CComPtr<IDirect3DSurface9> back_buffer_surface_;
+ CComPtr<IDirect3DSurface9> back_buffer_depth_surface_;
+
+ // D3DPresent parameters (for initializing and resetting the device.)
+ D3DPRESENT_PARAMETERS d3d_present_parameters_;
+
+ // Flag to tell use we need to use small index buffers.
+ bool use_small_index_buffers_;
+
+ // Flag to tell us whether we have or lost the device.
+ bool have_device_;
+
+ // Indicates we're rendering fullscreen rather than in the plugin region.
+ bool fullscreen_;
+ // Indicates we're showing the "Press Escape..." banner.
+ bool showing_fullscreen_message_;
+ // We want to show the message for about 3 seconds.
+ ElapsedTimeTimer fullscreen_message_timer_;
+ // Draws the actual message.
+ void ShowFullscreenMessage();
+
+ // Invalidates all resources which are in D3DPOOL_DEFAULT.
+ // Used before we try to reset the device, when the device is lost.
+ // (ie when suspending the computer, locking it, etc.)
+ // Returns true on success and false on failure.
+ bool InvalidateDeviceObjects();
+
+ // Restore all resources which are in D3DPOOL_DEFAULT.
+ // Used after we reset the direct3d device to restore these resources.
+ // Returns true on success and false on failure.
+ bool RestoreDeviceObjects();
+
+ // This function tests if the device is lost and sets the have_device_ flag
+ // appropriately.
+ // It attempts to reset the device if it is lost by calling ResetDevice().
+ void TestLostDevice();
+
+ // Attempts to reset the device.
+ // Returns true on success.
+ bool ResetDevice();
+
+ // The font to use to display the message when we go to fullscreen.
+ CComPtr<ID3DXFont> fullscreen_message_font_;
+ // The line used to draw the background for the message.
+ CComPtr<ID3DXLine> fullscreen_message_line_;
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_WIN_D3D9_RENDERER_D3D9_H_
diff --git a/o3d/core/win/d3d9/sampler_d3d9.cc b/o3d/core/win/d3d9/sampler_d3d9.cc
new file mode 100644
index 0000000..79ea219
--- /dev/null
+++ b/o3d/core/win/d3d9/sampler_d3d9.cc
@@ -0,0 +1,194 @@
+/*
+ * 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 SamplerD3D9.
+
+#include "core/cross/precompile.h"
+
+#include "core/win/d3d9/sampler_d3d9.h"
+
+#include "core/cross/error.h"
+#include "core/cross/renderer.h"
+#include "core/cross/renderer_platform.h"
+#include "core/win/d3d9/utils_d3d9.h"
+
+namespace o3d {
+
+SamplerD3D9::SamplerD3D9(ServiceLocator* service_locator,
+ IDirect3DDevice9* d3d_device)
+ : Sampler(service_locator),
+ renderer_(static_cast<RendererD3D9*>(
+ service_locator->GetService<Renderer>())),
+ d3d_device_(d3d_device) {
+ DCHECK(d3d_device);
+}
+
+SamplerD3D9::~SamplerD3D9() {
+}
+
+void SamplerD3D9::SetAddressMode(int sampler_unit,
+ D3DSAMPLERSTATETYPE sampler_type,
+ Sampler::AddressMode o3d_mode,
+ D3DTEXTUREADDRESS default_mode) {
+ D3DTEXTUREADDRESS d3d_mode = default_mode;
+ switch (o3d_mode) {
+ case WRAP:
+ d3d_mode = D3DTADDRESS_WRAP;
+ break;
+ case MIRROR:
+ d3d_mode = D3DTADDRESS_MIRROR;
+ break;
+ case CLAMP:
+ d3d_mode = D3DTADDRESS_CLAMP;
+ break;
+ case BORDER:
+ d3d_mode = D3DTADDRESS_BORDER;
+ break;
+ default:
+ DLOG(ERROR) << "Unknown Address mode " << static_cast<int>(o3d_mode);
+ return;
+ }
+
+ HR(d3d_device_->SetSamplerState(sampler_unit, sampler_type, d3d_mode));
+}
+
+namespace {
+
+D3DTEXTUREFILTERTYPE D3DMagFilter(Sampler::FilterType o3d_mag_filter) {
+ // For mag filters only POINT and LINEAR make sense. Everything else
+ // we convert to LINEAR.
+ switch (o3d_mag_filter) {
+ case Sampler::POINT:
+ return D3DTEXF_POINT;
+ case Sampler::LINEAR:
+ return D3DTEXF_LINEAR;
+ default:
+ return D3DTEXF_LINEAR;
+ }
+}
+
+D3DTEXTUREFILTERTYPE D3DMinFilter(Sampler::FilterType o3d_mag_filter) {
+ // Allowable min filters are POINT, LINEAR and ANISOTROPIC
+ switch (o3d_mag_filter) {
+ case Sampler::POINT:
+ return D3DTEXF_POINT;
+ case Sampler::LINEAR:
+ return D3DTEXF_LINEAR;
+ case Sampler::ANISOTROPIC:
+ return D3DTEXF_ANISOTROPIC;
+ default:
+ return D3DTEXF_LINEAR;
+ }
+}
+
+D3DTEXTUREFILTERTYPE D3DMipFilter(Sampler::FilterType o3d_mag_filter) {
+ // Allowable mip filters are NONE, POINT and LINEAR
+ switch (o3d_mag_filter) {
+ case Sampler::NONE:
+ return D3DTEXF_NONE;
+ case Sampler::POINT:
+ return D3DTEXF_POINT;
+ case Sampler::LINEAR:
+ return D3DTEXF_LINEAR;
+ default:
+ return D3DTEXF_LINEAR;
+ }
+}
+
+} // namespace
+
+void SamplerD3D9::SetTextureAndStates(int sampler_unit) {
+ DLOG_ASSERT(d3d_device_);
+
+ // First get the d3d texture and set it.
+ Texture* texture_object = texture();
+ if (!texture_object) {
+ texture_object = renderer_->error_texture();
+ if (!texture_object) {
+ O3D_ERROR(service_locator())
+ << "Missing texture for sampler " << name();
+ texture_object = renderer_->fallback_error_texture();
+ }
+ }
+
+ IDirect3DBaseTexture9* d3d_texture =
+ static_cast<IDirect3DBaseTexture9*>(texture_object->GetTextureHandle());
+
+ HR(d3d_device_->SetTexture(sampler_unit, d3d_texture));
+
+ SetAddressMode(sampler_unit,
+ D3DSAMP_ADDRESSU,
+ address_mode_u(),
+ D3DTADDRESS_WRAP);
+
+ SetAddressMode(sampler_unit,
+ D3DSAMP_ADDRESSV,
+ address_mode_v(),
+ D3DTADDRESS_WRAP);
+
+ if (texture_object->IsA(TextureCUBE::GetApparentClass())) {
+ SetAddressMode(sampler_unit,
+ D3DSAMP_ADDRESSW,
+ address_mode_w(),
+ D3DTADDRESS_WRAP);
+ }
+
+ HR(d3d_device_->SetSamplerState(sampler_unit,
+ D3DSAMP_MAGFILTER,
+ D3DMagFilter(mag_filter())));
+
+ HR(d3d_device_->SetSamplerState(sampler_unit,
+ D3DSAMP_MINFILTER,
+ D3DMinFilter(min_filter())));
+
+ HR(d3d_device_->SetSamplerState(sampler_unit,
+ D3DSAMP_MIPFILTER,
+ D3DMipFilter(mip_filter())));
+
+ Float4 color = border_color();
+ DWORD d3d_color = D3DCOLOR_COLORVALUE(color[0], color[1], color[2], color[3]);
+ HR(d3d_device_->SetSamplerState(sampler_unit,
+ D3DSAMP_BORDERCOLOR,
+ d3d_color));
+
+ HR(d3d_device_->SetSamplerState(sampler_unit,
+ D3DSAMP_MAXANISOTROPY,
+ max_anisotropy()));
+}
+
+void SamplerD3D9::ResetTexture(int sampler_unit) {
+ DLOG_ASSERT(d3d_device_);
+
+ HR(d3d_device_->SetTexture(sampler_unit, NULL));
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/sampler_d3d9.h b/o3d/core/win/d3d9/sampler_d3d9.h
new file mode 100644
index 0000000..f31e1b8
--- /dev/null
+++ b/o3d/core/win/d3d9/sampler_d3d9.h
@@ -0,0 +1,72 @@
+/*
+ * 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 SamplerD3D9 class.
+
+#ifndef O3D_CORE_WIN_D3D9_SAMPLER_D3D9_H_
+#define O3D_CORE_WIN_D3D9_SAMPLER_D3D9_H_
+
+#include <atlbase.h>
+#include <d3d9.h>
+#include "core/cross/sampler.h"
+
+namespace o3d {
+
+class RendererD3D9;
+
+// Sampler2DD3D9 is an implementation of the Sampler object for D3D9.
+class SamplerD3D9 : public Sampler {
+ public:
+ SamplerD3D9(ServiceLocator* service_locator, IDirect3DDevice9* d3d_device);
+ virtual ~SamplerD3D9();
+
+ // Sets the d3d texture and sampler states for the given sampler unit.
+ void SetTextureAndStates(int sampler_unit);
+
+ // Sets the d3d texture to NULL.
+ void ResetTexture(int sampler_unit);
+
+ private:
+ void SetAddressMode(int sampler_unit,
+ D3DSAMPLERSTATETYPE sampler_type,
+ Sampler::AddressMode o3d_mode,
+ D3DTEXTUREADDRESS default_mode);
+
+ RendererD3D9* renderer_;
+ CComPtr<IDirect3DDevice9> d3d_device_;
+
+ DISALLOW_COPY_AND_ASSIGN(SamplerD3D9);
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_WIN_D3D9_SAMPLER_D3D9_H_
diff --git a/o3d/core/win/d3d9/stream_bank_d3d9.cc b/o3d/core/win/d3d9/stream_bank_d3d9.cc
new file mode 100644
index 0000000..2405532
--- /dev/null
+++ b/o3d/core/win/d3d9/stream_bank_d3d9.cc
@@ -0,0 +1,184 @@
+/*
+ * 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 StreamBankD3D9.
+
+#include "core/cross/precompile.h"
+
+#include "core/win/d3d9/stream_bank_d3d9.h"
+
+#include "core/cross/buffer.h"
+#include "core/cross/param_cache.h"
+#include "core/cross/renderer.h"
+#include "core/cross/error.h"
+#include "core/win/d3d9/buffer_d3d9.h"
+#include "core/win/d3d9/d3d_entry_points.h"
+#include "core/win/d3d9/draw_element_d3d9.h"
+#include "core/win/d3d9/effect_d3d9.h"
+#include "core/win/d3d9/param_cache_d3d9.h"
+#include "core/win/d3d9/utils_d3d9.h"
+
+// Someone defines min, conflicting with std::min
+#ifdef min
+#undef min
+#endif
+
+namespace o3d {
+
+StreamBankD3D9::StreamBankD3D9(ServiceLocator* service_locator,
+ IDirect3DDevice9* d3d_device)
+ : StreamBank(service_locator),
+ d3d_device_(d3d_device),
+ vertex_declaration_(NULL) {
+ DCHECK(d3d_device);
+}
+
+StreamBankD3D9::~StreamBankD3D9() {
+ FreeVertexDeclaration();
+}
+
+void StreamBankD3D9::FreeVertexDeclaration() {
+ if (vertex_declaration_) {
+ vertex_declaration_->Release();
+ vertex_declaration_ = NULL;
+ }
+}
+
+// Releases any old vertex declaration so a new one will be created when
+// rendering that encompasses the change in streams.
+void StreamBankD3D9::OnUpdateStreams() {
+ FreeVertexDeclaration();
+}
+
+// Looks for any streams that are required by the vertex shader for which there
+// is no equivalent stream bound to the o3d streambank. If there are such
+// streams it returns failure.
+bool StreamBankD3D9::CheckForMissingVertexStreams(
+ EffectD3D9* effect,
+ Stream::Semantic* missing_semantic,
+ int* missing_semantic_index) {
+ DCHECK(missing_semantic);
+ DCHECK(missing_semantic_index);
+ EffectStreamInfoArray streamInfos;
+ effect->GetStreamInfo(&streamInfos);
+ for (int i = 0; i < streamInfos.size(); ++i) {
+ Stream::Semantic semantic = streamInfos[i].semantic();
+ int semantic_index = streamInfos[i].semantic_index();
+ StreamParamVector::const_iterator iter;
+ for (iter = vertex_stream_params_.begin();
+ iter != vertex_stream_params_.end();
+ ++iter) {
+ const Stream& stream = (*iter)->stream();
+ if (stream.semantic() == semantic &&
+ stream.semantic_index() == semantic_index) {
+ break;
+ }
+ }
+ if (iter == vertex_stream_params_.end()) {
+ // no matching stream was found.
+ *missing_semantic = semantic;
+ *missing_semantic_index = semantic_index;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool StreamBankD3D9::BindStreamsForRendering(unsigned int* max_vertices) {
+ DCHECK(max_vertices);
+ *max_vertices = UINT_MAX;
+ {
+ StreamParamVector::const_iterator stream_iter;
+ unsigned int count = 0;
+ for (stream_iter = vertex_stream_params_.begin();
+ stream_iter != vertex_stream_params_.end();
+ ++stream_iter, count++) {
+ const Stream& vertex_stream = (*stream_iter)->stream();
+ const Field& field = vertex_stream.field();
+ VertexBufferD3D9 *vertex_buffer =
+ down_cast<VertexBufferD3D9*>(field.buffer());
+ if (!vertex_buffer) {
+ O3D_ERROR(service_locator())
+ << "stream has no buffer in StreamBank '" << name() << "'";
+ return false;
+ }
+ // TODO: Support stride of 0. The plan is to make it if num_elements
+ // is 1 then do stride = 0. The problem is this is hard to do in GL.
+ // so for now we're not doing it.
+ HR(d3d_device_->SetStreamSource(count,
+ vertex_buffer->d3d_buffer(),
+ 0,
+ vertex_buffer->stride()));
+ // If the buffer has changed structure then we need to re-create the
+ // vertex declaration.
+ if (vertex_stream.last_field_change_count() !=
+ vertex_buffer->field_change_count()) {
+ FreeVertexDeclaration();
+ vertex_stream.set_last_field_change_count(
+ vertex_buffer->field_change_count());
+ }
+ *max_vertices = std::min(*max_vertices, vertex_stream.GetMaxVertices());
+ }
+ }
+
+ // Create the vertex declaration if it does not exist.
+ if (!vertex_declaration_) {
+ D3DVERTEXELEMENT9 *vertex_elements
+ = new D3DVERTEXELEMENT9[vertex_stream_params_.size()+1];
+
+ StreamParamVector::const_iterator stream_iter;
+ unsigned int count = 0;
+ for (stream_iter = vertex_stream_params_.begin();
+ stream_iter != vertex_stream_params_.end();
+ ++stream_iter, count++) {
+ const Stream& stream = (*stream_iter)->stream();
+ vertex_elements[count].Stream = count;
+ vertex_elements[count].Offset = stream.field().offset();
+ vertex_elements[count].Type = DX9DataType(stream.field());
+ vertex_elements[count].Method = D3DDECLMETHOD_DEFAULT;
+ vertex_elements[count].Usage = DX9UsageType(stream.semantic());
+ vertex_elements[count].UsageIndex = stream.semantic_index();
+ }
+ D3DVERTEXELEMENT9 end_element = D3DDECL_END();
+ vertex_elements[count] = end_element;
+
+ HR(d3d_device_->CreateVertexDeclaration(vertex_elements,
+ &vertex_declaration_));
+ delete [] vertex_elements;
+ }
+
+ HR(d3d_device_->SetVertexDeclaration(vertex_declaration_));
+
+ return true;
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/stream_bank_d3d9.h b/o3d/core/win/d3d9/stream_bank_d3d9.h
new file mode 100644
index 0000000..d1026d0
--- /dev/null
+++ b/o3d/core/win/d3d9/stream_bank_d3d9.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 declaration of the StreamBankD3D9 class.
+
+#ifndef O3D_CORE_WIN_D3D9_STREAM_BANK_D3D9_H_
+#define O3D_CORE_WIN_D3D9_STREAM_BANK_D3D9_H_
+
+#include <d3d9.h>
+#include "core/cross/stream_bank.h"
+#include "core/win/d3d9/effect_d3d9.h"
+
+namespace o3d {
+
+class EffectD3D9;
+
+// StreamBankD3D9 is the DX9 implementation of the StreamBank. It provides the
+// necessary interfaces for setting the geometry streams on the StreamBank.
+class StreamBankD3D9 : public StreamBank {
+ public:
+ explicit StreamBankD3D9(ServiceLocator* service_locator,
+ IDirect3DDevice9* d3d_device);
+ ~StreamBankD3D9();
+
+ // Sets the streams for rendering.
+ // Parameter:
+ // max_vertrices: pointer to variable to receive the maximum vertices
+ // the streams can render.
+ // Returns:
+ // True if all the streams are available.
+ bool BindStreamsForRendering(unsigned int* max_vertices);
+
+ // Checks for all required streams before rendering.
+ bool CheckForMissingVertexStreams(EffectD3D9* effect,
+ Stream::Semantic* missing_semantic,
+ int* missing_semantic_index);
+
+ protected:
+ // Overridden from StreamBank.
+ virtual void OnUpdateStreams();
+
+ private:
+
+ // Frees the vertex declaration if there is one.
+ void FreeVertexDeclaration();
+
+ IDirect3DDevice9* d3d_device_;
+ IDirect3DVertexDeclaration9* vertex_declaration_;
+};
+} // o3d
+
+#endif // O3D_CORE_WIN_D3D9_STREAM_BANK_D3D9_H_
diff --git a/o3d/core/win/d3d9/texture_d3d9.cc b/o3d/core/win/d3d9/texture_d3d9.cc
new file mode 100644
index 0000000..2364d74
--- /dev/null
+++ b/o3d/core/win/d3d9/texture_d3d9.cc
@@ -0,0 +1,747 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "core/cross/precompile.h"
+#include "core/win/d3d9/texture_d3d9.h"
+
+#include "core/cross/error.h"
+#include "core/cross/types.h"
+#include "core/win/d3d9/utils_d3d9.h"
+#include "core/win/d3d9/renderer_d3d9.h"
+#include "core/win/d3d9/render_surface_d3d9.h"
+
+namespace o3d {
+
+namespace {
+
+Texture::RGBASwizzleIndices g_d3d_abgr32f_swizzle_indices = {2, 1, 0, 3};
+
+// Converts an O3D texture format to a D3D texture format.
+D3DFORMAT DX9Format(Texture::Format format) {
+ switch (format) {
+ case Texture::XRGB8: return D3DFMT_X8R8G8B8;
+ case Texture::ARGB8: return D3DFMT_A8R8G8B8;
+ case Texture::ABGR16F: return D3DFMT_A16B16G16R16F;
+ case Texture::R32F: return D3DFMT_R32F;
+ case Texture::ABGR32F: return D3DFMT_A32B32G32R32F;
+ case Texture::DXT1: return D3DFMT_DXT1;
+ case Texture::DXT3: return D3DFMT_DXT3;
+ case Texture::DXT5: return D3DFMT_DXT5;
+ default: return D3DFMT_UNKNOWN;
+ };
+}
+
+// Converts a TextureCUBE::CubeFace value to an equivalent D3D9 value.
+static D3DCUBEMAP_FACES DX9CubeFace(TextureCUBE::CubeFace face) {
+ switch (face) {
+ case TextureCUBE::FACE_POSITIVE_X:
+ return D3DCUBEMAP_FACE_POSITIVE_X;
+ case TextureCUBE::FACE_NEGATIVE_X:
+ return D3DCUBEMAP_FACE_NEGATIVE_X;
+ case TextureCUBE::FACE_POSITIVE_Y:
+ return D3DCUBEMAP_FACE_POSITIVE_Y;
+ case TextureCUBE::FACE_NEGATIVE_Y:
+ return D3DCUBEMAP_FACE_NEGATIVE_Y;
+ case TextureCUBE::FACE_POSITIVE_Z:
+ return D3DCUBEMAP_FACE_POSITIVE_Z;
+ case TextureCUBE::FACE_NEGATIVE_Z:
+ return D3DCUBEMAP_FACE_NEGATIVE_Z;
+ }
+
+ // TODO: Figure out how to get errors out of here to the client.
+ DLOG(ERROR) << "Unknown Cube Face enumeration " << face;
+ return D3DCUBEMAP_FACE_FORCE_DWORD;
+}
+
+// Constructs an Direct3D texture object. Out variable return the status of
+// the constructed texture including if resize to POT is required, and the
+// actual mip dimensions used.
+HRESULT CreateTexture2DD3D9(RendererD3D9* renderer,
+ Bitmap* bitmap,
+ bool enable_render_surfaces,
+ bool* resize_to_pot,
+ unsigned int* mip_width,
+ unsigned int* mip_height,
+ IDirect3DTexture9** d3d_texture) {
+ IDirect3DDevice9 *d3d_device = renderer->d3d_device();
+ *resize_to_pot = !renderer->supports_npot() && !bitmap->IsPOT();
+ *mip_width = bitmap->width();
+ *mip_height = bitmap->height();
+
+ if (*resize_to_pot) {
+ *mip_width = Bitmap::GetPOTSize(*mip_width);
+ *mip_height = Bitmap::GetPOTSize(*mip_height);
+ }
+
+ DWORD usage = (enable_render_surfaces) ? D3DUSAGE_RENDERTARGET : 0;
+ D3DPOOL pool = (enable_render_surfaces) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
+ D3DFORMAT format = DX9Format(bitmap->format());
+
+ HRESULT tex_result = d3d_device->CreateTexture(*mip_width,
+ *mip_height,
+ bitmap->num_mipmaps(),
+ usage,
+ format,
+ pool,
+ d3d_texture,
+ NULL);
+ if (!HR(tex_result)) {
+ DLOG(ERROR) << "2D texture creation failed with the following parameters: "
+ << "(" << *mip_width << " x " << *mip_height << ") x "
+ << bitmap->num_mipmaps() << "; format = " << format;
+ }
+ return tex_result;
+}
+
+// Constructs an Direct3D cube texture object. Out variable return the
+// status of the constructed texture including if resize to POT is required,
+// and the actual mip edge length used.
+HRESULT CreateTextureCUBED3D9(RendererD3D9* renderer,
+ Bitmap* bitmap,
+ bool enable_render_surfaces,
+ bool* resize_to_pot,
+ unsigned int* edge_width,
+ IDirect3DCubeTexture9** d3d_texture) {
+ IDirect3DDevice9 *d3d_device = renderer->d3d_device();
+ *resize_to_pot = !renderer->supports_npot() && !bitmap->IsPOT();
+ *edge_width = bitmap->width();
+ if (*resize_to_pot) {
+ *edge_width = Bitmap::GetPOTSize(*edge_width);
+ }
+
+ DWORD usage = (enable_render_surfaces) ? D3DUSAGE_RENDERTARGET : 0;
+ D3DPOOL pool = (enable_render_surfaces) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
+ D3DFORMAT format = DX9Format(bitmap->format());
+
+ HRESULT tex_result = d3d_device->CreateCubeTexture(*edge_width,
+ bitmap->num_mipmaps(),
+ usage,
+ format,
+ pool,
+ d3d_texture,
+ NULL);
+ if (!HR(tex_result)) {
+ DLOG(ERROR) << "CUBE texture creation failed with the following "
+ << "parameters: "
+ << "(" << edge_width << " x " << edge_width << ") x "
+ << bitmap->num_mipmaps() << "; format = " << format;
+ }
+
+ return tex_result;
+}
+
+// Class providing a construction callback routine for extracting a
+// RenderSurface from a cube-face and mip-level of a cube-texture.
+// Note: This class maintains a reference-counted pointer to the texture
+// object, so that the lifetime of the Texture is guaranteed to be at least
+// as long as that of the class.
+class CubeFaceSurfaceConstructor : public SurfaceConstructor {
+ public:
+ CubeFaceSurfaceConstructor(TextureCUBED3D9 *texture,
+ TextureCUBE::CubeFace face,
+ int mip_level)
+ : cube_texture_(texture),
+ face_(face),
+ mip_level_(mip_level) {
+ }
+
+ virtual HRESULT ConstructSurface(IDirect3DSurface9** surface) {
+ IDirect3DCubeTexture9* d3d_cube_texture =
+ static_cast<IDirect3DCubeTexture9*>(cube_texture_->GetTextureHandle());
+ return d3d_cube_texture->GetCubeMapSurface(DX9CubeFace(face_),
+ mip_level_,
+ surface);
+ }
+
+ private:
+ TextureCUBED3D9::Ref cube_texture_;
+ TextureCUBE::CubeFace face_;
+ int mip_level_;
+ DISALLOW_COPY_AND_ASSIGN(CubeFaceSurfaceConstructor);
+};
+
+// Class providing a construction callback routine for extracting a
+// RenderSurface from a mip-level of a texture.
+// Note: This class maintains a reference-counted pointer to the texture
+// object, so that the lifetime of the Texture is guaranteed to be at least
+// as long as that of the class.
+class TextureSurfaceConstructor : public SurfaceConstructor {
+ public:
+ TextureSurfaceConstructor(Texture2DD3D9* texture, int mip_level)
+ : texture_(texture),
+ mip_level_(mip_level) {
+ }
+
+ virtual HRESULT ConstructSurface(IDirect3DSurface9** surface) {
+ IDirect3DTexture9* d3d_texture =
+ static_cast<IDirect3DTexture9*>(texture_->GetTextureHandle());
+ return d3d_texture->GetSurfaceLevel(mip_level_, surface);
+ }
+
+ private:
+ Texture2DD3D9::Ref texture_;
+ int mip_level_;
+ DISALLOW_COPY_AND_ASSIGN(TextureSurfaceConstructor);
+};
+
+} // unnamed namespace
+
+// Constructs a 2D texture object from the given (existing) D3D 2D texture.
+Texture2DD3D9::Texture2DD3D9(ServiceLocator* service_locator,
+ IDirect3DTexture9* tex,
+ const Bitmap &bitmap,
+ bool resize_to_pot,
+ bool enable_render_surfaces)
+ : Texture2D(service_locator,
+ bitmap.width(),
+ bitmap.height(),
+ bitmap.format(),
+ bitmap.num_mipmaps(),
+ bitmap.CheckAlphaIsOne(),
+ resize_to_pot,
+ enable_render_surfaces),
+ d3d_texture_(tex) {
+ DCHECK(tex);
+}
+
+// Attempts to create a IDirect3DTexture9 with the given specs. If the creation
+// of the texture succeeds then it creates a Texture2DD3D9 object around it and
+// returns it. This is the safe way to create a Texture2DD3D9 object that
+// contains a valid D3D9 texture.
+Texture2DD3D9* Texture2DD3D9::Create(ServiceLocator* service_locator,
+ Bitmap* bitmap,
+ RendererD3D9* renderer,
+ bool enable_render_surfaces) {
+ DCHECK_NE(bitmap->format(), Texture::UNKNOWN_FORMAT);
+ DCHECK(!bitmap->is_cubemap());
+ CComPtr<IDirect3DTexture9> d3d_texture;
+ bool resize_to_pot;
+ unsigned int mip_width, mip_height;
+ if (!HR(CreateTexture2DD3D9(renderer,
+ bitmap,
+ enable_render_surfaces,
+ &resize_to_pot,
+ &mip_width,
+ &mip_height,
+ &d3d_texture))) {
+ DLOG(ERROR) << "Failed to create Texture2D (D3D9) : ";
+ return NULL;
+ }
+
+ Texture2DD3D9 *texture = new Texture2DD3D9(service_locator,
+ d3d_texture,
+ *bitmap,
+ resize_to_pot,
+ enable_render_surfaces);
+
+ texture->backing_bitmap_.SetFrom(bitmap);
+ if (texture->backing_bitmap_.image_data()) {
+ for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) {
+ if (!texture->UpdateBackedMipLevel(i)) {
+ DLOG(ERROR) << "Failed to upload bitmap to texture.";
+ delete texture;
+ return NULL;
+ }
+ mip_width = std::max(1U, mip_width >> 1);
+ mip_height = std::max(1U, mip_height >> 1);
+ }
+ if (!resize_to_pot)
+ texture->backing_bitmap_.FreeData();
+ } else {
+ if (resize_to_pot) {
+ texture->backing_bitmap_.AllocateData();
+ memset(texture->backing_bitmap_.image_data(), 0,
+ texture->backing_bitmap_.GetTotalSize());
+ }
+ }
+
+ return texture;
+}
+
+// Destructor releases the D3D9 texture resource.
+Texture2DD3D9::~Texture2DD3D9() {
+ d3d_texture_ = NULL;
+}
+
+bool Texture2DD3D9::UpdateBackedMipLevel(unsigned int level) {
+ DCHECK_LT(level, levels());
+ DCHECK(backing_bitmap_.image_data());
+ DCHECK_EQ(backing_bitmap_.width(), width());
+ DCHECK_EQ(backing_bitmap_.height(), height());
+ DCHECK_EQ(backing_bitmap_.format(), format());
+ DCHECK_EQ(backing_bitmap_.num_mipmaps(), levels());
+
+ unsigned int mip_width = std::max(1, width() >> level);
+ unsigned int mip_height = std::max(1, height() >> level);
+ unsigned int rect_width = mip_width;
+ unsigned int rect_height = mip_height;
+ if (resize_to_pot_) {
+ rect_width = std::max(1U, Bitmap::GetPOTSize(width()) >> level);
+ rect_height = std::max(1U, Bitmap::GetPOTSize(height()) >> level);
+ }
+
+ RECT rect = {0, 0, rect_width, rect_height};
+ D3DLOCKED_RECT out_rect;
+ out_rect.pBits = 0;
+
+ if (!HR(d3d_texture_->LockRect(level, &out_rect, &rect, 0))) {
+ DLOG(ERROR) << "Failed to lock texture level " << level << ".";
+ return false;
+ }
+
+ DCHECK(out_rect.pBits);
+ // TODO: check that the returned pitch is what we expect.
+
+ const unsigned char *mip_data =
+ backing_bitmap_.GetMipData(level, TextureCUBE::FACE_POSITIVE_X);
+ if (resize_to_pot_) {
+ Bitmap::Scale(mip_width, mip_height, format(), mip_data,
+ rect_width, rect_height,
+ static_cast<unsigned char *>(out_rect.pBits));
+ } else {
+ unsigned int mip_size =
+ Bitmap::GetBufferSize(mip_width, mip_height, format());
+ memcpy(out_rect.pBits, mip_data, mip_size);
+ }
+
+ if (!HR(d3d_texture_->UnlockRect(level))) {
+ O3D_ERROR(service_locator())
+ << "Failed to unlock texture level " << level << ".";
+ return false;
+ }
+ return true;
+}
+
+RenderSurface::Ref Texture2DD3D9::GetRenderSurface(int mip_level, Pack* pack) {
+ DCHECK(pack);
+ if (!render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to get RenderSurface from non-render-surface-enabled"
+ << " Texture: " << name();
+ return RenderSurface::Ref(NULL);
+ }
+
+ if (mip_level >= levels() || mip_level < 0) {
+ O3D_ERROR(service_locator())
+ << "Attempting to access non-existent mip_level " << mip_level
+ << " in render-target texture \"" << name() << "\".";
+ return RenderSurface::Ref(NULL);
+ }
+
+ RenderSurface::Ref render_surface(
+ new RenderSurfaceD3D9(
+ service_locator(),
+ width() >> mip_level,
+ height() >> mip_level,
+ this,
+ new TextureSurfaceConstructor(this, mip_level)));
+
+ if (!render_surface.IsNull()) {
+ RegisterSurface(render_surface.Get(), pack);
+ }
+
+ return render_surface;
+}
+
+// Locks the given mipmap level of this texture for loading from main memory,
+// and returns a pointer to the buffer.
+bool Texture2DD3D9::Lock(int level, void** texture_data) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to lock inexistent level " << level << " on Texture \""
+ << name() << "\"";
+ return false;
+ }
+ if (IsLocked(level)) {
+ O3D_ERROR(service_locator())
+ << "Level " << level << " of texture \"" << name()
+ << "\" is already locked.";
+ return false;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to lock a render-target texture: " << name();
+ return false;
+ }
+ if (resize_to_pot_) {
+ DCHECK(backing_bitmap_.image_data());
+ *texture_data = backing_bitmap_.GetMipData(level,
+ TextureCUBE::FACE_POSITIVE_X);
+ locked_levels_ |= 1 << level;
+ return true;
+ } else {
+ RECT rect = {0, 0, width(), height()};
+ D3DLOCKED_RECT out_rect = {0};
+
+ if (HR(d3d_texture_->LockRect(level, &out_rect, &rect, 0))) {
+ *texture_data = out_rect.pBits;
+ locked_levels_ |= 1 << level;
+ return true;
+ } else {
+ O3D_ERROR(service_locator()) << "Failed to Lock Texture2D (D3D9)";
+ *texture_data = NULL;
+ return false;
+ }
+ }
+}
+
+// Unlocks the given mipmap level of this texture.
+bool Texture2DD3D9::Unlock(int level) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to unlock inexistent level " << level << " on Texture \""
+ << name() << "\"";
+ return false;
+ }
+ if (!IsLocked(level)) {
+ O3D_ERROR(service_locator())
+ << "Level " << level << " of texture \"" << name()
+ << "\" is not locked.";
+ return false;
+ }
+ bool result = false;
+ if (resize_to_pot_) {
+ result = UpdateBackedMipLevel(level);
+ } else {
+ result = HR(d3d_texture_->UnlockRect(level));
+ }
+ if (result) {
+ locked_levels_ &= ~(1 << level);
+ } else {
+ O3D_ERROR(service_locator()) << "Failed to Unlock Texture2D (D3D9)";
+ }
+ return result;
+}
+
+bool Texture2DD3D9::OnLostDevice() {
+ // Textures created with RenderSurface support are placed in the default
+ // pool, so release them here.
+ if (render_surfaces_enabled()) {
+ d3d_texture_ = NULL;
+ }
+ return true;
+}
+
+bool Texture2DD3D9::OnResetDevice() {
+ if (render_surfaces_enabled()) {
+ DCHECK(d3d_texture_ == NULL);
+ Renderer* renderer = service_locator()->GetService<Renderer>();
+ RendererD3D9 *renderer_d3d9 = down_cast<RendererD3D9*>(renderer);
+ bool resize_to_pot;
+ unsigned int mip_width, mip_height;
+ return HR(CreateTexture2DD3D9(renderer_d3d9,
+ &backing_bitmap_,
+ render_surfaces_enabled(),
+ &resize_to_pot,
+ &mip_width,
+ &mip_height,
+ &d3d_texture_));
+ }
+ return true;
+}
+
+const Texture::RGBASwizzleIndices& Texture2DD3D9::GetABGR32FSwizzleIndices() {
+ return g_d3d_abgr32f_swizzle_indices;
+}
+
+// Constructs a cube texture object from the given (existing) D3D Cube texture.
+TextureCUBED3D9::TextureCUBED3D9(ServiceLocator* service_locator,
+ IDirect3DCubeTexture9* tex,
+ const Bitmap& bitmap,
+ bool resize_to_pot,
+ bool enable_render_surfaces)
+ : TextureCUBE(service_locator,
+ bitmap.width(),
+ bitmap.format(),
+ bitmap.num_mipmaps(),
+ bitmap.CheckAlphaIsOne(),
+ resize_to_pot,
+ enable_render_surfaces),
+ d3d_cube_texture_(tex) {
+}
+
+// Attempts to create a D3D9 CubeTexture with the given specs. If creation
+// fails the method returns NULL. Otherwise, it wraps around the newly created
+// texture a TextureCUBED3D9 object and returns a pointer to it.
+TextureCUBED3D9* TextureCUBED3D9::Create(ServiceLocator* service_locator,
+ Bitmap *bitmap,
+ RendererD3D9 *renderer,
+ bool enable_render_surfaces) {
+ DCHECK_NE(bitmap->format(), Texture::UNKNOWN_FORMAT);
+ DCHECK(bitmap->is_cubemap());
+ DCHECK_EQ(bitmap->width(), bitmap->height());
+
+ CComPtr<IDirect3DCubeTexture9> d3d_texture;
+ bool resize_to_pot;
+ unsigned int edge;
+ if (!HR(CreateTextureCUBED3D9(renderer,
+ bitmap,
+ enable_render_surfaces,
+ &resize_to_pot,
+ &edge,
+ &d3d_texture))) {
+ DLOG(ERROR) << "Failed to create TextureCUBE (D3D9)";
+ return NULL;
+ }
+
+ TextureCUBED3D9 *texture = new TextureCUBED3D9(service_locator,
+ d3d_texture,
+ *bitmap,
+ resize_to_pot,
+ enable_render_surfaces);
+
+ texture->backing_bitmap_.SetFrom(bitmap);
+ if (texture->backing_bitmap_.image_data()) {
+ for (int face = 0; face < 6; ++face) {
+ unsigned int mip_edge = edge;
+ for (unsigned int i = 0; i < bitmap->num_mipmaps(); ++i) {
+ if (!texture->UpdateBackedMipLevel(i, static_cast<CubeFace>(face))) {
+ DLOG(ERROR) << "Failed to upload bitmap to texture.";
+ delete texture;
+ return NULL;
+ }
+ mip_edge = std::max(1U, mip_edge >> 1);
+ }
+ }
+ if (!resize_to_pot)
+ texture->backing_bitmap_.FreeData();
+ } else {
+ if (resize_to_pot) {
+ texture->backing_bitmap_.AllocateData();
+ memset(texture->backing_bitmap_.image_data(), 0,
+ texture->backing_bitmap_.GetTotalSize());
+ }
+ }
+
+ return texture;
+}
+
+
+
+// Destructor releases the D3D9 texture resource.
+TextureCUBED3D9::~TextureCUBED3D9() {
+ for (unsigned int i = 0; i < 6; ++i) {
+ if (locked_levels_[i] != 0) {
+ O3D_ERROR(service_locator())
+ << "TextureCUBE \"" << name() << "\" was never unlocked before "
+ << "being destroyed.";
+ break; // No need to report it more than once.
+ }
+ }
+ d3d_cube_texture_ = NULL;
+}
+
+bool TextureCUBED3D9::UpdateBackedMipLevel(unsigned int level,
+ TextureCUBE::CubeFace face) {
+ DCHECK_LT(level, levels());
+ DCHECK(backing_bitmap_.image_data());
+ DCHECK(backing_bitmap_.is_cubemap());
+ DCHECK_EQ(backing_bitmap_.width(), edge_length());
+ DCHECK_EQ(backing_bitmap_.height(), edge_length());
+ DCHECK_EQ(backing_bitmap_.format(), format());
+ DCHECK_EQ(backing_bitmap_.num_mipmaps(), levels());
+
+ unsigned int mip_edge = std::max(1, edge_length() >> level);
+ unsigned int rect_edge = mip_edge;
+ if (resize_to_pot_) {
+ rect_edge = std::max(1U, Bitmap::GetPOTSize(edge_length()) >> level);
+ }
+
+ RECT rect = {0, 0, rect_edge, rect_edge};
+ D3DLOCKED_RECT out_rect;
+ out_rect.pBits = 0;
+
+ if (!HR(d3d_cube_texture_->LockRect(DX9CubeFace(face), level, &out_rect,
+ &rect, 0))) {
+ O3D_ERROR(service_locator())
+ << "Failed to lock texture level " << level << " face " << face << ".";
+ return false;
+ }
+
+ DCHECK(out_rect.pBits);
+ // TODO: check that the returned pitch is what we expect.
+
+ const unsigned char *mip_data = backing_bitmap_.GetMipData(level, face);
+ if (resize_to_pot_) {
+ Bitmap::Scale(mip_edge, mip_edge, format(), mip_data,
+ rect_edge, rect_edge,
+ static_cast<unsigned char *>(out_rect.pBits));
+ } else {
+ unsigned int mip_size =
+ Bitmap::GetBufferSize(mip_edge, mip_edge, format());
+ memcpy(out_rect.pBits, mip_data, mip_size);
+ }
+
+ if (!HR(d3d_cube_texture_->UnlockRect(DX9CubeFace(face), level))) {
+ O3D_ERROR(service_locator())
+ << "Failed to unlock texture level " << level << " face " << face
+ << ".";
+ return false;
+ }
+ return true;
+}
+
+RenderSurface::Ref TextureCUBED3D9::GetRenderSurface(CubeFace face,
+ int mip_level,
+ Pack* pack) {
+ if (!render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to get RenderSurface from non-render-surface-enabled"
+ << " Texture: " << name();
+ return RenderSurface::Ref(NULL);
+ }
+
+ if (mip_level >= levels() || mip_level < 0) {
+ O3D_ERROR(service_locator())
+ << "Attempting to access non-existent mip_level " << mip_level
+ << " in render-target texture \"" << name() << "\".";
+ return RenderSurface::Ref(NULL);
+ }
+
+ int edge = edge_length() >> mip_level;
+ RenderSurface::Ref render_surface(
+ new RenderSurfaceD3D9(
+ service_locator(),
+ edge,
+ edge,
+ this,
+ new CubeFaceSurfaceConstructor(this, face, mip_level)));
+
+ if (!render_surface.IsNull()) {
+ RegisterSurface(render_surface.Get(), pack);
+ }
+
+ return render_surface;
+}
+
+// Locks the given face and mipmap level of this texture for loading from
+// main memory, and returns a pointer to the buffer.
+bool TextureCUBED3D9::Lock(CubeFace face, int level, void** texture_data) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to lock inexistent level " << level << " on Texture \""
+ << name();
+ return false;
+ }
+ if (IsLocked(level, face)) {
+ O3D_ERROR(service_locator())
+ << "Level " << level << " Face " << face << " of texture \"" << name()
+ << "\" is already locked.";
+ return false;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to lock a render-target texture: " << name();
+ return false;
+ }
+ if (resize_to_pot_) {
+ DCHECK(backing_bitmap_.image_data());
+ *texture_data = backing_bitmap_.GetMipData(level, face);
+ locked_levels_[face] |= 1 << level;
+ return true;
+ } else {
+ RECT rect = {0, 0, edge_length(), edge_length()};
+ D3DLOCKED_RECT out_rect = {0};
+
+ if (HR(d3d_cube_texture_->LockRect(DX9CubeFace(face), level,
+ &out_rect, &rect, 0))) {
+ *texture_data = out_rect.pBits;
+ locked_levels_[face] |= 1 << level;
+ return true;
+ } else {
+ O3D_ERROR(service_locator()) << "Failed to Lock Texture2D (D3D9)";
+ *texture_data = NULL;
+ return false;
+ }
+ }
+}
+
+// Unlocks the given face and mipmap level of this texture.
+bool TextureCUBED3D9::Unlock(CubeFace face, int level) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to unlock inexistent level " << level << " on Texture \""
+ << name();
+ return false;
+ }
+ if (!IsLocked(level, face)) {
+ O3D_ERROR(service_locator())
+ << "Level " << level << " of texture \"" << name()
+ << "\" is not locked.";
+ return false;
+ }
+ bool result = false;
+ if (resize_to_pot_) {
+ result = UpdateBackedMipLevel(level, face);
+ } else {
+ result = HR(d3d_cube_texture_->UnlockRect(DX9CubeFace(face),
+ level));
+ }
+ if (result) {
+ locked_levels_[face] &= ~(1 << level);
+ } else {
+ O3D_ERROR(service_locator()) << "Failed to Unlock Texture2D (D3D9)";
+ }
+ return result;
+}
+
+bool TextureCUBED3D9::OnLostDevice() {
+ // Textures created with RenderSurface support are placed in the default
+ // pool, so release them here.
+ if (render_surfaces_enabled()) {
+ d3d_cube_texture_ = NULL;
+ }
+ return true;
+}
+
+bool TextureCUBED3D9::OnResetDevice() {
+ if (render_surfaces_enabled()) {
+ DCHECK(d3d_cube_texture_ == NULL);
+ Renderer* renderer = service_locator()->GetService<Renderer>();
+ RendererD3D9 *renderer_d3d9 = down_cast<RendererD3D9*>(renderer);
+ bool resize_to_pot;
+ unsigned int mip_edge;
+ return HR(CreateTextureCUBED3D9(renderer_d3d9,
+ &backing_bitmap_,
+ render_surfaces_enabled(),
+ &resize_to_pot,
+ &mip_edge,
+ &d3d_cube_texture_));
+ }
+ return true;
+}
+
+const Texture::RGBASwizzleIndices& TextureCUBED3D9::GetABGR32FSwizzleIndices() {
+ return g_d3d_abgr32f_swizzle_indices;
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/texture_d3d9.h b/o3d/core/win/d3d9/texture_d3d9.h
new file mode 100644
index 0000000..fe954a2
--- /dev/null
+++ b/o3d/core/win/d3d9/texture_d3d9.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the declarations for Texture2DD3D9 and TextureCUBED3D9.
+
+#ifndef O3D_CORE_WIN_D3D9_TEXTURE_D3D9_H__
+#define O3D_CORE_WIN_D3D9_TEXTURE_D3D9_H__
+
+#include <atlbase.h>
+#include <vector>
+
+#include "core/cross/bitmap.h"
+#include "core/cross/texture.h"
+#include "core/cross/types.h"
+
+interface IDirect3DTexture9;
+interface IDirect3DCubeTexture9;
+interface IDirect3DDevice9;
+
+namespace o3d {
+
+class RendererD3D9;
+
+// Texture2DD3D9 implements the Texture2D interface with DX9.
+class Texture2DD3D9 : public Texture2D {
+ public:
+ typedef SmartPointer<Texture2DD3D9> Ref;
+
+ // Creates a new Texture2DD3D9 with the given specs. If the D3D9 texture
+ // creation fails then it returns NULL otherwise it returns a pointer to the
+ // newly created Texture object.
+ static Texture2DD3D9* Create(ServiceLocator* service_locator,
+ Bitmap* bitmap,
+ RendererD3D9* renderer,
+ bool enable_render_surfaces);
+
+ virtual ~Texture2DD3D9();
+
+ // Locks the image buffer of a given mipmap level for loading from
+ // main memory. A pointer to the current contents of the texture is returned
+ // in texture_data.
+ virtual bool Lock(int level, void** texture_data);
+
+ // Notifies DX9 that the texture data has been updated.
+ virtual bool Unlock(int level);
+
+ // Returns the implementation-specific texture handle for this texture.
+ virtual void* GetTextureHandle() const { return d3d_texture_; }
+
+ // Returns a RenderSurface object associated with a mip_level of a texture.
+ // Parameters:
+ // mip_level: [in] The mip-level of the surface to be returned.
+ // pack: [in] The pack in which the surface will reside.
+ // Returns:
+ // Reference to the RenderSurface object.
+ virtual RenderSurface::Ref GetRenderSurface(int mip_level, Pack* pack);
+
+ // Handler for lost device. This invalidates the texture for a device reset.
+ bool OnLostDevice();
+
+ // Handler for reset device. This restores the texture after a device reset.
+ bool OnResetDevice();
+
+ // Gets a RGBASwizzleIndices that contains a mapping from
+ // RGBA to the internal format used by the rendering API.
+ virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+
+ private:
+ // Initializes the Texture2DD3D9 from a DX9 texture.
+ Texture2DD3D9(ServiceLocator* service_locator,
+ IDirect3DTexture9* tex,
+ const Bitmap& bitmap,
+ bool resize_to_pot,
+ bool enable_render_surfaces);
+
+ // Updates a mip level, sending it from the backing bitmap to Direct3D,
+ // rescaling it if resize_to_pot_ is set.
+ bool UpdateBackedMipLevel(unsigned int level);
+
+ // A pointer to the Direct3D 2D texture object containing this texture.
+ CComPtr<IDirect3DTexture9> d3d_texture_;
+
+ // A bitmap used to back the NPOT textures on POT-only hardware.
+ Bitmap backing_bitmap_;
+
+ DISALLOW_COPY_AND_ASSIGN(Texture2DD3D9);
+};
+
+// TextureCUBED3D9 implements the TextureCUBE interface with DX9.
+class TextureCUBED3D9 : public TextureCUBE {
+ public:
+ typedef SmartPointer<TextureCUBED3D9> Ref;
+
+ // Creates a new TextureCUBED3D9 with the given specs. If the D3D9 texture
+ // creation fails then it returns NULL otherwise it returns a pointer to the
+ // newly created Texture object.
+ static TextureCUBED3D9* Create(ServiceLocator* service_locator,
+ Bitmap* bitmap,
+ RendererD3D9* renderer,
+ bool enable_render_surfaces);
+
+ virtual ~TextureCUBED3D9();
+
+ // Locks the image buffer of a given face and mipmap level for loading from
+ // main memory.
+ bool Lock(CubeFace face, int level, void** texture_data);
+
+ // Notifies DX9 that the image buffer of a given face and mipmap level has
+ // been updated.
+ bool Unlock(CubeFace face, int level);
+
+ // Returns the implementation-specific texture handle for this texture.
+ virtual void* GetTextureHandle() const { return d3d_cube_texture_; }
+
+ // Returns a RenderSurface object associated with a given cube face and
+ // mip_level of a texture.
+ // Parameters:
+ // face: [in] The cube face from which to extract the surface.
+ // mip_level: [in] The mip-level of the surface to be returned.
+ // pack: [in] The pack in which the surface will reside.
+ // Returns:
+ // Reference to the RenderSurface object.
+ virtual RenderSurface::Ref GetRenderSurface(CubeFace face,
+ int level,
+ Pack* pack);
+
+ // Handler for lost device. This invalidates the texture for a device reset.
+ bool OnLostDevice();
+
+ // Handler for reset device. This restores the texture after a device reset.
+ bool OnResetDevice();
+
+ // Gets a RGBASwizzleIndices that contains a mapping from
+ // RGBA to the internal format used by the rendering API.
+ virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+
+ private:
+ TextureCUBED3D9(ServiceLocator* service_locator,
+ IDirect3DCubeTexture9* tex,
+ const Bitmap& bitmap,
+ bool resize_to_pot,
+ bool enable_render_surfaces);
+
+ // Updates a mip level, sending it from the backing bitmap to Direct3D,
+ // rescaling it if resize_to_pot_ is set.
+ bool UpdateBackedMipLevel(unsigned int level, CubeFace face);
+
+ // A pointer to the Direct3D cube texture object containing this texture.
+ CComPtr<IDirect3DCubeTexture9> d3d_cube_texture_;
+
+ // A bitmap used to back the NPOT textures on POT-only hardware.
+ Bitmap backing_bitmap_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextureCUBED3D9);
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_WIN_D3D9_TEXTURE_D3D9_H__
diff --git a/o3d/core/win/d3d9/utils_d3d9.cc b/o3d/core/win/d3d9/utils_d3d9.cc
new file mode 100644
index 0000000..0d0d8e4
--- /dev/null
+++ b/o3d/core/win/d3d9/utils_d3d9.cc
@@ -0,0 +1,119 @@
+/*
+ * 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 of handy methods used by the
+// O3D DirectX code.
+
+#include "core/cross/precompile.h"
+#include "core/win/d3d9/utils_d3d9.h"
+
+#include "core/cross/field.h"
+
+namespace o3d {
+
+// Converts from a Field datatype to a suitable dx9 type
+D3DDECLTYPE DX9DataType(const Field& field) {
+ if (field.IsA(FloatField::GetApparentClass())) {
+ switch (field.num_components()) {
+ case 1:
+ return D3DDECLTYPE_FLOAT1;
+ case 2:
+ return D3DDECLTYPE_FLOAT2;
+ case 3:
+ return D3DDECLTYPE_FLOAT3;
+ case 4:
+ return D3DDECLTYPE_FLOAT4;
+ }
+ } else if (field.IsA(UByteNField::GetApparentClass())) {
+ switch (field.num_components()) {
+ case 4:
+ return D3DDECLTYPE_D3DCOLOR;
+ }
+ }
+ DLOG(ERROR) << "Unknown Stream DataType";
+ return D3DDECLTYPE_UNUSED;
+}
+
+// Converts from Stream::Semantic to a suitable dx9 usage type.
+D3DDECLUSAGE DX9UsageType(Stream::Semantic semantic) {
+ switch (semantic) {
+ case Stream::POSITION:
+ return D3DDECLUSAGE_POSITION;
+ break;
+ case Stream::NORMAL:
+ return D3DDECLUSAGE_NORMAL;
+ break;
+ case Stream::TANGENT:
+ return D3DDECLUSAGE_TANGENT;
+ break;
+ case Stream::BINORMAL:
+ return D3DDECLUSAGE_BINORMAL;
+ break;
+ case Stream::COLOR:
+ return D3DDECLUSAGE_COLOR;
+ break;
+ case Stream::TEXCOORD:
+ return D3DDECLUSAGE_TEXCOORD;
+ break;
+ }
+ DLOG(ERROR) << "Unknown DX9 Usage Type";
+ return D3DDECLUSAGE_SAMPLE;
+}
+
+// Convertes a dx9 semantic to a matching Stream semantic.
+Stream::Semantic SemanticFromDX9UsageType(D3DDECLUSAGE usage) {
+ switch (usage) {
+ case D3DDECLUSAGE_POSITION:
+ return Stream::POSITION;
+ break;
+ case D3DDECLUSAGE_NORMAL:
+ return Stream::NORMAL;
+ break;
+ case D3DDECLUSAGE_TANGENT:
+ return Stream::TANGENT;
+ break;
+ case D3DDECLUSAGE_BINORMAL:
+ return Stream::BINORMAL;
+ break;
+ case D3DDECLUSAGE_COLOR:
+ return Stream::COLOR;
+ break;
+ case D3DDECLUSAGE_TEXCOORD:
+ return Stream::TEXCOORD;
+ break;
+ default:
+ DLOG(ERROR) << "Unknown DX9 semantic type";
+ return Stream::UNKNOWN_SEMANTIC;
+ }
+}
+
+} // namespace o3d
diff --git a/o3d/core/win/d3d9/utils_d3d9.h b/o3d/core/win/d3d9/utils_d3d9.h
new file mode 100644
index 0000000..0bca546
--- /dev/null
+++ b/o3d/core/win/d3d9/utils_d3d9.h
@@ -0,0 +1,72 @@
+/*
+ * 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 of handy methods and macros used by the
+// O3D DirectX code.
+
+#ifndef O3D_CORE_WIN_D3D9_UTILS_D3D9_H_
+#define O3D_CORE_WIN_D3D9_UTILS_D3D9_H_
+
+#include <d3d9.h>
+#include <dxerr9.h>
+#include "base/logging.h"
+#include "core/cross/stream.h"
+
+#define HR(x) ::o3d::VerifyHResult((x), __FILE__, __LINE__, #x)
+
+namespace o3d {
+
+class Field;
+
+inline bool VerifyHResult(HRESULT hr, const char* file, int line,
+ const char* call) {
+ if (FAILED(hr)) {
+ DLOG(ERROR) << "DX Error in file " << file
+ << " line " << line << L": "
+ << DXGetErrorString9(hr) << L": " << call;
+ return false;
+ }
+ return true;
+}
+
+union Float2DWord {
+ float my_float;
+ DWORD my_dword;
+};
+
+D3DDECLTYPE DX9DataType(const Field& stream);
+D3DDECLUSAGE DX9UsageType(Stream::Semantic semantic);
+Stream::Semantic SemanticFromDX9UsageType(D3DDECLUSAGE usage);
+
+} // namespace o3d
+
+#endif // O3D_CORE_WIN_D3D9_UTILS_D3D9_H_
diff --git a/o3d/core/win/display_window_win.h b/o3d/core/win/display_window_win.h
new file mode 100644
index 0000000..9ba5670
--- /dev/null
+++ b/o3d/core/win/display_window_win.h
@@ -0,0 +1,58 @@
+/*
+ * 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_CORE_WIN_DISPLAY_WINDOW_WIN_H_
+#define O3D_CORE_WIN_DISPLAY_WINDOW_WIN_H_
+
+#include "core/cross/display_window.h"
+
+namespace o3d {
+
+/**
+ * The DisplayWindowWindows class is a platform-specific
+ * representation of a platform's display window. This implements the
+ * Windows subclass of the DisplayWindow.
+ */
+
+class DisplayWindowWindows : public DisplayWindow {
+ public:
+ DisplayWindowWindows() : hwnd_(NULL) {}
+ virtual ~DisplayWindowWindows() {}
+ HWND hwnd() const { return hwnd_; }
+ void set_hwnd(const HWND& hwnd) { hwnd_ = hwnd; }
+ private:
+ HWND hwnd_;
+ DISALLOW_COPY_AND_ASSIGN(DisplayWindowWindows);
+};
+} // end namespace o3d
+
+#endif // O3D_CORE_WIN_DISPLAY_WINDOW_WIN_H_
diff --git a/o3d/core/win/performance_timer.cc b/o3d/core/win/performance_timer.cc
new file mode 100644
index 0000000..8be923d
--- /dev/null
+++ b/o3d/core/win/performance_timer.cc
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+
+// The PerformanceTimer class measures elapsed time between Start and
+// Stop (using the highest resolution timer available on the
+// platform).
+
+#include "core/cross/precompile.h"
+
+#include "core/cross/performance_timer.h"
+
+#include "base/logging.h"
+
+namespace o3d {
+
+PerformanceTimer::PerformanceTimer(const char *name)
+ : name_(name),
+ start_time_(0),
+ accum_time_(0) {
+ start_time_ = 0;
+ accum_time_ = 0;
+}
+
+void PerformanceTimer::Start() {
+ LARGE_INTEGER start;
+ QueryPerformanceCounter(&start);
+ start_time_ = start.QuadPart;
+}
+
+void PerformanceTimer::Stop() {
+ LARGE_INTEGER end;
+ QueryPerformanceCounter(&end);
+ accum_time_ += end.QuadPart - start_time_;
+}
+
+double PerformanceTimer::GetElapsedTime() {
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+ return static_cast<double>(accum_time_) / freq.QuadPart;
+}
+
+void PerformanceTimer::Print() {
+ LOG(INFO) << name_.c_str() << " " << GetElapsedTime() << " seconds";
+}
+
+void PerformanceTimer::StopAndPrint() {
+ Stop();
+ Print();
+}
+}