Results 1 to 6 of 6

Thread: Lazarus port of Tom Nuydens "Mr. Potato Head" GLSL demo using modern GL functionality

  1. #1

    Lazarus port of Tom Nuydens "Mr. Potato Head" GLSL demo using modern GL functionality

    Full project folder is in the zip file I've attached. In case you're wondering, the "GLMath" unit I used to replace the fixed-function matrix API is a modified version of a unit by Chris Rorden (author of SurfIce, e.t.c). Note that you will obviously need an OpenGL 3.3+ capable GPU to run this, and it's also unfortunately Windows-only. (Not to be harsh but it's kind of Linuxes/OSXes fault for not having anything remotely similar to QueryPerformanceCounter. Seems like something you'd add early on in the development process...) Anways, felt like this might serve as a decent "modern OpenGL" tutorial, so I thought I'd post it here. Enjoy, (or not!)
    Attached Files Attached Files

  2. #2
    Thank you, will look at it tonight when I'm home.

  3. #3
    for not having anything remotely similar to QueryPerformanceCounter.
    *sigh*
    RDTSC has *much* better precision (about 30 nanoseconds) while performance counter on most systems is bastardized timestamp counter (for compatibility purposes I assume) and is rounded up to granulation of about 400 nanoseconds.
    Any CPU today outside of museum range has TSC invariancy meaning yes, you *can* use the counter safely, the frequency is stable and counyer is the same for all cores.
    Code:
     {$ifdef cpuarm}
        function UsecDelta (ptsc: pqword): double; cdecl; //allegedly valid ANY Linux and ANY non-x86 CPU
        var v: timeval;
        begin
          v:= ptimeval(ptsc)^;
          fpgettimeofday(ptimeval(ptsc), NIL); //one microsecond resolution
         {$push}
          {$overflowchecks off}
          {$rangechecks off}
          Result:=
            1000000.0 * longint(ptimeval(ptsc)^.tv_sec - v.tv_sec)
             + 1.0 * longint(ptimeval(ptsc)^.tv_usec - v.tv_usec);
         {$pop}
          if Result < 0.0 then Result:= 0.0;
        end;
      {$endif}
    
      {$ifdef CPUX86_64}
        function UsecDelta (ptsc: pqword): double; cdecl;
        var q: qword;
        begin
          q:= ptsc^;
          asm
            rdtsc
            shl rdx, 32
            or rdx, rax
            mov rax, qword[ptsc]
            mov qword[rax], rdx
          end ['rax', 'rdx'];
          if q >= ptsc^ then q:=ptsc^ - 1;
          Result:= (ptsc^ - q) * Mother^.Timer.RDTSCFactor;
        end;
     {$endif}
    
     {$ifdef CPU386}
        function UsecDelta (ptsc: pqword): double; cdecl;
        var q: qword;
        begin
          q:= ptsc^;
          asm
            mov ecx, ptsc
            rdtsc
            mov [ecx], eax
            mov [ecx + 4], edx
          end ['ecx', 'eax', 'edx'];
          if q >= ptsc^ then q:=ptsc^ - 1;
          Result:= (ptsc^ - q) * Mother^.Timer.RDTSCFactor;
        end;
     {$endif} 
    
    {$ifndef cpuarm}
    var
      _PrevTscCheckSec: double = 0;
      _PrevTsc: qword;
      _tsc: qword;
      function RecheckTSCFreq(period: double = TSCMeasuringInterval): longbool;
      var
        sec: double;
      begin
        try
          sec:= Second();
          if (sec - _PrevTscCheckSec) < period then Exit(false);
          _tsc:= GetTimeStamp();
          Result:= true;
          if _tsc <= _prevTsc then Result:= false;
          if Result then begin
            Mother^.Timer.RDTSCFrequency:= (_tsc - _prevTSC) / (sec - _prevTscCheckSec);
            Mother^.Timer.RdtscFactor:= 1000000.0 / Math.max(1.0, Mother^.Timer.RdtscFrequency);
          end;
          _prevTSC:= _tsc;
          _PrevTscCheckSec:= sec;
        except end;
      end;
    {$endif}  
    
      function GetTimeStamp: qword;
      //is *also* used for hash generation, so requirement obligatory increase is vital
     {$ifdef cpuarm}
      var v: timeval;
      begin
       {$push}
        {$overflowchecks off}
        {$rangechecks off}
        fpgettimeofday(@v, NIL); //one microsecond resolution
        Result:= qword((int64(1000000) * int64(v.tv_sec)) + int64(v.tv_usec));
       {$pop}
     {$else cpuarm}
      begin
        {$ifdef cpu64}
        //ONLY the rax register is free to access memory at addresses above 4Gb freely!
        asm
          rdtsc
          shl rdx, 32
          or rax, rdx
          mov qword[Result], rax
        end ['rax', 'rdx'];
        {$else}
        asm
          rdtsc
          mov dword[Result], eax
          mov dword[Result + 4], edx
        end ['eax', 'edx'];
        {$endif}
     {$endif cpuarm}
        if Result <= PrevTimeStamp then begin
          Result:=PrevTimeStamp + 1;
          inc(PrevTimeStamp);
        end
        else
          PrevTimeStamp:=Result;
      end;

  4. #4
    Honestly my original point was kind of an oversimplification. I basically meant "why isn't QueryPerformanceCounter implemented as an alias for a specific use of GetTimeOfDay that returns identical output to the Windows QueryPerformanceCounter on non-windows FPC platforms?" Also there's more to it than that, I suppose... a larger problem is that there's not really any easy way that I'm aware of to load specific sets of OpenGL extensions for non-windows platforms. (As in, everything up to and including OpenGL 3.3.) Obviously dglOpenGL will load EVERYTHING when you call InitOpenGL and ReadExtensions (on Windows), but for Linux it seems to be tied to the ancient GLX API, and for OSX I'm not sure it has support for modern functionality at all. So I just stuck to FPCs GL and GLEXT units. Again though, without trying to sound like an asshole, it's not my problem that Linux and OSX have significantly less user-friendly/robust OpenGL initialization APIs. Missing functionality is missing functionality. ​It's not something to be catered to.

  5. #5
    Thanks for the sample! One small nitpick: calls to LoadOpenGL('opengl32.dll'); Load_GL_version_1_2; ... Load_GL_version_3_2; - are not needed, at least not if you use units distributed with FPC. LoadOpenGL runs in GL unit initialization and the version loading functions cascade to lower versions.

  6. #6
    Quote Originally Posted by imcold View Post
    Thanks for the sample! One small nitpick: calls to LoadOpenGL('opengl32.dll'); Load_GL_version_1_2; ... Load_GL_version_3_2; - are not needed, at least not if you use units distributed with FPC. LoadOpenGL runs in GL unit initialization and the version loading functions cascade to lower versions.
    Yeah, I actually remembered that a few days after I originally posted this.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •