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.

383 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. fShareContext: TglcContext;
  70. function GetEnableVSync: Boolean;
  71. procedure SetEnableVSync(aValue: Boolean);
  72. procedure LogMsg(const aSeverity: TSeverity; const aMsg: String);
  73. procedure SetDebugMode(const aEnable: Boolean);
  74. protected
  75. fUseVersion: Boolean;
  76. fPixelFormatSettings: TglcContextPixelFormatSettings;
  77. fVersionSettings: TglcContextVersionSettings;
  78. procedure OpenContext; virtual;
  79. public
  80. property PixelFormatSettings: TglcContextPixelFormatSettings read fPixelFormatSettings;
  81. property VersionSettings: TglcContextVersionSettings read fVersionSettings;
  82. property ShareContext: TglcContext read fShareContext;
  83. constructor Create(const aControl: TWinControl;
  84. const aPixelFormatSettings: TglcContextPixelFormatSettings;
  85. const aShareContext: TglcContext = nil); overload; virtual;
  86. constructor Create(const aControl: TWinControl;
  87. const aPixelFormatSettings: TglcContextPixelFormatSettings;
  88. const aVersionSettings: TglcContextVersionSettings;
  89. const aShareContext: TglcContext = nil); overload; virtual;
  90. destructor Destroy; override;
  91. property ThreadID: TThreadID read fThreadID;
  92. property EnableVSync: Boolean read GetEnableVSync write SetEnableVSync;
  93. procedure BuildContext;
  94. procedure EnableDebugOutput(const aLogEvent: TLogEvent);
  95. procedure DisableDebugOutput;
  96. procedure CloseContext; virtual;
  97. procedure ReleaseShareContext; virtual;
  98. procedure Activate; virtual;
  99. procedure Deactivate; virtual; abstract;
  100. function IsActive: boolean; virtual; abstract;
  101. procedure SwapBuffers; virtual; abstract;
  102. procedure SetSwapInterval(const aInterval: GLint); virtual; abstract;
  103. function GetSwapInterval: GLint; virtual; abstract;
  104. {$IFDEF fpc}
  105. private class var
  106. fMainContextThreadID: TThreadID;
  107. public
  108. class property MainContextThreadID: TThreadID read fMainContextThreadID;
  109. {$ENDIF}
  110. public
  111. class function MakePF(DoubleBuffered: boolean = true;
  112. Stereo: boolean=false;
  113. MultiSampling: TMultiSample=1;
  114. ColorBits: Integer=32;
  115. DepthBits: Integer=24;
  116. StencilBits: Integer=0;
  117. AccumBits: Integer=0;
  118. AuxBuffers: Integer=0;
  119. Layer: Integer=0): TglcContextPixelFormatSettings;
  120. class function MakeVersion(const aMajor, aMinor: Integer; const aForwardCompatible: Boolean): TglcContextVersionSettings;
  121. class function GetPlatformClass: TglcContextClass;
  122. class function ChangeDisplaySettings(const aWidth, aHeight,
  123. aBitPerPixel, aFreq: Integer; const aFlags: TglcDisplayFlags): Boolean; virtual; abstract;
  124. class function IsAnyContextActive: boolean; virtual;
  125. end;
  126. implementation
  127. uses
  128. {$IFDEF WINDOWS}
  129. uglcContextWGL
  130. {$ELSE}{$IFDEF WIN32}
  131. uglcContextWGL{$IFNDEF fpc}, Windows{$ENDIF}
  132. {$ENDIF}{$ENDIF}
  133. {$IFDEF LINUX}
  134. uglcContextGtk2GLX
  135. {$ENDIF}
  136. ;
  137. {$IFNDEF fpc}
  138. var
  139. fMainContextThreadID: TThreadID;
  140. {$ENDIF}
  141. 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}
  142. var
  143. src, typ: String;
  144. sv: TSeverity;
  145. begin
  146. case source of
  147. GL_DEBUG_SOURCE_API_ARB : src:= 'API';
  148. GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB : src:= 'WINDOW';
  149. GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: src:= 'SHADER';
  150. GL_DEBUG_SOURCE_THIRD_PARTY_ARB : src:= '3RDPARTY';
  151. GL_DEBUG_SOURCE_APPLICATION_ARB : src:= 'APPLICATION';
  152. GL_DEBUG_SOURCE_OTHER_ARB : src:= 'OTHER';
  153. end;
  154. src:= 'GL_' + src;
  155. case type_ of
  156. GL_DEBUG_TYPE_ERROR_ARB : typ:= 'ERROR';
  157. GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB : typ:= 'DEPRECATED';
  158. GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB : typ:= 'UNDEF BEHAV';
  159. GL_DEBUG_TYPE_PORTABILITY_ARB : typ:= 'PORTABILITY';
  160. GL_DEBUG_TYPE_PERFORMANCE_ARB : typ:= 'PERFORMANCE';
  161. GL_DEBUG_TYPE_OTHER_ARB : typ:= 'OTHER';
  162. end;
  163. case severity of
  164. GL_DEBUG_SEVERITY_LOW_ARB: sv := svLow;
  165. GL_DEBUG_SEVERITY_MEDIUM_ARB: sv := svMedium;
  166. GL_DEBUG_SEVERITY_HIGH_ARB: sv := svHigh;
  167. end;
  168. TglcContext(userParam).LogMsg(sv, format('%s [%d] %s',[typ, id, message_]));
  169. end;
  170. procedure GlDebugCallbackAMD(id: GLuint; category: GLenum; severity: GLenum; {%H-}length: GLsizei; const message_: PGLchar; {%H-}userParam: PGLvoid); {$IFDEF WINDOWS}stdcall; {$ELSE}cdecl; {$ENDIF}
  171. var
  172. src: String;
  173. sv: TSeverity;
  174. begin
  175. case category of
  176. GL_DEBUG_CATEGORY_API_ERROR_AMD : src:= 'API';
  177. GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD : src:= 'WINDOW';
  178. GL_DEBUG_CATEGORY_DEPRECATION_AMD : src:= 'SHADER';
  179. GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD : src:= 'UNDEF BEHAV';
  180. GL_DEBUG_CATEGORY_PERFORMANCE_AMD : src:= 'PERFORMANCE';
  181. GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD : src:= 'SHADER';
  182. GL_DEBUG_CATEGORY_APPLICATION_AMD : src:= 'APPLICATION';
  183. GL_DEBUG_CATEGORY_OTHER_AMD : src:= 'OTHER';
  184. end;
  185. src:= 'GL_' + src;
  186. case severity of
  187. GL_DEBUG_SEVERITY_LOW_AMD: sv := svLow;
  188. GL_DEBUG_SEVERITY_MEDIUM_AMD: sv := svMedium;
  189. GL_DEBUG_SEVERITY_HIGH_AMD: sv := svHigh;
  190. end;
  191. TglcContext(userParam).LogMsg(sv, format('[%d] %s',[id, message_]));
  192. end;
  193. function TglcContext.GetEnableVSync: Boolean;
  194. begin
  195. result := fEnableVsync;
  196. end;
  197. procedure TglcContext.SetEnableVSync(aValue: Boolean);
  198. begin
  199. fEnableVsync := aValue;
  200. if IsActive then begin
  201. if fEnableVsync then
  202. SetSwapInterval(1)
  203. else
  204. SetSwapInterval(0);
  205. end;
  206. end;
  207. procedure TglcContext.LogMsg(const aSeverity: TSeverity; const aMsg: String);
  208. begin
  209. if Assigned(fLogEvent) then
  210. fLogEvent(self, aSeverity, aMsg);
  211. end;
  212. procedure TglcContext.SetDebugMode(const aEnable: Boolean);
  213. begin
  214. // ARB Debug Output
  215. if GL_ARB_debug_output then begin
  216. glDebugMessageCallbackARB(@GlDebugCallbackARB, self);
  217. glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nil, aEnable);
  218. if aEnable then begin
  219. glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
  220. glDebugMessageInsertARB(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, -1, PGLchar('Attached ARB_debug_output'));
  221. end;
  222. // AMD Debug Output
  223. end else if GL_AMD_debug_output then begin
  224. glDebugMessageCallbackAMD(@GlDebugCallbackAMD, self);
  225. glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, nil, aEnable);
  226. if aEnable then
  227. glDebugMessageInsertAMD(GL_DEBUG_CATEGORY_OTHER_AMD, GL_DEBUG_SEVERITY_LOW_ARB, 0, -1, PGLchar('Attached ARB_debug_output'));
  228. end;
  229. end;
  230. procedure TglcContext.OpenContext;
  231. begin
  232. fThreadID := GetCurrentThreadId;
  233. if fMainContextThreadID = 0 then
  234. fMainContextThreadID := fThreadID;
  235. end;
  236. class function TglcContext.MakePF(DoubleBuffered: boolean; Stereo: boolean; MultiSampling: TMultiSample; ColorBits: Integer;
  237. DepthBits: Integer; StencilBits: Integer; AccumBits: Integer; AuxBuffers: Integer; Layer: Integer): TglcContextPixelFormatSettings;
  238. begin
  239. Result.DoubleBuffered:= DoubleBuffered;
  240. Result.Stereo:= Stereo;
  241. Result.MultiSampling:= MultiSampling;
  242. Result.ColorBits:= ColorBits;
  243. Result.DepthBits:= DepthBits;
  244. Result.StencilBits:= StencilBits;
  245. Result.AccumBits:= AccumBits;
  246. Result.AuxBuffers:= AuxBuffers;
  247. Result.Layer:= Layer;
  248. end;
  249. class function TglcContext.MakeVersion(const aMajor, aMinor: Integer; const aForwardCompatible: Boolean): TglcContextVersionSettings;
  250. begin
  251. result.Major := aMajor;
  252. result.Minor := aMinor;
  253. result.ForwardCompatible := aForwardCompatible;
  254. end;
  255. class function TglcContext.GetPlatformClass: TglcContextClass;
  256. begin
  257. Result := nil;
  258. {$IFDEF WINDOWS}
  259. Result:= TglcContextWGL;
  260. {$ELSE}{$IFDEF WIN32}
  261. Result:= TglcContextWGL;
  262. {$ENDIF}{$ENDIF}
  263. {$IFDEF LINUX}
  264. Result:= TglcContextGtk2GLX;
  265. {$ENDIF}
  266. if not Assigned(result) then
  267. raise EGLError.Create('unable to find suitabe context class');
  268. end;
  269. class function TglcContext.IsAnyContextActive: boolean;
  270. begin
  271. Result:= GetPlatformClass.IsAnyContextActive;
  272. end;
  273. constructor TglcContext.Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings; const aShareContext: TglcContext);
  274. begin
  275. inherited Create;
  276. fShareContext := aShareContext;
  277. fPixelFormatSettings := aPixelFormatSettings;
  278. FControl := aControl;
  279. fThreadID := 0;
  280. fEnableVsync := false;
  281. fUseVersion := false;
  282. InitOpenGL();
  283. end;
  284. constructor TglcContext.Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings; const aVersionSettings: TglcContextVersionSettings; const aShareContext: TglcContext);
  285. begin
  286. Create(aControl, aPixelFormatSettings, aShareContext);
  287. fVersionSettings := aVersionSettings;
  288. fUseVersion := true;
  289. end;
  290. destructor TglcContext.Destroy;
  291. begin
  292. if (GetCurrentThreadId = fMainContextThreadID) then
  293. fMainContextThreadID := 0;
  294. CloseContext;
  295. inherited Destroy;
  296. end;
  297. procedure TglcContext.BuildContext;
  298. begin
  299. OpenContext;
  300. Activate;
  301. SetEnableVSync(fEnableVsync);
  302. end;
  303. procedure TglcContext.EnableDebugOutput(const aLogEvent: TLogEvent);
  304. begin
  305. fLogEvent := aLogEvent;
  306. SetDebugMode(true);
  307. end;
  308. procedure TglcContext.DisableDebugOutput;
  309. begin
  310. SetDebugMode(false);
  311. end;
  312. procedure TglcContext.CloseContext;
  313. begin
  314. if fMainContextThreadID = fThreadID then
  315. fMainContextThreadID := 0;
  316. end;
  317. procedure TglcContext.ReleaseShareContext;
  318. begin
  319. fShareContext := nil;
  320. end;
  321. procedure TglcContext.Activate;
  322. begin
  323. ReadImplementationProperties;
  324. ReadExtensions;
  325. end;
  326. initialization
  327. {$IFDEF fpc}TglcContext.{$ENDIF}fMainContextThreadID := 0;
  328. end.