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

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