[Solved] glActiveTexture - SIGSEGV error lazarus / 70-OpenGL ---------------------------------------------------------------------- Handoko · 2017-06-28 08:57 I found that glActiveTexture (in GLext unit) will always cause "External SIGSEGV" error. Tested on Lazarus 1.6.4 Linux 64-bit. Example code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses  OpenGLContext, GLext, ... procedure TForm1.myGLPaint(Sender: TObject);begin  glActiveTexture(GL_TEXTURE0); // this line causes SIGSEGV error     ...end; But if I put gles20 unit after GLext, the error won't happen: Example code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses  OpenGLContext, GLext, gles20, ... procedure TForm1.myGLPaint(Sender: TObject);begin  glActiveTexture(GL_TEXTURE0); // will not cause SIGSEGV error     ...end; I examined the code inside them, they are different: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i // GLext.pas  glActiveTexture: procedure(texture: GLenum); extdecl; // gles20.pas  glActiveTexture: procedure(texture:GLenum);{$ifdef windows}stdcall;{$else}cdecl;{$endif} I don't understand what extdecl and cdecl are. Is it a bug in GLext.pas? Should I submit a bug report? ---------------------------------------------------------------------- marcov · 2017-06-28 09:22 extdecl is a macro that is often defined in FPC headers to not have to repeat an ifdef for calling conventions all over again,  and it is probably the same  as {$ifdef windows}stdcall;{$else}cdecl;{$endif} It might be that the changing in unit order cause some other function to change meaning leading to the activetexture crash. Do you have proper errorhandling in place? ---------------------------------------------------------------------- Handoko · 2017-06-28 13:54 Can anyone help me test the code? I always get SIGSEGV error when run the code on Linux. To able to compile it on Linux, your computer should have libgl1-mesa-dev installed. Also, make sure your Lazarus has LazOpenGLContex 0.0.1 installed. Please let me know if the error also reproducible on other OS. If you have problem compiling the code, read here: http://forum.lazarus.freepascal.org/index.php/topic,35807.0.html Quote from: marcov on June 28, 2017, 11:22:33 am...  Do you have proper errorhandling in place? No, I have only very simple code to test the issue. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Forms, Controls, OpenGLContext, GL, GLext; type   { TForm1 }   TForm1 = class(TForm)  procedure FormCreate(Sender: TObject);  public    procedure GLPaint(Sender: TObject);  end; var  Form1: TForm1;  GLBox: TOpenGLControl; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  GLBox := TOpenGLControl.Create(Self);  GLBox.Parent := Self;  GLBox.Align := alClient;  GLBox.OnPaint := @GLPaint;  GLBox.Paint;end; procedure TForm1.GLPaint(Sender: TObject);begin   glActiveTexture(GL_TEXTURE0);  // This line will cause SIGSEGV error   glBegin(GL_TRIANGLES);    glVertex3f( 0, 1, 0);    glVertex3f(-1,-1, 0);    glVertex3f( 1,-1, 0);  glEnd;  GLBox.SwapBuffers;end; end. ---------------------------------------------------------------------- Pascal · 2017-06-28 19:01 Do not do the Paint in FromCreate as the handles are not set there! Just do Invalidate instead of Paint. Or ues Application.QueueAsyncCall. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormCreate(Sender: TObject);begin  ...  Application.QueueAsyncCall(@DoPaint, 0);end; procedure TForm1.DoPaint(Data: PtrInt);begin  GLBox.Paint;end; ---------------------------------------------------------------------- Handoko · 2017-06-28 19:15 Thank you for your reply, unfortunately both solutions didn't work. I am not familiar with QueueAsyncCall, but I followed your example. The SIGSEGV error still happened. I also tried to change the Paint to Invalidate, still no luck. Same results. Can you please download the testgl.zip and test it or fix it?. I am thinking this is a bug, which maybe only happens on Linux. Or perhaps something wrong with my computer. I can understand what you said about "the handles are not set there". But how can you explain, the code works correctly if I remove line #42: glActiveTexture(GL_TEXTURE0); ---------------------------------------------------------------------- Pascal · 2017-06-28 20:31 glActiveTexture is nil !!! It hasn't been initalized during loading of lib. ---------------------------------------------------------------------- Pascal · 2017-06-28 21:07 Loading of extentions fails. glext_LoadExtension('GL_version_1_3') fails as glActiveTexture := wglGetProcAddress('glActiveTexture') sets glActiveTexture  to nil I don't know what to do here. Maybe some OpenGL experts can help? ---------------------------------------------------------------------- Pascal · 2017-06-29 03:53 The solution is to call   glext_LoadExtension when the context is already set up (not in FormCreate): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Forms, Controls, OpenGLContext, GL, GLext; type   { TForm1 }   TForm1 = class(TForm)  procedure FormCreate(Sender: TObject);  public    procedure GLPaint(Sender: TObject);    procedure Start(Data: PtrInt);  end; var  Form1: TForm1;  GLBox: TOpenGLControl; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  GLBox := TOpenGLControl.Create(Self);  GLBox.Parent := Self;  GLBox.Align := alClient;  Application.QueueAsyncCall(@Start, 0); // Continue after everything is set upend; procedure TForm1.GLPaint(Sender: TObject);begin  glActiveTexture(GL_TEXTURE0);  // This line will cause SIGSEGV error   glBegin(GL_TRIANGLES);    glVertex3f( 0, 1, 0);    glVertex3f(-1,-1, 0);    glVertex3f( 1,-1, 0);  glEnd;  GLBox.SwapBuffers;end; procedure TForm1.Start(Data: PtrInt);begin  glext_LoadExtension('GL_version_2_0');  GLBox.OnPaint := @GLPaint;  GLBox.Invalidate;end; end. ---------------------------------------------------------------------- Handoko · 2017-06-29 08:19 Thank you for your help. I thought glActiveTexture is a basic command that will be available if the OpenGL library has loaded. Also in the Kronos (developer of OpenGL) page, it does not mentioned glActiveTexture will not be available unless we load it using wglGetProcAddress. Unit: gles20 In the unit initialization section, LoadGLESv2 will be called automatically and inside it, glActiveTexture will be loaded. So glActiveTexture is ready to be used. Unit: glExt In this unit, glActiveTexture will not be loaded automatically. We have to call glext_LoadExtension to load it manually. That is why if we add gles20 unit after glExt, the error won't show up. ---------------------------------------------------------------------- Pascal · 2017-06-29 08:36 Quote from: Handoko on June 29, 2017, 10:19:28 amThank you for your help. You are welcome! Quote from: Handoko on June 29, 2017, 10:19:28 amUnit: glExt In this unit, glActiveTexture will not be loaded automatically. We have to call glext_LoadExtension to load it manually. That is why if we add gles20 unit after glExt, the error won't show up. Yes, but you can't do it in FormCreate, where it will fail! ---------------------------------------------------------------------- Handoko · 2017-06-29 08:48 Quote from: Pascal on June 29, 2017, 10:36:25 amYes, but you can't do it in FormCreate, where it will fail! Yes, I understand. Actually, the question is about glActiveTexture. That code is just a quick demo i created to show the problem of glActiveTexture. ---------------------------------------------------------------------- Akira1364 · 2017-07-01 22:39 I know this thread is solved, but it's worth pointing out as a general tip for everyone: never, ever, ever do ANYTHING OpenGL related in "FormCreate" when using Lazarus with the FPC GL headers and/or TOpenGLControl. It will not work. Yes, I know it worked in really old Delphi versions like 6 and 7 but that's irrelevant now. The window initialization code in FPC isn't the same and doesn't do things in the same order. Do your OpenGL-startup related stuff in "FormShow" instead. ---------------------------------------------------------------------- Handoko · 2017-07-02 01:49 Thank you for the information. But there still something I do not fully understand. For general things (not OpenGL related), we should not do anything that required form handle on FormCreate because as mentioned by @Pascal, the handle has not created on FormCreate. This I already knew. But how do you explain my code test.zip works: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Forms, Controls, OpenGLContext, GL; type   { TForm1 }   TForm1 = class(TForm)    procedure FormCreate(Sender: TObject);  public    procedure GLPaint(Sender: TObject);  end; var  Form1: TForm1;  GLBox: TOpenGLControl; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  GLBox := TOpenGLControl.Create(Self);  GLBox.Parent := Self;  GLBox.Align := alClient;  GLBox.OnPaint := @GLPaint;  GLBox.Paint; // <<<---------- Call TOpenGLControl.Paint !!!end; procedure TForm1.GLPaint(Sender: TObject);begin  glBegin(GL_TRIANGLES);    glVertex3f( 0, 1, 0);    glVertex3f(-1,-1, 0);    glVertex3f( 1,-1, 0);  glEnd;  GLBox.SwapBuffers;end; end. Any explanation why my code works correctly on my tests on Linux64 machine? Does it work by luck? Also, please see the example "OpenGL Core Profile Tutorials" by @ChrisR: http://forum.lazarus.freepascal.org/index.php/topic,35649.0.html On his rendermain.pas, he did this (line #609): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TGLForm1.FormCreate(Sender: TObject);begin  gMouse.Y := -1;  {$IFDEF LCLCarbon}  Error: Carbon only supports Legacy OpenGL. Solution: compile to the Cocoa widgetset (Project/ProjectOptions/Additions&Overrides)  {$ENDIF}  {$IFDEF Darwin}  AppleMenu.Visible := true;  HelpMenu.Visible := false;  {$ENDIF}  GLBox.MakeCurrent();  InitGL;  GLBox.invalidate;end; Is it okay to call GLBox.Invalidate on FormCreate? ---------------------------------------------------------------------- Akira1364 · 2017-07-02 02:07 Your code works, yes, essentially "by luck" because you aren't attempting to actually initialize any GL functionality. However, it's also completely unnecessary. If you comment out the "GLBox.Paint" line, the visual results will be identical, since the OpenGL control will be painted at least once anyways when the form comes into view. The same goes for GLBox.Invalidate: there is no reason to call it at that point. The tutorial by ChrisR that you've posted, on the other hand, is an example of something that will fail a large percentage of the time on Windows and the majority of Linux distros at the MakeCurrent line, as the OpenGL control may or may not have initialized its context by that point. It is also equally likely to fail at the InitGL() line. All of that is only relevant when you do it in FormCreate, though: if you copy and paste the entire function into FormShow you should have zero problems overall regardless of platform. So maybe what I said was a bit of an oversimplification, but generally you're basically gambling with FormCreate. It's not guaranteed to work like it was under old Win32-only Delphi compilers. Better to do it in FormShow and be safe! ---------------------------------------------------------------------- Handoko · 2017-07-02 02:20 Thank you for the explanation. I will remember your advice.