2013-04-18 03:29:41 +00:00
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2011-12-09 23:30:05 +00:00
2011-12-01 03:00:21 +00:00
# include "ProgramShaderCache.h"
2013-06-11 13:41:30 +00:00
# include "DriverDetails.h"
2011-12-10 21:58:44 +00:00
# include "MathUtil.h"
2013-01-31 22:11:53 +00:00
# include "StreamBuffer.h"
2013-02-13 12:12:19 +00:00
# include "Debugger.h"
# include "Statistics.h"
2013-03-04 09:20:55 +00:00
# include "ImageWrite.h"
2013-03-25 14:14:24 +00:00
# include "Render.h"
2011-12-10 21:58:44 +00:00
2011-12-01 03:00:21 +00:00
namespace OGL
{
2011-12-21 06:15:48 +00:00
2013-02-22 09:25:38 +00:00
static const u32 UBO_LENGTH = 32 * 1024 * 1024 ;
2013-01-25 12:20:42 +00:00
2013-03-17 15:49:42 +00:00
GLintptr ProgramShaderCache : : s_vs_data_size ;
GLintptr ProgramShaderCache : : s_ps_data_size ;
2011-12-26 05:15:54 +00:00
GLintptr ProgramShaderCache : : s_vs_data_offset ;
2013-01-31 22:11:53 +00:00
u8 * ProgramShaderCache : : s_ubo_buffer ;
2013-01-14 12:58:11 +00:00
u32 ProgramShaderCache : : s_ubo_buffer_size ;
bool ProgramShaderCache : : s_ubo_dirty ;
2011-12-26 05:15:54 +00:00
2013-01-31 22:11:53 +00:00
static StreamBuffer * s_buffer ;
2013-05-04 21:30:13 +00:00
static int num_failures = 0 ;
2013-01-31 22:11:53 +00:00
2013-02-13 20:34:48 +00:00
LinearDiskCache < SHADERUID , u8 > g_program_disk_cache ;
static GLuint CurrentProgram = 0 ;
ProgramShaderCache : : PCache ProgramShaderCache : : pshaders ;
2013-02-13 12:12:19 +00:00
ProgramShaderCache : : PCacheEntry * ProgramShaderCache : : last_entry ;
SHADERUID ProgramShaderCache : : last_uid ;
2013-04-29 19:00:39 +00:00
UidChecker < PixelShaderUid , PixelShaderCode > ProgramShaderCache : : pixel_uid_checker ;
UidChecker < VertexShaderUid , VertexShaderCode > ProgramShaderCache : : vertex_uid_checker ;
2013-01-28 21:32:38 +00:00
2013-02-13 20:34:48 +00:00
static char s_glsl_header [ 1024 ] = " " ;
2011-12-26 05:15:54 +00:00
const char * UniformNames [ NUM_UNIFORMS ] =
{
// PIXEL SHADER UNIFORMS
I_COLORS ,
I_KCOLORS ,
I_ALPHA ,
I_TEXDIMS ,
I_ZBIAS ,
I_INDTEXSCALE ,
I_INDTEXMTX ,
I_FOG ,
I_PLIGHTS ,
I_PMATERIALS ,
// VERTEX SHADER UNIFORMS
I_POSNORMALMATRIX ,
I_PROJECTION ,
I_MATERIALS ,
I_LIGHTS ,
I_TEXMATRICES ,
I_TRANSFORMMATRICES ,
I_NORMALMATRICES ,
I_POSTTRANSFORMMATRICES ,
I_DEPTHPARAMS ,
} ;
2013-02-13 12:12:19 +00:00
void SHADER : : SetProgramVariables ( )
2011-12-26 05:15:54 +00:00
{
2013-02-13 12:12:19 +00:00
// glsl shader must be bind to set samplers
Bind ( ) ;
2013-01-02 15:56:08 +00:00
// Bind UBO
2011-12-26 05:15:54 +00:00
if ( g_ActiveConfig . backend_info . bSupportsGLSLUBO )
2011-12-11 10:08:18 +00:00
{
2013-02-13 12:12:19 +00:00
GLint PSBlock_id = glGetUniformBlockIndex ( glprogid , " PSBlock " ) ;
GLint VSBlock_id = glGetUniformBlockIndex ( glprogid , " VSBlock " ) ;
2013-01-02 15:56:08 +00:00
if ( PSBlock_id ! = - 1 )
2013-02-13 12:12:19 +00:00
glUniformBlockBinding ( glprogid , PSBlock_id , 1 ) ;
2013-01-02 15:56:08 +00:00
if ( VSBlock_id ! = - 1 )
2013-02-13 12:12:19 +00:00
glUniformBlockBinding ( glprogid , VSBlock_id , 2 ) ;
2011-12-26 05:15:54 +00:00
}
2013-01-02 15:56:08 +00:00
2011-12-26 05:15:54 +00:00
// We cache our uniform locations for now
// Once we move up to a newer version of GLSL, ~1.30
// We can remove this
2011-12-11 10:14:02 +00:00
2011-12-26 05:15:54 +00:00
// (Sonicadvance): For some reason this fails on my hardware
2013-02-13 12:12:19 +00:00
//glGetUniformIndices(glprogid, NUM_UNIFORMS, UniformNames, UniformLocations);
2011-12-26 05:15:54 +00:00
// Got to do it this crappy way.
2013-02-13 12:12:19 +00:00
UniformLocations [ 0 ] = glGetUniformLocation ( glprogid , UniformNames [ 0 ] ) ;
2011-12-26 05:15:54 +00:00
if ( ! g_ActiveConfig . backend_info . bSupportsGLSLUBO )
2013-02-05 17:22:23 +00:00
for ( int a = 1 ; a < NUM_UNIFORMS ; + + a )
2013-02-13 12:12:19 +00:00
UniformLocations [ a ] = glGetUniformLocation ( glprogid , UniformNames [ a ] ) ;
2011-12-11 10:14:02 +00:00
2013-01-02 15:56:08 +00:00
// Bind Texture Sampler
2013-01-18 23:39:31 +00:00
for ( int a = 0 ; a < = 9 ; + + a )
2011-12-26 05:15:54 +00:00
{
2013-01-18 23:12:02 +00:00
char name [ 8 ] ;
snprintf ( name , 8 , " samp%d " , a ) ;
2013-01-02 15:56:08 +00:00
// Still need to get sampler locations since we aren't binding them statically in the shaders
2013-02-13 12:12:19 +00:00
int loc = glGetUniformLocation ( glprogid , name ) ;
2013-01-18 23:12:02 +00:00
if ( loc ! = - 1 )
glUniform1i ( loc , a ) ;
2012-12-31 01:34:27 +00:00
}
2013-01-02 15:56:08 +00:00
2012-12-31 01:34:27 +00:00
}
2013-02-13 12:12:19 +00:00
void SHADER : : SetProgramBindings ( )
2012-12-31 01:34:27 +00:00
{
2013-05-06 11:43:04 +00:00
# ifndef USE_GLES3
2013-01-14 19:00:33 +00:00
if ( g_ActiveConfig . backend_info . bSupportsDualSourceBlend )
2012-12-31 01:34:27 +00:00
{
2013-01-02 15:56:08 +00:00
// So we do support extended blending
// So we need to set a few more things here.
// Bind our out locations
2013-02-13 12:12:19 +00:00
glBindFragDataLocationIndexed ( glprogid , 0 , 0 , " ocol0 " ) ;
glBindFragDataLocationIndexed ( glprogid , 0 , 1 , " ocol1 " ) ;
2011-12-26 05:15:54 +00:00
}
2013-04-08 12:50:58 +00:00
else if ( g_ogl_config . eSupportedGLSLVersion > GLSL_120 )
{
2013-02-13 12:12:19 +00:00
glBindFragDataLocation ( glprogid , 0 , " ocol0 " ) ;
2013-04-08 12:50:58 +00:00
}
else
{
// ogl2 shaders don't need to bind output colors.
// gl_FragColor already point to color channel
}
2013-05-06 11:43:04 +00:00
# endif
2012-12-31 01:34:27 +00:00
// Need to set some attribute locations
2013-02-13 12:12:19 +00:00
glBindAttribLocation ( glprogid , SHADER_POSITION_ATTRIB , " rawpos " ) ;
2013-01-14 21:59:08 +00:00
2013-02-13 12:12:19 +00:00
glBindAttribLocation ( glprogid , SHADER_POSMTX_ATTRIB , " fposmtx " ) ;
2013-01-14 21:59:08 +00:00
2013-02-13 12:12:19 +00:00
glBindAttribLocation ( glprogid , SHADER_COLOR0_ATTRIB , " color0 " ) ;
glBindAttribLocation ( glprogid , SHADER_COLOR1_ATTRIB , " color1 " ) ;
2013-01-14 21:59:08 +00:00
2013-02-13 12:12:19 +00:00
glBindAttribLocation ( glprogid , SHADER_NORM0_ATTRIB , " rawnorm0 " ) ;
glBindAttribLocation ( glprogid , SHADER_NORM1_ATTRIB , " rawnorm1 " ) ;
glBindAttribLocation ( glprogid , SHADER_NORM2_ATTRIB , " rawnorm2 " ) ;
2013-01-14 21:59:08 +00:00
for ( int i = 0 ; i < 8 ; i + + ) {
char attrib_name [ 8 ] ;
snprintf ( attrib_name , 8 , " tex%d " , i ) ;
2013-02-13 12:12:19 +00:00
glBindAttribLocation ( glprogid , SHADER_TEXTURE0_ATTRIB + i , attrib_name ) ;
2013-01-14 21:59:08 +00:00
}
2011-12-26 05:15:54 +00:00
}
2011-12-11 10:14:02 +00:00
2013-02-13 12:12:19 +00:00
void SHADER : : Bind ( )
{
if ( CurrentProgram ! = glprogid )
{
glUseProgram ( glprogid ) ;
CurrentProgram = glprogid ;
}
}
void ProgramShaderCache : : SetMultiPSConstant4fv ( unsigned int offset , const float * f , unsigned int count )
{
s_ubo_dirty = true ;
memcpy ( s_ubo_buffer + ( offset * 4 * sizeof ( float ) ) , f , count * 4 * sizeof ( float ) ) ;
}
void ProgramShaderCache : : SetMultiVSConstant4fv ( unsigned int offset , const float * f , unsigned int count )
{
s_ubo_dirty = true ;
memcpy ( s_ubo_buffer + ( offset * 4 * sizeof ( float ) ) + s_vs_data_offset , f , count * 4 * sizeof ( float ) ) ;
}
2012-12-31 01:34:27 +00:00
2013-02-13 12:12:19 +00:00
void ProgramShaderCache : : UploadConstants ( )
2011-12-26 05:15:54 +00:00
{
2013-02-13 12:12:19 +00:00
if ( s_ubo_dirty ) {
s_buffer - > Alloc ( s_ubo_buffer_size ) ;
size_t offset = s_buffer - > Upload ( s_ubo_buffer , s_ubo_buffer_size ) ;
2013-03-17 15:49:42 +00:00
glBindBufferRange ( GL_UNIFORM_BUFFER , 1 , s_buffer - > getBuffer ( ) , offset , s_ps_data_size ) ;
glBindBufferRange ( GL_UNIFORM_BUFFER , 2 , s_buffer - > getBuffer ( ) , offset + s_vs_data_offset , s_vs_data_size ) ;
2013-02-13 12:12:19 +00:00
s_ubo_dirty = false ;
2013-05-23 19:07:01 +00:00
ADDSTAT ( stats . thisFrame . bytesUniformStreamed , s_ubo_buffer_size ) ;
2011-12-11 10:32:57 +00:00
}
2013-02-13 12:12:19 +00:00
}
GLuint ProgramShaderCache : : GetCurrentProgram ( void )
{
return CurrentProgram ;
}
SHADER * ProgramShaderCache : : SetShader ( DSTALPHA_MODE dstAlphaMode , u32 components )
{
SHADERUID uid ;
GetShaderId ( & uid , dstAlphaMode , components ) ;
2013-03-26 21:16:29 +00:00
2013-02-13 12:12:19 +00:00
// Check if the shader is already set
if ( last_entry )
{
if ( uid = = last_uid )
{
GFX_DEBUGGER_PAUSE_AT ( NEXT_PIXEL_SHADER_CHANGE , true ) ;
last_entry - > shader . Bind ( ) ;
return & last_entry - > shader ;
}
}
2013-03-29 19:33:28 +00:00
2013-02-13 12:12:19 +00:00
last_uid = uid ;
2013-03-29 19:33:28 +00:00
2013-02-13 12:12:19 +00:00
// Check if shader is already in cache
PCache : : iterator iter = pshaders . find ( uid ) ;
2011-12-26 05:15:54 +00:00
if ( iter ! = pshaders . end ( ) )
2011-12-11 10:32:57 +00:00
{
2013-02-13 12:12:19 +00:00
PCacheEntry * entry = & iter - > second ;
last_entry = entry ;
GFX_DEBUGGER_PAUSE_AT ( NEXT_PIXEL_SHADER_CHANGE , true ) ;
last_entry - > shader . Bind ( ) ;
return & last_entry - > shader ;
}
2013-03-29 19:33:28 +00:00
2013-02-13 12:12:19 +00:00
// Make an entry in the table
PCacheEntry & newentry = pshaders [ uid ] ;
last_entry = & newentry ;
2013-02-13 15:30:15 +00:00
newentry . in_cache = 0 ;
2013-03-29 19:33:28 +00:00
2013-03-26 21:16:29 +00:00
VertexShaderCode vcode ;
PixelShaderCode pcode ;
GenerateVertexShaderCode ( vcode , components , API_OPENGL ) ;
GeneratePixelShaderCode ( pcode , dstAlphaMode , API_OPENGL , components ) ;
2013-03-29 19:33:28 +00:00
2013-02-13 12:12:19 +00:00
if ( g_ActiveConfig . bEnableShaderDebugging )
{
2013-03-26 21:16:29 +00:00
newentry . shader . strvprog = vcode . GetBuffer ( ) ;
newentry . shader . strpprog = pcode . GetBuffer ( ) ;
2011-12-11 11:13:05 +00:00
}
2011-12-11 10:08:18 +00:00
2013-02-13 12:12:19 +00:00
# if defined(_DEBUG) || defined(DEBUGFAST)
if ( g_ActiveConfig . iLog & CONF_SAVESHADERS ) {
static int counter = 0 ;
char szTemp [ MAX_PATH ] ;
sprintf ( szTemp , " %svs_%04i.txt " , File : : GetUserPath ( D_DUMP_IDX ) . c_str ( ) , counter + + ) ;
2013-03-26 21:16:29 +00:00
SaveData ( szTemp , vcode . GetBuffer ( ) ) ;
2013-02-13 12:12:19 +00:00
sprintf ( szTemp , " %sps_%04i.txt " , File : : GetUserPath ( D_DUMP_IDX ) . c_str ( ) , counter + + ) ;
2013-03-26 21:16:29 +00:00
SaveData ( szTemp , pcode . GetBuffer ( ) ) ;
2013-02-13 12:12:19 +00:00
}
# endif
2011-12-26 05:15:54 +00:00
2013-03-26 21:16:29 +00:00
if ( ! CompileShader ( newentry . shader , vcode . GetBuffer ( ) , pcode . GetBuffer ( ) ) ) {
2013-02-13 12:12:19 +00:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_ERROR , true ) ;
return NULL ;
}
INCSTAT ( stats . numPixelShadersCreated ) ;
SETSTAT ( stats . numPixelShadersAlive , pshaders . size ( ) ) ;
GFX_DEBUGGER_PAUSE_AT ( NEXT_PIXEL_SHADER_CHANGE , true ) ;
last_entry - > shader . Bind ( ) ;
return & last_entry - > shader ;
}
bool ProgramShaderCache : : CompileShader ( SHADER & shader , const char * vcode , const char * pcode )
{
GLuint vsid = CompileSingleShader ( GL_VERTEX_SHADER , vcode ) ;
GLuint psid = CompileSingleShader ( GL_FRAGMENT_SHADER , pcode ) ;
2013-03-29 19:33:28 +00:00
2013-02-13 12:12:19 +00:00
if ( ! vsid | | ! psid )
{
glDeleteShader ( vsid ) ;
glDeleteShader ( psid ) ;
return false ;
}
GLuint pid = shader . glprogid = glCreateProgram ( ) ; ;
glAttachShader ( pid , vsid ) ;
glAttachShader ( pid , psid ) ;
2011-12-26 05:15:54 +00:00
2013-03-25 14:14:24 +00:00
if ( g_ogl_config . bSupportsGLSLCache )
2013-02-13 12:12:19 +00:00
glProgramParameteri ( pid , GL_PROGRAM_BINARY_RETRIEVABLE_HINT , GL_TRUE ) ;
2011-12-26 05:15:54 +00:00
2013-02-13 12:12:19 +00:00
shader . SetProgramBindings ( ) ;
2012-12-31 01:34:27 +00:00
2013-02-13 12:12:19 +00:00
glLinkProgram ( pid ) ;
// original shaders aren't needed any more
glDeleteShader ( vsid ) ;
glDeleteShader ( psid ) ;
2013-02-07 11:47:41 +00:00
2013-03-07 19:26:56 +00:00
GLint linkStatus ;
glGetProgramiv ( pid , GL_LINK_STATUS , & linkStatus ) ;
2013-02-07 11:47:41 +00:00
GLsizei length = 0 ;
2013-02-13 12:12:19 +00:00
glGetProgramiv ( pid , GL_INFO_LOG_LENGTH , & length ) ;
2013-03-07 19:26:56 +00:00
if ( linkStatus ! = GL_TRUE | | ( length > 1 & & DEBUG_GLSL ) )
2013-02-07 11:47:41 +00:00
{
GLsizei charsWritten ;
GLchar * infoLog = new GLchar [ length ] ;
2013-02-13 12:12:19 +00:00
glGetProgramInfoLog ( pid , length , & charsWritten , infoLog ) ;
2013-02-07 11:47:41 +00:00
ERROR_LOG ( VIDEO , " Program info log: \n %s " , infoLog ) ;
char szTemp [ MAX_PATH ] ;
2013-05-04 21:30:13 +00:00
sprintf ( szTemp , " %sbad_p_%d.txt " , File : : GetUserPath ( D_DUMP_IDX ) . c_str ( ) , num_failures + + ) ;
2013-03-07 19:37:28 +00:00
std : : ofstream file ;
OpenFStream ( file , szTemp , std : : ios_base : : out ) ;
2013-08-16 21:05:35 +00:00
file < < s_glsl_header < < vcode < < s_glsl_header < < pcode < < infoLog ;
2013-03-07 19:37:28 +00:00
file . close ( ) ;
2013-05-04 21:30:13 +00:00
PanicAlert ( " Failed to link shaders! \n This usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series. \n \n If you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums. \n \n Debug info (%s, %s, %s): \n %s " ,
szTemp ,
g_ogl_config . gl_vendor ,
g_ogl_config . gl_renderer ,
g_ogl_config . gl_version ,
infoLog ) ;
2013-03-07 19:37:28 +00:00
delete [ ] infoLog ;
2013-02-07 11:47:41 +00:00
}
if ( linkStatus ! = GL_TRUE )
{
// Compile failed
ERROR_LOG ( VIDEO , " Program linking failed; see info log " ) ;
// Don't try to use this shader
2013-02-13 12:12:19 +00:00
glDeleteProgram ( pid ) ;
return false ;
2013-02-07 11:47:41 +00:00
}
2011-12-26 05:15:54 +00:00
2013-02-13 12:12:19 +00:00
shader . SetProgramVariables ( ) ;
return true ;
2011-12-26 05:15:54 +00:00
}
2013-02-13 12:12:19 +00:00
GLuint ProgramShaderCache : : CompileSingleShader ( GLuint type , const char * code )
2011-12-26 05:15:54 +00:00
{
2013-02-13 12:12:19 +00:00
GLuint result = glCreateShader ( type ) ;
2013-02-13 20:34:48 +00:00
const char * src [ ] = { s_glsl_header , code } ;
2013-02-13 12:12:19 +00:00
2013-02-13 20:34:48 +00:00
glShaderSource ( result , 2 , src , NULL ) ;
2013-02-13 12:12:19 +00:00
glCompileShader ( result ) ;
2013-03-07 19:26:56 +00:00
GLint compileStatus ;
glGetShaderiv ( result , GL_COMPILE_STATUS , & compileStatus ) ;
2013-02-13 12:12:19 +00:00
GLsizei length = 0 ;
glGetShaderiv ( result , GL_INFO_LOG_LENGTH , & length ) ;
2013-06-18 15:24:36 +00:00
if ( DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENINFOLOG ) )
length = 1024 ;
2013-03-07 19:26:56 +00:00
if ( compileStatus ! = GL_TRUE | | ( length > 1 & & DEBUG_GLSL ) )
2013-02-13 12:12:19 +00:00
{
GLsizei charsWritten ;
GLchar * infoLog = new GLchar [ length ] ;
glGetShaderInfoLog ( result , length , & charsWritten , infoLog ) ;
ERROR_LOG ( VIDEO , " PS Shader info log: \n %s " , infoLog ) ;
char szTemp [ MAX_PATH ] ;
2013-05-04 21:30:13 +00:00
sprintf ( szTemp ,
" %sbad_%s_%04i.txt " ,
File : : GetUserPath ( D_DUMP_IDX ) . c_str ( ) ,
type = = GL_VERTEX_SHADER ? " vs " : " ps " ,
num_failures + + ) ;
2013-03-07 19:37:28 +00:00
std : : ofstream file ;
OpenFStream ( file , szTemp , std : : ios_base : : out ) ;
2013-08-16 21:05:35 +00:00
file < < s_glsl_header < < code < < infoLog ;
2013-03-07 19:37:28 +00:00
file . close ( ) ;
2013-05-04 21:30:13 +00:00
PanicAlert ( " Failed to compile %s shader! \n This usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series. \n \n If you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums. \n \n Debug info (%s, %s, %s): \n %s " ,
type = = GL_VERTEX_SHADER ? " vertex " : " pixel " ,
szTemp ,
g_ogl_config . gl_vendor ,
g_ogl_config . gl_renderer ,
g_ogl_config . gl_version ,
infoLog ) ;
2013-02-13 12:12:19 +00:00
delete [ ] infoLog ;
}
if ( compileStatus ! = GL_TRUE )
{
// Compile failed
ERROR_LOG ( VIDEO , " Shader compilation failed; see info log " ) ;
// Don't try to use this shader
glDeleteShader ( result ) ;
return 0 ;
}
( void ) GL_REPORT_ERROR ( ) ;
return result ;
2011-12-26 05:15:54 +00:00
}
2013-03-29 13:54:44 +00:00
void ProgramShaderCache : : GetShaderId ( SHADERUID * uid , DSTALPHA_MODE dstAlphaMode , u32 components )
2011-12-26 05:15:54 +00:00
{
2013-03-26 21:16:29 +00:00
GetPixelShaderUid ( uid - > puid , dstAlphaMode , API_OPENGL , components ) ;
GetVertexShaderUid ( uid - > vuid , components , API_OPENGL ) ;
2013-04-29 19:00:39 +00:00
if ( g_ActiveConfig . bEnableShaderDebugging )
{
PixelShaderCode pcode ;
GeneratePixelShaderCode ( pcode , dstAlphaMode , API_OPENGL , components ) ;
pixel_uid_checker . AddToIndexAndCheck ( pcode , uid - > puid , " Pixel " , " p " ) ;
VertexShaderCode vcode ;
GenerateVertexShaderCode ( vcode , components , API_OPENGL ) ;
vertex_uid_checker . AddToIndexAndCheck ( vcode , uid - > vuid , " Vertex " , " v " ) ;
}
2013-03-29 13:54:44 +00:00
}
2013-02-13 12:12:19 +00:00
2011-12-26 07:58:52 +00:00
ProgramShaderCache : : PCacheEntry ProgramShaderCache : : GetShaderProgram ( void )
2011-12-26 05:15:54 +00:00
{
2013-02-13 12:12:19 +00:00
return * last_entry ;
2011-12-26 05:15:54 +00:00
}
void ProgramShaderCache : : Init ( void )
{
// We have to get the UBO alignment here because
// if we generate a buffer that isn't aligned
// then the UBO will fail.
if ( g_ActiveConfig . backend_info . bSupportsGLSLUBO )
2011-12-11 10:08:18 +00:00
{
2011-12-26 05:15:54 +00:00
GLint Align ;
glGetIntegerv ( GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT , & Align ) ;
2013-03-17 15:49:42 +00:00
s_ps_data_size = C_PENVCONST_END * sizeof ( float ) * 4 ;
s_vs_data_size = C_VENVCONST_END * sizeof ( float ) * 4 ;
s_vs_data_offset = ROUND_UP ( s_ps_data_size , Align ) ;
s_ubo_buffer_size = ROUND_UP ( s_ps_data_size , Align ) + ROUND_UP ( s_vs_data_size , Align ) ;
2011-12-26 05:15:54 +00:00
// We multiply by *4*4 because we need to get down to basic machine units.
// So multiply by four to get how many floats we have from vec4s
// Then once more to get bytes
2013-01-31 22:11:53 +00:00
s_buffer = new StreamBuffer ( GL_UNIFORM_BUFFER , UBO_LENGTH ) ;
2013-01-14 12:58:11 +00:00
2013-01-31 22:11:53 +00:00
s_ubo_buffer = new u8 [ s_ubo_buffer_size ] ;
2013-01-21 14:43:04 +00:00
memset ( s_ubo_buffer , 0 , s_ubo_buffer_size ) ;
2013-01-14 12:58:11 +00:00
s_ubo_dirty = true ;
2011-12-11 10:08:18 +00:00
}
2011-12-26 05:15:54 +00:00
// Read our shader cache, only if supported
2013-03-25 14:14:24 +00:00
if ( g_ogl_config . bSupportsGLSLCache )
2011-12-11 10:19:11 +00:00
{
2013-02-13 15:30:15 +00:00
GLint Supported ;
glGetIntegerv ( GL_NUM_PROGRAM_BINARY_FORMATS , & Supported ) ;
if ( ! Supported )
{
ERROR_LOG ( VIDEO , " GL_ARB_get_program_binary is supported, but no binary format is known. So disable shader cache. " ) ;
2013-03-25 14:14:24 +00:00
g_ogl_config . bSupportsGLSLCache = false ;
2013-02-13 15:30:15 +00:00
}
else
{
2013-02-13 15:50:56 +00:00
if ( ! File : : Exists ( File : : GetUserPath ( D_SHADERCACHE_IDX ) ) )
File : : CreateDir ( File : : GetUserPath ( D_SHADERCACHE_IDX ) . c_str ( ) ) ;
2013-02-13 15:30:15 +00:00
char cache_filename [ MAX_PATH ] ;
sprintf ( cache_filename , " %sogl-%s-shaders.cache " , File : : GetUserPath ( D_SHADERCACHE_IDX ) . c_str ( ) ,
SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strUniqueID . c_str ( ) ) ;
ProgramShaderCacheInserter inserter ;
g_program_disk_cache . OpenAndRead ( cache_filename , inserter ) ;
}
SETSTAT ( stats . numPixelShadersAlive , pshaders . size ( ) ) ;
2011-12-11 10:19:11 +00:00
}
2013-01-15 13:22:40 +00:00
2013-02-13 20:34:48 +00:00
CreateHeader ( ) ;
2013-01-15 13:22:40 +00:00
CurrentProgram = 0 ;
2013-02-13 12:12:19 +00:00
last_entry = NULL ;
2011-12-26 05:15:54 +00:00
}
void ProgramShaderCache : : Shutdown ( void )
{
2013-02-13 15:30:15 +00:00
// store all shaders in cache on disk
2013-03-25 14:14:24 +00:00
if ( g_ogl_config . bSupportsGLSLCache )
2011-12-11 10:08:18 +00:00
{
2011-12-11 10:14:02 +00:00
PCache : : iterator iter = pshaders . begin ( ) ;
2011-12-11 10:11:57 +00:00
for ( ; iter ! = pshaders . end ( ) ; + + iter )
2011-12-26 15:27:18 +00:00
{
2013-02-13 15:30:15 +00:00
if ( iter - > second . in_cache ) continue ;
GLint binary_size ;
glGetProgramiv ( iter - > second . shader . glprogid , GL_PROGRAM_BINARY_LENGTH , & binary_size ) ;
if ( ! binary_size ) continue ;
u8 * data = new u8 [ binary_size + sizeof ( GLenum ) ] ;
u8 * binary = data + sizeof ( GLenum ) ;
GLenum * prog_format = ( GLenum * ) data ;
glGetProgramBinary ( iter - > second . shader . glprogid , binary_size , NULL , prog_format , binary ) ;
g_program_disk_cache . Append ( iter - > first , data , binary_size + sizeof ( GLenum ) ) ;
delete [ ] data ;
2011-12-26 15:27:18 +00:00
}
2011-12-11 10:11:57 +00:00
2011-12-26 05:15:54 +00:00
g_program_disk_cache . Sync ( ) ;
g_program_disk_cache . Close ( ) ;
}
2013-01-15 16:10:43 +00:00
glUseProgram ( 0 ) ;
2011-12-26 05:15:54 +00:00
PCache : : iterator iter = pshaders . begin ( ) ;
for ( ; iter ! = pshaders . end ( ) ; + + iter )
iter - > second . Destroy ( ) ;
pshaders . clear ( ) ;
2013-04-29 19:00:39 +00:00
pixel_uid_checker . Invalidate ( ) ;
vertex_uid_checker . Invalidate ( ) ;
2011-12-26 05:15:54 +00:00
if ( g_ActiveConfig . backend_info . bSupportsGLSLUBO )
{
2013-01-31 22:11:53 +00:00
delete s_buffer ;
s_buffer = 0 ;
2013-01-14 12:58:11 +00:00
delete [ ] s_ubo_buffer ;
s_ubo_buffer = 0 ;
2011-12-11 10:08:18 +00:00
}
2011-12-01 03:00:21 +00:00
}
2013-02-13 20:34:48 +00:00
void ProgramShaderCache : : CreateHeader ( void )
{
2013-04-08 12:50:58 +00:00
GLSL_VERSION v = g_ogl_config . eSupportedGLSLVersion ;
2013-02-13 20:34:48 +00:00
snprintf ( s_glsl_header , sizeof ( s_glsl_header ) ,
" #version %s \n "
2013-05-06 04:22:21 +00:00
" %s \n " // default precision
2013-02-13 20:34:48 +00:00
" %s \n " // ubo
" \n " // A few required defines and ones that will make our lives a lot easier
2013-04-08 12:50:58 +00:00
" #define ATTRIN %s \n "
" #define ATTROUT %s \n "
" #define VARYIN %s \n "
" #define VARYOUT %s \n "
2013-02-13 20:34:48 +00:00
// Silly differences
" #define float2 vec2 \n "
" #define float3 vec3 \n "
" #define float4 vec4 \n "
2013-06-18 12:52:36 +00:00
// hlsl to glsl function translation
2013-06-18 17:42:14 +00:00
" #define frac fract \n "
" #define lerp mix \n "
2013-06-18 12:52:36 +00:00
2013-04-08 12:50:58 +00:00
// glsl 120 hack
" %s \n "
" %s \n "
" %s \n "
" %s \n "
" %s \n "
" #define COLOROUT(name) %s \n "
2013-07-13 22:24:23 +00:00
// texture2d hack
" %s \n "
" %s \n "
" %s \n "
2013-06-11 13:33:56 +00:00
2013-07-22 10:02:16 +00:00
, v = = GLSLES3 ? " 300 es " : v = = GLSL_120 ? " 120 " : v = = GLSL_130 ? " 130 " : v = = GLSL_140 ? " 140 " : " 150 "
2013-05-06 04:22:21 +00:00
, v = = GLSLES3 ? " precision highp float; " : " "
, g_ActiveConfig . backend_info . bSupportsGLSLUBO & & v < GLSL_140 ? " #extension GL_ARB_uniform_buffer_object : enable " : " "
2013-04-08 12:50:58 +00:00
, v = = GLSL_120 ? " attribute " : " in "
, v = = GLSL_120 ? " attribute " : " out "
2013-06-11 13:38:45 +00:00
, DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENCENTROID ) ? " in " : v = = GLSL_120 ? " varying " : " centroid in "
, DriverDetails : : HasBug ( DriverDetails : : BUG_BROKENCENTROID ) ? " out " : v = = GLSL_120 ? " varying " : " centroid out "
2013-04-08 12:50:58 +00:00
, v = = GLSL_120 ? " #define texture texture2D " : " "
, v = = GLSL_120 ? " #define round(x) floor((x)+0.5f) " : " "
, v = = GLSL_120 ? " #define out " : " "
, v = = GLSL_120 ? " #define ocol0 gl_FragColor " : " "
2013-04-19 13:21:45 +00:00
, v = = GLSL_120 ? " #define ocol1 gl_FragColor " : " " //TODO: implement dual source blend
2013-04-08 12:50:58 +00:00
, v = = GLSL_120 ? " " : " out vec4 name; "
2013-07-13 22:24:23 +00:00
, v = = GLSL_120 ? " #extension GL_ARB_texture_rectangle : enable " : " "
, v = = GLSL_120 ? " " : " #define texture2DRect(samp, uv) texelFetch(samp, ivec2(floor(uv)), 0) "
, v = = GLSL_120 ? " " : " #define sampler2DRect sampler2D "
2013-02-13 20:34:48 +00:00
) ;
}
2013-02-13 12:12:19 +00:00
void ProgramShaderCache : : ProgramShaderCacheInserter : : Read ( const SHADERUID & key , const u8 * value , u32 value_size )
{
2013-02-13 15:30:15 +00:00
const u8 * binary = value + sizeof ( GLenum ) ;
GLenum * prog_format = ( GLenum * ) value ;
GLint binary_size = value_size - sizeof ( GLenum ) ;
2013-02-13 12:12:19 +00:00
PCacheEntry entry ;
2013-02-13 15:30:15 +00:00
entry . in_cache = 1 ;
2013-02-13 12:12:19 +00:00
entry . shader . glprogid = glCreateProgram ( ) ;
2013-02-13 15:30:15 +00:00
glProgramBinary ( entry . shader . glprogid , * prog_format , binary , binary_size ) ;
2013-02-13 12:12:19 +00:00
GLint success ;
glGetProgramiv ( entry . shader . glprogid , GL_LINK_STATUS , & success ) ;
if ( success )
{
pshaders [ key ] = entry ;
entry . shader . SetProgramVariables ( ) ;
}
2013-02-13 15:30:15 +00:00
else
glDeleteProgram ( entry . shader . glprogid ) ;
2013-02-13 12:12:19 +00:00
}
2011-12-26 05:15:54 +00:00
} // namespace OGL