Merge branch 'master' into soc-2019-openxr
[blender.git] / intern / ghost / intern / GHOST_XrGraphicsBinding.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup GHOST
19  */
20
21 #include <algorithm>
22 #include <list>
23
24 #if defined(WITH_X11)
25 #  include "GHOST_ContextGLX.h"
26 #elif defined(WIN32)
27 #  include "GHOST_ContextWGL.h"
28 #  include "GHOST_ContextD3D.h"
29 #endif
30 #include "GHOST_C-api.h"
31 #include "GHOST_Xr_intern.h"
32
33 #include "GHOST_IXrGraphicsBinding.h"
34
35 static bool choose_swapchain_format_from_candidates(std::vector<int64_t> gpu_binding_formats,
36                                                     std::vector<int64_t> runtime_formats,
37                                                     int64_t *r_result)
38 {
39   if (gpu_binding_formats.empty()) {
40     return false;
41   }
42
43   auto res = std::find_first_of(gpu_binding_formats.begin(),
44                                 gpu_binding_formats.end(),
45                                 runtime_formats.begin(),
46                                 runtime_formats.end());
47   if (res == gpu_binding_formats.end()) {
48     return false;
49   }
50
51   *r_result = *res;
52   return true;
53 }
54
55 class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
56  public:
57   void initFromGhostContext(GHOST_Context *ghost_ctx) override
58   {
59 #if defined(WITH_X11)
60     GHOST_ContextGLX *ctx_glx = static_cast<GHOST_ContextGLX *>(ghost_ctx);
61     XVisualInfo *visual_info = glXGetVisualFromFBConfig(ctx_glx->m_display, ctx_glx->m_fbconfig);
62
63     oxr_binding.glx.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
64     oxr_binding.glx.xDisplay = ctx_glx->m_display;
65     oxr_binding.glx.glxFBConfig = ctx_glx->m_fbconfig;
66     oxr_binding.glx.glxDrawable = ctx_glx->m_window;
67     oxr_binding.glx.glxContext = ctx_glx->m_context;
68     oxr_binding.glx.visualid = visual_info->visualid;
69 #elif defined(WIN32)
70     GHOST_ContextWGL *ctx_wgl = static_cast<GHOST_ContextWGL *>(ghost_ctx);
71
72     oxr_binding.wgl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
73     oxr_binding.wgl.hDC = ctx_wgl->m_hDC;
74     oxr_binding.wgl.hGLRC = ctx_wgl->m_hGLRC;
75 #endif
76   }
77
78   bool chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
79                              int64_t *r_result) const override
80   {
81     std::vector<int64_t> gpu_binding_formats = {GL_RGBA8};
82     return choose_swapchain_format_from_candidates(gpu_binding_formats, runtime_formats, r_result);
83   }
84
85   std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(uint32_t image_count) override
86   {
87     std::vector<XrSwapchainImageOpenGLKHR> ogl_images(image_count);
88     std::vector<XrSwapchainImageBaseHeader *> base_images;
89
90     // Need to return vector of base header pointers, so of a different type. Need to build a new
91     // list with this type, and keep the initial one alive.
92     for (XrSwapchainImageOpenGLKHR &image : ogl_images) {
93       image.type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
94       base_images.push_back(reinterpret_cast<XrSwapchainImageBaseHeader *>(&image));
95     }
96
97     // Keep alive.
98     m_image_cache.push_back(std::move(ogl_images));
99
100     return base_images;
101   }
102
103   void drawViewBegin(XrSwapchainImageBaseHeader *swapchain_image) override
104   {
105     // TODO
106     (void)swapchain_image;
107   }
108   void drawViewEnd(XrSwapchainImageBaseHeader *swapchain_image, GHOST_Context *ogl_ctx) override
109   {
110     // TODO
111     (void)swapchain_image;
112     (void)ogl_ctx;
113   }
114
115  private:
116   std::list<std::vector<XrSwapchainImageOpenGLKHR>> m_image_cache;
117 };
118
119 #ifdef WIN32
120 class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
121  public:
122   void initFromGhostContext(GHOST_Context *ghost_ctx) override
123   {
124     GHOST_ContextD3D *ctx_d3d = static_cast<GHOST_ContextD3D *>(ghost_ctx);
125
126     oxr_binding.d3d11.type = XR_TYPE_GRAPHICS_BINDING_D3D11_KHR;
127     oxr_binding.d3d11.device = ctx_d3d->m_device;
128     m_ghost_ctx = ctx_d3d;
129   }
130
131   bool chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
132                              int64_t *r_result) const override
133   {
134     std::vector<int64_t> gpu_binding_formats = {DXGI_FORMAT_R8G8B8A8_UNORM};
135     return choose_swapchain_format_from_candidates(gpu_binding_formats, runtime_formats, r_result);
136   }
137
138   std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(uint32_t image_count) override
139   {
140     std::vector<XrSwapchainImageD3D11KHR> d3d_images(image_count);
141     std::vector<XrSwapchainImageBaseHeader *> base_images;
142
143     // Need to return vector of base header pointers, so of a different type. Need to build a new
144     // list with this type, and keep the initial one alive.
145     for (XrSwapchainImageD3D11KHR &image : d3d_images) {
146       image.type = XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR;
147       base_images.push_back(reinterpret_cast<XrSwapchainImageBaseHeader *>(&image));
148     }
149
150     // Keep alive.
151     m_image_cache.push_back(std::move(d3d_images));
152
153     return base_images;
154   }
155
156   void drawViewBegin(XrSwapchainImageBaseHeader * /*swapchain_image*/) override
157   {
158   }
159   void drawViewEnd(XrSwapchainImageBaseHeader *swapchain_image, GHOST_Context *ogl_ctx) override
160   {
161     XrSwapchainImageD3D11KHR *d3d_swapchain_image = reinterpret_cast<XrSwapchainImageD3D11KHR *>(
162         swapchain_image);
163
164 #  if 0
165     /* Ideally we'd just create a render target view for the OpenXR swapchain image texture and
166      * blit from the OpenGL context into it. The NV_DX_interop extension doesn't want to work with
167      * this though. At least not with Optimus hardware. See:
168      * https://github.com/mpv-player/mpv/issues/2949#issuecomment-197262807.
169      * Note: Even if this worked, the blitting code only supports one shared resource by now, we'd
170      * need at least two (for each eye). We could also entirely re-register shared resources all
171      * the time. Also, the runtime might recreate the swapchain image so the shared resource would
172      * have to be re-registered then as well. */
173
174     ID3D11RenderTargetView *rtv;
175     CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D,
176                                             DXGI_FORMAT_R8G8B8A8_UNORM);
177     D3D11_TEXTURE2D_DESC tex_desc;
178
179     d3d_swapchain_image->texture->GetDesc(&tex_desc);
180
181     m_ghost_ctx->m_device->CreateRenderTargetView(d3d_swapchain_image->texture, &rtv_desc, &rtv);
182     m_ghost_ctx->blitOpenGLOffscreenContext(ogl_ctx, rtv, tex_desc.Width, tex_desc.Height);
183 #  else
184     ID3D11Resource *res;
185     ID3D11Texture2D *tex;
186     D3D11_TEXTURE2D_DESC tex_desc;
187
188     d3d_swapchain_image->texture->GetDesc(&tex_desc);
189
190     ogl_ctx->activateDrawingContext();
191     m_ghost_ctx->blitOpenGLOffscreenContext(ogl_ctx, tex_desc.Width, tex_desc.Height);
192
193     m_ghost_ctx->m_backbuffer_view->GetResource(&res);
194     res->QueryInterface<ID3D11Texture2D>(&tex);
195
196     m_ghost_ctx->m_device_ctx->OMSetRenderTargets(0, nullptr, nullptr);
197     m_ghost_ctx->m_device_ctx->CopyResource(d3d_swapchain_image->texture, tex);
198
199     res->Release();
200     tex->Release();
201 #  endif
202   }
203
204  private:
205   GHOST_ContextD3D *m_ghost_ctx;
206   std::list<std::vector<XrSwapchainImageD3D11KHR>> m_image_cache;
207 };
208 #endif  // WIN32
209
210 std::unique_ptr<GHOST_IXrGraphicsBinding> GHOST_XrGraphicsBindingCreateFromType(
211     GHOST_TXrGraphicsBinding type)
212 {
213   switch (type) {
214     case GHOST_kXrGraphicsOpenGL:
215       return std::unique_ptr<GHOST_XrGraphicsBindingOpenGL>(new GHOST_XrGraphicsBindingOpenGL());
216 #ifdef WIN32
217     case GHOST_kXrGraphicsD3D11:
218       return std::unique_ptr<GHOST_XrGraphicsBindingD3D>(new GHOST_XrGraphicsBindingD3D());
219 #endif
220     default:
221       return nullptr;
222   }
223 }