summaryrefslogtreecommitdiffstats
path: root/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h')
-rw-r--r--xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h389
1 files changed, 389 insertions, 0 deletions
diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h
new file mode 100644
index 0000000..4dd97af
--- /dev/null
+++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h
@@ -0,0 +1,389 @@
1/*
2 * Copyright (C) 2005-2019 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#pragma once
10
11#ifdef __cplusplus
12
13#include <EGL/egl.h>
14#include <EGL/eglext.h>
15#include <angle_gl.h>
16#include <d3d11.h>
17#include <d3dcompiler.h>
18#include <kodi/AddonBase.h>
19#include <kodi/gui/General.h>
20#include <wrl/client.h>
21
22#pragma comment(lib, "d3dcompiler.lib")
23#ifndef GL_CLIENT_VERSION
24#define GL_CLIENT_VERSION 3
25#endif
26
27namespace kodi
28{
29namespace gui
30{
31namespace gl
32{
33
34class ATTRIBUTE_HIDDEN CGLonDX : public kodi::gui::IRenderHelper
35{
36public:
37 explicit CGLonDX() : m_pContext(reinterpret_cast<ID3D11DeviceContext*>(kodi::gui::GetHWContext()))
38 {
39 }
40 ~CGLonDX() override { destruct(); }
41
42 bool Init() override
43 {
44 EGLint egl_display_attrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE,
45 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
46 EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
47 EGL_DONT_CARE,
48 EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
49 EGL_DONT_CARE,
50 EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE,
51 EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE,
52 EGL_NONE};
53 EGLint egl_config_attrs[] = {EGL_RED_SIZE,
54 8,
55 EGL_GREEN_SIZE,
56 8,
57 EGL_BLUE_SIZE,
58 8,
59 EGL_ALPHA_SIZE,
60 8,
61 EGL_BIND_TO_TEXTURE_RGBA,
62 EGL_TRUE,
63 EGL_RENDERABLE_TYPE,
64 GL_CLIENT_VERSION == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT,
65 EGL_SURFACE_TYPE,
66 EGL_PBUFFER_BIT,
67 EGL_NONE};
68 EGLint egl_context_attrs[] = {EGL_CONTEXT_CLIENT_VERSION, GL_CLIENT_VERSION, EGL_NONE};
69
70 m_eglDisplay =
71 eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, egl_display_attrs);
72 if (m_eglDisplay == EGL_NO_DISPLAY)
73 {
74 Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL display (%s)", eglGetErrorString());
75 return false;
76 }
77
78 if (eglInitialize(m_eglDisplay, nullptr, nullptr) != EGL_TRUE)
79 {
80 Log(ADDON_LOG_ERROR, "GLonDX: unable to init EGL display (%s)", eglGetErrorString());
81 return false;
82 }
83
84 EGLint numConfigs = 0;
85 if (eglChooseConfig(m_eglDisplay, egl_config_attrs, &m_eglConfig, 1, &numConfigs) != EGL_TRUE ||
86 numConfigs == 0)
87 {
88 Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL config (%s)", eglGetErrorString());
89 return false;
90 }
91
92 m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, nullptr, egl_context_attrs);
93 if (m_eglContext == EGL_NO_CONTEXT)
94 {
95 Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL context (%s)", eglGetErrorString());
96 return false;
97 }
98
99 if (!createD3DResources())
100 return false;
101
102 if (eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext) != EGL_TRUE)
103 {
104 Log(ADDON_LOG_ERROR, "GLonDX: unable to make current EGL (%s)", eglGetErrorString());
105 return false;
106 }
107 return true;
108 }
109
110 void CheckGL(ID3D11DeviceContext* device)
111 {
112 if (m_pContext != device)
113 {
114 m_pSRView = nullptr;
115 m_pVShader = nullptr;
116 m_pPShader = nullptr;
117 m_pContext = device;
118
119 if (m_eglBuffer != EGL_NO_SURFACE)
120 {
121 eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
122 eglDestroySurface(m_eglDisplay, m_eglBuffer);
123 m_eglBuffer = EGL_NO_SURFACE;
124 }
125
126 // create new resources
127 if (!createD3DResources())
128 return;
129
130 eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext);
131 }
132 }
133
134 void Begin() override
135 {
136 // confirm on begin D3D context is correct
137 CheckGL(reinterpret_cast<ID3D11DeviceContext*>(kodi::gui::GetHWContext()));
138
139 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
140 glClear(GL_COLOR_BUFFER_BIT);
141 }
142
143 void End() override
144 {
145 glFlush();
146
147 // set our primitive shaders
148 m_pContext->VSSetShader(m_pVShader.Get(), nullptr, 0);
149 m_pContext->PSSetShader(m_pPShader.Get(), nullptr, 0);
150 m_pContext->PSSetShaderResources(0, 1, m_pSRView.GetAddressOf());
151 // draw texture
152 m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
153 m_pContext->IASetVertexBuffers(0, 0, nullptr, nullptr, nullptr);
154 m_pContext->IASetInputLayout(nullptr);
155 m_pContext->Draw(4, 0);
156 // unset shaders
157 m_pContext->PSSetShader(nullptr, nullptr, 0);
158 m_pContext->VSSetShader(nullptr, nullptr, 0);
159 // unbind our view
160 ID3D11ShaderResourceView* views[1] = {};
161 m_pContext->PSSetShaderResources(0, 1, views);
162 }
163
164private:
165 enum ShaderType
166 {
167 VERTEX_SHADER,
168 PIXEL_SHADER
169 };
170
171 bool createD3DResources()
172 {
173 HANDLE sharedHandle;
174 Microsoft::WRL::ComPtr<ID3D11Device> pDevice;
175 Microsoft::WRL::ComPtr<ID3D11RenderTargetView> pRTView;
176 Microsoft::WRL::ComPtr<ID3D11Resource> pRTResource;
177 Microsoft::WRL::ComPtr<ID3D11Texture2D> pRTTexture;
178 Microsoft::WRL::ComPtr<ID3D11Texture2D> pOffScreenTexture;
179 Microsoft::WRL::ComPtr<IDXGIResource> dxgiResource;
180
181 m_pContext->GetDevice(&pDevice);
182 m_pContext->OMGetRenderTargets(1, &pRTView, nullptr);
183 if (!pRTView)
184 return false;
185
186 pRTView->GetResource(&pRTResource);
187 if (FAILED(pRTResource.As(&pRTTexture)))
188 return false;
189
190 D3D11_TEXTURE2D_DESC texDesc;
191 pRTTexture->GetDesc(&texDesc);
192 texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
193 texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
194 texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
195 if (FAILED(pDevice->CreateTexture2D(&texDesc, nullptr, &pOffScreenTexture)))
196 {
197 Log(ADDON_LOG_ERROR, "GLonDX: unable to create intermediate texture");
198 return false;
199 }
200
201 CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(pOffScreenTexture.Get(),
202 D3D11_SRV_DIMENSION_TEXTURE2D);
203 if (FAILED(pDevice->CreateShaderResourceView(pOffScreenTexture.Get(), &srvDesc, &m_pSRView)))
204 {
205 Log(ADDON_LOG_ERROR, "GLonDX: unable to create shader view");
206 return false;
207 }
208
209 if (FAILED(pOffScreenTexture.As(&dxgiResource)) ||
210 FAILED(dxgiResource->GetSharedHandle(&sharedHandle)))
211 {
212 Log(ADDON_LOG_ERROR, "GLonDX: unable get shared handle for texture");
213 return false;
214 }
215
216 // initiate simple shaders
217 if (FAILED(d3dCreateShader(VERTEX_SHADER, vs_out_shader_text, &m_pVShader)))
218 {
219 Log(ADDON_LOG_ERROR, "GLonDX: unable to create vertex shader view");
220 return false;
221 }
222
223 if (FAILED(d3dCreateShader(PIXEL_SHADER, ps_out_shader_text, &m_pPShader)))
224 {
225 Log(ADDON_LOG_ERROR, "GLonDX: unable to create pixel shader view");
226 return false;
227 }
228
229 // create EGL buffer from D3D shared texture
230 EGLint egl_buffer_attrs[] = {EGL_WIDTH,
231 static_cast<EGLint>(texDesc.Width),
232 EGL_HEIGHT,
233 static_cast<EGLint>(texDesc.Height),
234 EGL_TEXTURE_TARGET,
235 EGL_TEXTURE_2D,
236 EGL_TEXTURE_FORMAT,
237 EGL_TEXTURE_RGBA,
238 EGL_NONE};
239
240 m_eglBuffer =
241 eglCreatePbufferFromClientBuffer(m_eglDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
242 sharedHandle, m_eglConfig, egl_buffer_attrs);
243
244 if (m_eglBuffer == EGL_NO_SURFACE)
245 {
246 Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL buffer (%s)", eglGetErrorString());
247 return false;
248 }
249 return true;
250 }
251
252 HRESULT d3dCreateShader(ShaderType shaderType,
253 const std::string& source,
254 IUnknown** ppShader) const
255 {
256 Microsoft::WRL::ComPtr<ID3DBlob> pBlob;
257 Microsoft::WRL::ComPtr<ID3DBlob> pErrors;
258
259 auto hr = D3DCompile(source.c_str(), source.length(), nullptr, nullptr, nullptr, "main",
260 shaderType == PIXEL_SHADER ? "ps_4_0" : "vs_4_0", 0, 0, &pBlob, &pErrors);
261
262 if (SUCCEEDED(hr))
263 {
264 Microsoft::WRL::ComPtr<ID3D11Device> pDevice;
265 m_pContext->GetDevice(&pDevice);
266
267 if (shaderType == PIXEL_SHADER)
268 {
269 hr = pDevice->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr,
270 reinterpret_cast<ID3D11PixelShader**>(ppShader));
271 }
272 else
273 {
274 hr = pDevice->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr,
275 reinterpret_cast<ID3D11VertexShader**>(ppShader));
276 }
277
278 if (FAILED(hr))
279 {
280 Log(ADDON_LOG_ERROR, "GLonDX: unable to create %s shader",
281 shaderType == PIXEL_SHADER ? "pixel" : "vertex");
282 }
283 }
284 else
285 {
286 Log(ADDON_LOG_ERROR, "GLonDX: unable to compile shader (%s)", pErrors->GetBufferPointer());
287 }
288 return hr;
289 }
290
291 static const char* eglGetErrorString()
292 {
293#define CASE_STR(value) \
294 case value: \
295 return #value
296 switch (eglGetError())
297 {
298 CASE_STR(EGL_SUCCESS);
299 CASE_STR(EGL_NOT_INITIALIZED);
300 CASE_STR(EGL_BAD_ACCESS);
301 CASE_STR(EGL_BAD_ALLOC);
302 CASE_STR(EGL_BAD_ATTRIBUTE);
303 CASE_STR(EGL_BAD_CONTEXT);
304 CASE_STR(EGL_BAD_CONFIG);
305 CASE_STR(EGL_BAD_CURRENT_SURFACE);
306 CASE_STR(EGL_BAD_DISPLAY);
307 CASE_STR(EGL_BAD_SURFACE);
308 CASE_STR(EGL_BAD_MATCH);
309 CASE_STR(EGL_BAD_PARAMETER);
310 CASE_STR(EGL_BAD_NATIVE_PIXMAP);
311 CASE_STR(EGL_BAD_NATIVE_WINDOW);
312 CASE_STR(EGL_CONTEXT_LOST);
313 default:
314 return "Unknown";
315 }
316#undef CASE_STR
317 }
318
319 void destruct()
320 {
321 if (m_eglDisplay != EGL_NO_DISPLAY)
322 {
323 eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
324
325 if (m_eglBuffer != EGL_NO_SURFACE)
326 {
327 eglDestroySurface(m_eglDisplay, m_eglBuffer);
328 m_eglBuffer = EGL_NO_SURFACE;
329 }
330
331 if (m_eglContext != EGL_NO_CONTEXT)
332 {
333 eglDestroyContext(m_eglDisplay, m_eglContext);
334 m_eglContext = EGL_NO_CONTEXT;
335 }
336
337 eglTerminate(m_eglDisplay);
338 m_eglDisplay = EGL_NO_DISPLAY;
339 }
340
341 m_pSRView = nullptr;
342 m_pVShader = nullptr;
343 m_pPShader = nullptr;
344 m_pContext = nullptr;
345 }
346
347 EGLConfig m_eglConfig = EGL_NO_CONFIG_KHR;
348 EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
349 EGLContext m_eglContext = EGL_NO_CONTEXT;
350 EGLSurface m_eglBuffer = EGL_NO_SURFACE;
351
352 ID3D11DeviceContext* m_pContext = nullptr; // don't hold context
353 Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_pSRView = nullptr;
354 Microsoft::WRL::ComPtr<ID3D11VertexShader> m_pVShader = nullptr;
355 Microsoft::WRL::ComPtr<ID3D11PixelShader> m_pPShader = nullptr;
356
357#define TO_STRING(...) #__VA_ARGS__
358 std::string vs_out_shader_text = TO_STRING(void main(uint id
359 : SV_VertexId, out float2 tex
360 : TEXCOORD0, out float4 pos
361 : SV_POSITION) {
362 tex = float2(id % 2, (id % 4) >> 1);
363 pos = float4((tex.x - 0.5f) * 2, -(tex.y - 0.5f) * 2, 0, 1);
364 });
365
366 std::string ps_out_shader_text = TO_STRING(
367 Texture2D texMain : register(t0);
368 SamplerState Sampler
369 {
370 Filter = MIN_MAG_MIP_LINEAR;
371 AddressU = CLAMP;
372 AddressV = CLAMP;
373 Comparison = NEVER;
374 };
375
376 float4 main(in float2 tex : TEXCOORD0) : SV_TARGET
377 {
378 return texMain.Sample(Sampler, tex);
379 });
380#undef TO_STRING
381}; /* class CGLonDX */
382
383} /* namespace gl */
384
385using CRenderHelper = gl::CGLonDX;
386} /* namespace gui */
387} /* namespace kodi */
388
389#endif /* __cplusplus */