You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

366 lines
12 KiB

  1. unit uglcContext;
  2. { Package: OpenGLCore
  3. Prefix: glc - OpenGL Core
  4. Beschreibung: diese Unit enthält eine abstrakte Klassen-Kapselung für OpenGL Kontexte
  5. Abstrakte Contextklasse zum Erstellen von Renderkontexten auf Windows & Linux(bzw X11/Gtk2)
  6. Für aktuelle Plattform passende Klasse kann per GetPlatformClass gefunden werden.
  7. Bsp.:
  8. //muss im GUI/Main-Thread aufgerufen werden:
  9. pf := TglcContext.GetPlatformClass().MakePF();
  10. fContext := TglcContext.GetPlatformClass().Create(MyTWinControl, PF);
  11. //_kann_ in Background Thread abgerufen werden:
  12. fContext.BuildContext();
  13. [Arbeit mit dem Context]
  14. fContext.CloseContext();
  15. //im MainThread
  16. FreeAndNil(fContext)
  17. weitere Funktionen:
  18. MakePF() erzeugt PixelFormatDescriptor mit Defaults
  19. BuildContext() baut Kontext (kann in BackgrounThread aufgerufen werden)
  20. CloseContext() gibt den Kontext frei (muss im selben Thread aufgerufen werden wie BuildContext;
  21. wird der Kontext nur im MainThread genutzt, muss CloseContext nicht explizit aufgerufen
  22. werden und wird beim zerstören des Kontext-Objekts ausgeführt)
  23. Activate/Deactiveate Kontext aktiv schalten oder nicht
  24. SwapBuffers DoubleBuffering
  25. SetSwapInterval VSync
  26. Share ShareLists
  27. EnableDebugOutput GL-Debug via ARB_debug_output oder AMD_debug_output de/aktivieren
  28. }
  29. interface
  30. uses
  31. SysUtils, Controls, dglOpenGL;
  32. const
  33. GLC_CONTEXT_VERSION_UNKNOWN = -1;
  34. type
  35. {$IFNDEF fpc}
  36. TThreadID = Cardinal;
  37. {$ENDIF}
  38. TMultiSample = 1..high(byte);
  39. TglcContextPixelFormatSettings = packed record
  40. DoubleBuffered: boolean;
  41. Stereo: boolean;
  42. MultiSampling: TMultiSample;
  43. ColorBits: Integer;
  44. DepthBits: Integer;
  45. StencilBits: Integer;
  46. AccumBits: Integer;
  47. AuxBuffers: Integer;
  48. Layer: Integer;
  49. end;
  50. TglcContextVersionSettings = packed record
  51. Major: Integer;
  52. Minor: Integer;
  53. ForwardCompatible: Boolean;
  54. end;
  55. TSeverity = (svLow, svMedium, svHigh);
  56. TLogEvent = procedure(const aSender: TObject; const aSeverity: TSeverity; const aMsg: String) of Object;
  57. TglcDisplayFlag = (
  58. dfFullscreen);
  59. TglcDisplayFlags = set of TglcDisplayFlag;
  60. EGLError = class(Exception);
  61. { TglcContext }
  62. TglcContextClass = class of TglcContext;
  63. TglcContext = class
  64. private
  65. fControl: TWinControl;
  66. fThreadID: TThreadID;
  67. fEnableVsync: Boolean;
  68. fLogEvent: TLogEvent;
  69. function GetEnableVSync: Boolean;
  70. procedure SetEnableVSync(aValue: Boolean);
  71. procedure LogMsg(const aSeverity: TSeverity; const aMsg: String);
  72. procedure SetDebugMode(const aEnable: Boolean);
  73. protected
  74. fUseVersion: Boolean;
  75. fPixelFormatSettings: TglcContextPixelFormatSettings;
  76. fVersionSettings: TglcContextVersionSettings;
  77. procedure OpenContext; virtual;
  78. public
  79. property PixelFormatSettings: TglcContextPixelFormatSettings read fPixelFormatSettings;
  80. property VersionSettings: TglcContextVersionSettings read fVersionSettings;
  81. constructor Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings); overload; virtual;
  82. constructor Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings; const aVersionSettings: TglcContextVersionSettings); overload; virtual;
  83. destructor Destroy; override;
  84. property ThreadID: TThreadID read fThreadID;
  85. property EnableVSync: Boolean read GetEnableVSync write SetEnableVSync;
  86. procedure BuildContext;
  87. procedure EnableDebugOutput(const aLogEvent: TLogEvent);
  88. procedure DisableDebugOutput;
  89. procedure CloseContext; virtual;
  90. procedure Activate; virtual; abstract;
  91. procedure Deactivate; virtual; abstract;
  92. function IsActive: boolean; virtual; abstract;
  93. procedure SwapBuffers; virtual; abstract;
  94. procedure SetSwapInterval(const aInterval: GLint); virtual; abstract;
  95. function GetSwapInterval: GLint; virtual; abstract;
  96. procedure Share(const aContext: TglcContext); virtual; abstract;
  97. {$IFDEF fpc}
  98. private class var
  99. fMainContextThreadID: TThreadID;
  100. public
  101. class property MainContextThreadID: TThreadID read fMainContextThreadID;
  102. {$ENDIF}
  103. public
  104. class function MakePF(DoubleBuffered: boolean = true;
  105. Stereo: boolean=false;
  106. MultiSampling: TMultiSample=1;
  107. ColorBits: Integer=32;
  108. DepthBits: Integer=24;
  109. StencilBits: Integer=0;
  110. AccumBits: Integer=0;
  111. AuxBuffers: Integer=0;
  112. Layer: Integer=0): TglcContextPixelFormatSettings;
  113. class function MakeVersion(const aMajor, aMinor: Integer; const aForwardCompatible: Boolean): TglcContextVersionSettings;
  114. class function GetPlatformClass: TglcContextClass;
  115. class function ChangeDisplaySettings(const aWidth, aHeight,
  116. aBitPerPixel, aFreq: Integer; const aFlags: TglcDisplayFlags): Boolean; virtual; abstract;
  117. class function IsAnyContextActive: boolean; virtual;
  118. end;
  119. implementation
  120. uses
  121. {$IFDEF WINDOWS}
  122. uglcContextWGL
  123. {$ELSE}{$IFDEF WIN32}
  124. uglcContextWGL{$IFNDEF fpc}, Windows{$ENDIF}
  125. {$ENDIF}{$ENDIF}
  126. {$IFDEF LINUX}
  127. uglcContextGtk2GLX
  128. {$ENDIF}
  129. ;
  130. {$IFNDEF fpc}
  131. var
  132. fMainContextThreadID: TThreadID;
  133. {$ENDIF}
  134. procedure GlDebugCallbackARB(source: GLenum; type_: GLenum; id: GLuint; severity: GLenum; {%H-}length: GLsizei; const message_: PGLchar; {%H-}userParam: PGLvoid); {$IFDEF WINDOWS}stdcall; {$ELSE}cdecl; {$ENDIF}
  135. var
  136. src, typ: String;
  137. sv: TSeverity;
  138. begin
  139. case source of
  140. GL_DEBUG_SOURCE_API_ARB : src:= 'API';
  141. GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB : src:= 'WINDOW';
  142. GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: src:= 'SHADER';
  143. GL_DEBUG_SOURCE_THIRD_PARTY_ARB : src:= '3RDPARTY';
  144. GL_DEBUG_SOURCE_APPLICATION_ARB : src:= 'APPLICATION';
  145. GL_DEBUG_SOURCE_OTHER_ARB : src:= 'OTHER';
  146. end;
  147. src:= 'GL_' + src;
  148. case type_ of
  149. GL_DEBUG_TYPE_ERROR_ARB : typ:= 'ERROR';
  150. GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB : typ:= 'DEPRECATED';
  151. GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB : typ:= 'UNDEF BEHAV';
  152. GL_DEBUG_TYPE_PORTABILITY_ARB : typ:= 'PORTABILITY';
  153. GL_DEBUG_TYPE_PERFORMANCE_ARB : typ:= 'PERFORMANCE';
  154. GL_DEBUG_TYPE_OTHER_ARB : typ:= 'OTHER';
  155. end;
  156. case severity of
  157. GL_DEBUG_SEVERITY_LOW_ARB: sv := svLow;
  158. GL_DEBUG_SEVERITY_MEDIUM_ARB: sv := svMedium;
  159. GL_DEBUG_SEVERITY_HIGH_ARB: sv := svHigh;
  160. end;
  161. TglcContext(userParam).LogMsg(sv, format('%s [%d] %s',[typ, id, message_]));
  162. end;
  163. procedure GlDebugCallbackAMD(id: GLuint; category: GLenum; severity: GLenum; {%H-}length: GLsizei; const message_: PGLchar; {%H-}userParam: PGLvoid); {$IFDEF WINDOWS}stdcall; {$ELSE}cdecl; {$ENDIF}
  164. var
  165. src: String;
  166. sv: TSeverity;
  167. begin
  168. case category of
  169. GL_DEBUG_CATEGORY_API_ERROR_AMD : src:= 'API';
  170. GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD : src:= 'WINDOW';
  171. GL_DEBUG_CATEGORY_DEPRECATION_AMD : src:= 'SHADER';
  172. GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD : src:= 'UNDEF BEHAV';
  173. GL_DEBUG_CATEGORY_PERFORMANCE_AMD : src:= 'PERFORMANCE';
  174. GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD : src:= 'SHADER';
  175. GL_DEBUG_CATEGORY_APPLICATION_AMD : src:= 'APPLICATION';
  176. GL_DEBUG_CATEGORY_OTHER_AMD : src:= 'OTHER';
  177. end;
  178. src:= 'GL_' + src;
  179. case severity of
  180. GL_DEBUG_SEVERITY_LOW_AMD: sv := svLow;
  181. GL_DEBUG_SEVERITY_MEDIUM_AMD: sv := svMedium;
  182. GL_DEBUG_SEVERITY_HIGH_AMD: sv := svHigh;
  183. end;
  184. TglcContext(userParam).LogMsg(sv, format('[%d] %s',[id, message_]));
  185. end;
  186. function TglcContext.GetEnableVSync: Boolean;
  187. begin
  188. result := fEnableVsync;
  189. end;
  190. procedure TglcContext.SetEnableVSync(aValue: Boolean);
  191. begin
  192. fEnableVsync := aValue;
  193. if IsActive then begin
  194. if fEnableVsync then
  195. SetSwapInterval(1)
  196. else
  197. SetSwapInterval(0);
  198. end;
  199. end;
  200. procedure TglcContext.LogMsg(const aSeverity: TSeverity; const aMsg: String);
  201. begin
  202. if Assigned(fLogEvent) then
  203. fLogEvent(self, aSeverity, aMsg);
  204. end;
  205. procedure TglcContext.SetDebugMode(const aEnable: Boolean);
  206. begin
  207. // ARB Debug Output
  208. if GL_ARB_debug_output then begin
  209. glDebugMessageCallbackARB(@GlDebugCallbackARB, self);
  210. glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nil, aEnable);
  211. if aEnable then begin
  212. glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
  213. glDebugMessageInsertARB(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, -1, PGLchar('Attached ARB_debug_output'));
  214. end;
  215. // AMD Debug Output
  216. end else if GL_AMD_debug_output then begin
  217. glDebugMessageCallbackAMD(@GlDebugCallbackAMD, self);
  218. glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, nil, aEnable);
  219. if aEnable then
  220. glDebugMessageInsertAMD(GL_DEBUG_CATEGORY_OTHER_AMD, GL_DEBUG_SEVERITY_LOW_ARB, 0, -1, PGLchar('Attached ARB_debug_output'));
  221. end;
  222. end;
  223. procedure TglcContext.OpenContext;
  224. begin
  225. fThreadID := GetCurrentThreadId;
  226. if fMainContextThreadID = 0 then
  227. fMainContextThreadID := fThreadID;
  228. end;
  229. class function TglcContext.MakePF(DoubleBuffered: boolean; Stereo: boolean; MultiSampling: TMultiSample; ColorBits: Integer;
  230. DepthBits: Integer; StencilBits: Integer; AccumBits: Integer; AuxBuffers: Integer; Layer: Integer): TglcContextPixelFormatSettings;
  231. begin
  232. Result.DoubleBuffered:= DoubleBuffered;
  233. Result.Stereo:= Stereo;
  234. Result.MultiSampling:= MultiSampling;
  235. Result.ColorBits:= ColorBits;
  236. Result.DepthBits:= DepthBits;
  237. Result.StencilBits:= StencilBits;
  238. Result.AccumBits:= AccumBits;
  239. Result.AuxBuffers:= AuxBuffers;
  240. Result.Layer:= Layer;
  241. end;
  242. class function TglcContext.MakeVersion(const aMajor, aMinor: Integer; const aForwardCompatible: Boolean): TglcContextVersionSettings;
  243. begin
  244. result.Major := aMajor;
  245. result.Minor := aMinor;
  246. result.ForwardCompatible := aForwardCompatible;
  247. end;
  248. class function TglcContext.GetPlatformClass: TglcContextClass;
  249. begin
  250. Result := nil;
  251. {$IFDEF WINDOWS}
  252. Result:= TglcContextWGL;
  253. {$ELSE}{$IFDEF WIN32}
  254. Result:= TglcContextWGL;
  255. {$ENDIF}{$ENDIF}
  256. {$IFDEF LINUX}
  257. Result:= TglcContextGtk2GLX;
  258. {$ENDIF}
  259. if not Assigned(result) then
  260. raise EGLError.Create('unable to find suitabe context class');
  261. end;
  262. class function TglcContext.IsAnyContextActive: boolean;
  263. begin
  264. Result:= GetPlatformClass.IsAnyContextActive;
  265. end;
  266. constructor TglcContext.Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings);
  267. begin
  268. inherited Create;
  269. fPixelFormatSettings := aPixelFormatSettings;
  270. FControl := aControl;
  271. fThreadID := 0;
  272. fEnableVsync := false;
  273. fUseVersion := false;
  274. InitOpenGL();
  275. end;
  276. constructor TglcContext.Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings; const aVersionSettings: TglcContextVersionSettings);
  277. begin
  278. Create(aControl, aPixelFormatSettings);
  279. fVersionSettings := aVersionSettings;
  280. fUseVersion := true;
  281. end;
  282. destructor TglcContext.Destroy;
  283. begin
  284. if (GetCurrentThreadId = fMainContextThreadID) then
  285. fMainContextThreadID := 0;
  286. CloseContext;
  287. inherited Destroy;
  288. end;
  289. procedure TglcContext.BuildContext;
  290. begin
  291. OpenContext;
  292. Activate;
  293. ReadImplementationProperties;
  294. ReadExtensions;
  295. SetEnableVSync(fEnableVsync);
  296. end;
  297. procedure TglcContext.EnableDebugOutput(const aLogEvent: TLogEvent);
  298. begin
  299. fLogEvent := aLogEvent;
  300. SetDebugMode(true);
  301. end;
  302. procedure TglcContext.DisableDebugOutput;
  303. begin
  304. SetDebugMode(false);
  305. end;
  306. procedure TglcContext.CloseContext;
  307. begin
  308. if fMainContextThreadID = fThreadID then
  309. fMainContextThreadID := 0;
  310. end;
  311. initialization
  312. {$IFDEF fpc}TglcContext.{$ENDIF}fMainContextThreadID := 0;
  313. end.