source: trunk/src/gl/gl_context.cc @ 520

Last change on this file since 520 was 520, checked in by epyon, 9 years ago
  • ecs updates
  • animation updates
  • ragdoll manager
  • lua has own random engine
  • several minor fixes
  • particle engine/particle group
  • shitload of other stuff
  • bullet world
File size: 35.7 KB
RevLine 
[395]1// Copyright (C) 2012-2015 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.
[37]6
7#include "nv/gl/gl_context.hh"
8
9#include "nv/gl/gl_enum.hh"
10#include "nv/lib/gl.hh"
[301]11#include "nv/gl/gl_device.hh"
[365]12#include "nv/core/logger.hh"
[37]13
14using namespace nv;
15
[491]16nv::vertex_array nv::gl_context::create_vertex_array( const vertex_array_desc& desc )
[313]17{
18        vertex_array result = m_vertex_arrays.create();
[491]19        gl_vertex_array_info* info = m_vertex_arrays.get( result );
20
21        glGenVertexArrays( 1, &info->glid );
22        info->count       = desc.count;
23        info->index       = desc.index;
24        info->index_owner = desc.index_owner;
25        info->index_type  = desc.index_type;
26
27        for ( uint32 i = 0; i < desc.count; ++i )
28                info->attr[i] = desc.attr[i];
29
30        glBindVertexArray( info->glid );
31
32        for ( uint32 i = 0; i < info->count; ++i )
33        {
34                const vertex_buffer_attribute& vba = info->attr[i];
35                uint32 location = static_cast<uint32>( vba.location );
36                glEnableVertexAttribArray( location );
37                const gl_buffer_info* vinfo = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( vba.vbuffer ) );
38                if ( vinfo && vinfo->type == VERTEX_BUFFER )
39                        glBindBuffer( GL_ARRAY_BUFFER, vinfo->glid );
40                else
41                {
42                        // TODO: report error
43                }
44
45                glVertexAttribPointer(
46                        location,
47                        static_cast<GLint>( vba.components ),
48                        nv::datatype_to_gl_enum( vba.dtype ),
49                        GL_FALSE,
50                        static_cast<GLsizei>( vba.stride ),
51                        reinterpret_cast<void*>( vba.offset )
52                        );
53        }
54        glBindBuffer( GL_ARRAY_BUFFER, 0 );
55
56        if ( info->index.is_valid() )
57        {
58                const gl_buffer_info* iinfo = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( info->index ) );
59                if ( iinfo && iinfo->type == INDEX_BUFFER )
60                {
61                        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, iinfo->glid );
62                }
63                else
64                {
65                        // TODO: report error
66                }
67        }
68        glBindVertexArray( 0 );
69
70        if ( info->index.is_valid() )
71        {
72                glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
73        }
74
[492]75//      for ( uint32 i = 0; i < info->count; ++i )
76//      {
77//              glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
78//      }
[491]79
80
[313]81        return result;
82}
83
[492]84nv::framebuffer nv::gl_context::create_framebuffer( uint32 temp_samples )
[313]85{
[491]86        unsigned glid   = 0;
87        glGenFramebuffers( 1, &glid );
88        framebuffer result = m_framebuffers.create();
89        gl_framebuffer_info* info = m_framebuffers.get( result );
90        info->glid = glid;
91        info->depth_rb_glid = 0;
92        info->color_attachment_count = 0;
[492]93        info->sample_count = temp_samples;
[491]94        return result;
[313]95}
96
97void nv::gl_context::release( vertex_array va )
98{
[491]99        gl_vertex_array_info* info = m_vertex_arrays.get( va );
[313]100        if ( info )
101        {
102                for ( uint32 i = 0; i < info->count; ++i )
103                {
[469]104                        if ( info->attr[i].owner )
[501]105                                release( info->attr[i].vbuffer );
[313]106                }
[501]107                if ( info->index.is_valid() && info->index_owner) release( info->index );
[491]108                glDeleteVertexArrays( 1, &info->glid );
[313]109                m_vertex_arrays.destroy( va );
110        }
111}
112
113void nv::gl_context::release( framebuffer f )
114{
115        gl_framebuffer_info* info = m_framebuffers.get( f );
116        if ( info )
117        {
118                // TODO: release textures?
[331]119                glBindFramebuffer( GL_FRAMEBUFFER, 0 );
120                glBindRenderbuffer( GL_RENDERBUFFER, 0 );
121                if ( info->depth_rb_glid == 0 )
122                        glDeleteRenderbuffers( 1, &info->depth_rb_glid );
123                glDeleteFramebuffers( 1, &info->glid );
[335]124                m_framebuffers.destroy( f );
[313]125        }
126}
127
[520]128nv::image_data* nv::gl_context::dump_image( image_format f, image_data* reuse )
129{
130        NV_ASSERT_ALWAYS( f.type   == nv::UBYTE, "Bad format passed to dump" );
131        NV_ASSERT_ALWAYS( f.format == nv::RGB || f.format == nv::RGBA, "Bad format passed to dump" );
132        glPixelStorei( GL_PACK_ALIGNMENT, 1 );
133        image_data* result = reuse;
134        if ( !result ) result = new image_data( f, ivec2( m_viewport.z, m_viewport.w ) );
135        glReadPixels( 0, 0, m_viewport.z, m_viewport.w, f.format == nv::RGB ? GL_RGB : GL_RGBA, datatype_to_gl_enum( f.type ), const_cast< uint8* >( result->get_data() ) );
136        return result;
137}
138
139
[313]140const framebuffer_info* nv::gl_context::get_framebuffer_info( framebuffer f ) const
141{
142        return m_framebuffers.get( f );
143}
144
[500]145void nv::gl_context::attach( framebuffer f, output_slot slot, texture t, int layer /* = -1*/ )
[331]146{
147        // TODO: framebuffer variable, so no re-binding?
148        // TODO: support 1d, 3d textures, cubemaps or layers?
149        // TODO: support GL_READ_FRAMEBUFFER?
150        const gl_framebuffer_info* info  = m_framebuffers.get( f );
[406]151        const gl_texture_info*     tinfo = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
[331]152        if ( info )
153        {
154                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
155                unsigned gl_type = texture_type_to_enum( tinfo->type );
[500]156                unsigned tglid = tinfo ? tinfo->glid : 0;
[313]157
[500]158                if ( layer >= 0 )
[331]159                {
[500]160                        glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + unsigned( slot ), tglid, 0, layer );
[331]161                }
162                else
163                {
[500]164                        glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + unsigned( slot ), gl_type, tglid, 0 );
[331]165                }
166
167        }
168}
169
[463]170void nv::gl_context::attach( framebuffer f, texture depth, int layer /*= -1*/ )
[331]171{
172        // TODO: framebuffer variable, so no re-binding?
173        // TODO: support GL_READ_FRAMEBUFFER?
174        const gl_framebuffer_info* info  = m_framebuffers.get( f );
[406]175        const gl_texture_info*     tinfo = static_cast< const gl_texture_info* >( m_device->get_texture_info( depth ) );
[331]176        if ( info )
177        {
178                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
179                unsigned gl_type = texture_type_to_enum( tinfo->type );
[463]180                unsigned glid = ( tinfo ? tinfo->glid : 0 );
181                if ( layer >= 0 )
[331]182                {
[500]183                        glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, glid, 0, layer );
[331]184                }
185                else
186                {
[463]187                        glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gl_type, glid, 0 );
[331]188                }
189        }
[463]190
[331]191}
192
193void nv::gl_context::attach( framebuffer f, ivec2 size )
194{
195        // TODO: framebuffer variable, so no re-binding?
196        // TODO: support GL_READ_FRAMEBUFFER?
197        gl_framebuffer_info* info  = m_framebuffers.get( f );
198        if ( info )
199        {
200                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
[462]201                if ( info->depth_rb_glid )
202                        glDeleteRenderbuffers( 1, &(info->depth_rb_glid) );
[331]203                glGenRenderbuffers( 1, &(info->depth_rb_glid) );
204                glBindRenderbuffer( GL_RENDERBUFFER, info->depth_rb_glid );
[492]205                if ( info->sample_count > 1 )
206                        glRenderbufferStorageMultisample( GL_RENDERBUFFER, info->sample_count, GL_DEPTH_COMPONENT16, size.x, size.y );
207                else
208                        glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.x, size.y );
[331]209                glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, info->depth_rb_glid );
210                glBindRenderbuffer( GL_RENDERBUFFER, 0 );
211        }
212
213}
214
[503]215void nv::gl_context::blit( framebuffer f, buffer_mask mask, ivec2 src1, ivec2 src2, ivec2 dst1, ivec2 dst2 )
[331]216{
217        gl_framebuffer_info* info  = m_framebuffers.get( f );
218        if ( info )
219        {
220                glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
[503]221                unsigned filter = mask == buffer_mask::COLOR_BUFFER ? GL_LINEAR : GL_NEAREST;
[331]222                glBlitFramebuffer( src1.x, src1.y, src2.x, src2.y, dst1.x, dst1.y, dst2.x, dst2.y, clear_state_buffers_to_mask( mask ), filter );
223        }
224}
225
226
[503]227void nv::gl_context::blit( framebuffer from, framebuffer to, buffer_mask mask, ivec2 src1, ivec2 src2, ivec2 dst1, ivec2 dst2 )
[492]228{
229        gl_framebuffer_info* finfo = m_framebuffers.get( from );
230        gl_framebuffer_info* tinfo = m_framebuffers.get( to );
231        if ( finfo )
232        {
233                glBindFramebuffer( GL_READ_FRAMEBUFFER, finfo->glid );
234                glBindFramebuffer( GL_DRAW_FRAMEBUFFER, tinfo ? tinfo->glid : 0 );
[503]235                unsigned filter = mask == buffer_mask::COLOR_BUFFER ? GL_LINEAR : GL_NEAREST;
[492]236                glBlitFramebuffer( src1.x, src1.y, src2.x, src2.y, dst1.x, dst1.y, dst2.x, dst2.y, clear_state_buffers_to_mask( mask ), filter );
237                glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
238                if ( tinfo ) glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
239        }
240}
241
[331]242bool nv::gl_context::check( framebuffer_slot ft )
243{
[462]244        glDrawBuffer( 0 );
245        glReadBuffer( 0 );
[491]246
247        unsigned result = glCheckFramebufferStatus( framebuffer_slot_to_enum(ft) );
248        if ( result == GL_FRAMEBUFFER_COMPLETE ) return true;
249        switch ( result )
[331]250        {
[492]251        case GL_FRAMEBUFFER_UNDEFINED                     : NV_LOG_ERROR( "gl_context::check : Framebuffer undefined!" ); break;
252        case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE        : NV_LOG_ERROR( "gl_context::check : Incomplete multisample!" ); break;
253        case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS      : NV_LOG_ERROR( "gl_context::check : Incomplete layer targets!" ); break;
[491]254        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete attachment!" ); break;
255        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : NV_LOG_ERROR( "gl_context::check : Framebuffer missing attachment!" ); break;
[466]256//              case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete dimensions!" ); break;
257//              case GL_FRAMEBUFFER_INCOMPLETE_FORMATS            : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete formats!" ); break;
[491]258        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete draw buffer!" ); break;
259        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete read buffer!" ); break;
260        case GL_FRAMEBUFFER_UNSUPPORTED                   : NV_LOG_ERROR( "gl_context::check : Framebuffer format combination unsupported!" ); break;
261        default: NV_LOG_ERROR( "gl_context::check : Unknown Framebuffer error! (", result, ")" ); break;
[331]262        }
[462]263        glDrawBuffer( GL_BACK );
264        glReadBuffer( GL_BACK );
[331]265        return false;
266}
267
268void nv::gl_context::bind( framebuffer f, framebuffer_slot ft /*= FRAMEBUFFER_BOTH */ )
269{
270        const gl_framebuffer_info* info = m_framebuffers.get( f );
271        if ( info )
272        {
273                glBindFramebuffer( framebuffer_slot_to_enum(ft), info->glid );
274        }
275        else
276        {
277                glBindFramebuffer( framebuffer_slot_to_enum(ft), 0 );
278        }
279}
280
[501]281
[491]282void nv::gl_context::bind( buffer b, texture t )
283{
284        const gl_buffer_info*  binfo = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
285        const gl_texture_info* tinfo = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
286        NV_ASSERT( binfo && tinfo, "Bad buffer or texture passed to create_texture" );
287        if ( binfo && tinfo )
288        {
289                NV_ASSERT_ALWAYS( binfo->type == TEXTURE_BUFFER && tinfo->type == TEXTURE_1D_BUFFER, "bad texture or buffer type!" );
[492]290                bind( t, TEXTURE_0 );
[491]291                glTexBuffer( GL_TEXTURE_BUFFER, image_format_to_internal_enum( tinfo->format.format ), binfo->glid );
292        }
293}
294
[473]295void nv::gl_context::bind( buffer b, uint32 index, size_t offset /*= 0*/, size_t size /*= 0 */ )
296{
297        const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
298        if ( info )
299        {
300                if ( size == 0 )
301                        glBindBufferBase( buffer_type_to_enum( info->type ), index, info->glid );
302                else
[487]303                        glBindBufferRange( buffer_type_to_enum( info->type ), index, info->glid, static_cast<GLintptr>( offset ), static_cast<GLsizeiptr>( size ) );
[473]304        }
305}
306
[301]307void gl_context::bind( texture t, texture_slot slot )
[299]308{
[492]309        if ( m_bound_textures[ slot ] != t )
[301]310        {
[492]311                const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
312                if ( info )
313                {
314                        set_active_texture( slot );
315                        glBindTexture( texture_type_to_enum( info->type ), info->glid );
[501]316                        m_bound_textures[slot] = t;
[492]317                }
[301]318        }
[299]319}
320
[303]321void nv::gl_context::bind( program p )
[299]322{
[406]323        gl_device* gdevice    = static_cast<gl_device*>( m_device );
324        gl_program_info* info = gdevice->m_programs.get( p );
[303]325        if ( info )
326        {
[501]327                if ( m_bound_program != p )
328                        glUseProgram( info->glid );
[406]329                gdevice->update_uniforms( info );
[493]330                if ( !info->validated )
331                {
332                        validate_program( p );
333                }
[501]334                m_bound_program = p;
[303]335        }
[299]336}
337
[493]338bool nv::gl_context::validate_program( program p )
339{
340        gl_device* gdevice = static_cast<gl_device*>( m_device );
341        gl_program_info* info = gdevice->m_programs.get( p );
342        if ( info )
343        {
344                info->validated = true;
345                const uint32 buffer_size = 1024;
346                char buffer[buffer_size] = { 0 };
347                int length;
348                int status;
349                glValidateProgram( info->glid );
350                glGetProgramiv( info->glid, GL_VALIDATE_STATUS, &status );
351
352                if ( status == GL_FALSE )
353                {
354                        glGetProgramInfoLog( info->glid, buffer_size, &length, buffer );
355                        NV_LOG_ERROR( "Program #", info->glid, " validation error : ", buffer );
356                        return false;
357                }
358                return true;
359        }
360        return false;
361}
362
363
[313]364// void nv::gl_context::bind( buffer b )
365// {
366//      const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
367//      if ( info )
368//      {
369//              glBindBuffer( buffer_type_to_enum( info->type ), info->glid );
370//      }
371// }
[299]372
[302]373void nv::gl_context::bind( vertex_array va )
[299]374{
[491]375        gl_vertex_array_info* info = m_vertex_arrays.get( va );
[302]376        if ( info )
[299]377        {
[491]378                glBindVertexArray( info->glid );
[299]379        }
380}
381
[313]382void nv::gl_context::unbind( program )
383{
[501]384        if ( m_bound_program )
385                glUseProgram( 0 );
386        m_bound_program = program();
[313]387}
388
[492]389void nv::gl_context::set_active_texture( texture_slot slot )
390{
391        if ( slot != m_active_slot )
[501]392        {
[492]393                glActiveTexture( GL_TEXTURE0 + static_cast<GLenum>( slot ) );
[501]394                m_active_slot = slot;
395        }
[492]396}
397
[313]398// void nv::gl_context::unbind( buffer b )
399// {
400//      const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
401//      if ( info )
402//      {
403//              glBindBuffer( buffer_type_to_enum( info->type ), 0 );
404//      }
405// }
406
[302]407void nv::gl_context::unbind( vertex_array va )
[299]408{
[313]409        const vertex_array_info* info = m_vertex_arrays.get( va );
[302]410        if ( info )
[299]411        {
[491]412                glBindVertexArray( 0 );
[299]413        }
414}
415
[313]416void nv::gl_context::unbind( framebuffer f )
417{
418        // this way we are sure that the extension is loaded
419        const gl_framebuffer_info* info = m_framebuffers.get( f );
420        if ( info )
421        {
422                glBindFramebuffer( GL_FRAMEBUFFER, 0 );
423        }
[331]424        glDrawBuffer( GL_BACK );
425        glReadBuffer( GL_BACK );
[313]426}
427
[406]428void nv::gl_context::update( texture t, const void* data )
[299]429{
[301]430        const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
[491]431        NV_ASSERT_ALWAYS( info->type != TEXTURE_1D_BUFFER, "Buffer texture passed to update!" );
[492]432        NV_ASSERT_ALWAYS( info->type != TEXTURE_2D_MULTISAMPLE, "Multisample texture passed to update!" );
[301]433        if ( info )
434        {
[331]435                image_format format  = info->format;
[463]436                ivec3        size    = info->size;
[331]437                unsigned     gl_type = texture_type_to_enum( info->type );
[299]438
[501]439                bind( t, texture_slot::TEXTURE_0 );
[463]440                if ( info->type == TEXTURE_3D || info->type == TEXTURE_2D_ARRAY )
[501]441//                      glTexImage3D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum( format.format ) ), size.x, size.y, size.z, 0, nv::image_format_to_enum( format.format ), nv::datatype_to_gl_enum( format.type ), data );
442                        glTexSubImage3D( gl_type, 0, 0, 0, 0, size.x, size.y, size.z, nv::image_format_to_enum( format.format ), nv::datatype_to_gl_enum( format.type ), data );
[463]443                else
[501]444//                      glTexImage2D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum(format.format) ), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
445                        glTexSubImage2D( gl_type, 0, 0, 0, size.x, size.y, nv::image_format_to_enum( format.format ), nv::datatype_to_gl_enum( format.type ), data );
[301]446        }
[299]447}
448
[499]449void* nv::gl_context::map_buffer( buffer b, buffer_access ba, size_t offset, size_t length )
450{
451        const gl_buffer_info* info = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( b ) );
452        unsigned int glenum = buffer_type_to_enum( info->type );
453        glBindBuffer( glenum, info->glid );
454        void* result = glMapBufferRange( glenum, GLintptr( offset ), GLsizeiptr( length ), buffer_access_to_bitfield( ba ) );
455        if ( result == nullptr )
456        {
457                while ( GLenum err = glGetError() )
458                switch ( err )
459                {
460                case GL_INVALID_VALUE     : NV_LOG_ERROR( "map_buffer failed : GL_INVALID_VALUE" ) break;
461                case GL_INVALID_OPERATION : NV_LOG_ERROR( "map_buffer failed : GL_INVALID_OPERATION " ) break;
462                case GL_OUT_OF_MEMORY     : NV_LOG_ERROR( "map_buffer failed : GL_OUT_OF_MEMORY " ) break;
[500]463                default:
[499]464                        break;
465                }
466        }
467        return result;
468}
469
470void nv::gl_context::unmap_buffer( buffer b )
471{
472        const gl_buffer_info* info = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( b ) );
473        glUnmapBuffer( buffer_type_to_enum( info->type ) );
474}
475
[485]476// void nv::gl_context::update( buffer b, uint32 index, const void* data, size_t offset, size_t size )
477// {
478//      const gl_buffer_info* info = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( b ) );
479//      if ( info )
480//      {
481//              GLenum glenum = buffer_type_to_enum( info->type );
482//              if ( size == 0 )
483//                      glBindBufferBase( glenum, index, info->glid );
484//              else
485//                      glBindBufferRange( glenum, index, info->glid, offset, size );
486//              glBufferSubData( glenum, GLintptr( offset ), GLsizeiptr( size ), data );
487//      }
488// }
[473]489
[376]490void gl_context::update( buffer b, const void* data, nv::size_t offset, nv::size_t size )
[299]491{
[302]492        const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
493        if ( info )
494        {
[313]495                GLenum glenum = buffer_type_to_enum( info->type );
496                glBindBuffer( glenum, info->glid );
[406]497                glBufferSubData( glenum, GLintptr( offset ), GLsizeiptr( size ), data );
[302]498        }
[299]499}
500
[37]501void gl_context::clear( const clear_state& cs )
502{
503        // apply_framebuffer
[44]504       
[37]505        apply_scissor_test( cs.scissor_test );
506        apply_color_mask( cs.color_mask );
507        apply_depth_mask( cs.depth_mask );
508        // stencil_mask_separate
509
510        if ( m_clear_color != cs.color )
511        {
512                glClearColor( cs.color.r, cs.color.g, cs.color.b, cs.color.a );
513                m_clear_color = cs.color;
514        }
515
516        if ( m_clear_depth != cs.depth )
517        {
518                glClearDepth( cs.depth );
519                m_clear_depth = cs.depth;
520        }
521
522        if ( m_clear_stencil != cs.stencil )
523        {
524                glClearStencil( cs.stencil );
525                m_clear_stencil = cs.stencil;
526        }
[44]527       
528        glClear( clear_state_buffers_to_mask( cs.buffers ) );
[37]529}
530
531const ivec4& gl_context::get_viewport()
532{
533        return m_viewport;
534}
535
536void gl_context::set_viewport( const ivec4& viewport )
537{
[501]538        if ( m_viewport != viewport )
539        {
540                NV_ASSERT_ALWAYS( viewport.z > 0 && viewport.w > 0, "viewport dimensions must be greater than zero!" );
541                m_viewport = viewport;
542                glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
543        }
[37]544}
545
546void gl_context::enable( unsigned int what, bool value )
547{
548        if ( value )
549        {
550                glEnable( what );
551        }
552        else
553        {
554                glDisable( what );
555        }
556}
557
558void gl_context::apply_stencil_test( const stencil_test& stencil )
559{
560        if ( m_render_state.stencil_test.enabled != stencil.enabled )
561        {
562                enable( GL_STENCIL_TEST, stencil.enabled );
563                m_render_state.stencil_test.enabled = stencil.enabled;
564        }
[331]565       
[37]566        if ( stencil.enabled )
567        {
568                apply_stencil_face( GL_FRONT, m_render_state.stencil_test.front_face, stencil.front_face );
569                apply_stencil_face( GL_BACK,  m_render_state.stencil_test.back_face,  stencil.back_face );
570        }
571}
572
[121]573void gl_context::apply_stencil_face( unsigned face, stencil_test_face& stencil, const stencil_test_face& new_stencil )
[37]574{
575        if (( stencil.op_fail       != new_stencil.op_fail       ) ||
576                ( stencil.op_depth_fail != new_stencil.op_depth_fail ) ||
577                ( stencil.op_depth_pass != new_stencil.op_depth_pass ) )
578        {
579                glStencilOpSeparate( face,
580                        stencil_operation_to_enum( new_stencil.op_fail ),
581                        stencil_operation_to_enum( new_stencil.op_depth_fail ),
582                        stencil_operation_to_enum( new_stencil.op_depth_pass )
583                );
584
585                stencil.op_fail       = new_stencil.op_fail;
586                stencil.op_depth_fail = new_stencil.op_depth_fail;
587                stencil.op_depth_pass = new_stencil.op_depth_pass;
588        }
589
590        if (( stencil.function  != new_stencil.function ) ||
591                ( stencil.ref_value != new_stencil.ref_value ) ||
592                ( stencil.mask      != new_stencil.mask ))
593        {
594                glStencilFuncSeparate( face,
595                        stencil_function_to_enum( new_stencil.function ),
596                        new_stencil.ref_value,
597                        new_stencil.mask
598                );
599
600                stencil.function  = new_stencil.function;
601                stencil.ref_value = new_stencil.ref_value;
602                stencil.mask      = new_stencil.mask;
603        }
604}
605
606void gl_context::apply_scissor_test( const scissor_test& scissor )
607{
608        if ( m_render_state.scissor_test.enabled != scissor.enabled )
609        {
610                enable( GL_SCISSOR_TEST, scissor.enabled );
611                m_render_state.scissor_test.enabled = scissor.enabled;
612        }
613
614
615        if ( scissor.enabled )
616        {
[403]617                NV_ASSERT_ALWAYS( scissor.dim.x > 0 && scissor.dim.y > 0, "scissor_test.rect dimension equal to zero!" );
618
[37]619                if ( m_render_state.scissor_test.dim != scissor.dim || m_render_state.scissor_test.pos != scissor.pos )
620                {
621                        glScissor(
622                                scissor.pos.x, scissor.pos.y,
623                                scissor.dim.x, scissor.dim.y
624                        );
625                        m_render_state.scissor_test.dim = scissor.dim;
626                        m_render_state.scissor_test.pos = scissor.pos;
627                }
628        }
629}
630
631void gl_context::apply_depth_test( const depth_test& depth )
632{
633        if ( m_render_state.depth_test.enabled != depth.enabled )
634        {
635                enable( GL_DEPTH_TEST, depth.enabled );
636                m_render_state.depth_test.enabled = depth.enabled;
637        }
638
639        if ( depth.enabled )
640        {
641                if ( m_render_state.depth_test.function != depth.function )
642                {
643                        glDepthFunc( depth_state_function_to_enum( depth.function ) );
644                        m_render_state.depth_test.function = depth.function;
645                }
646        }
647}
648
649void gl_context::apply_depth_mask( bool mask )
650{
651        if ( m_render_state.depth_mask != mask )
652        {
653                glDepthMask( mask );
654                m_render_state.depth_mask = mask;
655        }
656}
657
[492]658void gl_context::apply_multisample( bool multisample )
659{
660        if ( m_render_state.multisample != multisample )
661        {
662                glDepthMask( multisample );
663                m_render_state.multisample = multisample;
664        }
665}
666
[233]667void gl_context::apply_polygon_mode( const polygon_mode& mode )
668{
669        if ( m_render_state.polygon_mode.fill != mode.fill )
670        {
671                glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( mode.fill ) );
672                m_render_state.polygon_mode.fill = mode.fill;
673        }
674}
675
676
[37]677void gl_context::apply_depth_range( const depth_range& range )
678{
[403]679        NV_ASSERT_ALWAYS( range.near >= 0.0 && range.near <= 1.0, "render_state.depth_range.near must be between zero and one!" );
680        NV_ASSERT_ALWAYS( range.far  >= 0.0 && range.far  <= 1.0, "render_state.depth_range.far must be between zero and one!" );
[37]681
682        if ((m_render_state.depth_range.far  != range.far) ||
683                (m_render_state.depth_range.near != range.near))
684        {
685                glDepthRange( range.near, range.far );
686
687                m_render_state.depth_range.far  = range.far;
688                m_render_state.depth_range.near = range.near;
689        }
690}
691
692void gl_context::apply_color_mask( const color_mask& mask )
693{
694        if ( m_render_state.color_mask != mask )
695        {
696                glColorMask( mask.red, mask.green, mask.blue, mask.alpha );
697                m_render_state.color_mask = mask;
698        }
699}
700
701void gl_context::apply_blending( const blending& blend )
702{
703        if ( m_render_state.blending.enabled != blend.enabled )
704        {
705                enable( GL_BLEND, blend.enabled );
706                m_render_state.blending.enabled = blend.enabled;
707        }
708
709        if ( blend.enabled )
710        {
711                if ((m_render_state.blending.src_rgb_factor   != blend.src_rgb_factor ) ||
712                        (m_render_state.blending.dst_rgb_factor   != blend.dst_rgb_factor ) ||
713                        (m_render_state.blending.src_alpha_factor != blend.src_alpha_factor ) ||
714                        (m_render_state.blending.dst_alpha_factor != blend.dst_alpha_factor ))
715                {
716                        glBlendFuncSeparate(
717                                blending_factor_to_enum( blend.src_rgb_factor ),
718                                blending_factor_to_enum( blend.dst_rgb_factor ),
719                                blending_factor_to_enum( blend.src_alpha_factor ),
720                                blending_factor_to_enum( blend.dst_alpha_factor )
721                        );
722
723                        m_render_state.blending.src_rgb_factor   = blend.src_rgb_factor;
724                        m_render_state.blending.dst_rgb_factor   = blend.dst_rgb_factor;
725                        m_render_state.blending.src_alpha_factor = blend.src_alpha_factor;
726                        m_render_state.blending.dst_alpha_factor = blend.dst_alpha_factor;
727                }
728
729                if ((m_render_state.blending.rgb_equation   != blend.rgb_equation ) ||
730                        (m_render_state.blending.alpha_equation != blend.alpha_equation ))
731                {
732                        glBlendEquationSeparate(
733                                blending_equation_to_enum( blend.rgb_equation ),
734                                blending_equation_to_enum( blend.alpha_equation )
735                        );
736
737                        m_render_state.blending.rgb_equation   = blend.rgb_equation;
738                        m_render_state.blending.alpha_equation = blend.alpha_equation;
739                }
740
741                if (( m_render_state.blending.color != blend.color ))
742                {
743                        glBlendColor( blend.color.r, blend.color.g, blend.color.b, blend.color.a );
744                        m_render_state.blending.color = blend.color;
745                }
746        }
747}
748
749
750void gl_context::apply_culling( const culling& cull )
751{
752        if ( m_render_state.culling.enabled != cull.enabled )
753        {
754                enable( GL_CULL_FACE, cull.enabled );
755                m_render_state.culling.enabled = cull.enabled;
756        }
757
758        if ( cull.enabled )
759        {
760                if ( m_render_state.culling.face != cull.face )
761                {
[462]762                        glCullFace( culling_face_type_to_enum( cull.face ) );
[37]763                        m_render_state.culling.face = cull.face;
764                }
[462]765        }
[37]766
[462]767        if ( m_render_state.culling.order != cull.order )
768        {
769                glFrontFace( culling_order_type_to_enum( cull.order ) );
770                m_render_state.culling.order = cull.order;
[37]771        }
772}
773
774
775void gl_context::force_apply_render_state( const render_state& state )
776{
777        enable( GL_CULL_FACE, state.culling.enabled );
778        glCullFace( culling_face_type_to_enum( state.culling.face ) );
779        glFrontFace( culling_order_type_to_enum( state.culling.order ) );
780
781        enable( GL_SCISSOR_TEST, state.scissor_test.enabled );
782        glScissor(
783                state.scissor_test.pos.x, state.scissor_test.pos.y,
784                state.scissor_test.dim.x, state.scissor_test.dim.y
785        );
786
787        enable( GL_STENCIL_TEST, state.stencil_test.enabled );
788        force_apply_stencil_face( GL_FRONT, state.stencil_test.front_face );
789        force_apply_stencil_face( GL_BACK,  state.stencil_test.back_face  );
790
791        enable( GL_DEPTH_TEST, state.depth_test.enabled );
792        glDepthFunc( depth_state_function_to_enum( state.depth_test.function ) );
793        glDepthRange( state.depth_range.near, state.depth_range.far );
794
795        enable( GL_BLEND, state.blending.enabled );
796        glBlendFuncSeparate(
797                blending_factor_to_enum( state.blending.src_rgb_factor ),
798                blending_factor_to_enum( state.blending.dst_rgb_factor ),
799                blending_factor_to_enum( state.blending.src_alpha_factor ),
800                blending_factor_to_enum( state.blending.dst_alpha_factor )
801        );
802        glBlendEquationSeparate(
803                blending_equation_to_enum( state.blending.rgb_equation ),
804                blending_equation_to_enum( state.blending.alpha_equation )
805        );
806        glBlendColor(
807                state.blending.color.r, state.blending.color.g,
808                state.blending.color.b, state.blending.color.a
809        );
810
811        glDepthMask( state.depth_mask );
812        glColorMask(
813                state.color_mask.red, state.color_mask.green,
814                state.color_mask.blue, state.color_mask.alpha
815        );
[233]816        glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( state.polygon_mode.fill ) );
[37]817}
818
[121]819void gl_context::force_apply_stencil_face( unsigned face, const stencil_test_face& stencil )
[37]820{
821        glStencilOpSeparate( face,
822                stencil_operation_to_enum( stencil.op_fail ),
823                stencil_operation_to_enum( stencil.op_depth_fail ),
824                stencil_operation_to_enum( stencil.op_depth_pass )
825        );
826
827        glStencilFuncSeparate( face,
828                stencil_function_to_enum( stencil.function ),
829                stencil.ref_value,
830                stencil.mask
831        );
832}
833
834
835void gl_context::apply_render_state( const render_state& state )
836{
837        // apply_primitive_restart
838        apply_culling( state.culling );
839        // apply_program_point_size
840        // apply_rasterization_mode
841        apply_scissor_test( state.scissor_test );
842        apply_stencil_test( state.stencil_test );
843        apply_depth_test( state.depth_test );
844        apply_depth_range( state.depth_range );
845        apply_blending( state.blending );
846        apply_color_mask( state.color_mask );
847        apply_depth_mask( state.depth_mask );
[492]848        apply_multisample( state.multisample );
[233]849        apply_polygon_mode( state.polygon_mode );
[37]850}
851
[44]852
[326]853gl_context::gl_context( device* a_device, void* a_handle )
854        : context( a_device ), m_handle( a_handle )
[44]855{
[331]856        // TODO: configurable:
[491]857//      load_gl_extensions( GL_EXT_FRAMEBUFFER_BLIT | GL_EXT_FRAMEBUFFER_OBJECT | GL_EXT_TEXTURE_ARRAY );
[492]858        m_active_slot = texture_slot( -1 );
[326]859        force_apply_render_state( m_render_state );
[245]860}
861
862nv::gl_context::~gl_context()
863{
[313]864        while ( m_framebuffers.size() > 0 )
865                release( m_framebuffers.get_handle(0) );
866        while ( m_vertex_arrays.size() > 0 )
867                release( m_vertex_arrays.get_handle(0) );
[245]868}
869
[303]870void nv::gl_context::apply_engine_uniforms( program p, const scene_state& s )
[245]871{
[406]872        gl_program_info* info = static_cast<gl_device*>( m_device )->m_programs.get( p );
[303]873        if ( info )
874        {
[392]875                for ( auto& u : *info->m_engine_uniforms )
[303]876                {
877                        u->set( this, &s );
878                }
879        }
880}
881
[501]882nv::texture nv::gl_context::create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, const void* data /*= nullptr */ )
883{
884        texture result = create_texture( type, aformat.format );
885        gl_texture_info* info = static_cast<gl_device*>( m_device )->get_full_texture_info( result );
886        bind( result, texture_slot::TEXTURE_0 );
887        unsigned glid = info->glid;
888        unsigned gl_type = texture_type_to_enum( type );
889        GLenum gl_internal = GLenum( image_format_to_internal_enum( aformat.format ) );
890        unsigned gl_enum = image_format_to_enum( aformat.format );
891
892        bool is_depth = aformat.format == DEPTH16 || aformat.format == DEPTH24 || aformat.format == DEPTH32;
893
894        // Detect if mipmapping was requested
895        //      if ( gl_type == GL_TEXTURE_2D && gl_enum != GL_RED_INTEGER && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
896        //      {
897        //              // TODO: This should not be done if we use framebuffers!
898        //              glTexParameteri( gl_type, GL_GENERATE_MIPMAP, GL_TRUE);
899        //      }
900
901        if ( asampler.filter_max != sampler::NEAREST )
902        {
903                asampler.filter_max = sampler::LINEAR;
904        }
905
906        if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE )
907        {
908                glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_min ) ) );
909                glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_max ) ) );
910        }
911
912        if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE && gl_enum != GL_RED_INTEGER )
913        {
914                glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, GLint( nv::sampler_wrap_to_enum( asampler.wrap_s ) ) );
915                glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, GLint( nv::sampler_wrap_to_enum( asampler.wrap_t ) ) );
916        }
917
918        if ( is_depth )
919        {
920                //              glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
921                //              glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
922
923                // This is to allow usage of shadow2DProj function in the shader
924                glTexParameteri( gl_type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE );
925                glTexParameteri( gl_type, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );
926        }
927
928        // #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
929        // #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
930        //
931        //      float aniso = 0.0f;
932        //      glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &aniso );
933        //      NV_LOG_INFO( "Anisotropy at ", aniso, " (", int( aniso ), " ) " );
934        //      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso );
935
936        if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE )
937                glTexImage2D( gl_type, 0, gl_internal, size.x, size.y, 0, gl_enum, nv::datatype_to_gl_enum( aformat.type ), data );
938        else
939                glTexImage2DMultisample( gl_type, 4, gl_internal, size.x, size.y, 1 );
940
941        if ( gl_type == GL_TEXTURE_2D && gl_enum != GL_RED_INTEGER && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
942        {
943                // TODO: This should not be done if we use framebuffers!
944                glGenerateMipmap( gl_type );
945        }
946
947        bind( texture(), texture_slot::TEXTURE_0 );
948
949        info->type = type;
950        info->format = aformat;
951        info->tsampler = asampler;
952        info->size = ivec3( size.x, size.y, 1 );
953        info->glid = glid;
954
955        return result;
956}
957
958nv::texture nv::gl_context::create_texture( texture_type type, ivec3 size, image_format aformat, sampler asampler, const void* data /*= nullptr */ )
959{
960        texture result = create_texture( type, aformat.format );
961        gl_texture_info* info = static_cast<gl_device*>( m_device )->get_full_texture_info( result );
962        bind( result, texture_slot::TEXTURE_0 );
963        unsigned glid = info->glid;
964
965        unsigned gl_type = texture_type_to_enum( type );
966
967        bool is_depth = aformat.format == DEPTH16 || aformat.format == DEPTH24 || aformat.format == DEPTH32;
968
969        if ( asampler.filter_max != sampler::NEAREST )
970        {
971                asampler.filter_max = sampler::LINEAR;
972        }
973
974        glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_min ) ) );
975        glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_max ) ) );
976        glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, GLint( nv::sampler_wrap_to_enum( asampler.wrap_s ) ) );
977        glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, GLint( nv::sampler_wrap_to_enum( asampler.wrap_t ) ) );
[515]978        glTexParameteri( gl_type, GL_TEXTURE_WRAP_R, GLint( nv::sampler_wrap_to_enum( asampler.wrap_r ) ) );
[501]979
980        if ( is_depth )
981        {
982                glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
983                glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
984
985                // This is to allow usage of shadow2DProj function in the shader
986                glTexParameteri( gl_type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE );
987                glTexParameteri( gl_type, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );
988        }
989
990        //glTexStorage3D( GL_TEXTURE_2D_ARRAY, mipLevelCount, GL_RGBA8, width, height, layerCount );
991        glTexImage3D( gl_type, 0, GLint( nv::image_format_to_internal_enum( aformat.format ) ), size.x, size.y, size.z, 0, nv::image_format_to_enum( aformat.format ), nv::datatype_to_gl_enum( aformat.type ), data );
992
993        bind( texture(), texture_slot::TEXTURE_0 );
994
995        info->type = type;
996        info->format = aformat;
997        info->tsampler = asampler;
998        info->size = size;
999        info->glid = glid;
1000
1001        return result;
1002}
1003
1004nv::buffer nv::gl_context::create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source /*= nullptr */ )
1005{
1006        buffer result = static_cast<gl_device*>( m_device )->create_buffer( type, hint );
1007        if ( size > 0 ) create_buffer( result, size, source );
1008        return result;
1009}
1010
1011void nv::gl_context::create_buffer( buffer b, size_t size, const void* source /*= nullptr */ )
1012{
1013        gl_buffer_info* info = static_cast<gl_device*>( m_device )->get_full_buffer_info( b );
1014        if ( info )
1015        {
1016                unsigned glenum = buffer_type_to_enum( info->type );
1017                glBindBuffer( glenum, info->glid );
1018                glBufferData( glenum, GLsizeiptr( size ), source, buffer_hint_to_enum( info->hint ) );
1019                glBindBuffer( glenum, 0 );
1020        }
1021}
1022
[342]1023void nv::gl_context::set_draw_buffers( uint32 count, const output_slot* slots )
[331]1024{
[342]1025        if ( count == 0 ) return;
1026        if ( count == 1 )
1027        {
1028                set_draw_buffer( slots[0] );
1029                return;
1030        }
[331]1031        unsigned int buffers[8];
[398]1032        count = nv::min<uint32>( count, 8 );
[331]1033        for ( uint32 i = 0; i < count; ++i )
1034        {
1035                buffers[i] = output_slot_to_enum( slots[i] );
1036                if ( slots[i] > OUTPUT_7 ) buffers[i] = 0;
1037        }
[406]1038        glDrawBuffers( GLsizei( count ), buffers );
[331]1039}
1040
1041void nv::gl_context::set_draw_buffer( output_slot slot )
1042{
1043        glDrawBuffer( output_slot_to_enum(slot) );
1044}
1045
1046void nv::gl_context::set_read_buffer( output_slot slot )
1047{
1048        glReadBuffer( output_slot_to_enum(slot) );
1049}
1050
[473]1051void gl_context::draw( primitive prim, const render_state& rs, program p, vertex_array va, nv::size_t count, nv::size_t first )
[303]1052{
[245]1053        apply_render_state( rs );
[313]1054        const vertex_array_info* info = m_vertex_arrays.get( va );
[302]1055        if ( count > 0 && info )
[245]1056        {
[299]1057                bind( p );
1058                bind( va );
[302]1059                if ( info->index.is_valid() )
[245]1060                {
[473]1061                        glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( info->index_type ), reinterpret_cast< const void* >( get_datatype_info( info->index_type ).size * first ) );
[245]1062                }
1063                else
1064                {
[487]1065                        glDrawArrays( primitive_to_enum(prim), static_cast<GLint>( first ), static_cast<GLsizei>( count ) );
[245]1066                }
[299]1067                unbind( va );
1068                //unbind( p );
[245]1069        }
1070}
[502]1071
1072void nv::gl_context::draw_instanced( primitive prim, const render_state& rs, program p, size_t instances, vertex_array va, size_t count, size_t first /*= 0 */ )
1073{
1074        apply_render_state( rs );
1075        const vertex_array_info* info = m_vertex_arrays.get( va );
1076        if ( count > 0 && info )
1077        {
1078                bind( p );
1079                bind( va );
1080                if ( info->index.is_valid() )
1081                {
1082                        glDrawElementsInstanced( primitive_to_enum( prim ), static_cast<GLsizei>( count ), datatype_to_gl_enum( info->index_type ), reinterpret_cast<const void*>( get_datatype_info( info->index_type ).size * first ), instances );
1083                }
1084                else
1085                {
1086                        glDrawArraysInstanced( primitive_to_enum( prim ), static_cast<GLint>( first ), static_cast<GLsizei>( count ), instances );
1087                }
1088                unbind( va );
1089                //unbind( p );
1090        }
1091}
Note: See TracBrowser for help on using the repository browser.