Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [Solved] Simplest Vertex/Fragment Shaders using QGLWidget Derivation

[Solved] Simplest Vertex/Fragment Shaders using QGLWidget Derivation

Scheduled Pinned Locked Moved General and Desktop
29 Posts 3 Posters 22.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    Hornsj2
    wrote on last edited by
    #3

    Thanks because I am completely stumped.

    I'm using what are essentially "pass-through" shaders copied from the qt example in the 4.7 QGLShaderProgram.

    The projection is orthographic and the viewport should contain the geometry but nothing shows up!

    The shaders compile and link, the attributes are passed in as they should be. but no triangle!

    1 Reply Last reply
    0
    • Z Offline
      Z Offline
      ZapB
      wrote on last edited by
      #4

      It's not something daft like the camera is co-planar withthe triangle is it? I notice that you triangles vertices are all in the plane z=0. Try offsetting them a little perhaps?

      Nokia Certified Qt Specialist
      Interested in hearing about Qt related work

      1 Reply Last reply
      0
      • H Offline
        H Offline
        Hornsj2
        wrote on last edited by
        #5

        Not a bad guess but I think since the view volume goes by default from -1 to 1 in qt's orthographic matrix I should be able to see something at 0.

        1 Reply Last reply
        0
        • Z Offline
          Z Offline
          ZapB
          wrote on last edited by
          #6

          OK I can shed a little more light on this now I think. It has taken quite a bit of digging today hence the delay.

          Short story is, don't use the CoreProfile, use CompatibilityProfile instead for now.

          Here is the full story...for info I am using OpenGL 3.3 since my card does not support OpenGL 4.x but it is essentially the same in this case...

          I constructed my own little test harness which I managed to get working with an OpenGL 2 context. When switching to OpenGL 3.3 context and running with the compatibility profile all is still fine. However, running with a QGLFormat I noticed the following output when a call to QGLShaderProgram::addShaderFromSourceFile() is made:

          @QGLShaderProgram: shader programs are not supported@

          That seems wrong to me so I decided to delve into Qt itself. I have built a copy of Qt from the master branch of git (the public repo) in debug mode so that I could step into the above function. Doing so and see where the rabbit hole goes I wound up at this snippter of code:

          @
          QGLExtensions::Extensions QGLExtensions::currentContextExtensions()
          {
          QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
          Extensions glExtensions;

          if (extensions.match("GL_ARB_texture_rectangle"))
              glExtensions |= TextureRectangle;
          if (extensions.match("GL_ARB_multisample"))
              glExtensions |= SampleBuffers;
          if (extensions.match("GL_SGIS_generate_mipmap"))
              glExtensions |= GenerateMipmap;
          if (extensions.match("GL_ARB_texture_compression"))
              glExtensions |= TextureCompression;
          if (extensions.match("GL_EXT_texture_compression_s3tc"))
              glExtensions |= DDSTextureCompression;
          if (extensions.match("GL_OES_compressed_ETC1_RGB8_texture"))
              glExtensions |= ETC1TextureCompression;
          if (extensions.match("GL_IMG_texture_compression_pvrtc"))
              glExtensions |= PVRTCTextureCompression;
          if (extensions.match("GL_ARB_fragment_program"))
              glExtensions |= FragmentProgram;
          if (extensions.match("GL_ARB_fragment_shader"))
              glExtensions |= FragmentShader;
          ....
          

          @

          The problem lies in the call to

          @glGetString(GL_EXTENSIONS)@

          since this is now removed from OpenGL >= 3.1. Instead the following functions should be used:

          @
          glGetInteger(GL_NUM_EXTENSIONS)
          glGetStringi(GL_EXTENSIONS, i)
          @

          where i is the index of the extension to query and 0 <= i < glGetInteger(GL_NUM_EXTENSIONS).

          When the above extension matching code fails (due to using the CoreProfile) this in turn makes Qt's OpenGL support think that no extensions are available which is of course broken.

          So the crux of the problem seems to be the way that Qt is querying for OpenGL extensions when using OpenGL 3.0 or higher (although OpenGL 3.0 still supports the old method too).

          Therefore to fix this properly a patch to Qt itself is required. I'll have a quick bash at doing this now but I am short on time today (as always). Hopefully it will be a fairly simple fix although I think some refactoring of the QGLExtensionMatcher class will be needed.

          I have filed a "bug":http://bugreports.qt.nokia.com/browse/QTBUG-18529 for this. Please vote on it to increase the odds of it getting fixed in time for Qt 4.8.0.

          I'll post back here and on the bug if I get anywhere with a fix.

          Nokia Certified Qt Specialist
          Interested in hearing about Qt related work

          1 Reply Last reply
          0
          • H Offline
            H Offline
            Hornsj2
            wrote on last edited by
            #7

            Hey, great find. You sure do have a lot more knowledge and willpower in finding these bugs. I don't think I would have thought to dig into the framework. I'm sure everyone from Nokia on down appreciates it.

            Thanks.

            1 Reply Last reply
            0
            • Z Offline
              Z Offline
              ZapB
              wrote on last edited by
              #8

              I'm still digging into Qt's OpenGL support to see where the function entry point addresses are resolved but I am out of time for today - taking the wife out since it is Mother's Day here ;-)

              I'll see if I can get any further with a patch tomorrow evening.

              If you use the CompatibilityProfile does your simple pair of shaders and test harness work?

              Nokia Certified Qt Specialist
              Interested in hearing about Qt related work

              1 Reply Last reply
              0
              • H Offline
                H Offline
                Hornsj2
                wrote on last edited by
                #9

                !http://joshuahorns.com/Untitled.png(My ScreenShot)!

                That's what I get... just a "clear color" screen. You were able to get shader code running? Could you post that? I might just give up and use pure opengl calls directly. I'm probably doing something very dumb with QGLShaderProgram but I can't for the life of me figure it out.

                1 Reply Last reply
                0
                • Z Offline
                  Z Offline
                  ZapB
                  wrote on last edited by
                  #10

                  OK here's what I have for my simple test harness at present. Toggling which profile I use causes it to work or give a blank clear colour like you have. BTW what graphics card and driver are you using?

                  main.cpp:

                  @
                  #include "shaderwidget.h"

                  #include <QApplication>
                  #include <QGLFormat>

                  #include <GL/glut.h>

                  int main( int argc, char* argv[] )
                  {
                  QApplication a( argc, argv );
                  glutInit( &argc, argv );

                  QGLFormat glFormat;
                  glFormat.setVersion( 3, 3 );
                  glFormat.setProfile&#40; QGLFormat::CompatibilityProfile &#41;;
                  //glFormat.setProfile&#40; QGLFormat::CoreProfile &#41;;
                  glFormat.setSampleBuffers( true );
                  
                  ShaderWidget w( glFormat );
                  w.show();
                  
                  return a.exec&#40;&#41;;
                  

                  }
                  @

                  shaderwidget.h:
                  @
                  #ifndef SHADERWIDGET_H
                  #define SHADERWIDGET_H

                  #include <QGLWidget>

                  #include <QGLShaderProgram>

                  class ShaderWidget : public QGLWidget
                  {
                  Q_OBJECT
                  public:
                  ShaderWidget( const QGLFormat& format, QWidget* parent = 0 );
                  ~ShaderWidget();

                  protected:
                  virtual void initializeGL();
                  virtual void resizeGL( int w, int h );
                  virtual void paintGL();

                  virtual void keyPressEvent( QKeyEvent* e );
                  

                  private:
                  QGLShaderProgram m_shader;

                  float m_theta;
                  float m_phi;
                  

                  };

                  #endif // SHADERWIDGET_H
                  @

                  shaderwidget.cpp:

                  @
                  #include <GL/glew.h>

                  #include "shaderwidget.h"

                  #include <QCoreApplication>
                  #include <QKeyEvent>

                  #include <GL/glut.h>

                  ShaderWidget::ShaderWidget( const QGLFormat& format, QWidget* parent )
                  : QGLWidget( format, parent ),
                  m_shader(),
                  m_theta( 0.0f ),
                  m_phi( 0.0f )
                  {
                  QGLFormat glFormat = QGLWidget::format();
                  qDebug() << QString( "OpenGL Version = %1, %2" )
                  .arg( glFormat.majorVersion() )
                  .arg( glFormat.minorVersion() );

                  if ( !glFormat.sampleBuffers() )
                      qWarning() << "Could not enable sample buffers";
                  
                  qDebug() << "OpenGL context valid =" << context()->isValid();
                  

                  }

                  ShaderWidget::~ShaderWidget()
                  {
                  }

                  void ShaderWidget::initializeGL()
                  {
                  // Set the clear color to black
                  glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );

                  // Set the drawing color to green
                  glColor3f( 0.9f, 0.9f, 0.0f );
                  
                  bool result;
                  result = m_shader.addShaderFromSourceFile&#40; QGLShader::Vertex, "simple.vert" &#41;;
                  if ( !result )
                      qDebug() << m_shader.log();
                  result = m_shader.addShaderFromSourceFile&#40; QGLShader::Fragment, "simple.frag" &#41;;
                  if ( !result )
                      qDebug() << m_shader.log();
                  result = m_shader.link();
                  if ( !result )
                      qDebug() << m_shader.log();
                  

                  }

                  void ShaderWidget::resizeGL( int w, int h )
                  {
                  // Prevent a divde by zero
                  if ( h == 0 )
                  h = 1;

                  // Set the viewport to window dimensions
                  glViewport( 0, 0, w, h );
                  
                  // Reset the coordinate system
                  glMatrixMode( GL_PROJECTION );
                  glLoadIdentity();
                  
                  // Establish the clipping volume by setting up an perspective projection
                  double aspectRatio = double( w ) / double( h );
                  double verticalViewingAngle = 45.0;
                  gluPerspective( verticalViewingAngle, aspectRatio, 1.0, 425.0 );
                  
                  glMatrixMode( GL_MODELVIEW );
                  glLoadIdentity();
                  

                  }

                  void ShaderWidget::paintGL()
                  {
                  // Clear the buffer with the current clearing color
                  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

                  glPushMatrix();
                  glTranslatef( 0.0f, 0.0f, -200.0 );
                  glRotatef( m_theta, 1.0f, 0.0f, 0.0f );
                  glRotatef( m_phi,   0.0f, 1.0f, 0.0f );
                  
                  m_shader.bind();
                  
                  glutSolidTeapot( 40 );
                  
                  glPopMatrix();
                  

                  }

                  void ShaderWidget::keyPressEvent( QKeyEvent* e )
                  {
                  switch ( e->key() )
                  {
                  case Qt::Key_Escape:
                  QCoreApplication::instance()->quit();
                  break;

                      case Qt::Key_Left:
                          m_phi += 1.0f;
                          updateGL();
                          break;
                  
                      case Qt::Key_Right:
                          m_phi -= 1.0f;
                          updateGL();
                          break;
                  
                      case Qt::Key_Up:
                          m_theta += 1.0f;
                          updateGL();
                          break;
                  
                      case Qt::Key_Down:
                          m_theta -= 1.0f;
                          updateGL();
                          break;
                  
                      default:
                          QGLWidget::keyPressEvent( e );
                  }
                  

                  }
                  @

                  The vertex shader, simple.vert:

                  @
                  varying vec4 secondaryColor;

                  void main( void )
                  {
                  // Normal MVP transform
                  vec4 clipCoord = gl_ModelViewProjectionMatrix * gl_Vertex;
                  gl_Position = clipCoord;

                  // Copy primary color
                  gl_FrontColor = gl_Color;
                  
                  // Calculate NDC
                  vec3 ndc = clipCoord.xyz / clipCoord.w;
                  
                  // Map from [-1,1] to [0,1] before outputting
                  secondaryColor = vec4( ( ndc * 0.5 ) + 0.5, 1.0 );
                  

                  }
                  @

                  and finally the fragment shader:

                  @
                  varying vec4 secondaryColor;

                  void main(void)
                  {
                  // Mix primary and secondary colors 50:50
                  gl_FragColor = mix( gl_Color, vec4( vec3( secondaryColor ), 1.0 ), 0.5 );
                  }
                  @

                  I know that this still uses the older-style shader code but I wanted to start from something that I know works and then slowly move it towards a pure OpenGL >= 3.1 Core Profile appproach and see what breaks on the way. That is how I found this bug in extension wrangling for OpenGL 3.1 or newer.

                  Does the above work for you?

                  Nokia Certified Qt Specialist
                  Interested in hearing about Qt related work

                  1 Reply Last reply
                  0
                  • H Offline
                    H Offline
                    Hornsj2
                    wrote on last edited by
                    #11

                    I suspect it will work. I'll try it after I get home from work tonight.

                    The "problem" is that, as you know, the core profile removes deprecated functionality. In the case of the code above the following will have been removed ( my goal was to keep my code "pure" and not have any deprecated functions and simply turning on compatibility seems to not work with QGLShaderProgram):

                    1. The matrix stack, and by extension all matrix related manipulation such as the following:
                      @ Reset the coordinate system
                      glMatrixMode( GL_PROJECTION );
                      glLoadIdentity();

                      // Establish the clipping volume by setting up an perspective projection
                      double aspectRatio = double( w ) / double( h );
                      double verticalViewingAngle = 45.0;
                      gluPerspective( verticalViewingAngle, aspectRatio, 1.0, 425.0 );

                      glMatrixMode( GL_MODELVIEW );
                      glLoadIdentity()
                      @

                      and this
                      @
                      glPushMatrix();
                      glTranslatef( 0.0f, 0.0f, -200.0 );
                      glRotatef( m_theta, 1.0f, 0.0f, 0.0f );
                      glRotatef( m_phi, 0.0f, 1.0f, 0.0f );
                      @

                    2. You already touched on it but I'll toss it out there again. Some built in shader variables such as gl_FragColor are deprecated / removed in the core profile.

                    The fact that the above works and my code doesn't, even though I turn on the compatibility profile, leads me to believe QGLShaderProgram can't be used in my project. For completeness I'll test my tessellation shader additions with your harness and make a merge request.

                    I've never used Gitorious but I signed up and it wants a public key. If I understand the directions I can generate a public key with Putty. Is that right? Also, once that's done where do I store the key? Is it to be placed in a certificate store? Also, are there rules as far as comments or will Nokia clean that up?

                    1 Reply Last reply
                    0
                    • Z Offline
                      Z Offline
                      ZapB
                      wrote on last edited by
                      #12

                      [quote author="Hornsj2" date="1301913471"]I suspect it will work. I'll try it after I get home from work tonight.

                      The "problem" is that, as you know, the core profile removes deprecated functionality. In the case of the code above the following will have been removed ( my goal was to keep my code "pure" and not have any deprecated functions and simply turning on compatibility seems to not work with QGLShaderProgram):
                      [/quote]

                      Yes I know, but as I said I wanted to start off from a starting point that I know works with Qt and QGLShaderProgram. I was then going to remove the old fixed functionality calls and modify the shaders to use the Core Profile when I found this bug in Qt's extension mangling support so I did not go any further yet.

                      [quote author="Hornsj2" date="1301913471"]
                      The fact that the above works and my code doesn't, even though I turn on the compatibility profile, leads me to believe QGLShaderProgram can't be used in my project.
                      [/quote]

                      Not yet, because of the problem reported above, namely that QGLShaderProgram believes that it cannot use shaders when you are using the Core Profile due to this bug.

                      [quote author="Hornsj2" date="1301913471"]
                      For completeness I'll test my tessellation shader additions with your harness and make a merge request.
                      [/quote]

                      It should work if you use the compatibility mode - except if there is a bug in your shaders of course ;-)

                      [quote author="Hornsj2" date="1301913471"]
                      I've never used Gitorious but I signed up and it wants a public key. If I understand the directions I can generate a public key with Putty. Is that right? Also, once that's done where do I store the key? Is it to be placed in a certificate store?
                      [/quote]

                      Sounds about right for generating the key. It's been ages since I used PuTTY to generate a key. Have a google for it, should be easy to find instructions.

                      [quote author="Hornsj2" date="1301913471"]
                      Also, are there rules as far as comments or will Nokia clean that up?
                      [/quote]

                      You need to follow Qt's "coding style guidelines":https://qt.gitorious.org/qt/pages/QtCodingStyle. There is more info "here ":https://qt.gitorious.org/qt/pages/Home.

                      Good luck.

                      Nokia Certified Qt Specialist
                      Interested in hearing about Qt related work

                      1 Reply Last reply
                      0
                      • H Offline
                        H Offline
                        Hornsj2
                        wrote on last edited by
                        #13

                        Thanks for the reply.

                        I might not have thought it through, but I think it might go deeper than changing the logic guarding the use of shaders. Again I realize I might be telling you something you already have thought of.

                        It would seem that, in addition to changing the method for checking extensions, maybe the function pointer declarations in Qt's OpenGL support need to be looked at. I do know there are some preprocessor guards that rely on that check in Qt. These guards encapsulate OpenGL function pointer definitions and defines. I ran into that with my tessellation work.

                        1 Reply Last reply
                        0
                        • Z Offline
                          Z Offline
                          ZapB
                          wrote on last edited by
                          #14

                          Yes they do. As a starter for 10 I am looking at where to resolve the function pointer for glGetStringi() so that I can at least query the extensions ;-)

                          Also, the logic in QGLShaderProgram needs to be amended since shaders are part of the specification and not provided by extensions for newer OpenGL versions.

                          There is quite some work to do to properly support OpenGL 3.1 or newer.

                          Nokia Certified Qt Specialist
                          Interested in hearing about Qt related work

                          1 Reply Last reply
                          0
                          • H Offline
                            H Offline
                            Hornsj2
                            wrote on last edited by
                            #15

                            Great. It sounds like I should integrate my changes into your changes if you will be reworking that part of the code. I had to add tessellation support, in part, there.

                            1 Reply Last reply
                            0
                            • Z Offline
                              Z Offline
                              ZapB
                              wrote on last edited by
                              #16

                              I have spoken to sroedal (Qt OpenGL dude) on irc this afternoon and he is committing a patch that is very similar to what I wrote yesterday afternoon. It allows for proper parsing of OpenGL extensions when using the Core profile. It should hopefully hit Qt master branch on gitorious within a day or so.

                              I'll try applying it locally tonight and see if QGLShader then starts working or if further changes are needed to make it realise that shaders are supported.

                              I also asked about having Qt resolve the Core profile entry points and the response was thet using GLEW is the current advice - which is what we had been doing anyway. I still think it would be nice that if we ask Qt for a OpenGL 3.2 Core profile context that it then resolves the function pointers for the Core profile entry points for us without having to use GLEW. But that is another problem I guess.

                              I'll keep you updated.

                              Nokia Certified Qt Specialist
                              Interested in hearing about Qt related work

                              1 Reply Last reply
                              0
                              • H Offline
                                H Offline
                                Hornsj2
                                wrote on last edited by
                                #17

                                Your posted example with fixed function works fine. I'll try using the entire shader pipeline.

                                It's normally slow going for me during the week. Weekends are my most productive time for these projects.

                                By "entire shader pipeline" I mean vert,geom, tess control, tess eval, frag.

                                1 Reply Last reply
                                0
                                • Z Offline
                                  Z Offline
                                  ZapB
                                  wrote on last edited by
                                  #18

                                  Cool. I'll look forward to seeing your example. I have not used the tesselation shaders yet so I would be keen to see a nice little example. I probably won't get back to this until the weekend either but I'll keep an eye out for that patch hitting Qt master.

                                  Nokia Certified Qt Specialist
                                  Interested in hearing about Qt related work

                                  1 Reply Last reply
                                  0
                                  • H Offline
                                    H Offline
                                    Hornsj2
                                    wrote on last edited by
                                    #19

                                    Promises promises... yeah I got caught today moving stuff. I WILL have the shaders tested by tomorrow night.

                                    1 Reply Last reply
                                    0
                                    • H Offline
                                      H Offline
                                      Hornsj2
                                      wrote on last edited by
                                      #20

                                      By the way my tessellation tests will be posted in the proper thread.

                                      1 Reply Last reply
                                      0
                                      • Z Offline
                                        Z Offline
                                        ZapB
                                        wrote on last edited by
                                        #21

                                        No worries, real life happens - especially when nice weather lands ;-)

                                        I have just checked and the patch to Qt master that I mentioned earlier has no been applied. So now shaders should work even if you select the Core profile.

                                        The main part of the patch is in src/opengl/qgl.cpp in the helper class QGLExtensionMatcher found "here":https://qt.gitorious.org/qt/qt/blobs/master/src/opengl/qgl.cpp#line5373.

                                        The corresponding commit message was:

                                        @
                                        commit 2f59eaeee1fbe33d07b0e7d0747afd8658df95ac
                                        Author: Samuel R<C3><B8>dal sroedal@trolltech.com
                                        Date: Wed May 26 16:39:02 2010 +0200

                                        Made extension resolving work with Core profile.
                                        
                                        The Core profile was introduced in OpenGL 3.2 and if chosen removes
                                        all deprecated functionality from the OpenGL API.
                                        
                                        In the Core profile glGetString(GL_EXTENSIONS) is unsupported, so
                                        instead we need to use glGetStringi(GL_EXTENSIONS, index) together with
                                        glGetIntegerv(GL_NUM_EXTENSIONS). Also optimized the QGLExtensionMatcher
                                        to not have to recompute the split positions all the time.
                                        
                                        Preliminary support to prevent non-core-functions to be called in the GL
                                        2 engine has also been added.
                                        
                                        Reviewed-by: Kim
                                        

                                        @

                                        Nokia Certified Qt Specialist
                                        Interested in hearing about Qt related work

                                        1 Reply Last reply
                                        0
                                        • H Offline
                                          H Offline
                                          Hornsj2
                                          wrote on last edited by
                                          #22

                                          removed.

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved