summaryrefslogtreecommitdiffstats
path: root/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
committermanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
commitbe933ef2241d79558f91796cc5b3a161f72ebf9c (patch)
treefe3ab2f130e20c99001f2d7a81d610c78c96a3f4 /xbmc/addons/kodi-dev-kit/include/kodi/gui/gl
parent5f8335c1e49ce108ef3481863833c98efa00411b (diff)
downloadkodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.gz
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.bz2
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.zip
sync with upstream
Diffstat (limited to 'xbmc/addons/kodi-dev-kit/include/kodi/gui/gl')
-rw-r--r--xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/CMakeLists.txt7
-rw-r--r--xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GL.h112
-rw-r--r--xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GLonDX.h389
-rw-r--r--xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/Shader.h571
4 files changed, 1079 insertions, 0 deletions
diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/CMakeLists.txt b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/CMakeLists.txt
new file mode 100644
index 0000000..844902d
--- /dev/null
+++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/CMakeLists.txt
@@ -0,0 +1,7 @@
1set(HEADERS GL.h
2 GLonDX.h
3 Shader.h)
4
5if(NOT ENABLE_STATIC_LIBS)
6 core_add_library(addons_kodi-dev-kit_include_kodi_gui_gl)
7endif()
diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GL.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GL.h
new file mode 100644
index 0000000..16d43e3
--- /dev/null
+++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/GL.h
@@ -0,0 +1,112 @@
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//==============================================================================
14/// @defgroup cpp_kodi_gui_helpers_gl OpenGL helpers
15/// @ingroup cpp_kodi_gui_helpers
16/// @brief **Auxiliary functions for Open GL**\n
17/// This group includes help for definitions, functions, and classes for
18/// OpenGL.
19///
20/// To use OpenGL for your system, add the @ref GL.h "#include <kodi/gui/gl/GL.h>".
21///
22/// The @ref HAS_GL is declared if Open GL is required and @ref HAS_GLES if Open GL
23/// Embedded Systems (ES) is required, with ES the version is additionally given
24/// in the definition, this can be "2" or "3".
25///
26///
27///-----------------------------------------------------------------------------
28///
29/// Following @ref GL_TYPE_STRING define can be used, for example, to manage
30/// different folders for GL and GLES and make the selection easier.
31/// This are on OpenGL <b>"GL"</b> and on Open GL|ES <b>"GLES"</b>.
32///
33/// **Example:**
34/// ~~~~~~~~~~~~~~~~~{.cpp}
35/// kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/frag.glsl");
36/// ~~~~~~~~~~~~~~~~~
37///
38///
39///----------------------------------------------------------------------------
40///
41/// In addition, @ref BUFFER_OFFSET is declared in it which can be used to give an
42/// offset on the array to GL.
43///
44/// **Example:**
45/// ~~~~~~~~~~~~~~~~~{.cpp}
46/// const struct PackedVertex {
47/// float position[3]; // Position x, y, z
48/// float color[4]; // Color r, g, b, a
49/// } vertices[3] = {
50/// { { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
51/// { { 0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
52/// { { 0.0f, 0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }
53/// };
54///
55/// glVertexAttribPointer(m_aPosition, 3, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), BUFFER_OFFSET(offsetof(PackedVertex, position)));
56/// glEnableVertexAttribArray(m_aPosition);
57///
58/// glVertexAttribPointer(m_aColor, 4, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), BUFFER_OFFSET(offsetof(PackedVertex, color)));
59/// glEnableVertexAttribArray(m_aColor);
60/// ~~~~~~~~~~~~~~~~~
61
62#if HAS_GL
63#define GL_TYPE_STRING "GL"
64// always define GL_GLEXT_PROTOTYPES before include gl headers
65#if !defined(GL_GLEXT_PROTOTYPES)
66#define GL_GLEXT_PROTOTYPES
67#endif
68#if defined(TARGET_LINUX)
69#include <GL/gl.h>
70#include <GL/glext.h>
71#elif defined(TARGET_FREEBSD)
72#include <GL/gl.h>
73#elif defined(TARGET_DARWIN)
74#include <OpenGL/gl3.h>
75#include <OpenGL/gl3ext.h>
76#elif defined(WIN32)
77#error Use of GL under Windows is not possible
78#endif
79#elif HAS_GLES >= 2
80#define GL_TYPE_STRING "GLES"
81#if defined(WIN32)
82#if defined(HAS_ANGLE)
83#include <angle_gl.h>
84#else
85#error Use of GLES only be available under Windows by the use of angle
86#endif
87#elif defined(TARGET_DARWIN)
88#if HAS_GLES == 3
89#include <OpenGLES/ES3/gl.h>
90#include <OpenGLES/ES3/glext.h>
91#else
92#include <OpenGLES/ES2/gl.h>
93#include <OpenGLES/ES2/glext.h>
94#endif
95#else
96#if HAS_GLES == 3
97#include <GLES3/gl3.h>
98#include <GLES3/gl3ext.h>
99#else
100#include <GLES2/gl2.h>
101#include <GLES2/gl2ext.h>
102#endif
103#endif
104#endif
105
106#ifndef BUFFER_OFFSET
107/// @ingroup cpp_kodi_gui_helpers_gl
108/// @brief To give a offset number as pointer value.
109#define BUFFER_OFFSET(i) ((char*)nullptr + (i))
110#endif
111
112#endif /* __cplusplus */
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 */
diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/Shader.h b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/Shader.h
new file mode 100644
index 0000000..bf6d48c
--- /dev/null
+++ b/xbmc/addons/kodi-dev-kit/include/kodi/gui/gl/Shader.h
@@ -0,0 +1,571 @@
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 "GL.h"
12
13#ifdef __cplusplus
14
15#include <stdio.h>
16#include <string>
17#include <vector>
18
19#include <kodi/AddonBase.h>
20#include <kodi/Filesystem.h>
21
22#define LOG_SIZE 1024
23#define GLchar char
24
25namespace kodi
26{
27namespace gui
28{
29namespace gl
30{
31
32//========================================================================
33/// CShader - base class
34class ATTRIBUTE_HIDDEN CShader
35{
36public:
37 CShader() = default;
38 virtual ~CShader() = default;
39 virtual bool Compile(const std::string& extraBegin = "", const std::string& extraEnd = "") = 0;
40 virtual void Free() = 0;
41 virtual GLuint Handle() = 0;
42
43 bool LoadSource(const std::string& file)
44 {
45 char buffer[16384];
46
47 kodi::vfs::CFile source;
48 if (!source.OpenFile(file))
49 {
50 kodi::Log(ADDON_LOG_ERROR, "CShader::%s: Failed to open file '%s'", __FUNCTION__,
51 file.c_str());
52 return false;
53 }
54 size_t len = source.Read(buffer, sizeof(buffer));
55 m_source.assign(buffer);
56 m_source[len] = 0;
57 source.Close();
58 return true;
59 }
60
61 bool OK() const { return m_compiled; }
62
63protected:
64 std::string m_source;
65 std::string m_lastLog;
66 bool m_compiled = false;
67};
68//------------------------------------------------------------------------
69
70//========================================================================
71/// CVertexShader
72class ATTRIBUTE_HIDDEN CVertexShader : public CShader
73{
74public:
75 CVertexShader() = default;
76 ~CVertexShader() override { Free(); }
77
78 void Free() override
79 {
80 if (m_vertexShader)
81 glDeleteShader(m_vertexShader);
82 m_vertexShader = 0;
83 }
84
85 bool Compile(const std::string& extraBegin = "", const std::string& extraEnd = "") override
86 {
87 GLint params[4];
88
89 Free();
90
91 m_vertexShader = glCreateShader(GL_VERTEX_SHADER);
92
93 GLsizei count = 0;
94 const char* sources[3];
95 if (!extraBegin.empty())
96 sources[count++] = extraBegin.c_str();
97 if (!m_source.empty())
98 sources[count++] = m_source.c_str();
99 if (!extraEnd.empty())
100 sources[count++] = extraEnd.c_str();
101
102 glShaderSource(m_vertexShader, count, sources, nullptr);
103 glCompileShader(m_vertexShader);
104 glGetShaderiv(m_vertexShader, GL_COMPILE_STATUS, params);
105 if (params[0] != GL_TRUE)
106 {
107 GLchar log[LOG_SIZE];
108 glGetShaderInfoLog(m_vertexShader, LOG_SIZE, nullptr, log);
109 kodi::Log(ADDON_LOG_ERROR, "CVertexShader::%s: %s", __FUNCTION__, log);
110 fprintf(stderr, "CVertexShader::%s: %s\n", __FUNCTION__, log);
111 m_lastLog = log;
112 m_compiled = false;
113 }
114 else
115 {
116 GLchar log[LOG_SIZE];
117 glGetShaderInfoLog(m_vertexShader, LOG_SIZE, nullptr, log);
118 m_lastLog = log;
119 m_compiled = true;
120 }
121 return m_compiled;
122 }
123
124 GLuint Handle() override { return m_vertexShader; }
125
126protected:
127 GLuint m_vertexShader = 0;
128};
129//------------------------------------------------------------------------
130
131//========================================================================
132/// CPixelShader
133class ATTRIBUTE_HIDDEN CPixelShader : public CShader
134{
135public:
136 CPixelShader() = default;
137 ~CPixelShader() { Free(); }
138 void Free() override
139 {
140 if (m_pixelShader)
141 glDeleteShader(m_pixelShader);
142 m_pixelShader = 0;
143 }
144
145 bool Compile(const std::string& extraBegin = "", const std::string& extraEnd = "") override
146 {
147 GLint params[4];
148
149 Free();
150
151 m_pixelShader = glCreateShader(GL_FRAGMENT_SHADER);
152
153 GLsizei count = 0;
154 const char* sources[3];
155 if (!extraBegin.empty())
156 sources[count++] = extraBegin.c_str();
157 if (!m_source.empty())
158 sources[count++] = m_source.c_str();
159 if (!extraEnd.empty())
160 sources[count++] = extraEnd.c_str();
161
162 glShaderSource(m_pixelShader, count, sources, 0);
163 glCompileShader(m_pixelShader);
164 glGetShaderiv(m_pixelShader, GL_COMPILE_STATUS, params);
165 if (params[0] != GL_TRUE)
166 {
167 GLchar log[LOG_SIZE];
168 glGetShaderInfoLog(m_pixelShader, LOG_SIZE, nullptr, log);
169 kodi::Log(ADDON_LOG_ERROR, "CPixelShader::%s: %s", __FUNCTION__, log);
170 fprintf(stderr, "CPixelShader::%s: %s\n", __FUNCTION__, log);
171 m_lastLog = log;
172 m_compiled = false;
173 }
174 else
175 {
176 GLchar log[LOG_SIZE];
177 glGetShaderInfoLog(m_pixelShader, LOG_SIZE, nullptr, log);
178 m_lastLog = log;
179 m_compiled = true;
180 }
181 return m_compiled;
182 }
183
184 GLuint Handle() override { return m_pixelShader; }
185
186protected:
187 GLuint m_pixelShader = 0;
188};
189//------------------------------------------------------------------------
190
191//============================================================================
192/// @defgroup cpp_kodi_gui_helpers_gl_CShaderProgram GL Shader Program
193/// @ingroup cpp_kodi_gui_helpers_gl
194/// @brief @cpp_class{ kodi::gui::gl::CShaderProgram }
195/// **Class to manage an OpenGL shader program**\n
196/// With this class the used GL shader code can be defined on the GPU and
197/// its variables can be managed between CPU and GPU.
198///
199/// It has the header @ref Shader.h "#include <kodi/gui/gl/Shader.h>"
200/// be included to enjoy it.
201///
202/// ----------------------------------------------------------------------------
203///
204/// <b>Example:</b>
205///
206/// ~~~~~~~~~~~~~{.cpp}
207///
208/// #include <kodi/gui/gl/Shader.h>
209/// ...
210///
211/// class ATTRIBUTE_HIDDEN CExample
212/// : ...,
213/// public kodi::gui::gl::CShaderProgram
214/// {
215/// public:
216/// CExample() = default;
217///
218/// bool Start();
219/// void Render();
220///
221/// // override functions for kodi::gui::gl::CShaderProgram
222/// void OnCompiledAndLinked() override;
223/// bool OnEnabled() override;
224///
225/// private:
226/// ...
227/// GLint m_aPosition = -1;
228/// GLint m_aColor = -1;
229/// };
230///
231/// bool CExample::Start()
232/// {
233/// // Define shaders and load
234/// std::string fraqShader = kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/glsl.frag");
235/// std::string vertShader = kodi::GetAddonPath("resources/shaders/" GL_TYPE_STRING "/glsl.vert");
236/// if (!LoadShaderFiles(vertShader, fraqShader) || !CompileAndLink())
237/// return false;
238///
239/// ...
240/// return true;
241/// }
242///
243/// ...
244///
245/// void CExample::Render()
246/// {
247/// ...
248///
249/// EnableShader();
250/// ...
251/// DO WORK
252/// ...
253/// DisableShader();
254/// }
255///
256/// void CExample::OnCompiledAndLinked()
257/// {
258/// ...
259/// DO YOUR WORK HERE FOR WHAT IS ONE TIME REQUIRED DURING COMPILE OF SHADER, E.G.:
260///
261/// m_aPosition = glGetAttribLocation(ProgramHandle(), "a_position");
262/// m_aColor = glGetAttribLocation(ProgramHandle(), "a_color");
263/// }
264///
265/// bool OnEnabled() override
266/// {
267/// ...
268/// DO YOUR WORK HERE FOR WHAT REQUIRED DURING ENABLE OF SHADER
269/// ...
270/// return true;
271/// }
272///
273/// ADDONCREATOR(CExample);
274/// ~~~~~~~~~~~~~
275///
276class ATTRIBUTE_HIDDEN CShaderProgram
277{
278public:
279 //==========================================================================
280 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
281 /// @brief Construct a new shader.
282 ///
283 /// Load must be done later with @ref LoadShaderFiles.
284 ///
285 CShaderProgram() = default;
286 //--------------------------------------------------------------------------
287
288 //==========================================================================
289 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
290 /// @brief Construct a new shader and load defined shader files.
291 ///
292 /// @param[in] vert Path to used GL vertext shader
293 /// @param[in] frag Path to used GL fragment shader
294 ///
295 CShaderProgram(const std::string& vert, const std::string& frag) { LoadShaderFiles(vert, frag); }
296 //--------------------------------------------------------------------------
297
298 //==========================================================================
299 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
300 /// @brief Destructor.
301 ///
302 virtual ~CShaderProgram() { ShaderFree(); }
303 //--------------------------------------------------------------------------
304
305 //==========================================================================
306 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
307 /// @brief To load manually the needed shader files.
308 ///
309 /// @param[in] vert Path to used GL vertext shader
310 /// @param[in] frag Path to used GL fragment shader
311 ///
312 ///
313 /// @note The use of the files is optional, but it must either be passed over
314 /// here or via @ref CompileAndLink, or both of the source code.
315 ///
316 bool LoadShaderFiles(const std::string& vert, const std::string& frag)
317 {
318 if (!kodi::vfs::FileExists(vert) || !m_pVP.LoadSource(vert))
319 {
320 kodi::Log(ADDON_LOG_ERROR, "%s: Failed to load '%s'", __func__, vert.c_str());
321 return false;
322 }
323
324 if (!kodi::vfs::FileExists(frag) || !m_pFP.LoadSource(frag))
325 {
326 kodi::Log(ADDON_LOG_ERROR, "%s: Failed to load '%s'", __func__, frag.c_str());
327 return false;
328 }
329
330 return true;
331 }
332 //--------------------------------------------------------------------------
333
334 //==========================================================================
335 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
336 /// @brief To compile and link the shader to the GL interface.
337 ///
338 /// Optionally, additional source code can be transferred here, or it can be
339 /// used independently without any files
340 ///
341 /// @param[in] vertexExtraBegin [opt] To additionally add vextex source
342 /// code to the beginning of the loaded file
343 /// source code
344 /// @param[in] vertexExtraEnd [opt] To additionally add vextex source
345 /// code to the end of the loaded file
346 /// source code
347 /// @param[in] fragmentExtraBegin [opt] To additionally add fragment source
348 /// code to the beginning of the loaded file
349 /// source code
350 /// @param[in] fragmentExtraEnd [opt] To additionally add fragment source
351 /// code to the end of the loaded file
352 /// source code
353 /// @return true if compile was successed
354 ///
355 ///
356 /// @note In the case of a compile error, it will be written once into the Kodi
357 /// log and in addition to the console output to quickly detect the errors when
358 /// writing the damage.
359 ///
360 ///
361 bool CompileAndLink(const std::string& vertexExtraBegin = "",
362 const std::string& vertexExtraEnd = "",
363 const std::string& fragmentExtraBegin = "",
364 const std::string& fragmentExtraEnd = "")
365 {
366 GLint params[4];
367
368 // free resources
369 ShaderFree();
370 m_ok = false;
371
372 // compiled vertex shader
373 if (!m_pVP.Compile(vertexExtraBegin, vertexExtraEnd))
374 {
375 kodi::Log(ADDON_LOG_ERROR, "GL: Error compiling vertex shader");
376 return false;
377 }
378
379 // compile pixel shader
380 if (!m_pFP.Compile(fragmentExtraBegin, fragmentExtraEnd))
381 {
382 m_pVP.Free();
383 kodi::Log(ADDON_LOG_ERROR, "GL: Error compiling fragment shader");
384 return false;
385 }
386
387 // create program object
388 m_shaderProgram = glCreateProgram();
389 if (!m_shaderProgram)
390 {
391 kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: Failed to create GL program", __FUNCTION__);
392 ShaderFree();
393 return false;
394 }
395
396 // attach the vertex shader
397 glAttachShader(m_shaderProgram, m_pVP.Handle());
398 glAttachShader(m_shaderProgram, m_pFP.Handle());
399
400 // link the program
401 glLinkProgram(m_shaderProgram);
402 glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, params);
403 if (params[0] != GL_TRUE)
404 {
405 GLchar log[LOG_SIZE];
406 glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, nullptr, log);
407 kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: %s", __FUNCTION__, log);
408 fprintf(stderr, "CShaderProgram::%s: %s@n", __FUNCTION__, log);
409 ShaderFree();
410 return false;
411 }
412
413 m_validated = false;
414 m_ok = true;
415 OnCompiledAndLinked();
416 return true;
417 }
418 //--------------------------------------------------------------------------
419
420 //==========================================================================
421 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
422 /// @brief To activate the shader and use it on the GPU.
423 ///
424 /// @return true if enable was successfull done
425 ///
426 ///
427 /// @note During this call, the @ref OnEnabled stored in the child is also
428 /// called
429 ///
430 bool EnableShader()
431 {
432 if (ShaderOK())
433 {
434 glUseProgram(m_shaderProgram);
435 if (OnEnabled())
436 {
437 if (!m_validated)
438 {
439 // validate the program
440 GLint params[4];
441 glValidateProgram(m_shaderProgram);
442 glGetProgramiv(m_shaderProgram, GL_VALIDATE_STATUS, params);
443 if (params[0] != GL_TRUE)
444 {
445 GLchar log[LOG_SIZE];
446 glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, nullptr, log);
447 kodi::Log(ADDON_LOG_ERROR, "CShaderProgram::%s: %s", __FUNCTION__, log);
448 fprintf(stderr, "CShaderProgram::%s: %s\n", __FUNCTION__, log);
449 }
450 m_validated = true;
451 }
452 return true;
453 }
454 else
455 {
456 glUseProgram(0);
457 return false;
458 }
459 return true;
460 }
461 return false;
462 }
463 //--------------------------------------------------------------------------
464
465 //==========================================================================
466 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
467 /// @brief To deactivate the shader use on the GPU.
468 ///
469 void DisableShader()
470 {
471 if (ShaderOK())
472 {
473 glUseProgram(0);
474 OnDisabled();
475 }
476 }
477 //--------------------------------------------------------------------------
478
479 //==========================================================================
480 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
481 /// @brief Used to check if shader has been loaded before.
482 ///
483 /// @return true if enable was successfull done
484 ///
485 /// @note The CompileAndLink call sets these values
486 ///
487 ATTRIBUTE_FORCEINLINE bool ShaderOK() const { return m_ok; }
488 //--------------------------------------------------------------------------
489
490 //==========================================================================
491 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
492 /// @brief To get the vertex shader class used by Kodi at the addon.
493 ///
494 /// @return pointer to vertex shader class
495 ///
496 ATTRIBUTE_FORCEINLINE CVertexShader& VertexShader() { return m_pVP; }
497 //--------------------------------------------------------------------------
498
499 //==========================================================================
500 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
501 /// @brief To get the fragment shader class used by Kodi at the addon.
502 ///
503 /// @return pointer to fragment shader class
504 ///
505 ATTRIBUTE_FORCEINLINE CPixelShader& PixelShader() { return m_pFP; }
506 //--------------------------------------------------------------------------
507
508 //==========================================================================
509 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
510 /// @brief Used to get the definition created in the OpenGL itself.
511 ///
512 /// @return GLuint of GL shader program handler
513 ///
514 ATTRIBUTE_FORCEINLINE GLuint ProgramHandle() { return m_shaderProgram; }
515 //--------------------------------------------------------------------------
516
517 //==========================================================================
518 /// @defgroup cpp_kodi_gui_helpers_gl_CShaderProgram_child Child Functions
519 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram
520 /// @brief @cpp_class{ kodi::gui::gl::CShaderProgram child functions }
521 ///
522 /// Functions that are added by parent in the child
523 /// @{
524 //==========================================================================
525 ///
526 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram_child
527 /// @brief Mandatory child function to set the necessary CPU to GPU data
528 ///
529 virtual void OnCompiledAndLinked(){};
530 //--------------------------------------------------------------------------
531
532 //==========================================================================
533 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram_child
534 /// @brief Optional function to exchange data between CPU and GPU while
535 /// activating the shader
536 ///
537 /// @return true if enable was successfull done
538 ///
539 virtual bool OnEnabled() { return true; };
540 //--------------------------------------------------------------------------
541
542 //==========================================================================
543 /// @ingroup cpp_kodi_gui_helpers_gl_CShaderProgram_child
544 /// @brief Optional child function that may have to be performed when
545 /// switching off the shader
546 virtual void OnDisabled(){};
547 //--------------------------------------------------------------------------
548 /// @}
549
550private:
551 void ShaderFree()
552 {
553 if (m_shaderProgram)
554 glDeleteProgram(m_shaderProgram);
555 m_shaderProgram = 0;
556 m_ok = false;
557 }
558
559 CVertexShader m_pVP;
560 CPixelShader m_pFP;
561 GLuint m_shaderProgram = 0;
562 bool m_ok = false;
563 bool m_validated = false;
564};
565//------------------------------------------------------------------------
566
567} /* namespace gl */
568} /* namespace gui */
569} /* namespace kodi */
570
571#endif /* __cplusplus */