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