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