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