[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / guilib / Shader.cpp
blob37aedcfaebc5065950fbe933837031506c58a42d
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "Shader.h"
11 #include "ServiceBroker.h"
12 #include "filesystem/File.h"
13 #include "rendering/RenderSystem.h"
14 #include "utils/GLUtils.h"
15 #include "utils/StringUtils.h"
16 #include "utils/log.h"
18 #ifdef HAS_GLES
19 #define GLchar char
20 #endif
22 #define LOG_SIZE 1024
24 using namespace Shaders;
25 using namespace XFILE;
27 //////////////////////////////////////////////////////////////////////
28 // CShader
29 //////////////////////////////////////////////////////////////////////
30 bool CShader::LoadSource(const std::string& filename, const std::string& prefix)
32 if(filename.empty())
33 return true;
35 CFileStream file;
37 std::string path = "special://xbmc/system/shaders/";
38 path += CServiceBroker::GetRenderSystem()->GetShaderPath(filename);
39 path += filename;
40 if(!file.Open(path))
42 CLog::Log(LOGERROR, "CYUVShaderGLSL::CYUVShaderGLSL - failed to open file {}", filename);
43 return false;
45 getline(file, m_source, '\0');
47 size_t pos = 0;
48 size_t versionPos = m_source.find("#version");
49 if (versionPos != std::string::npos)
51 versionPos = m_source.find('\n', versionPos);
52 if (versionPos != std::string::npos)
53 pos = versionPos + 1;
55 m_source.insert(pos, prefix);
57 m_filenames = filename;
59 return true;
62 bool CShader::AppendSource(const std::string& filename)
64 if(filename.empty())
65 return true;
67 CFileStream file;
68 std::string temp;
70 std::string path = "special://xbmc/system/shaders/";
71 path += CServiceBroker::GetRenderSystem()->GetShaderPath(filename);
72 path += filename;
73 if(!file.Open(path))
75 CLog::Log(LOGERROR, "CShader::AppendSource - failed to open file {}", filename);
76 return false;
78 getline(file, temp, '\0');
79 m_source.append(temp);
81 m_filenames.append(" " + filename);
83 return true;
86 bool CShader::InsertSource(const std::string& filename, const std::string& loc)
88 if(filename.empty())
89 return true;
91 CFileStream file;
92 std::string temp;
94 std::string path = "special://xbmc/system/shaders/";
95 path += CServiceBroker::GetRenderSystem()->GetShaderPath(filename);
96 path += filename;
97 if(!file.Open(path))
99 CLog::Log(LOGERROR, "CShader::InsertSource - failed to open file {}", filename);
100 return false;
102 getline(file, temp, '\0');
104 size_t locPos = m_source.find(loc);
105 if (locPos == std::string::npos)
107 CLog::Log(LOGERROR, "CShader::InsertSource - could not find location {}", loc);
108 return false;
111 m_source.insert(locPos, temp);
113 m_filenames.append(" " + filename);
115 return true;
118 std::string CShader::GetSourceWithLineNumbers() const
120 int i{1};
121 auto lines = StringUtils::Split(m_source, "\n");
122 for (auto& line : lines)
124 line.insert(0, StringUtils::Format("{:3}: ", i));
125 i++;
128 auto output = StringUtils::Join(lines, "\n");
130 return output;
134 //////////////////////////////////////////////////////////////////////
135 // CGLSLVertexShader
136 //////////////////////////////////////////////////////////////////////
138 bool CGLSLVertexShader::Compile()
140 GLint params[4];
142 Free();
144 m_vertexShader = glCreateShader(GL_VERTEX_SHADER);
145 const char *ptr = m_source.c_str();
146 glShaderSource(m_vertexShader, 1, &ptr, 0);
147 glCompileShader(m_vertexShader);
148 glGetShaderiv(m_vertexShader, GL_COMPILE_STATUS, params);
149 VerifyGLState();
150 if (params[0] != GL_TRUE)
152 GLchar log[LOG_SIZE];
153 CLog::Log(LOGERROR, "GL: Error compiling vertex shader");
154 glGetShaderInfoLog(m_vertexShader, LOG_SIZE, NULL, log);
155 CLog::Log(LOGERROR, "{}", log);
156 m_lastLog = log;
157 m_compiled = false;
159 else
161 GLchar log[LOG_SIZE];
162 GLsizei length;
163 glGetShaderInfoLog(m_vertexShader, LOG_SIZE, &length, log);
164 if (length > 0)
166 CLog::Log(LOGDEBUG, "GL: Vertex Shader compilation log:");
167 CLog::Log(LOGDEBUG, "{}", log);
169 m_lastLog = log;
170 m_compiled = true;
172 return m_compiled;
175 void CGLSLVertexShader::Free()
177 if (m_vertexShader)
178 glDeleteShader(m_vertexShader);
179 m_vertexShader = 0;
182 //////////////////////////////////////////////////////////////////////
183 // CGLSLPixelShader
184 //////////////////////////////////////////////////////////////////////
185 bool CGLSLPixelShader::Compile()
187 GLint params[4];
189 Free();
191 // Pixel shaders are not mandatory.
192 if (m_source.length()==0)
194 CLog::Log(LOGINFO, "GL: No pixel shader, fixed pipeline in use");
195 return true;
198 m_pixelShader = glCreateShader(GL_FRAGMENT_SHADER);
199 const char *ptr = m_source.c_str();
200 glShaderSource(m_pixelShader, 1, &ptr, 0);
201 glCompileShader(m_pixelShader);
202 glGetShaderiv(m_pixelShader, GL_COMPILE_STATUS, params);
203 if (params[0] != GL_TRUE)
205 GLchar log[LOG_SIZE];
206 CLog::Log(LOGERROR, "GL: Error compiling pixel shader");
207 glGetShaderInfoLog(m_pixelShader, LOG_SIZE, NULL, log);
208 CLog::Log(LOGERROR, "{}", log);
209 m_lastLog = log;
210 m_compiled = false;
212 else
214 GLchar log[LOG_SIZE];
215 GLsizei length;
216 glGetShaderInfoLog(m_pixelShader, LOG_SIZE, &length, log);
217 if (length > 0)
219 CLog::Log(LOGDEBUG, "GL: Pixel Shader compilation log:");
220 CLog::Log(LOGDEBUG, "{}", log);
222 m_lastLog = log;
223 m_compiled = true;
225 return m_compiled;
228 void CGLSLPixelShader::Free()
230 if (m_pixelShader)
231 glDeleteShader(m_pixelShader);
232 m_pixelShader = 0;
235 //////////////////////////////////////////////////////////////////////
236 // CGLSLShaderProgram
237 //////////////////////////////////////////////////////////////////////
238 CGLSLShaderProgram::CGLSLShaderProgram()
240 m_pFP = new CGLSLPixelShader();
241 m_pVP = new CGLSLVertexShader();
244 CGLSLShaderProgram::CGLSLShaderProgram(const std::string& vert,
245 const std::string& frag)
247 m_pFP = new CGLSLPixelShader();
248 m_pFP->LoadSource(frag);
249 m_pVP = new CGLSLVertexShader();
250 m_pVP->LoadSource(vert);
253 CGLSLShaderProgram::~CGLSLShaderProgram()
255 Free();
258 void CGLSLShaderProgram::Free()
260 m_pVP->Free();
261 VerifyGLState();
262 m_pFP->Free();
263 VerifyGLState();
264 if (m_shaderProgram)
266 glDeleteProgram(m_shaderProgram);
268 m_shaderProgram = 0;
269 m_ok = false;
270 m_lastProgram = 0;
273 bool CGLSLShaderProgram::CompileAndLink()
275 GLint params[4];
277 // free resources
278 Free();
280 // compiled vertex shader
281 if (!m_pVP->Compile())
283 CLog::Log(LOGERROR, "GL: Error compiling vertex shader: {}", m_pVP->GetName());
284 CLog::Log(LOGDEBUG, "GL: vertex shader source:\n{}", m_pVP->GetSourceWithLineNumbers());
285 return false;
288 // compile pixel shader
289 if (!m_pFP->Compile())
291 m_pVP->Free();
292 CLog::Log(LOGERROR, "GL: Error compiling fragment shader: {}", m_pFP->GetName());
293 CLog::Log(LOGDEBUG, "GL: fragment shader source:\n{}", m_pFP->GetSourceWithLineNumbers());
294 return false;
297 // create program object
298 if (!(m_shaderProgram = glCreateProgram()))
300 CLog::Log(LOGERROR, "GL: Error creating shader program handle");
301 goto error;
304 // attach the vertex shader
305 glAttachShader(m_shaderProgram, m_pVP->Handle());
306 VerifyGLState();
308 // if we have a pixel shader, attach it. If not, fixed pipeline
309 // will be used.
310 if (m_pFP->Handle())
312 glAttachShader(m_shaderProgram, m_pFP->Handle());
313 VerifyGLState();
316 // link the program
317 glLinkProgram(m_shaderProgram);
318 glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, params);
319 if (params[0]!=GL_TRUE)
321 GLchar log[LOG_SIZE];
322 CLog::Log(LOGERROR, "GL: Error linking shader");
323 glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, NULL, log);
324 CLog::Log(LOGERROR, "{}", log);
325 goto error;
327 VerifyGLState();
329 m_validated = false;
330 m_ok = true;
331 OnCompiledAndLinked();
332 VerifyGLState();
333 return true;
335 error:
336 m_ok = false;
337 Free();
338 return false;
341 bool CGLSLShaderProgram::Enable()
343 if (OK())
345 glUseProgram(m_shaderProgram);
346 if (OnEnabled())
348 if (!m_validated)
350 // validate the program
351 GLint params[4];
352 glValidateProgram(m_shaderProgram);
353 glGetProgramiv(m_shaderProgram, GL_VALIDATE_STATUS, params);
354 if (params[0]!=GL_TRUE)
356 GLchar log[LOG_SIZE];
357 CLog::Log(LOGERROR, "GL: Error validating shader");
358 glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, NULL, log);
359 CLog::Log(LOGERROR, "{}", log);
361 m_validated = true;
363 VerifyGLState();
364 return true;
366 else
368 glUseProgram(0);
369 return false;
371 return true;
373 return false;
376 void CGLSLShaderProgram::Disable()
378 if (OK())
380 glUseProgram(0);
381 OnDisabled();