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

Last change on this file since 301 was 301, checked in by epyon, 11 years ago
  • textures are now handled by lightweight handles
  • textures now need to be manually released via context
  • removed all old texture2d functionality
  • unreleased textures will be auto-released
  • textures are properly tracked via entity system
  • detailed stats and checking now possible
File size: 16.6 KB
RevLine 
[37]1// Copyright (C) 2012-2013 Kornel Kisielewicz
2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#include "nv/gl/gl_context.hh"
6
7#include "nv/gl/gl_enum.hh"
8#include "nv/lib/gl.hh"
[171]9#include "nv/lib/sdl.hh"
[301]10#include "nv/gl/gl_device.hh"
[299]11#include "nv/gl/gl_program.hh"
12#include "nv/gl/gl_vertex_buffer.hh"
[37]13
14using namespace nv;
15
[301]16void gl_context::bind( texture t, texture_slot slot )
[299]17{
[301]18        const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
19        if ( info )
20        {
21                glActiveTexture( GL_TEXTURE0 + static_cast< GLenum >( slot ) );
22                glBindTexture( GL_TEXTURE_2D, info->glid );
23        }
[299]24}
25
26void nv::gl_context::bind( program* p )
27{
28        gl_program* glp = static_cast< gl_program* >( p );
[300]29        glUseProgram( glp->glid );
[299]30        glp->update_uniforms();
31}
32
33void nv::gl_context::bind( vertex_buffer* b )
34{
[300]35        GLuint id = static_cast< gl_vertex_buffer* >( b )->glid;
[299]36        glBindBuffer( GL_ARRAY_BUFFER, id );
37}
38
39void nv::gl_context::bind( index_buffer* b )
40{
[300]41        GLuint id = static_cast< gl_index_buffer* >( b )->glid;
[299]42        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, id );
43}
44
45void nv::gl_context::bind( vertex_array* va )
46{
47        for ( vertex_buffer_attribute_map::iterator i = va->m_map.begin();      i != va->m_map.end(); ++i )
48        {
49                uint32 location             = static_cast<uint32>( i->first );
50                vertex_buffer_attribute* va = i->second;
51                vertex_buffer*           vb = va->get_buffer();
52                glEnableVertexAttribArray( location );
53                bind( vb );
54                glVertexAttribPointer(
55                        location,
56                        static_cast<GLint>( va->get_components() ),
57                        nv::datatype_to_gl_enum( va->get_datatype() ),
58                        GL_FALSE,
59                        static_cast<GLsizei>( va->get_stride() ),
60                        (void*)va->get_offset()
61                        );
62                unbind( vb );
63        }
64
65        if ( va->m_index )
66        {
67                bind( va->m_index );
68        }
69}
70
71void nv::gl_context::unbind( program* )
72{
73        glUseProgram( 0 );
74}
75
76void nv::gl_context::unbind( vertex_buffer* )
77{
78        glBindBuffer( GL_ARRAY_BUFFER, 0 );
79}
80
81void nv::gl_context::unbind( index_buffer* )
82{
83        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
84}
85
86void nv::gl_context::unbind( vertex_array* va )
87{
88        if ( va->m_index )
89        {
90                unbind( va->m_index );
91        }
92
93        for ( vertex_buffer_attribute_map::iterator i = va->m_map.begin();      i != va->m_map.end(); ++i )
94        {
95                glDisableVertexAttribArray( static_cast<uint32>( i->first ) );
96        }
97}
98
[301]99void nv::gl_context::update( texture t, void* data )
[299]100{
[301]101        const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
102        if ( info )
103        {
104                image_format format = info->format;
105                ivec2        size   = info->size;
[299]106
[301]107                glBindTexture( GL_TEXTURE_2D, info->glid );
108                glTexImage2D( GL_TEXTURE_2D, 0, (GLint)nv::image_format_to_enum(format.format), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
109        }
[299]110}
111
112void gl_context::update( vertex_buffer* b, const void* data, size_t offset, size_t size )
113{
114        bind( b );
115        glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)offset, (GLsizeiptr)size, data );
116}
117
118void gl_context::update( index_buffer* b, const void* data, size_t offset, size_t size )
119{
120        bind( b );
121        glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, (GLintptr)offset, (GLsizeiptr)size, data );
122}
123
[37]124void gl_context::clear( const clear_state& cs )
125{
126        // apply_framebuffer
[44]127       
[37]128        apply_scissor_test( cs.scissor_test );
129        apply_color_mask( cs.color_mask );
130        apply_depth_mask( cs.depth_mask );
131        // stencil_mask_separate
132
133        if ( m_clear_color != cs.color )
134        {
135                glClearColor( cs.color.r, cs.color.g, cs.color.b, cs.color.a );
136                m_clear_color = cs.color;
137        }
138
139        if ( m_clear_depth != cs.depth )
140        {
141                glClearDepth( cs.depth );
142                m_clear_depth = cs.depth;
143        }
144
145        if ( m_clear_stencil != cs.stencil )
146        {
147                glClearStencil( cs.stencil );
148                m_clear_stencil = cs.stencil;
149        }
[44]150       
151        glClear( clear_state_buffers_to_mask( cs.buffers ) );
[37]152}
153
154const ivec4& gl_context::get_viewport()
155{
156        return m_viewport;
157}
158
159void gl_context::set_viewport( const ivec4& viewport )
160{
161        if ( viewport.z < 0 || viewport.w < 0 )
162        {
[64]163                NV_THROW( logic_error, "viewport width and height must be greater than zero!");
[37]164        }
165
166        m_viewport = viewport;
167        glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
168}
169
170void gl_context::enable( unsigned int what, bool value )
171{
172        if ( value )
173        {
174                glEnable( what );
175        }
176        else
177        {
178                glDisable( what );
179        }
180}
181
182void gl_context::apply_stencil_test( const stencil_test& stencil )
183{
184        if ( m_render_state.stencil_test.enabled != stencil.enabled )
185        {
186                enable( GL_STENCIL_TEST, stencil.enabled );
187                m_render_state.stencil_test.enabled = stencil.enabled;
188        }
189
190        if ( stencil.enabled )
191        {
192                apply_stencil_face( GL_FRONT, m_render_state.stencil_test.front_face, stencil.front_face );
193                apply_stencil_face( GL_BACK,  m_render_state.stencil_test.back_face,  stencil.back_face );
194        }
195}
196
[121]197void gl_context::apply_stencil_face( unsigned face, stencil_test_face& stencil, const stencil_test_face& new_stencil )
[37]198{
199        if (( stencil.op_fail       != new_stencil.op_fail       ) ||
200                ( stencil.op_depth_fail != new_stencil.op_depth_fail ) ||
201                ( stencil.op_depth_pass != new_stencil.op_depth_pass ) )
202        {
203                glStencilOpSeparate( face,
204                        stencil_operation_to_enum( new_stencil.op_fail ),
205                        stencil_operation_to_enum( new_stencil.op_depth_fail ),
206                        stencil_operation_to_enum( new_stencil.op_depth_pass )
207                );
208
209                stencil.op_fail       = new_stencil.op_fail;
210                stencil.op_depth_fail = new_stencil.op_depth_fail;
211                stencil.op_depth_pass = new_stencil.op_depth_pass;
212        }
213
214        if (( stencil.function  != new_stencil.function ) ||
215                ( stencil.ref_value != new_stencil.ref_value ) ||
216                ( stencil.mask      != new_stencil.mask ))
217        {
218                glStencilFuncSeparate( face,
219                        stencil_function_to_enum( new_stencil.function ),
220                        new_stencil.ref_value,
221                        new_stencil.mask
222                );
223
224                stencil.function  = new_stencil.function;
225                stencil.ref_value = new_stencil.ref_value;
226                stencil.mask      = new_stencil.mask;
227        }
228}
229
230void gl_context::apply_scissor_test( const scissor_test& scissor )
231{
232        if ( m_render_state.scissor_test.enabled != scissor.enabled )
233        {
234                enable( GL_SCISSOR_TEST, scissor.enabled );
235                m_render_state.scissor_test.enabled = scissor.enabled;
236        }
237
238        if ( scissor.dim.x < 0 || scissor.dim.y < 0 )
239        {
[64]240                NV_THROW( logic_error, "scissor_test.rect width and height must be greater than zero!" );
[37]241        }
242
243        if ( scissor.enabled )
244        {
245                if ( m_render_state.scissor_test.dim != scissor.dim || m_render_state.scissor_test.pos != scissor.pos )
246                {
247                        glScissor(
248                                scissor.pos.x, scissor.pos.y,
249                                scissor.dim.x, scissor.dim.y
250                        );
251                        m_render_state.scissor_test.dim = scissor.dim;
252                        m_render_state.scissor_test.pos = scissor.pos;
253                }
254        }
255}
256
257void gl_context::apply_depth_test( const depth_test& depth )
258{
259        if ( m_render_state.depth_test.enabled != depth.enabled )
260        {
261                enable( GL_DEPTH_TEST, depth.enabled );
262                m_render_state.depth_test.enabled = depth.enabled;
263        }
264
265        if ( depth.enabled )
266        {
267                if ( m_render_state.depth_test.function != depth.function )
268                {
269                        glDepthFunc( depth_state_function_to_enum( depth.function ) );
270                        m_render_state.depth_test.function = depth.function;
271                }
272        }
273}
274
275void gl_context::apply_depth_mask( bool mask )
276{
277        if ( m_render_state.depth_mask != mask )
278        {
279                glDepthMask( mask );
280                m_render_state.depth_mask = mask;
281        }
282}
283
[233]284void gl_context::apply_polygon_mode( const polygon_mode& mode )
285{
286        if ( m_render_state.polygon_mode.fill != mode.fill )
287        {
288                glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( mode.fill ) );
289                m_render_state.polygon_mode.fill = mode.fill;
290        }
291}
292
293
[37]294void gl_context::apply_depth_range( const depth_range& range )
295{
296        if ( range.near < 0.0 || range.near > 1.0 )
297        {
[64]298                NV_THROW( logic_error, "render_state.depth_range.near must be between zero and one!");
[37]299        }
300        if ( range.far < 0.0 || range.far > 1.0 )
301        {
[64]302                NV_THROW( logic_error, "render_state.depth_range.far must be between zero and one!");
[37]303        }
304
305        if ((m_render_state.depth_range.far  != range.far) ||
306                (m_render_state.depth_range.near != range.near))
307        {
308                glDepthRange( range.near, range.far );
309
310                m_render_state.depth_range.far  = range.far;
311                m_render_state.depth_range.near = range.near;
312        }
313}
314
315void gl_context::apply_color_mask( const color_mask& mask )
316{
317        if ( m_render_state.color_mask != mask )
318        {
319                glColorMask( mask.red, mask.green, mask.blue, mask.alpha );
320                m_render_state.color_mask = mask;
321        }
322}
323
324void gl_context::apply_blending( const blending& blend )
325{
326        if ( m_render_state.blending.enabled != blend.enabled )
327        {
328                enable( GL_BLEND, blend.enabled );
329                m_render_state.blending.enabled = blend.enabled;
330        }
331
332        if ( blend.enabled )
333        {
334                if ((m_render_state.blending.src_rgb_factor   != blend.src_rgb_factor ) ||
335                        (m_render_state.blending.dst_rgb_factor   != blend.dst_rgb_factor ) ||
336                        (m_render_state.blending.src_alpha_factor != blend.src_alpha_factor ) ||
337                        (m_render_state.blending.dst_alpha_factor != blend.dst_alpha_factor ))
338                {
339                        glBlendFuncSeparate(
340                                blending_factor_to_enum( blend.src_rgb_factor ),
341                                blending_factor_to_enum( blend.dst_rgb_factor ),
342                                blending_factor_to_enum( blend.src_alpha_factor ),
343                                blending_factor_to_enum( blend.dst_alpha_factor )
344                        );
345
346                        m_render_state.blending.src_rgb_factor   = blend.src_rgb_factor;
347                        m_render_state.blending.dst_rgb_factor   = blend.dst_rgb_factor;
348                        m_render_state.blending.src_alpha_factor = blend.src_alpha_factor;
349                        m_render_state.blending.dst_alpha_factor = blend.dst_alpha_factor;
350                }
351
352                if ((m_render_state.blending.rgb_equation   != blend.rgb_equation ) ||
353                        (m_render_state.blending.alpha_equation != blend.alpha_equation ))
354                {
355                        glBlendEquationSeparate(
356                                blending_equation_to_enum( blend.rgb_equation ),
357                                blending_equation_to_enum( blend.alpha_equation )
358                        );
359
360                        m_render_state.blending.rgb_equation   = blend.rgb_equation;
361                        m_render_state.blending.alpha_equation = blend.alpha_equation;
362                }
363
364                if (( m_render_state.blending.color != blend.color ))
365                {
366                        glBlendColor( blend.color.r, blend.color.g, blend.color.b, blend.color.a );
367                        m_render_state.blending.color = blend.color;
368                }
369        }
370}
371
372
373void gl_context::apply_culling( const culling& cull )
374{
375        if ( m_render_state.culling.enabled != cull.enabled )
376        {
377                enable( GL_CULL_FACE, cull.enabled );
378                m_render_state.culling.enabled = cull.enabled;
379        }
380
381        if ( cull.enabled )
382        {
383                if ( m_render_state.culling.face != cull.face )
384                {
385                        glCullFace( culling_face_type_to_enum(cull.face) );
386                        m_render_state.culling.face = cull.face;
387                }
388
389                if ( m_render_state.culling.order != cull.order )
390                {
391                        glFrontFace( culling_order_type_to_enum( cull.order ) );
392                        m_render_state.culling.order = cull.order;
393                }
394        }
395}
396
397
398void gl_context::force_apply_render_state( const render_state& state )
399{
400        enable( GL_CULL_FACE, state.culling.enabled );
401        glCullFace( culling_face_type_to_enum( state.culling.face ) );
402        glFrontFace( culling_order_type_to_enum( state.culling.order ) );
403
404        enable( GL_SCISSOR_TEST, state.scissor_test.enabled );
405        glScissor(
406                state.scissor_test.pos.x, state.scissor_test.pos.y,
407                state.scissor_test.dim.x, state.scissor_test.dim.y
408        );
409
410        enable( GL_STENCIL_TEST, state.stencil_test.enabled );
411        force_apply_stencil_face( GL_FRONT, state.stencil_test.front_face );
412        force_apply_stencil_face( GL_BACK,  state.stencil_test.back_face  );
413
414        enable( GL_DEPTH_TEST, state.depth_test.enabled );
415        glDepthFunc( depth_state_function_to_enum( state.depth_test.function ) );
416        glDepthRange( state.depth_range.near, state.depth_range.far );
417
418        enable( GL_BLEND, state.blending.enabled );
419        glBlendFuncSeparate(
420                blending_factor_to_enum( state.blending.src_rgb_factor ),
421                blending_factor_to_enum( state.blending.dst_rgb_factor ),
422                blending_factor_to_enum( state.blending.src_alpha_factor ),
423                blending_factor_to_enum( state.blending.dst_alpha_factor )
424        );
425        glBlendEquationSeparate(
426                blending_equation_to_enum( state.blending.rgb_equation ),
427                blending_equation_to_enum( state.blending.alpha_equation )
428        );
429        glBlendColor(
430                state.blending.color.r, state.blending.color.g,
431                state.blending.color.b, state.blending.color.a
432        );
433
434        glDepthMask( state.depth_mask );
435        glColorMask(
436                state.color_mask.red, state.color_mask.green,
437                state.color_mask.blue, state.color_mask.alpha
438        );
[233]439        glPolygonMode( GL_FRONT_AND_BACK, polygon_mode_fill_to_enum( state.polygon_mode.fill ) );
[37]440}
441
[121]442void gl_context::force_apply_stencil_face( unsigned face, const stencil_test_face& stencil )
[37]443{
444        glStencilOpSeparate( face,
445                stencil_operation_to_enum( stencil.op_fail ),
446                stencil_operation_to_enum( stencil.op_depth_fail ),
447                stencil_operation_to_enum( stencil.op_depth_pass )
448        );
449
450        glStencilFuncSeparate( face,
451                stencil_function_to_enum( stencil.function ),
452                stencil.ref_value,
453                stencil.mask
454        );
455}
456
457
458void gl_context::apply_render_state( const render_state& state )
459{
460        // apply_primitive_restart
461        apply_culling( state.culling );
462        // apply_program_point_size
463        // apply_rasterization_mode
464        apply_scissor_test( state.scissor_test );
465        apply_stencil_test( state.stencil_test );
466        apply_depth_test( state.depth_test );
467        apply_depth_range( state.depth_range );
468        apply_blending( state.blending );
469        apply_color_mask( state.color_mask );
470        apply_depth_mask( state.depth_mask );
[233]471        apply_polygon_mode( state.polygon_mode );
[37]472}
473
[44]474
[245]475gl_context::gl_context( device* a_device )
476        : context( a_device )
[44]477{
[245]478}
479
480
481nv::gl_context::~gl_context()
482{
483}
484
485void gl_context::draw( primitive prim, const render_state& rs, program* p, vertex_array* va, size_t count )
486{
487        apply_render_state( rs );
488        if ( count > 0 )
489        {
[299]490                bind( p );
491                bind( va );
[245]492                if ( va->has_index_buffer() )
493                {
494                        glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( va->get_index_buffer_type() ), 0 );
495                }
496                else
497                {
498                        glDrawArrays( primitive_to_enum(prim), 0, static_cast<GLsizei>( count ) );
499                }
[299]500                unbind( va );
501                //unbind( p );
[245]502        }
503}
504
505nv::sdl_gl_context::sdl_gl_context( device* a_device, void* a_sdl_win_handle )
506        : gl_context( a_device ), m_handle( nullptr )
507{
[171]508#if NV_SDL_VERSION == NV_SDL_20
[245]509        m_handle = SDL_GL_CreateContext( static_cast<SDL_Window*>( a_sdl_win_handle ) );
[171]510
511        if ( m_handle == 0 )
512        {
513                NV_LOG( LOG_CRITICAL, "GL Context creation failed: " << SDL_GetError( ) );
514                return; // TODO: Error report
515        }
516#else
517        NV_UNUSED( a_win_handle );
[198]518        NV_UNUSED( m_handle );
[171]519#endif
520
521        nv::load_gl_library();
522        NV_LOG( LOG_INFO, "OpenGL Vendor       : " << glGetString(GL_VENDOR) );
523        NV_LOG( LOG_INFO, "OpenGL Renderer     : " << glGetString(GL_RENDERER) );
524        NV_LOG( LOG_INFO, "OpenGL Version      : " << glGetString(GL_VERSION) );
525        NV_LOG( LOG_INFO, "OpenGL GLSL Version : " << glGetString(GL_SHADING_LANGUAGE_VERSION) );
526#if NV_SDL_VERSION == NV_SDL_20
[245]527        //      SDL_GL_SetSwapInterval(1);
[171]528#endif
529
[108]530        // TODO: do we really need this?
531        glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
[171]532
[44]533        force_apply_render_state( m_render_state );
534}
[45]535
[245]536nv::sdl_gl_context::~sdl_gl_context()
[171]537{
538#if NV_SDL_VERSION == NV_SDL_20
539        SDL_GL_DeleteContext(static_cast<SDL_GLContext>( m_handle ) );
540#endif
541}
542
[245]543nv::native_gl_context::native_gl_context( device* a_device, void* a_native_win_handle )
544        : gl_context( a_device ), m_handle( nullptr )
545{
546#if NV_PLATFORM == NV_WINDOWS
[171]547
[245]548// TODO: error checking
549        HDC hdc = (HDC)a_native_win_handle;
550
551        const int wgl_attrib_list[] =
[108]552        {
[245]553                WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
554                WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
555                WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
556                WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
557                WGL_PIXEL_TYPE_ARB,     WGL_TYPE_RGBA_ARB,
558                WGL_COLOR_BITS_ARB,     32,
559                WGL_DEPTH_BITS_ARB,     24,
560                WGL_STENCIL_BITS_ARB,   8,
561                0, 0  //End
562        };
563
564        unsigned int num_formats;
565        int pixel_format;
566        PIXELFORMATDESCRIPTOR pfd;
567
568        if ( FALSE == wglChoosePixelFormatARB(hdc, wgl_attrib_list, NULL, 1, &pixel_format, &num_formats) )
569        {
570                return;
[108]571        }
[245]572
573        if ( FALSE == SetPixelFormat(hdc, pixel_format, &pfd) )
574        {
575                //int err = GetLastError();
576                return;
577        }
578
579        int attribs[] =
580        {
581                WGL_CONTEXT_MAJOR_VERSION_ARB,   2,
582                WGL_CONTEXT_MINOR_VERSION_ARB,   1,
583                WGL_CONTEXT_PROFILE_MASK_ARB,  WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
584                //WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
585                0, 0  //End
586        };
587
588        HGLRC handle;
589        if ( 0 == (handle = wglCreateContextAttribsARB(hdc, 0, attribs) ) )
590        {
591                return;
592        }
593
594        if ( FALSE == dynwglMakeCurrent( hdc, handle ) )
595        {
596                return;
597        }     
598
599        m_handle = (void*)handle;
600#else
601        NV_ASSERT( false, "Native GL context not implemented for this platform!" );
602#endif
603        force_apply_render_state( m_render_state );
[45]604}
[245]605
606nv::native_gl_context::~native_gl_context()
607{
608#if NV_PLATFORM == NV_WINDOWS
609        dynwglDeleteContext( (HGLRC)m_handle );
610#endif
611}
Note: See TracBrowser for help on using the repository browser.