From 532f679f8acd28a7d2c47ca22d2b545fc4adda6b Mon Sep 17 00:00:00 2001
From: Sam Hocevar <sam@hocevar.net>
Date: Sun, 23 Jun 2013 10:18:31 +0000
Subject: [PATCH] gpu: get rid of the global D3D device pointer and move D3D
 initialisation code from the Video to the Renderer class.

---
 src/gpu/framebuffer.cpp       |  26 ++++-----
 src/gpu/indexbuffer.cpp       |  20 ++++---
 src/gpu/renderer.cpp          |  58 +++++++++++++++++--
 src/gpu/shader.cpp            |  70 +++++++++++------------
 src/gpu/texture.cpp           |  22 ++++----
 src/gpu/vertexbuffer.cpp      | 102 +++++++++++++++++++---------------
 src/lol/gpu/renderer.h        |   2 +
 src/lol/gpu/vertexbuffer.h    |   3 +-
 src/platform/sdl/sdlapp.cpp   |  16 +++---
 src/platform/xbox/xboxapp.cpp |   7 +--
 src/video.cpp                 |  73 ------------------------
 11 files changed, 198 insertions(+), 201 deletions(-)

diff --git a/src/gpu/framebuffer.cpp b/src/gpu/framebuffer.cpp
index dd22defe..a47d897a 100644
--- a/src/gpu/framebuffer.cpp
+++ b/src/gpu/framebuffer.cpp
@@ -23,12 +23,6 @@
 
 using namespace std;
 
-#if defined USE_D3D9
-extern IDirect3DDevice9 *g_d3ddevice;
-#elif defined _XBOX
-extern D3DDevice *g_d3ddevice;
-#endif
-
 namespace lol
 {
 
@@ -46,9 +40,11 @@ class FramebufferData
     bool m_bound;
 
 #if defined USE_D3D9
+    IDirect3DDevice9 *m_dev;
     IDirect3DTexture9 *m_texture;
     IDirect3DSurface9 *m_surface, *m_back_surface;
 #elif defined _XBOX
+    D3DDevice9 *m_dev;
     D3DTexture *m_texture;
     D3DSurface *m_surface, *m_back_surface;
 #else
@@ -292,7 +288,9 @@ Framebuffer::Framebuffer(ivec2 size, FramebufferFormat fbo_format)
     m_data->m_size = size;
     m_data->m_bound = false;
 #if defined USE_D3D9
-    if (FAILED(g_d3ddevice->CreateTexture(size.x, size.y, 1,
+    m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
+
+    if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1,
                                           D3DUSAGE_RENDERTARGET,
                                           (D3DFORMAT)fbo_format.GetFormat(), D3DPOOL_DEFAULT,
                                           &m_data->m_texture, nullptr)))
@@ -300,11 +298,13 @@ Framebuffer::Framebuffer(ivec2 size, FramebufferFormat fbo_format)
     if (FAILED(m_data->m_texture->GetSurfaceLevel(0, &m_data->m_surface)))
         Abort();
 #elif defined _XBOX
-    if (FAILED(g_d3ddevice->CreateTexture(size.x, size.y, 1, 0,
+    m_data->m_dev = (D3DDevice9 *)g_renderer->GetDevice();
+
+    if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1, 0,
                                           fbo_format.GetFormat(), D3DPOOL_DEFAULT,
                                           &m_data->m_texture, nullptr)))
         Abort();
-    if (FAILED(g_d3ddevice->CreateRenderTarget(size.x, size.y,
+    if (FAILED(m_data->m_dev->CreateRenderTarget(size.x, size.y,
                                                fbo_format.GetFormat(),
                                                D3DMULTISAMPLE_NONE, 0, 0,
                                                &m_data->m_surface, nullptr)))
@@ -422,9 +422,9 @@ void Framebuffer::Bind()
     ASSERT(!m_data->m_bound, "trying to bind an already bound framebuffer");
 
 #if defined USE_D3D9 || defined _XBOX
-    if (FAILED(g_d3ddevice->GetRenderTarget(0, &m_data->m_back_surface)))
+    if (FAILED(m_data->m_dev->GetRenderTarget(0, &m_data->m_back_surface)))
         Abort();
-    if (FAILED(g_d3ddevice->SetRenderTarget(0, m_data->m_surface)))
+    if (FAILED(m_data->m_dev->SetRenderTarget(0, m_data->m_surface)))
         Abort();
 #else
 #   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
@@ -448,12 +448,12 @@ void Framebuffer::Unbind()
 
 #if defined USE_D3D9 || defined _XBOX
 #   if defined _XBOX
-    if (FAILED(g_d3ddevice->Resolve(D3DRESOLVE_RENDERTARGET0, nullptr,
+    if (FAILED(m_data->m_dev->Resolve(D3DRESOLVE_RENDERTARGET0, nullptr,
                                     m_data->m_texture, nullptr, 0, 0, nullptr,
                                     0, 0, nullptr)))
         Abort();
 #   endif
-    if (FAILED(g_d3ddevice->SetRenderTarget(0, m_data->m_back_surface)))
+    if (FAILED(m_data->m_dev->SetRenderTarget(0, m_data->m_back_surface)))
         Abort();
     m_data->m_back_surface->Release();
 #else
diff --git a/src/gpu/indexbuffer.cpp b/src/gpu/indexbuffer.cpp
index 32c08042..f61e0ba8 100644
--- a/src/gpu/indexbuffer.cpp
+++ b/src/gpu/indexbuffer.cpp
@@ -23,12 +23,6 @@
 
 using namespace std;
 
-#if defined USE_D3D9
-extern IDirect3DDevice9 *g_d3ddevice;
-#elif defined _XBOX
-extern D3DDevice *g_d3ddevice;
-#endif
-
 namespace lol
 {
 
@@ -44,8 +38,10 @@ class IndexBufferData
     size_t m_size;
 
 #if defined USE_D3D9
+    IDirect3DDevice9 *m_dev;
     IDirect3DIndexBuffer9 *m_ibo;
 #elif defined _XBOX
+    D3DDevice9 *m_dev;
     D3DIndexBuffer *m_ibo;
 #else
     GLuint m_ibo;
@@ -65,7 +61,13 @@ IndexBuffer::IndexBuffer(size_t size)
     if (!size)
         return;
 #if defined USE_D3D9 || defined _XBOX
-    if (FAILED(g_d3ddevice->CreateIndexBuffer(size, D3DUSAGE_WRITEONLY,
+#   if defined USE_D3D9
+    m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
+#   elif defined _XBOX
+    m_data->m_dev = (D3DDevice9 *)g_renderer->GetDevice();
+#   endif
+
+    if (FAILED(m_data->m_dev->CreateIndexBuffer(size, D3DUSAGE_WRITEONLY,
                                               D3DFMT_INDEX16, D3DPOOL_MANAGED,
                                               &m_data->m_ibo, nullptr)))
         Abort();
@@ -126,7 +128,7 @@ void IndexBuffer::Bind()
         return;
 
 #if defined USE_D3D9 || defined _XBOX
-    if (FAILED(g_d3ddevice->SetIndices(m_data->m_ibo)))
+    if (FAILED(m_data->m_dev->SetIndices(m_data->m_ibo)))
         Abort();
 #else
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_data->m_ibo);
@@ -142,7 +144,7 @@ void IndexBuffer::Unbind()
         return;
 
 #if defined USE_D3D9 || defined _XBOX
-    if (FAILED(g_d3ddevice->SetIndices(nullptr)))
+    if (FAILED(m_data->m_dev->SetIndices(nullptr)))
         Abort();
 #else
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
diff --git a/src/gpu/renderer.cpp b/src/gpu/renderer.cpp
index 95c2f008..2fc3480f 100644
--- a/src/gpu/renderer.cpp
+++ b/src/gpu/renderer.cpp
@@ -31,10 +31,11 @@
 #include "core.h"
 #include "lolgl.h"
 
+/* FIXME: find a way to pass g_hwnd from the windowing system */
 #if defined USE_D3D9
-extern IDirect3DDevice9 *g_d3ddevice;
+extern HWND g_hwnd;
 #elif defined _XBOX
-extern D3DDevice *g_d3ddevice;
+HWND g_hwnd = 0;
 #endif
 
 namespace lol
@@ -62,9 +63,12 @@ private:
     DepthFunc m_depth_func;
     CullMode m_face_culling;
 
+private:
 #if defined USE_D3D9
+    IDirect3D9 *m_d3d_ctx;
     IDirect3DDevice9 *m_d3d_dev;
 #elif defined _XBOX
+    Direct3D *m_d3d_ctx;
     D3DDevice *m_d3d_dev;
 #endif
 };
@@ -77,8 +81,45 @@ Renderer::Renderer(ivec2 size)
   : m_data(new RendererData())
 {
 #if defined USE_D3D9 || defined _XBOX
-    /* FIXME: we should be in charge of creating this */
-    m_data->m_d3d_dev = g_d3ddevice;
+    /* Create Direct3D context */
+    m_data->m_d3d_ctx = Direct3DCreate9(D3D_SDK_VERSION);
+    if (!m_data->m_d3d_ctx)
+    {
+        Log::Error("cannot initialise D3D\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Create Direct3D device */
+#   if defined _XBOX
+    XVIDEO_MODE VideoMode;
+    XGetVideoMode(&VideoMode);
+    size = lol::min(size, ivec2(VideoMode.dwDisplayWidth,
+                                VideoMode.dwDisplayHeight);
+#   endif
+    D3DPRESENT_PARAMETERS d3dpp;
+    memset(&d3dpp, 0, sizeof(d3dpp));
+    d3dpp.BackBufferWidth = size.x;
+    d3dpp.BackBufferHeight = size.y;
+    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
+    d3dpp.BackBufferCount = 1;
+    d3dpp.hDeviceWindow = g_hwnd;
+#   if defined USE_SDL
+    d3dpp.Windowed = TRUE;
+#   endif
+    d3dpp.EnableAutoDepthStencil = TRUE;
+    d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
+    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+
+    HRESULT hr = VideoData::d3d_ctx->CreateDevice(0, D3DDEVTYPE_HAL, g_hwnd,
+                                                  D3DCREATE_HARDWARE_VERTEXPROCESSING,
+                                                  &d3dpp, &m_data->m_d3d_dev);
+    if (FAILED(hr))
+    {
+        Log::Error("cannot create D3D device\n");
+        exit(EXIT_FAILURE);
+    }
+
 #else
 #   if defined USE_GLEW && !defined __APPLE__
     /* Initialise GLEW if necessary */
@@ -130,6 +171,15 @@ Renderer::~Renderer()
     delete m_data;
 }
 
+void *Renderer::GetDevice()
+{
+#if defined USE_D3D9 || defined _XBOX
+    return m_data->m_d3d_dev;
+#else
+    return nullptr;
+#endif
+}
+
 /*
  * Buffer clearing
  */
diff --git a/src/gpu/shader.cpp b/src/gpu/shader.cpp
index 0f09b438..762f3e72 100644
--- a/src/gpu/shader.cpp
+++ b/src/gpu/shader.cpp
@@ -32,12 +32,6 @@
 
 using namespace std;
 
-#if defined USE_D3D9
-extern IDirect3DDevice9 *g_d3ddevice;
-#elif defined _XBOX
-extern D3DDevice *g_d3ddevice;
-#endif
-
 namespace lol
 {
 
@@ -51,10 +45,12 @@ class ShaderData
 
 private:
 #if defined USE_D3D9
+    IDirect3DDevice9 *m_dev;
     IDirect3DVertexShader9 *vert_shader;
     IDirect3DPixelShader9 *frag_shader;
     ID3DXConstantTable *vert_table, *frag_table;
 #elif defined _XBOX
+    D3DDevice9 *m_dev;
     D3DVertexShader *vert_shader;
     D3DPixelShader *frag_shader;
     ID3DXConstantTable *vert_table, *frag_table;
@@ -193,6 +189,12 @@ Shader::Shader(char const *vert, char const *frag)
     /* Compile vertex shader */
     data->vert_crc = ShaderData::hash(vert);
 #if defined USE_D3D9 || defined _XBOX
+#   if defined USE_D3D9
+    data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
+#   elif defined _XBOX
+    data->m_dev = (D3DDevice9 *)g_renderer->GetDevice();
+#   endif
+
     hr = D3DXCompileShader(vert, (UINT)strlen(vert), macros, nullptr, "main",
                            "vs_3_0", 0, &shader_code, &error_msg,
                            &data->vert_table);
@@ -202,7 +204,7 @@ Shader::Shader(char const *vert, char const *frag)
                    error_msg ? error_msg->GetBufferPointer() : "error");
         Log::Error("shader source:\n%s\n", vert);
     }
-    g_d3ddevice->CreateVertexShader((DWORD *)shader_code->GetBufferPointer(),
+    data->m_dev->CreateVertexShader((DWORD *)shader_code->GetBufferPointer(),
                                     &data->vert_shader);
     shader_code->Release();
 #elif !defined __CELLOS_LV2__
@@ -246,7 +248,7 @@ Shader::Shader(char const *vert, char const *frag)
                    error_msg ? error_msg->GetBufferPointer() : "error");
         Log::Error("shader source:\n%s\n", frag);
     }
-    g_d3ddevice->CreatePixelShader((DWORD *)shader_code->GetBufferPointer(),
+    data->m_dev->CreatePixelShader((DWORD *)shader_code->GetBufferPointer(),
                                    &data->frag_shader);
     shader_code->Release();
 #elif !defined __CELLOS_LV2__
@@ -419,9 +421,9 @@ void Shader::SetUniform(ShaderUniform const &uni, ivec4 const &v)
 {
 #if defined USE_D3D9 || defined _XBOX
     if (uni.flags & 1)
-        g_d3ddevice->SetPixelShaderConstantI((UINT)uni.frag, &v[0], 1);
+        data->m_dev->SetPixelShaderConstantI((UINT)uni.frag, &v[0], 1);
     if (uni.flags & 2)
-        g_d3ddevice->SetVertexShaderConstantI((UINT)uni.vert, &v[0], 1);
+        data->m_dev->SetVertexShaderConstantI((UINT)uni.vert, &v[0], 1);
 #elif !defined __CELLOS_LV2__
     glUniform4i(uni.frag, v.x, v.y, v.z, v.w);
 #else
@@ -475,9 +477,9 @@ void Shader::SetUniform(ShaderUniform const &uni, vec4 const &v)
 {
 #if defined USE_D3D9 || defined _XBOX
     if (uni.flags & 1)
-        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &v[0], 1);
+        data->m_dev->SetPixelShaderConstantF((UINT)uni.frag, &v[0], 1);
     if (uni.flags & 2)
-        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &v[0], 1);
+        data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &v[0], 1);
 #elif !defined __CELLOS_LV2__
     glUniform4fv(uni.frag, 1, &v[0]);
 #else
@@ -493,9 +495,9 @@ void Shader::SetUniform(ShaderUniform const &uni, mat2 const &m)
 #if defined USE_D3D9 || defined _XBOX
     /* FIXME: do we need padding here like for the mat3 version? */
     if (uni.flags & 1)
-        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 1);
+        data->m_dev->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 1);
     if (uni.flags & 2)
-        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 1);
+        data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 1);
 #elif !defined __CELLOS_LV2__
     glUniformMatrix2fv(uni.frag, 1, GL_FALSE, &m[0][0]);
 #else
@@ -514,9 +516,9 @@ void Shader::SetUniform(ShaderUniform const &uni, mat3 const &m)
      * a new data structure; a 4×4 matrix will do. */
     mat4 tmp(m, 1.0f);
     if (uni.flags & 1)
-        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &tmp[0][0], 3);
+        data->m_dev->SetPixelShaderConstantF((UINT)uni.frag, &tmp[0][0], 3);
     if (uni.flags & 2)
-        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &tmp[0][0], 3);
+        data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &tmp[0][0], 3);
 #elif !defined __CELLOS_LV2__
     glUniformMatrix3fv(uni.frag, 1, GL_FALSE, &m[0][0]);
 #else
@@ -533,9 +535,9 @@ void Shader::SetUniform(ShaderUniform const &uni, mat4 const &m)
 {
 #if defined USE_D3D9 || defined _XBOX
     if (uni.flags & 1)
-        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 4);
+        data->m_dev->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 4);
     if (uni.flags & 2)
-        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 4);
+        data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 4);
 #elif !defined __CELLOS_LV2__
     glUniformMatrix4fv(uni.frag, 1, GL_FALSE, &m[0][0]);
 #else
@@ -549,10 +551,10 @@ void Shader::SetUniform(ShaderUniform const &uni, mat4 const &m)
 void Shader::SetUniform(ShaderUniform const &uni, ShaderTexture tex, int index)
 {
 #if defined USE_D3D9 || defined _XBOX
-    g_d3ddevice->SetTexture(index, (LPDIRECT3DTEXTURE9)tex.m_flags);
-    g_d3ddevice->SetSamplerState(index, D3DSAMP_MAGFILTER, tex.m_attrib & 0xff);
-    g_d3ddevice->SetSamplerState(index, D3DSAMP_MINFILTER, (tex.m_attrib >> 8) & 0xff);
-    g_d3ddevice->SetSamplerState(index, D3DSAMP_MIPFILTER, (tex.m_attrib >> 16) & 0xff);
+    data->m_dev->SetTexture(index, (LPDIRECT3DTEXTURE9)tex.m_flags);
+    data->m_dev->SetSamplerState(index, D3DSAMP_MAGFILTER, tex.m_attrib & 0xff);
+    data->m_dev->SetSamplerState(index, D3DSAMP_MINFILTER, (tex.m_attrib >> 8) & 0xff);
+    data->m_dev->SetSamplerState(index, D3DSAMP_MIPFILTER, (tex.m_attrib >> 16) & 0xff);
 #elif !defined __CELLOS_LV2__
     glActiveTexture(GL_TEXTURE0 + index);
     //glEnable(GL_TEXTURE_2D);
@@ -573,10 +575,10 @@ void Shader::SetUniform(ShaderUniform const &uni, Array<float> const &v)
     /* FIXME: this will not work properly because we don't know how tell DX9
      * it's a bunch of floats instead of vec4. */
     if (uni.flags & 1)
-        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag,
+        data->m_dev->SetPixelShaderConstantF((UINT)uni.frag,
                                              &v[0], v.Count() / 4);
     if (uni.flags & 2)
-        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert,
+        data->m_dev->SetVertexShaderConstantF((UINT)uni.vert,
                                               &v[0], v.Count() / 4);
 #elif !defined __CELLOS_LV2__
     glUniform1fv(uni.frag, v.Count(), &v[0]);
@@ -596,10 +598,10 @@ void Shader::SetUniform(ShaderUniform const &uni, Array<vec2> const &v)
     /* FIXME: this will not work properly because we don't know how tell DX9
      * it's a bunch of vec2 instead of vec4. */
     if (uni.flags & 1)
-        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag,
+        data->m_dev->SetPixelShaderConstantF((UINT)uni.frag,
                                              &v[0][0], v.Count() / 2);
     if (uni.flags & 2)
-        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert,
+        data->m_dev->SetVertexShaderConstantF((UINT)uni.vert,
                                               &v[0][0], v.Count() / 2);
 #elif !defined __CELLOS_LV2__
     glUniform2fv(uni.frag, v.Count(), &v[0][0]);
@@ -619,10 +621,10 @@ void Shader::SetUniform(ShaderUniform const &uni, Array<vec3> const &v)
     /* FIXME: this will not work properly because we don't know how tell DX9
      * it's a bunch of vec3 instead of vec4. */
     if (uni.flags & 1)
-        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag,
+        data->m_dev->SetPixelShaderConstantF((UINT)uni.frag,
                                              &v[0][0], v.Count());
     if (uni.flags & 2)
-        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert,
+        data->m_dev->SetVertexShaderConstantF((UINT)uni.vert,
                                               &v[0][0], v.Count());
 #elif !defined __CELLOS_LV2__
     glUniform3fv(uni.frag, v.Count(), &v[0][0]);
@@ -640,10 +642,10 @@ void Shader::SetUniform(ShaderUniform const &uni, Array<vec4> const &v)
 {
 #if defined USE_D3D9 || defined _XBOX
     if (uni.flags & 1)
-        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag,
+        data->m_dev->SetPixelShaderConstantF((UINT)uni.frag,
                                              &v[0][0], v.Count());
     if (uni.flags & 2)
-        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert,
+        data->m_dev->SetVertexShaderConstantF((UINT)uni.vert,
                                               &v[0][0], v.Count());
 #elif !defined __CELLOS_LV2__
     glUniform4fv(uni.frag, v.Count(), &v[0][0]);
@@ -661,8 +663,8 @@ void Shader::Bind() const
 {
 #if defined USE_D3D9 || defined _XBOX
     HRESULT hr;
-    hr = g_d3ddevice->SetVertexShader(data->vert_shader);
-    hr = g_d3ddevice->SetPixelShader(data->frag_shader);
+    hr = data->m_dev->SetVertexShader(data->vert_shader);
+    hr = data->m_dev->SetPixelShader(data->frag_shader);
 #elif !defined __CELLOS_LV2__
     glUseProgram(data->prog_id);
 #else
@@ -677,8 +679,8 @@ void Shader::Unbind() const
 {
 #if defined USE_D3D9 || defined _XBOX
     HRESULT hr;
-    hr = g_d3ddevice->SetVertexShader(nullptr);
-    hr = g_d3ddevice->SetPixelShader(nullptr);
+    hr = data->m_dev->SetVertexShader(nullptr);
+    hr = data->m_dev->SetPixelShader(nullptr);
 #elif !defined __CELLOS_LV2__
     /* FIXME: untested */
     glUseProgram(0);
diff --git a/src/gpu/texture.cpp b/src/gpu/texture.cpp
index 88794a74..6b143b00 100644
--- a/src/gpu/texture.cpp
+++ b/src/gpu/texture.cpp
@@ -23,12 +23,6 @@
 
 using namespace std;
 
-#if defined USE_D3D9
-extern IDirect3DDevice9 *g_d3ddevice;
-#elif defined _XBOX
-extern D3DDevice *g_d3ddevice;
-#endif
-
 namespace lol
 {
 
@@ -45,11 +39,13 @@ class TextureData
     PixelFormat m_format;
 
 #if defined USE_D3D9
+    IDirect3DDevice9 *m_dev;
     IDirect3DTexture9 *m_texture;
     D3DTEXTUREFILTERTYPE m_mag_filter;
-    D3DTEXTUREFILTERTYPE  m_min_filter;
-    D3DTEXTUREFILTERTYPE  m_mip_filter;
+    D3DTEXTUREFILTERTYPE m_min_filter;
+    D3DTEXTUREFILTERTYPE m_mip_filter;
 #elif defined _XBOX
+    D3DDevice9 *m_dev;
     D3DTexture *m_texture;
 #else
     GLuint m_texture;
@@ -75,6 +71,12 @@ Texture::Texture(ivec2 size, PixelFormat format)
     m_data->m_format = format;
 
 #if defined USE_D3D9 || defined _XBOX
+#   if defined USE_D3D9
+    m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
+#   elif defined _XBOX
+    m_data->m_dev = (D3DDevice9 *)g_renderer->GetDevice();
+#   endif
+
     static struct
     {
         D3DFORMAT format;
@@ -109,7 +111,7 @@ Texture::Texture(ivec2 size, PixelFormat format)
     int d3d_usage = D3DUSAGE_WRITEONLY;
 #   endif
 
-    g_d3ddevice->CreateTexture(m_data->m_size.x, m_data->m_size.y, 1,
+    m_data->m_dev->CreateTexture(m_data->m_size.x, m_data->m_size.y, 1,
                                d3d_usage, d3d_format,
                                D3DPOOL_DEFAULT, &m_data->m_texture, nullptr);
     m_data->m_bytes_per_elem = GET_CLAMPED(d3d_formats, format).bytes;
@@ -185,7 +187,7 @@ ShaderTexture Texture::GetTexture() const
 void Texture::Bind()
 {
 #if defined _XBOX || defined USE_D3D9
-    g_d3ddevice->SetTexture(0, m_data->m_texture);
+    m_data->m_dev->SetTexture(0, m_data->m_texture);
 #else
 #   if !defined HAVE_GLES_2X
     glEnable(GL_TEXTURE_2D);
diff --git a/src/gpu/vertexbuffer.cpp b/src/gpu/vertexbuffer.cpp
index b325502d..19f0e41c 100644
--- a/src/gpu/vertexbuffer.cpp
+++ b/src/gpu/vertexbuffer.cpp
@@ -23,12 +23,6 @@
 
 using namespace std;
 
-#if defined USE_D3D9
-extern IDirect3DDevice9 *g_d3ddevice;
-#elif defined _XBOX
-extern D3DDevice *g_d3ddevice;
-#endif
-
 namespace lol
 {
 
@@ -45,8 +39,10 @@ class VertexBufferData
     size_t m_size;
 
 #if defined USE_D3D9
+    IDirect3DDevice9 *m_dev;
     IDirect3DVertexBuffer9 *m_vbo;
 #elif defined _XBOX
+    D3DDevice9 *m_dev;
     D3DVertexBuffer *m_vbo;
 #else
     GLuint m_vbo;
@@ -54,6 +50,26 @@ class VertexBufferData
 #endif
 };
 
+//
+// The VertexDeclarationData class
+// -------------------------------
+//
+
+class VertexDeclarationData
+{
+    friend class VertexBuffer;
+    friend class VertexDeclaration;
+
+#if defined USE_D3D9
+    IDirect3DDevice9 *m_dev;
+    IDirect3DVertexDeclaration9 *m_vdecl;
+#elif defined _XBOX
+    D3DDevice9 *m_dev;
+    D3DVertexDeclaration *m_vdecl;
+#else
+#endif
+};
+
 //
 // The VertexDeclaration class
 // ---------------------------
@@ -72,7 +88,9 @@ VertexDeclaration::VertexDeclaration(VertexStreamBase const &s1,
                                      VertexStreamBase const &s9,
                                      VertexStreamBase const &s10,
                                      VertexStreamBase const &s11,
-                                     VertexStreamBase const &s12) : m_count(0)
+                                     VertexStreamBase const &s12)
+  : m_count(0),
+    m_data(new VertexDeclarationData())
 {
     if (&s1 != &VertexStreamBase::Empty) AddStream(s1);
     if (&s2 != &VertexStreamBase::Empty) AddStream(s2);
@@ -92,29 +110,19 @@ VertexDeclaration::VertexDeclaration(VertexStreamBase const &s1,
 VertexDeclaration::~VertexDeclaration()
 {
 #if defined _XBOX || defined USE_D3D9
-#   if defined USE_D3D9
-    IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
-#   elif defined _XBOX
-    D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
-#   endif
-
-    if (FAILED(vdecl->Release()))
+    if (FAILED(m_data->m_vdecl->Release()))
         Abort();
 #else
 
 #endif
+
+    delete m_data;
 }
 
 void VertexDeclaration::Bind()
 {
 #if defined _XBOX || defined USE_D3D9
-#   if defined USE_D3D9
-    IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
-#   elif defined _XBOX
-    D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
-#   endif
-
-    if (FAILED(g_d3ddevice->SetVertexDeclaration(vdecl)))
+    if (FAILED(m_data->m_dev->SetVertexDeclaration(m_data->m_vdecl)))
         Abort();
 #else
     /* FIXME: Nothing to do? */
@@ -130,28 +138,28 @@ void VertexDeclaration::DrawElements(MeshPrimitive type, int skip, int count)
     switch (type)
     {
     case MeshPrimitive::Triangles:
-        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST,
-                                              skip, count)))
+        if (FAILED(m_data->m_dev->DrawPrimitive(D3DPT_TRIANGLELIST,
+                                                skip, count)))
             Abort();
         break;
     case MeshPrimitive::TriangleStrips:
-        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
-                                              skip, count)))
+        if (FAILED(m_data->m_dev->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+                                                skip, count)))
             Abort();
         break;
     case MeshPrimitive::TriangleFans:
-        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,
-                                              skip, count)))
+        if (FAILED(m_data->m_dev->DrawPrimitive(D3DPT_TRIANGLEFAN,
+                                                skip, count)))
             Abort();
         break;
     case MeshPrimitive::Points:
-        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_POINTLIST,
-                                              skip, count)))
+        if (FAILED(m_data->m_dev->DrawPrimitive(D3DPT_POINTLIST,
+                                                skip, count)))
             Abort();
         break;
     case MeshPrimitive::Lines:
-        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_LINELIST,
-                                              skip, count)))
+        if (FAILED(m_data->m_dev->DrawPrimitive(D3DPT_LINELIST,
+                                                skip, count)))
             Abort();
         break;
     }
@@ -190,29 +198,29 @@ void VertexDeclaration::DrawIndexedElements(MeshPrimitive type, int vbase,
     {
     case MeshPrimitive::Triangles:
         count = count / 3;
-        if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
+        if (FAILED(m_data->m_dev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
                                            vbase, vskip, vcount, skip, count)))
             Abort();
         break;
     case MeshPrimitive::TriangleStrips:
         count = count - 2;
-        if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,
+        if (FAILED(m_data->m_dev->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,
                                            vbase, vskip, vcount, skip, count)))
             Abort();
         break;
     case MeshPrimitive::TriangleFans:
         count = count - 2;
-        if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN,
+        if (FAILED(m_data->m_dev->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN,
                                            vbase, vskip, vcount, skip, count)))
             Abort();
         break;
     case MeshPrimitive::Points:
-        if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_POINTLIST,
+        if (FAILED(m_data->m_dev->DrawIndexedPrimitive(D3DPT_POINTLIST,
                                            vbase, vskip, vcount, skip, count)))
             Abort();
         break;
     case MeshPrimitive::Lines:
-        if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_LINELIST,
+        if (FAILED(m_data->m_dev->DrawIndexedPrimitive(D3DPT_LINELIST,
                                            vbase, vskip, vcount, skip, count)))
             Abort();
         break;
@@ -258,7 +266,7 @@ void VertexDeclaration::Unbind()
         if (m_streams[i].index != stream)
         {
             stream = m_streams[i].index;
-            if (FAILED(g_d3ddevice->SetStreamSource(stream, 0, 0, 0)))
+            if (FAILED(m_data->m_dev->SetStreamSource(stream, 0, 0, 0)))
                 Abort();
         }
     /* "NULL is an invalid input to SetVertexDeclaration" (DX9 guide), so
@@ -329,7 +337,8 @@ void VertexDeclaration::SetStream(VertexBuffer *vb, ShaderAttrib attr1,
     /* FIXME: precompute most of the crap above! */
     if (stream >= 0)
     {
-        if (FAILED(g_d3ddevice->SetStreamSource(stream, vb->m_data->m_vbo, 0, stride)))
+        if (FAILED(m_data->m_dev->SetStreamSource(stream, vb->m_data->m_vbo,
+                                                  0, stride)))
             Abort();
     }
 #else
@@ -553,15 +562,14 @@ void VertexDeclaration::Initialize()
     elements[m_count] = end_element[0];
 
 #   if defined USE_D3D9
-    IDirect3DVertexDeclaration9 *vdecl;
+    m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
 #   elif defined _XBOX
-    D3DVertexDeclaration *vdecl;
+    m_data->m_dev = (D3DDevice9 *)g_renderer->GetDevice();
 #   endif
 
-    if (FAILED(g_d3ddevice->CreateVertexDeclaration(elements, &vdecl)))
+    if (FAILED(m_data->m_dev->CreateVertexDeclaration(elements,
+                                                      &m_data->m_vdecl)))
         Abort();
-
-    m_data = vdecl;
 #else
 
 #endif
@@ -636,7 +644,13 @@ VertexBuffer::VertexBuffer(size_t size)
     if (!size)
         return;
 #if defined USE_D3D9 || defined _XBOX
-    if (FAILED(g_d3ddevice->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, nullptr,
+#   if defined USE_D3D9
+    m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
+#   elif defined _XBOX
+    m_data->m_dev = (D3DDevice9 *)g_renderer->GetDevice();
+#   endif
+
+    if (FAILED(m_data->m_dev->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, nullptr,
                                                D3DPOOL_MANAGED, &m_data->m_vbo, nullptr)))
         Abort();
 #else
diff --git a/src/lol/gpu/renderer.h b/src/lol/gpu/renderer.h
index 5bb2f125..921ec4d6 100644
--- a/src/lol/gpu/renderer.h
+++ b/src/lol/gpu/renderer.h
@@ -138,6 +138,8 @@ private:
     Renderer(ivec2 size);
     ~Renderer();
 
+    void *GetDevice();
+
 public:
     void Clear(ClearMask mask);
 
diff --git a/src/lol/gpu/vertexbuffer.h b/src/lol/gpu/vertexbuffer.h
index a69f4ba7..98b1383a 100644
--- a/src/lol/gpu/vertexbuffer.h
+++ b/src/lol/gpu/vertexbuffer.h
@@ -311,7 +311,8 @@ private:
     struct { uint8_t stream_type, index, usage, size; int reg; } m_streams[12 + 1];
     int m_count;
 
-    void *m_data;
+private:
+    class VertexDeclarationData *m_data;
 };
 
 } /* namespace lol */
diff --git a/src/platform/sdl/sdlapp.cpp b/src/platform/sdl/sdlapp.cpp
index dee374f2..57289083 100644
--- a/src/platform/sdl/sdlapp.cpp
+++ b/src/platform/sdl/sdlapp.cpp
@@ -34,7 +34,6 @@
 
 #if defined USE_SDL && defined USE_D3D9
 HWND g_hwnd = nullptr;
-extern IDirect3DDevice9 *g_d3ddevice;
 #endif
 
 namespace lol
@@ -115,24 +114,25 @@ void SdlApp::ShowPointer(bool show)
 void SdlApp::Tick()
 {
 #if defined USE_SDL && defined USE_D3D9
+    IDirect3DDevice9 *d3d_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
     HRESULT hr;
-    hr = g_d3ddevice->BeginScene();
+    hr = d3d_dev->BeginScene();
     if (FAILED(hr))
         Abort();
 #endif
+
     /* Tick the renderer, show the frame and clamp to desired framerate. */
     Ticker::TickDraw();
-#if defined USE_SDL
-#   if defined USE_D3D9
-    hr = g_d3ddevice->EndScene();
+
+#if defined USE_SDL && defined USE_D3D9
+    hr = d3d_dev->EndScene();
     if (FAILED(hr))
         Abort();
-    hr = g_d3ddevice->Present(nullptr, nullptr, nullptr, nullptr);
+    hr = d3d_dev->Present(nullptr, nullptr, nullptr, nullptr);
     if (FAILED(hr))
         Abort();
-#   else
+#elif defined USE_SDL
     SDL_GL_SwapBuffers();
-#   endif
 #endif
 }
 
diff --git a/src/platform/xbox/xboxapp.cpp b/src/platform/xbox/xboxapp.cpp
index 7d66cba6..9ec253bd 100644
--- a/src/platform/xbox/xboxapp.cpp
+++ b/src/platform/xbox/xboxapp.cpp
@@ -20,10 +20,6 @@
 #include "xboxapp.h"
 #include "xboxinput.h"
 
-#if defined _XBOX
-extern D3DDevice *g_d3ddevice;
-#endif
-
 namespace lol
 {
 
@@ -67,7 +63,8 @@ void XboxApp::Tick()
     Ticker::TickDraw();
 
 #if defined _XBOX
-    g_d3ddevice->Present(nullptr, nullptr, nullptr, nullptr);
+    D3DDevice9 *d3d_dev = (D3DDevice9 *)g_renderer->GetDevice();
+    d3d_dev->Present(nullptr, nullptr, nullptr, nullptr);
 #endif
 }
 
diff --git a/src/video.cpp b/src/video.cpp
index 3340f353..a9e12983 100644
--- a/src/video.cpp
+++ b/src/video.cpp
@@ -31,15 +31,6 @@
 
 using namespace std;
 
-/* FIXME: g_d3ddevice should never be exported */
-#if defined USE_D3D9
-IDirect3DDevice9 *g_d3ddevice;
-extern HWND g_hwnd;
-#elif defined _XBOX
-D3DDevice *g_d3ddevice;
-HWND g_hwnd = 0;
-#endif
-
 namespace lol
 {
 
@@ -49,81 +40,17 @@ class VideoData
 
 private:
     static DebugRenderMode render_mode;
-#if defined USE_D3D9 || defined _XBOX
-#   if defined USE_D3D9
-    static IDirect3D9 *d3d_ctx;
-    static IDirect3DDevice9 *d3d_dev;
-#   elif defined _XBOX
-    static Direct3D *d3d_ctx;
-    static D3DDevice *d3d_dev;
-#   endif
-#endif
 };
 
 DebugRenderMode VideoData::render_mode = DebugRenderMode::Default;
 
-#if defined USE_D3D9 || defined _XBOX
-#   if defined USE_D3D9
-IDirect3D9 *VideoData::d3d_ctx;
-IDirect3DDevice9 *VideoData::d3d_dev;
-#   elif defined _XBOX
-Direct3D *VideoData::d3d_ctx;
-D3DDevice *VideoData::d3d_dev;
-#   endif
-#endif
-
 /*
  * Public Video class
  */
 
 void Video::Setup(ivec2 size)
 {
-#if defined USE_D3D9 || defined _XBOX
-    VideoData::d3d_ctx = Direct3DCreate9(D3D_SDK_VERSION);
-    if (!VideoData::d3d_ctx)
-    {
-        Log::Error("cannot initialise D3D\n");
-        exit(EXIT_FAILURE);
-    }
-
-    /* Choose best viewport size */
-#   if defined _XBOX
-    XVIDEO_MODE VideoMode;
-    XGetVideoMode(&VideoMode);
-    size = lol::min(size, ivec2(VideoMode.dwDisplayWidth,
-                                VideoMode.dwDisplayHeight);
-#   endif
-    D3DPRESENT_PARAMETERS d3dpp;
-    memset(&d3dpp, 0, sizeof(d3dpp));
-    d3dpp.BackBufferWidth = size.x;
-    d3dpp.BackBufferHeight = size.y;
-    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
-    d3dpp.BackBufferCount = 1;
-    d3dpp.hDeviceWindow = g_hwnd;
-#   if defined USE_SDL
-    d3dpp.Windowed = TRUE;
-#   endif
-    d3dpp.EnableAutoDepthStencil = TRUE;
-    d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
-    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
-    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
-
-    HRESULT hr = VideoData::d3d_ctx->CreateDevice(0, D3DDEVTYPE_HAL, g_hwnd,
-                                                  D3DCREATE_HARDWARE_VERTEXPROCESSING,
-                                                  &d3dpp, &VideoData::d3d_dev);
-    if (FAILED(hr))
-    {
-        Log::Error("cannot create D3D device\n");
-        exit(EXIT_FAILURE);
-    }
-
-    g_d3ddevice = VideoData::d3d_dev;
-
     g_renderer = new Renderer(size);
-#else
-    /* Initialise OpenGL */
-    g_renderer = new Renderer(size);
-#endif
 
     /* Initialise reasonable scene default properties */
     SetDebugRenderMode(DebugRenderMode::Default);