[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / guilib / Shader.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "system.h"
22
23 #if defined(HAS_GL) || HAS_GLES == 2
24
25 #include "Shader.h"
26 #include "settings/Settings.h"
27 #include "filesystem/File.h"
28 #include "utils/log.h"
29 #include "utils/GLUtils.h"
30
31 #ifdef HAS_GLES
32 #define GLchar char
33 #endif
34
35 #define LOG_SIZE 1024
36
37 using namespace Shaders;
38 using namespace XFILE;
39 using namespace std;
40
41 //////////////////////////////////////////////////////////////////////
42 // CShader
43 //////////////////////////////////////////////////////////////////////
44 bool CShader::LoadSource(const string& filename, const string& prefix)
45 {
46   if(filename.empty())
47     return true;
48
49   CFileStream file;
50
51   if(!file.Open("special://xbmc/system/shaders/" + filename))
52   {
53     CLog::Log(LOGERROR, "CYUVShaderGLSL::CYUVShaderGLSL - failed to open file %s", filename.c_str());
54     return false;
55   }
56   getline(file, m_source, '\0');
57   m_source.insert(0, prefix);
58   return true;
59 }
60
61 //////////////////////////////////////////////////////////////////////
62 // CGLSLVertexShader
63 //////////////////////////////////////////////////////////////////////
64
65 bool CGLSLVertexShader::Compile()
66 {
67   GLint params[4];
68
69   Free();
70
71 #ifdef HAS_GL
72   if(!GLEW_VERSION_2_0)
73   {
74     CLog::Log(LOGERROR, "GL: GLSL vertex shaders not supported");
75     return false;
76   }
77 #endif
78
79   m_vertexShader = glCreateShader(GL_VERTEX_SHADER);
80   const char *ptr = m_source.c_str();
81   glShaderSource(m_vertexShader, 1, &ptr, 0);
82   glCompileShader(m_vertexShader);
83   glGetShaderiv(m_vertexShader, GL_COMPILE_STATUS, params);
84   VerifyGLState();
85   if (params[0]!=GL_TRUE)
86   {
87     GLchar log[LOG_SIZE];
88     CLog::Log(LOGERROR, "GL: Error compiling vertex shader");
89     glGetShaderInfoLog(m_vertexShader, LOG_SIZE, NULL, log);
90     CLog::Log(LOGERROR, "%s", log);
91     m_lastLog = log;
92     m_compiled = false;
93   }
94   else
95   {
96     GLchar log[LOG_SIZE];
97     CLog::Log(LOGDEBUG, "GL: Vertex Shader compilation log:");
98     glGetShaderInfoLog(m_vertexShader, LOG_SIZE, NULL, log);
99     CLog::Log(LOGDEBUG, "%s", log);
100     m_lastLog = log;
101     m_compiled = true;
102   }
103   return m_compiled;
104 }
105
106 void CGLSLVertexShader::Free()
107 {
108 #ifdef HAS_GL
109   if(!GLEW_VERSION_2_0)
110     return;
111 #endif
112
113   if (m_vertexShader)
114     glDeleteShader(m_vertexShader);
115   m_vertexShader = 0;
116 }
117
118 #ifndef HAS_GLES
119
120 //////////////////////////////////////////////////////////////////////
121 // CARBVertexShader
122 //////////////////////////////////////////////////////////////////////
123 bool CARBVertexShader::Compile()
124 {
125   GLint err = 0;
126
127   Free();
128
129   // Pixel shaders are not mandatory.
130   if (m_source.length()==0)
131   {
132     CLog::Log(LOGNOTICE, "GL: No vertex shader, fixed pipeline in use");
133     return true;
134   }
135
136   glEnable(GL_VERTEX_PROGRAM_ARB);
137   glGenProgramsARB(1, &m_vertexShader);
138   glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_vertexShader);
139
140   glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
141                      m_source.length(), m_source.c_str());
142
143   glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &err);
144   if (err>0)
145   {
146     CLog::Log(LOGERROR, "GL: Error compiling ARB vertex shader");
147     m_compiled = false;
148   }
149   else
150   {
151     m_compiled = true;
152   }
153   glDisable(GL_VERTEX_PROGRAM_ARB);
154   return m_compiled;
155 }
156
157 void CARBVertexShader::Free()
158 {
159   if (m_vertexShader)
160     glDeleteProgramsARB(1, &m_vertexShader);
161   m_vertexShader = 0;
162 }
163 #endif
164
165 //////////////////////////////////////////////////////////////////////
166 // CGLSLPixelShader
167 //////////////////////////////////////////////////////////////////////
168 bool CGLSLPixelShader::Compile()
169 {
170 #ifdef HAS_GL
171   if(!GLEW_VERSION_2_0)
172   {
173     CLog::Log(LOGERROR, "GL: GLSL pixel shaders not supported");
174     return false;
175   }
176 #endif
177
178   GLint params[4];
179
180   Free();
181
182   // Pixel shaders are not mandatory.
183   if (m_source.length()==0)
184   {
185     CLog::Log(LOGNOTICE, "GL: No pixel shader, fixed pipeline in use");
186     return true;
187   }
188
189   m_pixelShader = glCreateShader(GL_FRAGMENT_SHADER);
190   const char *ptr = m_source.c_str();
191   glShaderSource(m_pixelShader, 1, &ptr, 0);
192   glCompileShader(m_pixelShader);
193   glGetShaderiv(m_pixelShader, GL_COMPILE_STATUS, params);
194   if (params[0]!=GL_TRUE)
195   {
196     GLchar log[LOG_SIZE];
197     CLog::Log(LOGERROR, "GL: Error compiling pixel shader");
198     glGetShaderInfoLog(m_pixelShader, LOG_SIZE, NULL, log);
199     CLog::Log(LOGERROR, "%s", log);
200     m_lastLog = log;
201     m_compiled = false;
202   }
203   else
204   {
205     GLchar log[LOG_SIZE];
206     CLog::Log(LOGDEBUG, "GL: Pixel Shader compilation log:");
207     glGetShaderInfoLog(m_pixelShader, LOG_SIZE, NULL, log);
208     CLog::Log(LOGDEBUG, "%s", log);
209     m_lastLog = log;
210     m_compiled = true;
211   }
212   return m_compiled;
213 }
214
215 void CGLSLPixelShader::Free()
216 {
217 #ifdef HAS_GL
218   if(!GLEW_VERSION_2_0)
219     return;
220 #endif
221   if (m_pixelShader)
222     glDeleteShader(m_pixelShader);
223   m_pixelShader = 0;
224 }
225
226 #ifndef HAS_GLES
227
228 //////////////////////////////////////////////////////////////////////
229 // CARBPixelShader
230 //////////////////////////////////////////////////////////////////////
231 bool CARBPixelShader::Compile()
232 {
233   GLint err = 0;
234
235   Free();
236
237   // Pixel shaders are not mandatory.
238   if (m_source.length()==0)
239   {
240     CLog::Log(LOGNOTICE, "GL: No pixel shader, fixed pipeline in use");
241     return true;
242   }
243
244   glEnable(GL_FRAGMENT_PROGRAM_ARB);
245   glGenProgramsARB(1, &m_pixelShader);
246   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_pixelShader);
247
248   glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
249                      m_source.length(), m_source.c_str());
250
251   glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &err);
252   if (err>0)
253   {
254     const char* errStr = (const char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
255     if (!errStr)
256       errStr = "NULL";
257     CLog::Log(LOGERROR, "GL: Error compiling ARB pixel shader, GL_PROGRAM_ERROR_STRING_ARB = %s", errStr);
258     m_compiled = false;
259   }
260   else
261   {
262     m_compiled = true;
263   }
264   glDisable(GL_FRAGMENT_PROGRAM_ARB);
265   return m_compiled;
266 }
267
268 void CARBPixelShader::Free()
269 {
270   if (m_pixelShader)
271     glDeleteProgramsARB(1, &m_pixelShader);
272   m_pixelShader = 0;
273 }
274
275 #endif
276
277 //////////////////////////////////////////////////////////////////////
278 // CGLSLShaderProgram
279 //////////////////////////////////////////////////////////////////////
280 void CGLSLShaderProgram::Free()
281 {
282 #ifdef HAS_GL
283   if(!GLEW_VERSION_2_0)
284     return;
285 #endif
286   m_pVP->Free();
287   VerifyGLState();
288   m_pFP->Free();
289   VerifyGLState();
290   if (m_shaderProgram)
291   {
292     glDeleteProgram(m_shaderProgram);
293   }
294   m_shaderProgram = 0;
295   m_ok = false;
296   m_lastProgram = 0;
297 }
298
299 bool CGLSLShaderProgram::CompileAndLink()
300 {
301 #ifdef HAS_GL
302   // check that we support shaders
303   if(!GLEW_VERSION_2_0)
304   {
305     CLog::Log(LOGERROR, "GL: GLSL shaders not supported");
306     return false;
307   }
308 #endif
309
310   GLint params[4];
311
312   // free resources
313   Free();
314
315   // compiled vertex shader
316   if (!m_pVP->Compile())
317   {
318     CLog::Log(LOGERROR, "GL: Error compiling vertex shader");
319     return false;
320   }
321   CLog::Log(LOGDEBUG, "GL: Vertex Shader compiled successfully");
322
323   // compile pixel shader
324   if (!m_pFP->Compile())
325   {
326     m_pVP->Free();
327     CLog::Log(LOGERROR, "GL: Error compiling fragment shader");
328     return false;
329   }
330   CLog::Log(LOGDEBUG, "GL: Fragment Shader compiled successfully");
331
332   // create program object
333   if (!(m_shaderProgram = glCreateProgram()))
334   {
335     CLog::Log(LOGERROR, "GL: Error creating shader program handle");
336     goto error;
337   }
338
339   // attach the vertex shader
340   glAttachShader(m_shaderProgram, m_pVP->Handle());
341   VerifyGLState();
342
343   // if we have a pixel shader, attach it. If not, fixed pipeline
344   // will be used.
345   if (m_pFP->Handle())
346   {
347     glAttachShader(m_shaderProgram, m_pFP->Handle());
348     VerifyGLState();
349   }
350
351   // link the program
352   glLinkProgram(m_shaderProgram);
353   glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, params);
354   if (params[0]!=GL_TRUE)
355   {
356     GLchar log[LOG_SIZE];
357     CLog::Log(LOGERROR, "GL: Error linking shader");
358     glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, NULL, log);
359     CLog::Log(LOGERROR, "%s", log);
360     goto error;
361   }
362   VerifyGLState();
363
364   m_validated = false;
365   m_ok = true;
366   OnCompiledAndLinked();
367   VerifyGLState();
368   return true;
369
370  error:
371   m_ok = false;
372   Free();
373   return false;
374 }
375
376 bool CGLSLShaderProgram::Enable()
377 {
378 #ifdef HAS_GL
379   if(!GLEW_VERSION_2_0)
380     return false;
381 #endif
382
383   if (OK())
384   {
385     glUseProgram(m_shaderProgram);
386     if (OnEnabled())
387     {
388       if (!m_validated)
389       {
390         // validate the program
391         GLint params[4];
392         glValidateProgram(m_shaderProgram);
393         glGetProgramiv(m_shaderProgram, GL_VALIDATE_STATUS, params);
394         if (params[0]!=GL_TRUE)
395         {
396           GLchar log[LOG_SIZE];
397           CLog::Log(LOGERROR, "GL: Error validating shader");
398           glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, NULL, log);
399           CLog::Log(LOGERROR, "%s", log);
400         }
401         m_validated = true;
402       }
403       VerifyGLState();
404       return true;
405     }
406     else
407     {
408       glUseProgram(0);
409       return false;
410     }
411     return true;
412   }
413   return false;
414 }
415
416 void CGLSLShaderProgram::Disable()
417 {
418 #ifdef HAS_GL
419   if(!GLEW_VERSION_2_0)
420     return;
421 #endif
422
423   if (OK())
424   {
425     glUseProgram(0);
426     OnDisabled();
427   }
428 }
429
430 #ifndef HAS_GLES
431
432 //////////////////////////////////////////////////////////////////////
433 // CARBShaderProgram
434 //////////////////////////////////////////////////////////////////////
435 void CARBShaderProgram::Free()
436 {
437   m_pVP->Free();
438   VerifyGLState();
439   m_pFP->Free();
440   VerifyGLState();
441   m_ok = false;
442 }
443
444 bool CARBShaderProgram::CompileAndLink()
445 {
446   // free resources
447   Free();
448
449   // compiled vertex shader
450   if (!m_pVP->Compile())
451   {
452     CLog::Log(LOGERROR, "GL: Error compiling vertex shader");
453     goto error;
454   }
455
456   // compile pixel shader
457   if (!m_pFP->Compile())
458   {
459     m_pVP->Free();
460     CLog::Log(LOGERROR, "GL: Error compiling fragment shader");
461     goto error;
462   }
463
464   m_ok = true;
465   OnCompiledAndLinked();
466   VerifyGLState();
467   return true;
468
469  error:
470   m_ok = false;
471   Free();
472   return false;
473 }
474
475 bool CARBShaderProgram::Enable()
476 {
477   if (OK())
478   {
479     if (m_pFP->OK())
480     {
481       glEnable(GL_FRAGMENT_PROGRAM_ARB);
482       glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_pFP->Handle());
483     }
484     if (m_pVP->OK())
485     {
486       glEnable(GL_VERTEX_PROGRAM_ARB);
487       glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_pVP->Handle());
488     }
489     if (OnEnabled())
490     {
491       VerifyGLState();
492       return true;
493     }
494     else
495     {
496       glDisable(GL_FRAGMENT_PROGRAM_ARB);
497       glDisable(GL_VERTEX_PROGRAM_ARB);
498       return false;
499     }
500   }
501   return false;
502 }
503
504 void CARBShaderProgram::Disable()
505 {
506   if (OK())
507   {
508     glDisable(GL_FRAGMENT_PROGRAM_ARB);
509     glDisable(GL_VERTEX_PROGRAM_ARB);
510     OnDisabled();
511   }
512 }
513
514 #endif
515
516 #endif