From 5f8335c1e49ce108ef3481863833c98efa00411b Mon Sep 17 00:00:00 2001 From: manuel Date: Thu, 2 Jul 2020 23:09:26 +0200 Subject: sync with upstream --- .../include/kodi/gui/gl/GLonDX.h | 369 +++++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h (limited to 'xbmc/addons/kodi-addon-dev-kit/include/kodi/gui/gl/GLonDX.h') 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 @@ +/* + * Copyright (C) 2005-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma comment( lib, "d3dcompiler.lib" ) +#ifndef GL_CLIENT_VERSION +#define GL_CLIENT_VERSION 3 +#endif + +namespace kodi +{ +namespace gui +{ +namespace gl +{ + +class ATTRIBUTE_HIDDEN CGLonDX : public kodi::gui::IRenderHelper +{ +public: + explicit CGLonDX() : m_pContext(reinterpret_cast(kodi::gui::GetHWContext())) {} + ~CGLonDX() override { destruct(); } + + bool Init() override + { + EGLint egl_display_attrs[] = + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE, + EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE, + EGL_NONE + }; + EGLint egl_config_attrs[] = + { + EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, + EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE, + EGL_RENDERABLE_TYPE, GL_CLIENT_VERSION == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_NONE + }; + EGLint egl_context_attrs[] = + { + EGL_CONTEXT_CLIENT_VERSION, GL_CLIENT_VERSION, EGL_NONE + }; + + m_eglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, egl_display_attrs); + if (m_eglDisplay == EGL_NO_DISPLAY) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL display (%s)", eglGetErrorString()); + return false; + } + + if (eglInitialize(m_eglDisplay, nullptr, nullptr) != EGL_TRUE) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to init EGL display (%s)", eglGetErrorString()); + return false; + } + + EGLint numConfigs = 0; + if (eglChooseConfig(m_eglDisplay, egl_config_attrs, &m_eglConfig, 1, &numConfigs) != EGL_TRUE || numConfigs == 0) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to get EGL config (%s)", eglGetErrorString()); + return false; + } + + m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, nullptr, egl_context_attrs); + if (m_eglContext == EGL_NO_CONTEXT) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL context (%s)", eglGetErrorString()); + return false; + } + + if (!createD3DResources()) + return false; + + if (eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext) != EGL_TRUE) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to make current EGL (%s)", eglGetErrorString()); + return false; + } + return true; + } + + void CheckGL(ID3D11DeviceContext* device) + { + if (m_pContext != device) + { + m_pSRView = nullptr; + m_pVShader = nullptr; + m_pPShader = nullptr; + m_pContext = device; + + if (m_eglBuffer != EGL_NO_SURFACE) + { + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(m_eglDisplay, m_eglBuffer); + m_eglBuffer = EGL_NO_SURFACE; + } + + // create new resources + if (!createD3DResources()) + return; + + eglMakeCurrent(m_eglDisplay, m_eglBuffer, m_eglBuffer, m_eglContext); + } + } + + void Begin() override + { + // confirm on begin D3D context is correct + CheckGL(reinterpret_cast(kodi::gui::GetHWContext())); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + } + + void End() override + { + glFlush(); + + // set our primitive shaders + m_pContext->VSSetShader(m_pVShader.Get(), nullptr, 0); + m_pContext->PSSetShader(m_pPShader.Get(), nullptr, 0); + m_pContext->PSSetShaderResources(0, 1, m_pSRView.GetAddressOf()); + // draw texture + m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_pContext->IASetVertexBuffers(0, 0, nullptr, nullptr, nullptr); + m_pContext->IASetInputLayout(nullptr); + m_pContext->Draw(4, 0); + // unset shaders + m_pContext->PSSetShader(nullptr, nullptr, 0); + m_pContext->VSSetShader(nullptr, nullptr, 0); + // unbind our view + ID3D11ShaderResourceView* views[1] = {}; + m_pContext->PSSetShaderResources(0, 1, views); + } + +private: + enum ShaderType + { + VERTEX_SHADER, + PIXEL_SHADER + }; + + bool createD3DResources() + { + HANDLE sharedHandle; + Microsoft::WRL::ComPtr pDevice; + Microsoft::WRL::ComPtr pRTView; + Microsoft::WRL::ComPtr pRTResource; + Microsoft::WRL::ComPtr pRTTexture; + Microsoft::WRL::ComPtr pOffScreenTexture; + Microsoft::WRL::ComPtr dxgiResource; + + m_pContext->GetDevice(&pDevice); + m_pContext->OMGetRenderTargets(1, &pRTView, nullptr); + if (!pRTView) + return false; + + pRTView->GetResource(&pRTResource); + if (FAILED(pRTResource.As(&pRTTexture))) + return false; + + D3D11_TEXTURE2D_DESC texDesc; + pRTTexture->GetDesc(&texDesc); + texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; + if (FAILED(pDevice->CreateTexture2D(&texDesc, nullptr, &pOffScreenTexture))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create intermediate texture"); + return false; + } + + CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(pOffScreenTexture.Get(), D3D11_SRV_DIMENSION_TEXTURE2D); + if (FAILED(pDevice->CreateShaderResourceView(pOffScreenTexture.Get(), &srvDesc, &m_pSRView))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create shader view"); + return false; + } + + if (FAILED(pOffScreenTexture.As(&dxgiResource)) || + FAILED(dxgiResource->GetSharedHandle(&sharedHandle))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable get shared handle for texture"); + return false; + } + + // initiate simple shaders + if (FAILED(d3dCreateShader(VERTEX_SHADER, vs_out_shader_text, &m_pVShader))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create vertex shader view"); + return false; + } + + if (FAILED(d3dCreateShader(PIXEL_SHADER, ps_out_shader_text, &m_pPShader))) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create pixel shader view"); + return false; + } + + // create EGL buffer from D3D shared texture + EGLint egl_buffer_attrs[] = + { + EGL_WIDTH, static_cast(texDesc.Width), + EGL_HEIGHT, static_cast(texDesc.Height), + EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_NONE + }; + + m_eglBuffer = eglCreatePbufferFromClientBuffer(m_eglDisplay, + EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, + sharedHandle, m_eglConfig, egl_buffer_attrs); + + if (m_eglBuffer == EGL_NO_SURFACE) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create EGL buffer (%s)", eglGetErrorString()); + return false; + } + return true; + } + + HRESULT d3dCreateShader(ShaderType shaderType, const std::string& source, IUnknown** ppShader) const + { + Microsoft::WRL::ComPtr pBlob; + Microsoft::WRL::ComPtr pErrors; + + auto hr = D3DCompile(source.c_str(), source.length(), nullptr, nullptr, nullptr, "main", + shaderType == PIXEL_SHADER ? "ps_4_0" : "vs_4_0", 0, 0, &pBlob, &pErrors); + + if (SUCCEEDED(hr)) + { + Microsoft::WRL::ComPtr pDevice; + m_pContext->GetDevice(&pDevice); + + if (shaderType == PIXEL_SHADER) + { + hr = pDevice->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, + reinterpret_cast(ppShader)); + } + else + { + hr = pDevice->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, + reinterpret_cast(ppShader)); + } + + if (FAILED(hr)) + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to create %s shader", + shaderType == PIXEL_SHADER ? "pixel" : "vertex"); + } + } + else + { + Log(ADDON_LOG_ERROR, "GLonDX: unable to compile shader (%s)", pErrors->GetBufferPointer()); + } + return hr; + } + + static const char* eglGetErrorString() + { +#define CASE_STR( value ) case value: return #value + switch (eglGetError()) + { + CASE_STR(EGL_SUCCESS); + CASE_STR(EGL_NOT_INITIALIZED); + CASE_STR(EGL_BAD_ACCESS); + CASE_STR(EGL_BAD_ALLOC); + CASE_STR(EGL_BAD_ATTRIBUTE); + CASE_STR(EGL_BAD_CONTEXT); + CASE_STR(EGL_BAD_CONFIG); + CASE_STR(EGL_BAD_CURRENT_SURFACE); + CASE_STR(EGL_BAD_DISPLAY); + CASE_STR(EGL_BAD_SURFACE); + CASE_STR(EGL_BAD_MATCH); + CASE_STR(EGL_BAD_PARAMETER); + CASE_STR(EGL_BAD_NATIVE_PIXMAP); + CASE_STR(EGL_BAD_NATIVE_WINDOW); + CASE_STR(EGL_CONTEXT_LOST); + default: + return "Unknown"; + } +#undef CASE_STR + } + + void destruct() + { + if (m_eglDisplay != EGL_NO_DISPLAY) + { + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + if (m_eglBuffer != EGL_NO_SURFACE) + { + eglDestroySurface(m_eglDisplay, m_eglBuffer); + m_eglBuffer = EGL_NO_SURFACE; + } + + if (m_eglContext != EGL_NO_CONTEXT) + { + eglDestroyContext(m_eglDisplay, m_eglContext); + m_eglContext = EGL_NO_CONTEXT; + } + + eglTerminate(m_eglDisplay); + m_eglDisplay = EGL_NO_DISPLAY; + } + + m_pSRView = nullptr; + m_pVShader = nullptr; + m_pPShader = nullptr; + m_pContext = nullptr; + } + + EGLConfig m_eglConfig = EGL_NO_CONFIG_KHR; + EGLDisplay m_eglDisplay = EGL_NO_DISPLAY; + EGLContext m_eglContext = EGL_NO_CONTEXT; + EGLSurface m_eglBuffer = EGL_NO_SURFACE; + + ID3D11DeviceContext* m_pContext = nullptr; // don't hold context + Microsoft::WRL::ComPtr m_pSRView = nullptr; + Microsoft::WRL::ComPtr m_pVShader = nullptr; + Microsoft::WRL::ComPtr m_pPShader = nullptr; + +#define TO_STRING(...) #__VA_ARGS__ + std::string vs_out_shader_text = TO_STRING( + void main(uint id : SV_VertexId, out float2 tex : TEXCOORD0, out float4 pos : SV_POSITION) + { + tex = float2(id % 2, (id % 4) >> 1); + pos = float4((tex.x - 0.5f) * 2, -(tex.y - 0.5f) * 2, 0, 1); + }); + + std::string ps_out_shader_text = TO_STRING( + Texture2D texMain : register(t0); + SamplerState Sampler + { + Filter = MIN_MAG_MIP_LINEAR; + AddressU = CLAMP; + AddressV = CLAMP; + Comparison = NEVER; + }; + + float4 main(in float2 tex : TEXCOORD0) : SV_TARGET + { + return texMain.Sample(Sampler, tex); + }); +#undef TO_STRING +}; /* class CGLonDX */ + +} /* namespace gl */ + +using CRenderHelper = gl::CGLonDX; +} /* namespace gui */ +} /* namespace kodi */ -- cgit v1.2.3