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

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