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.

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