diff options
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.h | 389 |
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 | |||
| 27 | namespace kodi | ||
| 28 | { | ||
| 29 | namespace gui | ||
| 30 | { | ||
| 31 | namespace gl | ||
| 32 | { | ||
| 33 | |||
| 34 | class ATTRIBUTE_HIDDEN CGLonDX : public kodi::gui::IRenderHelper | ||
| 35 | { | ||
| 36 | public: | ||
| 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 | |||
| 164 | private: | ||
| 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 | |||
| 385 | using CRenderHelper = gl::CGLonDX; | ||
| 386 | } /* namespace gui */ | ||
| 387 | } /* namespace kodi */ | ||
| 388 | |||
| 389 | #endif /* __cplusplus */ | ||
