source: trunk/src/gl/gl_device.cc @ 548

Last change on this file since 548 was 543, checked in by epyon, 8 years ago
  • fixes in handle store
  • removal of get_handle
  • indices instead of handles
  • efficient handle store clears
File size: 15.3 KB
Line 
1// Copyright (C) 2012-2017 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/gl/gl_device.hh"
8
9#include "nv/gl/gl_window.hh"
10#include "nv/core/logging.hh"
11#include "nv/lib/sdl_image.hh"
12#include "nv/gl/gl_enum.hh"
13#include "nv/lib/gl.hh"
14
15using namespace nv;
16
17gl_device::gl_device()
18{
19        m_shader_header.append( "#version 330 core\n" );
20        for ( auto& i : get_uniform_factory() )
21                m_shader_header.append( "uniform "+datatype_to_glsl_type( i.second->get_datatype() )+" "+ i.first +";\n" );
22        for ( auto& i : get_link_uniform_factory() )
23                m_shader_header.append( "uniform sampler2D "+i.first +";\n" );
24}
25
26// this is a temporary function that will be removed once we find a way to
27// pass binary file data around
28image_data* gl_device::create_image_data( string_view filename )
29{
30        load_sdl_image_library();
31        SDL_Surface* image = IMG_Load( filename.data() );
32        if (!image)
33        {
34                NV_LOG_ERROR( "Image file ", filename, " not found!" );
35                return nullptr;
36        }
37        // TODO: BGR vs RGB, single channel
38        pixel_format pformat = RGBA8;
39        switch ( image->format->BytesPerPixel )
40        {
41        case 4: pformat = RGBA8; break;
42        case 3: pformat = RGB8; break;
43        case 1: pformat = R8; break;
44        default: NV_ASSERT( false, "BytesPerPixel != 4,3 or 1!" );
45        }
46        image_data* data = new image_data( pformat, ivec2( image->w, image->h ), static_cast<nv::uint8*>( image->pixels ) );
47        return data;
48}
49
50// this is a temporary function that will be removed once we find a way to
51// pass binary file data around
52image_data* gl_device::create_image_data( const uint8* data, uint32 size )
53{
54        load_sdl_image_library();
55        SDL_Surface* image = IMG_LoadTyped_RW( SDL_RWFromMem( const_cast<uint8*>( data ), int( size ) ), 1, "png" );
56        if ( !image )
57        {
58                NV_LOG_ERROR( "Image binary data cannot be loaded found!" );
59                return nullptr;
60        }
61        // TODO: BGR vs RGB, single channel
62        NV_ASSERT( image->format->BytesPerPixel > 2, "bytes per pixel > 2!" );
63        pixel_format format( image->format->BytesPerPixel == 3 ? RGB8 : RGBA8 );
64        image_data* idata = new image_data( format, ivec2( image->w, image->h ), static_cast<nv::uint8*>( image->pixels ) );
65        return idata;
66}
67
68
69gl_device::~gl_device()
70{
71        for ( auto& t : m_textures )
72                release( &t );
73        for ( auto& b : m_buffers )
74                release( &b );
75        for ( auto& p : m_programs )
76                release( &p );
77        for ( auto& s : m_shaders )
78                release( &s );
79}
80
81nv::shader nv::gl_device::create_shader( shader_type type, string_view sh_source )
82{
83        uint32 glid = 0;
84        if ( !compile( shader_type_to_enum( type ), sh_source, glid ) )
85                return shader();
86
87        shader result = m_shaders.create();
88        gl_shader_info* info = m_shaders.get( result );
89        info->type = type;
90        info->glid = glid;
91        info->ref  = 0;
92
93        return result;
94}
95
96nv::program nv::gl_device::create_program( shader vs, shader fs )
97{
98        program result = m_programs.create();
99        gl_program_info* info = m_programs.get( result );
100
101        info->m_attribute_map = new attribute_map;
102        info->m_engine_uniforms = new engine_uniform_list;
103        info->m_uniform_map = new uniform_map;
104
105        info->glid = glCreateProgram();
106        info->validated = false;
107
108        compile( result, vs, fs );
109        prepare_program( result );
110        return result;
111
112}
113
114nv::texture nv::gl_device::create_texture( texture_type type, pixel_format format )
115{
116        unsigned glid = 0;
117
118        glGenTextures( 1, &glid );
119
120        texture result = m_textures.create();
121        gl_texture_info* info = m_textures.get( result );
122        info->type = type;
123        info->format = format;
124        info->tsampler = sampler();
125        info->size = ivec3( 1, 1, 1 );
126        info->glid = glid;
127
128        return result;
129}
130
131void nv::gl_device::release( texture t )
132{
133        if ( auto info = m_textures.get( t ) )
134        {
135                release( info );
136                m_textures.destroy( t );
137        }
138}
139
140void nv::gl_device::release( gl_shader_info* s )
141{
142        if ( s && s->ref == 0 && s->glid != 0 )
143                glDeleteShader( s->glid );
144}
145
146void nv::gl_device::release( gl_program_info* p )
147{
148        if ( p && p->glid != 0 )
149        {
150                for ( auto& i : *p->m_uniform_map )
151                        delete i.second;
152
153                gl_shader_info* vi = m_shaders.get( p->vertex );
154                gl_shader_info* fi = m_shaders.get( p->fragment );
155                if ( vi )
156                {
157                        glDetachShader( p->glid, vi->glid );
158                        vi->ref--;
159                        release( vi );
160                }
161                if ( fi )
162                {
163                        glDetachShader( p->glid, fi->glid );
164                        fi->ref--;
165                        release( fi );
166                }
167                glDeleteProgram( p->glid );
168
169                delete p->m_attribute_map;
170                delete p->m_engine_uniforms;
171                delete p->m_uniform_map;
172        }
173
174}
175
176void nv::gl_device::release( gl_texture_info* t )
177{
178        if ( t && t->glid != 0 )
179                glDeleteTextures( 1, &( t->glid ) );
180}
181
182void nv::gl_device::release( gl_buffer_info* b )
183{
184        if ( b && b->glid != 0 )
185                glDeleteBuffers( 1, &( b->glid ) );
186}
187
188void nv::gl_device::release( buffer b )
189{
190        if ( auto info = m_buffers.get( b ) )
191        {
192                release( info );
193                m_buffers.destroy( b );
194        }
195}
196
197const texture_info* nv::gl_device::get_texture_info( texture t ) const
198{
199        return m_textures.get( t );
200}
201
202nv::buffer nv::gl_device::create_buffer( buffer_type type, buffer_hint hint )
203{
204        unsigned glid = 0;
205        glGenBuffers( 1, &glid );
206
207        buffer result = m_buffers.create();
208        gl_buffer_info* info = m_buffers.get( result );
209        info->type = type;
210        info->hint = hint;
211        info->size = 0;
212        info->glid = glid;
213        return result;
214}
215
216void nv::gl_device::attach( program p, shader s )
217{
218        gl_program_info* pinfo = m_programs.get( p );
219        gl_shader_info*  sinfo = m_shaders.get( s );
220
221        if ( sinfo && pinfo )
222        {
223                glAttachShader( pinfo->glid, sinfo->glid );
224                sinfo->ref++;
225        }
226
227}
228
229void nv::gl_device::detach( program p, shader s )
230{
231        gl_program_info* pinfo = m_programs.get( p );
232        gl_shader_info*  sinfo = m_shaders.get( s );
233        if ( sinfo && pinfo )
234        {
235                glDetachShader( pinfo->glid, sinfo->glid );
236                sinfo->ref--;
237        }
238}
239const buffer_info* nv::gl_device::get_buffer_info( buffer t ) const
240{
241        return m_buffers.get( t );
242}
243
244void nv::gl_device::release( program p )
245{
246        if ( auto info = m_programs.get( p ) )
247        {
248                release( info );
249                m_programs.destroy( p );
250        }
251}
252
253void nv::gl_device::release( shader s )
254{
255        if ( auto info = m_shaders.get( s ) )
256        {
257                release( info );
258                m_shaders.destroy( s );
259        }
260}
261
262
263nv::gl_texture_info* nv::gl_device::get_full_texture_info( texture t )
264{
265        return m_textures.get( t );
266
267}
268
269nv::gl_buffer_info* nv::gl_device::get_full_buffer_info( buffer t )
270{
271        return m_buffers.get( t );
272}
273
274void nv::gl_device::prepare_program( program p )
275{
276        gl_program_info* info = m_programs.get( p );
277        if ( info )
278        {
279                auto& map  = get_uniform_factory();
280                auto& lmap = get_link_uniform_factory();
281
282                for ( auto& i : *info->m_uniform_map )
283                {
284                        auto j = lmap.find( i.first );
285                        if ( j != lmap.end() )
286                        {
287                                j->second->set( i.second );
288                        }                       
289
290                        auto k = map.find( i.first );
291                        if ( k != map.end() )
292                        {
293                                info->m_engine_uniforms->push_back( k->second->create( i.second ) );
294                        }                               
295                }
296        }
297}
298
299uniform_base* nv::gl_device::get_uniform( program p, const string_view& name, bool fatal /*= true */ ) const
300{
301        const gl_program_info* info = m_programs.get( p );
302        {
303                nv::uniform_map::const_iterator i = info->m_uniform_map->find( name );
304                if ( i != info->m_uniform_map->end() )
305                {
306                        return i->second;
307                }
308                if ( fatal )
309                {
310                        NV_LOG_CRITICAL( "gl_device : uniform '", name, "' not found in program!" );
311                        NV_ABORT( "gl_device : uniform not found!" );
312                }
313        }
314        return nullptr;
315}
316
317int nv::gl_device::get_attribute_location( program p, const string_view& name, bool fatal /*= true */ ) const
318{
319        const gl_program_info* info = m_programs.get( p );
320        if ( info )
321        {
322                attribute_map::const_iterator i = info->m_attribute_map->find( name );
323                if ( i != info->m_attribute_map->end() )
324                {
325                        return i->second.location;
326                }
327                if ( fatal )
328                {
329                        NV_LOG_CRITICAL( "gl_device : attribute '", name, "' not found in program!" );
330                        NV_ABORT( "gl_device : attribute not found!" );
331                }
332        }
333        return -1;
334}
335
336bool nv::gl_device::bind_block( program p, const string_view& name, uint32 index )
337{
338        const gl_program_info* info = m_programs.get( p );
339        if ( info )
340        {
341                int id = get_block_location( p, name, false );
342                if ( id < 0 ) return false;
343                glUniformBlockBinding( info->glid, unsigned( id ), index );
344                return true;
345        }
346        return false;
347}
348
349int nv::gl_device::get_block_location( program p, const string_view& name, bool fatal /*= true */ ) const
350{
351        const gl_program_info* info = m_programs.get( p );
352        if ( info )
353        {
354                GLuint result = glGetUniformBlockIndex( info->glid, name.data() );
355                if ( result != GL_INVALID_INDEX ) return static_cast<int>( result );
356                if ( fatal )
357                {
358                        NV_LOG_CRITICAL( "gl_device : block '", name, "' not found in program!" );
359                        NV_ABORT( "gl_device : block not found!" );
360                }
361        }
362        return -1;
363}
364
365bool nv::gl_device::compile( program pp, shader vp, shader fp )
366{
367        gl_program_info* p = m_programs.get( pp );
368        p->vertex = vp;
369        p->fragment = fp;
370
371        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::POSITION   ), "nv_position"  );
372        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::TEXCOORD   ), "nv_texcoord"  );
373        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::NORMAL     ), "nv_normal"    );
374        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::COLOR      ), "nv_color"     );
375        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::TANGENT    ), "nv_tangent"   );
376        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::BONEINDEX  ), "nv_boneindex" );
377        glBindAttribLocation( p->glid, static_cast<GLuint>( slot::BONEWEIGHT ), "nv_boneweight");
378
379        attach( pp, p->vertex );
380        attach( pp, p->fragment );
381        glLinkProgram( p->glid );
382
383        const uint32 buffer_size = 2048;
384        char buffer[ buffer_size ] = { 0 };
385        int length;
386        int status;
387
388        glGetProgramiv( p->glid, GL_LINK_STATUS, &status );
389        glGetProgramInfoLog( p->glid, buffer_size, &length, buffer );
390
391        NV_LOG_INFO( "Program #", p->glid, (status == GL_FALSE ? " failed to compile!" : " compiled successfully.") );
392
393        if ( length > 0 )
394        {
395                NV_LOG_INFO( "Program #", p->glid, " log: ", string_view( buffer, size_t( length ) ) );
396        }
397
398        if ( status == GL_FALSE )
399        {
400                return false;
401        }
402
403        load_attributes( p );
404        load_uniforms( p );
405        return true;
406}
407
408void nv::gl_device::update_uniforms( gl_program_info* p )
409{
410        for ( auto& i : *p->m_uniform_map )
411        {
412                uniform_base* ubase = i.second;
413                if ( ubase->is_dirty() )
414                {
415                        GLint   uloc = ubase->get_location();
416                        GLsizei size = static_cast<GLsizei>( ubase->get_length() );
417                        switch( ubase->get_type() )
418                        {
419                        case FLOAT          : glUniform1fv( uloc, size, static_cast< uniform< enum_to_type< FLOAT >::type >*>( ubase )->get_value() ); break;
420                        case INT            : glUniform1iv( uloc, size, static_cast< uniform< enum_to_type< INT >::type >*>( ubase )->get_value() ); break;
421                        case FLOAT_VECTOR_2 : glUniform2fv( uloc, size, reinterpret_cast<const GLfloat*>( static_cast< uniform< enum_to_type< FLOAT_VECTOR_2 >::type >*>( ubase )->get_value())); break;
422                        case FLOAT_VECTOR_3 : glUniform3fv( uloc, size, reinterpret_cast<const GLfloat*>( static_cast< uniform< enum_to_type< FLOAT_VECTOR_3 >::type >*>( ubase )->get_value())); break;
423                        case FLOAT_VECTOR_4 : glUniform4fv( uloc, size, reinterpret_cast<const GLfloat*>( static_cast< uniform< enum_to_type< FLOAT_VECTOR_4 >::type >*>( ubase )->get_value())); break;
424                        case INT_VECTOR_2   : glUniform2iv( uloc, size, reinterpret_cast<const GLint*>( static_cast< uniform< enum_to_type< INT_VECTOR_2 >::type >*>( ubase )->get_value())); break;
425                        case INT_VECTOR_3   : glUniform3iv( uloc, size, reinterpret_cast<const GLint*>( static_cast< uniform< enum_to_type< INT_VECTOR_3 >::type >*>( ubase )->get_value())); break;
426                        case INT_VECTOR_4   : glUniform4iv( uloc, size, reinterpret_cast<const GLint*>( static_cast< uniform< enum_to_type< INT_VECTOR_4 >::type >*>( ubase )->get_value())); break;
427                        case FLOAT_MATRIX_2 : glUniformMatrix2fv( uloc, size, GL_FALSE, reinterpret_cast<const GLfloat*>( static_cast< uniform< enum_to_type< FLOAT_MATRIX_2 >::type >*>( ubase )->get_value())); break;
428                        case FLOAT_MATRIX_3 : glUniformMatrix3fv( uloc, size, GL_FALSE, reinterpret_cast<const GLfloat*>( static_cast< uniform< enum_to_type< FLOAT_MATRIX_3 >::type >*>( ubase )->get_value())); break;
429                        case FLOAT_MATRIX_4 : glUniformMatrix4fv( uloc, size, GL_FALSE, reinterpret_cast<const GLfloat*>( static_cast< uniform< enum_to_type< FLOAT_MATRIX_4 >::type >*>( ubase )->get_value())); break;
430                        default : break; // error?
431                        }
432                        ubase->clean();
433                }
434        }
435}
436
437void nv::gl_device::load_attributes( gl_program_info* p )
438{
439        int params;
440        glGetProgramiv( p->glid, GL_ACTIVE_ATTRIBUTES, &params );
441
442        for ( unsigned i = 0; i < unsigned( params ); ++i )
443        {
444                int attr_nlen;
445                int attr_len;
446                unsigned attr_type;
447                char name_buffer[128];
448
449                glGetActiveAttrib( p->glid, i, 128, &attr_nlen, &attr_len, &attr_type, name_buffer );
450
451                string_view name( name_buffer, size_t( attr_nlen ) );
452
453                // skip built-ins
454                if ( name.substr(0,3) == "gl_" ) continue;
455
456                int attr_loc = glGetAttribLocation( p->glid, name.data() );
457
458                attribute& attr = (*p->m_attribute_map)[ name ];
459                attr.location = attr_loc;
460                attr.type     = gl_enum_to_datatype( attr_type );
461                attr.length   = attr_len;
462        }
463}
464
465void nv::gl_device::load_uniforms( gl_program_info* p )
466{
467        int params;
468        int bparams;
469        glGetProgramiv( p->glid, GL_ACTIVE_UNIFORMS, &params );
470        glGetProgramiv( p->glid, GL_ACTIVE_UNIFORM_BLOCKS, &bparams );
471
472        for ( unsigned i = 0; i < unsigned( params ); ++i )
473        {
474                int uni_nlen;
475                int uni_len;
476                unsigned uni_type;
477                char name_buffer[128];
478
479                glGetActiveUniform( p->glid, i, 128, &uni_nlen, &uni_len, &uni_type, name_buffer );
480
481                string_view name( name_buffer, uint32( uni_nlen ) );
482
483                // skip built-ins
484                if ( name.substr(0,3) == "gl_" ) continue;
485
486                int uni_loc = glGetUniformLocation( p->glid, name.data() );
487                datatype utype = gl_enum_to_datatype( uni_type );
488
489                // check for array
490                uint32 arrchar = name.find( '[' );
491                if ( arrchar != string_view::npos )
492                {
493                        name = name.substr( 0, arrchar );
494                }
495
496                uniform_base* u = uniform_base::create( utype, uni_loc, size_t( uni_len ) );
497                NV_ASSERT( u, "Unknown uniform type!" );
498                (*p->m_uniform_map)[ name ] = u;
499                //NV_LOG_DEBUG( "Uniform : ", name, " - ", utype, "/", uni_len );
500
501        }
502
503        for ( unsigned i = 0; i < unsigned( bparams ); ++i )
504        {
505                int uni_len;
506                char name_buffer[128];
507
508                glGetActiveUniformBlockName( p->glid, i, 128, &uni_len, name_buffer );
509                NV_LOG_INFO( string_view( name_buffer, size_t( uni_len ) ) );
510        }
511}
512
513bool nv::gl_device::compile( uint32 sh_type, string_view shader_code, unsigned& glid )
514{
515        glid = glCreateShader( sh_type );
516
517        const char* pc = shader_code.data();
518        int l = int( shader_code.length() );
519
520        glShaderSource( glid, 1, &pc, &l );
521        glCompileShader( glid );
522
523        const uint32 buffer_size = 1024;
524        char buffer[ buffer_size ] = { 0 };
525        int length;
526        int compile_ok = GL_FALSE;
527        glGetShaderiv(glid, GL_COMPILE_STATUS, &compile_ok);
528        glGetShaderInfoLog( glid, buffer_size, &length, buffer );
529
530        if ( length > 0 )
531        {
532                if ( compile_ok == 0 )
533                {
534                        NV_LOG_ERROR( "Shader #", glid, " error: ", string_view( buffer, size_t( length ) ) );
535                }
536                else
537                {
538                        NV_LOG_INFO( "Shader #", glid, " compiled successfully: ", string_view( buffer, size_t( length ) ) );
539                }
540        }
541        else
542        {
543                NV_LOG_INFO( "Shader #", glid, " compiled successfully." );
544        }
545        return compile_ok != 0;
546
547}
548
Note: See TracBrowser for help on using the repository browser.