Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/ghost/CMakeLists.txt2
-rw-r--r--intern/ghost/GHOST_C-api.h19
-rw-r--r--intern/ghost/GHOST_ISystem.h6
-rw-r--r--intern/ghost/GHOST_Types.h5
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp19
-rw-r--r--intern/ghost/intern/GHOST_ContextD3D.cpp358
-rw-r--r--intern/ghost/intern/GHOST_ContextD3D.h133
-rw-r--r--intern/ghost/intern/GHOST_System.cpp10
-rw-r--r--intern/ghost/intern/GHOST_System.h13
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp42
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h14
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp14
12 files changed, 634 insertions, 1 deletions
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index cc671e31f92..c4f1efe1580 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -280,11 +280,13 @@ elseif(WIN32)
)
list(APPEND SRC
+ intern/GHOST_ContextD3D.cpp
intern/GHOST_DisplayManagerWin32.cpp
intern/GHOST_DropTargetWin32.cpp
intern/GHOST_SystemWin32.cpp
intern/GHOST_WindowWin32.cpp
+ intern/GHOST_ContextD3D.h
intern/GHOST_DisplayManagerWin32.h
intern/GHOST_DropTargetWin32.h
intern/GHOST_SystemWin32.h
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index ba46a868df6..a3cc9aa1df5 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -229,6 +229,25 @@ extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemha
extern GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
GHOST_ContextHandle contexthandle);
+#ifdef WIN32
+/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \param systemhandle The handle to the system
+ * \return A handle to the new context ( == NULL if creation failed).
+ */
+GHOST_ContextHandle GHOST_CreateDirectXContext(GHOST_SystemHandle systemhandle);
+
+/**
+ * Dispose of a context.
+ * \param systemhandle The handle to the system
+ * \param contexthandle Handle to the context to be disposed.
+ * \return Indication of success.
+ */
+GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
+ GHOST_ContextHandle contexthandle);
+#endif
+
/**
* Returns the window user data.
* \param windowhandle The handle to the window
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 4634eb1bc66..5d529141ca7 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -267,6 +267,12 @@ class GHOST_ISystem {
virtual GHOST_IContext *createOffscreenContext() = 0;
/**
+ * Overload to allow requesting a different context type. By default only OpenGL is supported.
+ * However by explicitly overloading this a system may add support for others.
+ */
+ virtual GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type) = 0;
+
+ /**
* Dispose of a context.
* \param context Pointer to the context to be disposed.
* \return Indication of success.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 98dd1de867f..38a6a0b04d2 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -140,7 +140,10 @@ typedef enum { GHOST_kWindowOrderTop = 0, GHOST_kWindowOrderBottom } GHOST_TWind
typedef enum {
GHOST_kDrawingContextTypeNone = 0,
- GHOST_kDrawingContextTypeOpenGL
+ GHOST_kDrawingContextTypeOpenGL,
+#ifdef WIN32
+ GHOST_kDrawingContextTypeD3D,
+#endif
} GHOST_TDrawingContextType;
typedef enum {
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 3c3860bd2c0..9a7e3da828b 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -146,6 +146,25 @@ GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
return system->disposeContext(context);
}
+#ifdef WIN32
+GHOST_ContextHandle GHOST_CreateDirectXContext(GHOST_SystemHandle systemhandle)
+{
+ GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
+
+ return (GHOST_ContextHandle)system->createOffscreenContext(GHOST_kDrawingContextTypeD3D);
+}
+
+GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
+ GHOST_ContextHandle contexthandle)
+{
+ GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
+ GHOST_IContext *context = (GHOST_IContext *)contexthandle;
+
+ return system->disposeContext(context);
+}
+
+#endif
+
GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
const char *title,
GHOST_TInt32 left,
diff --git a/intern/ghost/intern/GHOST_ContextD3D.cpp b/intern/ghost/intern/GHOST_ContextD3D.cpp
new file mode 100644
index 00000000000..ed65d499073
--- /dev/null
+++ b/intern/ghost/intern/GHOST_ContextD3D.cpp
@@ -0,0 +1,358 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ *
+ * For testing purposes, it can be useful to do some DirectX only drawing. A patch for this can be
+ * found here: https://developer.blender.org/P1284
+ */
+
+#include <iostream>
+#include <string>
+
+#include <GL/glew.h>
+#include <GL/wglew.h>
+
+#include "GHOST_ContextWGL.h" /* For shared drawing */
+#include "GHOST_ContextD3D.h"
+
+HMODULE GHOST_ContextD3D::s_d3d_lib = NULL;
+PFN_D3D11_CREATE_DEVICE GHOST_ContextD3D::s_D3D11CreateDeviceFn = NULL;
+
+GHOST_ContextD3D::GHOST_ContextD3D(bool stereoVisual, HWND hWnd)
+ : GHOST_Context(stereoVisual), m_hWnd(hWnd)
+{
+}
+
+GHOST_ContextD3D::~GHOST_ContextD3D()
+{
+ m_device->Release();
+ m_device_ctx->ClearState();
+ m_device_ctx->Release();
+}
+
+GHOST_TSuccess GHOST_ContextD3D::swapBuffers()
+{
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::activateDrawingContext()
+{
+ return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::releaseDrawingContext()
+{
+ return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::setupD3DLib()
+{
+ if (s_d3d_lib == NULL) {
+ s_d3d_lib = LoadLibraryA("d3d11.dll");
+
+ WIN32_CHK(s_d3d_lib != NULL);
+
+ if (s_d3d_lib == NULL) {
+ fprintf(stderr, "LoadLibrary(\"d3d11.dll\") failed!\n");
+ return GHOST_kFailure;
+ }
+ }
+
+ if (s_D3D11CreateDeviceFn == NULL) {
+ s_D3D11CreateDeviceFn = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(s_d3d_lib,
+ "D3D11CreateDevice");
+
+ WIN32_CHK(s_D3D11CreateDeviceFn != NULL);
+
+ if (s_D3D11CreateDeviceFn == NULL) {
+ fprintf(stderr, "GetProcAddress(s_d3d_lib, \"D3D11CreateDevice\") failed!\n");
+ return GHOST_kFailure;
+ }
+ }
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::initializeDrawingContext()
+{
+ if (setupD3DLib() == GHOST_kFailure) {
+ return GHOST_kFailure;
+ }
+
+ HRESULT hres = s_D3D11CreateDeviceFn(
+ NULL,
+ D3D_DRIVER_TYPE_HARDWARE,
+ NULL,
+ /* For debugging you may want to pass D3D11_CREATE_DEVICE_DEBUG here, but that requires
+ * additional setup, see
+ * https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-layers#debug-layer.
+ */
+ 0,
+ NULL,
+ 0,
+ D3D11_SDK_VERSION,
+ &m_device,
+ NULL,
+ &m_device_ctx);
+
+ WIN32_CHK(hres == S_OK);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::releaseNativeHandles()
+{
+ return GHOST_kFailure;
+}
+
+class GHOST_SharedOpenGLResource {
+ struct SharedData {
+ HANDLE device;
+ GLuint fbo;
+ HANDLE render_buf{nullptr};
+ } m_shared;
+
+ public:
+ GHOST_SharedOpenGLResource(ID3D11Device *device,
+ ID3D11DeviceContext *device_ctx,
+ unsigned int width,
+ unsigned int height,
+ ID3D11RenderTargetView *render_target = nullptr)
+ : m_device(device), m_device_ctx(device_ctx), m_cur_width(width), m_cur_height(height)
+ {
+ ID3D11Resource *backbuffer_res;
+
+ if (!render_target) {
+ D3D11_TEXTURE2D_DESC texDesc{};
+ D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc{};
+ ID3D11Texture2D *tex;
+
+ texDesc.Width = width;
+ texDesc.Height = height;
+ texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ texDesc.SampleDesc.Count = 1;
+ texDesc.ArraySize = 1;
+ texDesc.MipLevels = 1;
+ texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+
+ device->CreateTexture2D(&texDesc, NULL, &tex);
+ if (!tex) {
+ /* If texture creation fails, we just return and leave the render target unset. So it needs
+ * to be NULL-checked before use. */
+ fprintf(stderr, "Error creating texture for shared DirectX-OpenGL resource\n");
+ return;
+ }
+
+ renderTargetViewDesc.Format = texDesc.Format;
+ renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ renderTargetViewDesc.Texture2D.MipSlice = 0;
+
+ device->CreateRenderTargetView(tex, &renderTargetViewDesc, &render_target);
+
+ tex->Release();
+ }
+
+ m_render_target = render_target;
+ if (m_render_target) {
+ m_render_target->GetResource(&backbuffer_res);
+ }
+ if (backbuffer_res) {
+ backbuffer_res->QueryInterface<ID3D11Texture2D>(&m_render_target_tex);
+ backbuffer_res->Release();
+ }
+
+ if (!m_render_target || !m_render_target_tex) {
+ fprintf(stderr, "Error creating render target for shared DirectX-OpenGL resource\n");
+ return;
+ }
+ }
+
+ ~GHOST_SharedOpenGLResource()
+ {
+ if (m_render_target_tex) {
+ m_render_target_tex->Release();
+ }
+ if (m_render_target) {
+ m_render_target->Release();
+ }
+
+ if (m_is_initialized) {
+ if (m_shared.render_buf) {
+ wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
+ }
+ if (m_shared.device) {
+ wglDXCloseDeviceNV(m_shared.device);
+ }
+ glDeleteFramebuffers(1, &m_shared.fbo);
+ glDeleteRenderbuffers(1, &m_gl_render_buf);
+ }
+ }
+
+ void reregisterSharedObject()
+ {
+ if (m_shared.render_buf) {
+ wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
+ }
+
+ if (!m_render_target_tex) {
+ return;
+ }
+
+ m_shared.render_buf = wglDXRegisterObjectNV(m_shared.device,
+ m_render_target_tex,
+ m_gl_render_buf,
+ GL_RENDERBUFFER,
+ WGL_ACCESS_READ_WRITE_NV);
+
+ if (!m_shared.render_buf) {
+ fprintf(stderr, "Error registering shared object using wglDXRegisterObjectNV()\n");
+ return;
+ }
+ }
+
+ GHOST_TSuccess initialize()
+ {
+ m_shared.device = wglDXOpenDeviceNV(m_device);
+ if (m_shared.device == NULL) {
+ fprintf(stderr, "Error opening shared device using wglDXOpenDeviceNV()\n");
+ return GHOST_kFailure;
+ }
+
+ /* Build the renderbuffer. */
+ glGenRenderbuffers(1, &m_gl_render_buf);
+ glBindRenderbuffer(GL_RENDERBUFFER, m_gl_render_buf);
+
+ reregisterSharedObject();
+
+ /* Build the framebuffer */
+ glGenFramebuffers(1, &m_shared.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, m_shared.fbo);
+ glFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_gl_render_buf);
+ m_is_initialized = true;
+
+ return GHOST_kSuccess;
+ }
+
+ void ensureUpdated(unsigned int width, unsigned int height)
+ {
+ if (m_is_initialized == false) {
+ initialize();
+ }
+
+ if ((m_cur_width != width) || (m_cur_height != height)) {
+ m_cur_width = width;
+ m_cur_height = height;
+ reregisterSharedObject();
+ }
+ }
+
+ GHOST_TSuccess blit(unsigned int width, unsigned int height)
+ {
+ GLint fbo;
+ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fbo);
+
+ if (!m_render_target || !m_render_target_tex) {
+ return GHOST_kFailure;
+ }
+
+ ensureUpdated(width, height);
+
+#ifdef NDEBUG
+ const float clear_col[] = {0.8f, 0.5f, 1.0f, 1.0f};
+ m_device_ctx->ClearRenderTargetView(m_render_target, clear_col);
+#endif
+ m_device_ctx->OMSetRenderTargets(1, &m_render_target, nullptr);
+
+ beginGLOnly();
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_shared.fbo);
+ GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (err != GL_FRAMEBUFFER_COMPLETE) {
+ fprintf(
+ stderr, "Error: Framebuffer for shared DirectX-OpenGL resource incomplete %u\n", err);
+ return GHOST_kFailure;
+ }
+
+ /* No glBlitNamedFramebuffer, gotta be 3.3 compatible. */
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
+ glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ endGLOnly();
+
+ return GHOST_kSuccess;
+ }
+
+ ID3D11RenderTargetView *m_render_target{nullptr};
+ ID3D11Texture2D *m_render_target_tex{nullptr};
+
+ private:
+ void beginGLOnly()
+ {
+ wglDXLockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
+ }
+ void endGLOnly()
+ {
+ wglDXUnlockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
+ }
+
+ ID3D11Device *m_device;
+ ID3D11DeviceContext *m_device_ctx;
+ GLuint m_gl_render_buf;
+ unsigned int m_cur_width, m_cur_height;
+ bool m_is_initialized{false};
+};
+
+GHOST_SharedOpenGLResource *GHOST_ContextD3D::createSharedOpenGLResource(
+ unsigned int width, unsigned int height, ID3D11RenderTargetView *render_target)
+{
+ if (!(WGL_NV_DX_interop && WGL_NV_DX_interop2)) {
+ fprintf(stderr,
+ "Error: Can't render OpenGL framebuffer using Direct3D. NV_DX_interop extension not "
+ "available.");
+ return nullptr;
+ }
+ GHOST_SharedOpenGLResource *shared_res = new GHOST_SharedOpenGLResource(
+ m_device, m_device_ctx, width, height, render_target);
+
+ return shared_res;
+}
+GHOST_SharedOpenGLResource *GHOST_ContextD3D::createSharedOpenGLResource(unsigned int width,
+ unsigned int height)
+{
+ return createSharedOpenGLResource(width, height, nullptr);
+}
+
+void GHOST_ContextD3D::disposeSharedOpenGLResource(GHOST_SharedOpenGLResource *shared_res)
+{
+ delete shared_res;
+}
+
+GHOST_TSuccess GHOST_ContextD3D::blitFromOpenGLContext(GHOST_SharedOpenGLResource *shared_res,
+ unsigned int width,
+ unsigned int height)
+{
+ return shared_res->blit(width, height);
+}
+
+ID3D11Texture2D *GHOST_ContextD3D::getSharedTexture2D(GHOST_SharedOpenGLResource *shared_res)
+{
+ return shared_res->m_render_target_tex;
+}
diff --git a/intern/ghost/intern/GHOST_ContextD3D.h b/intern/ghost/intern/GHOST_ContextD3D.h
new file mode 100644
index 00000000000..601282fc80f
--- /dev/null
+++ b/intern/ghost/intern/GHOST_ContextD3D.h
@@ -0,0 +1,133 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ */
+
+#ifndef __GHOST_CONTEXTD3D_H__
+#define __GHOST_CONTEXTD3D_H__
+
+#ifndef WIN32
+# error WIN32 only!
+#endif // WIN32
+
+#include <D3D11.h>
+
+#include "GHOST_Context.h"
+
+class GHOST_ContextD3D : public GHOST_Context {
+ public:
+ GHOST_ContextD3D(bool stereoVisual, HWND hWnd);
+ ~GHOST_ContextD3D();
+
+ /**
+ * Swaps front and back buffers of a window.
+ * \return A boolean success indicator.
+ */
+ GHOST_TSuccess swapBuffers();
+
+ /**
+ * Activates the drawing context of this window.
+ * \return A boolean success indicator.
+ */
+ GHOST_TSuccess activateDrawingContext();
+
+ /**
+ * Release the drawing context of the calling thread.
+ * \return A boolean success indicator.
+ */
+ GHOST_TSuccess releaseDrawingContext();
+
+ /**
+ * Call immediately after new to initialize. If this fails then immediately delete the object.
+ * \return Indication as to whether initialization has succeeded.
+ */
+ GHOST_TSuccess initializeDrawingContext();
+
+ /**
+ * Updates the drawing context of this window. Needed
+ * whenever the window is changed.
+ * \return Indication of success.
+ */
+ GHOST_TSuccess updateDrawingContext()
+ {
+ return GHOST_kFailure;
+ }
+
+ /**
+ * Checks if it is OK for a remove the native display
+ * \return Indication as to whether removal has succeeded.
+ */
+ GHOST_TSuccess releaseNativeHandles();
+
+ /**
+ * Sets the swap interval for swapBuffers.
+ * \param interval The swap interval to use.
+ * \return A boolean success indicator.
+ */
+ GHOST_TSuccess setSwapInterval(int /*interval*/)
+ {
+ return GHOST_kFailure;
+ }
+
+ /**
+ * Gets the current swap interval for swapBuffers.
+ * \param intervalOut Variable to store the swap interval if it can be read.
+ * \return Whether the swap interval can be read.
+ */
+ GHOST_TSuccess getSwapInterval(int &)
+ {
+ return GHOST_kFailure;
+ }
+
+ /**
+ * Gets the OpenGL framebuffer associated with the OpenGL context
+ * \return The ID of an OpenGL framebuffer object.
+ */
+ unsigned int getDefaultFramebuffer()
+ {
+ return 0;
+ }
+
+ class GHOST_SharedOpenGLResource *createSharedOpenGLResource(
+ unsigned int width, unsigned int height, ID3D11RenderTargetView *render_target);
+ class GHOST_SharedOpenGLResource *createSharedOpenGLResource(unsigned int width,
+ unsigned int height);
+ void disposeSharedOpenGLResource(class GHOST_SharedOpenGLResource *shared_res);
+ GHOST_TSuccess blitFromOpenGLContext(class GHOST_SharedOpenGLResource *shared_res,
+ unsigned int width,
+ unsigned int height);
+ ID3D11Texture2D *getSharedTexture2D(class GHOST_SharedOpenGLResource *shared_res);
+
+ bool isUpsideDown() const
+ {
+ return true;
+ }
+
+ private:
+ GHOST_TSuccess setupD3DLib();
+
+ static HMODULE s_d3d_lib;
+ static PFN_D3D11_CREATE_DEVICE s_D3D11CreateDeviceFn;
+
+ HWND m_hWnd;
+
+ ID3D11Device *m_device;
+ ID3D11DeviceContext *m_device_ctx;
+};
+
+#endif /* __GHOST_CONTEXTD3D_H__ */
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index fc9ce1f66e1..12096d65240 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -122,6 +122,16 @@ GHOST_TSuccess GHOST_System::disposeWindow(GHOST_IWindow *window)
return success;
}
+GHOST_IContext *GHOST_System::createOffscreenContext(GHOST_TDrawingContextType type)
+{
+ switch (type) {
+ case GHOST_kDrawingContextTypeOpenGL:
+ return createOffscreenContext();
+ default:
+ return NULL;
+ }
+}
+
bool GHOST_System::validWindow(GHOST_IWindow *window)
{
return m_windowManager->getWindowFound(window);
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 26b566e6b7e..dff27b0903d 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -112,6 +112,19 @@ class GHOST_System : public GHOST_ISystem {
GHOST_TSuccess disposeWindow(GHOST_IWindow *window);
/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+ virtual GHOST_IContext *createOffscreenContext() = 0;
+
+ /**
+ * Overload to allow requesting a different context type. By default only OpenGL is supported.
+ * However by explicitly overloading this a system may add support for others.
+ */
+ GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type);
+
+ /**
* Returns whether a window is valid.
* \param window Pointer to the window to be checked.
* \return Indication of validity.
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 4a4016cbca1..7d2a8f5810c 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -21,6 +21,7 @@
* \ingroup GHOST
*/
+#include "GHOST_ContextD3D.h"
#include "GHOST_SystemWin32.h"
#include "GHOST_EventDragnDrop.h"
@@ -405,6 +406,47 @@ GHOST_TSuccess GHOST_SystemWin32::disposeContext(GHOST_IContext *context)
return GHOST_kSuccess;
}
+/**
+ * Create a new offscreen DirectX 11 context.
+ * Never explicitly delete the window, use #disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+GHOST_IContext *GHOST_SystemWin32::createOffscreenContextD3D()
+{
+ GHOST_Context *context;
+
+ HWND wnd = CreateWindowA("STATIC",
+ "Blender XR",
+ WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ 0,
+ 0,
+ 64,
+ 64,
+ NULL,
+ NULL,
+ GetModuleHandle(NULL),
+ NULL);
+
+ context = new GHOST_ContextD3D(false, wnd);
+ if (context->initializeDrawingContext() == GHOST_kFailure) {
+ delete context;
+ }
+
+ return context;
+}
+
+GHOST_IContext *GHOST_SystemWin32::createOffscreenContext(GHOST_TDrawingContextType type)
+{
+ switch (type) {
+ case GHOST_kDrawingContextTypeOpenGL:
+ return createOffscreenContext();
+ case GHOST_kDrawingContextTypeD3D:
+ return createOffscreenContextD3D();
+ default:
+ return NULL;
+ }
+}
+
bool GHOST_SystemWin32::processEvents(bool waitForEvent)
{
MSG msg;
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index b069e6cf3b6..c5af3e120be 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -131,6 +131,13 @@ class GHOST_SystemWin32 : public GHOST_System {
GHOST_IContext *createOffscreenContext();
/**
+ * Create a new offscreen context.
+ * Never explicitly delete the window, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+ GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type);
+
+ /**
* Dispose of a context.
* \param context Pointer to the context to be disposed.
* \return Indication of success.
@@ -249,6 +256,13 @@ class GHOST_SystemWin32 : public GHOST_System {
GHOST_TSuccess exit();
/**
+ * Create a new offscreen DirectX context.
+ * Never explicitly delete the window, use disposeContext() instead.
+ * \return The new context (or 0 if creation failed).
+ */
+ GHOST_IContext *createOffscreenContextD3D();
+
+ /**
* Converts raw WIN32 key codes from the wndproc to GHOST keys.
* \param vKey The virtual key from hardKey
* \param ScanCode The ScanCode of pressed key (similar to PS/2 Set 1)
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 2ab0e837efb..1d2630bc66d 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -23,6 +23,7 @@
#define _USE_MATH_DEFINES
+#include "GHOST_ContextD3D.h"
#include "GHOST_WindowManager.h"
#include "GHOST_WindowWin32.h"
#include "GHOST_SystemWin32.h"
@@ -750,6 +751,19 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
# error // must specify either core or compat at build time
#endif
}
+ else if (type == GHOST_kDrawingContextTypeD3D) {
+ GHOST_Context *context;
+
+ context = new GHOST_ContextD3D(false, m_hWnd);
+ if (context->initializeDrawingContext()) {
+ return context;
+ }
+ else {
+ delete context;
+ }
+
+ return context;
+ }
return NULL;
}