GR32_Bindings.pas 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. unit GR32_Bindings;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Run-time Function Bindings for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Mattias Andersson
  26. * [email protected]
  27. *
  28. * Portions created by the Initial Developer are Copyright (C) 2005-2010
  29. * the Initial Developer. All Rights Reserved.
  30. *
  31. * Contributor(s):
  32. *
  33. * ***** END LICENSE BLOCK ***** *)
  34. interface
  35. {$I GR32.inc}
  36. uses
  37. Classes, GR32_System;
  38. type
  39. TFunctionName = type string;
  40. TFunctionID = type Integer;
  41. PFunctionInfo = ^TFunctionInfo;
  42. TFunctionInfo = record
  43. FunctionID: Integer;
  44. Proc: Pointer;
  45. CPUFeatures: TCPUFeatures;
  46. Flags: Integer;
  47. Priority: Integer; // Smaller is better
  48. end;
  49. TFunctionPriority = function (Info: PFunctionInfo): Integer;
  50. PFunctionBinding = ^TFunctionBinding;
  51. TFunctionBinding = record
  52. FunctionID: Integer;
  53. BindVariable: PPointer;
  54. end;
  55. { TFunctionRegistry }
  56. { This class fascilitates a registry that allows multiple function to be
  57. registered together with information about their CPU requirements and
  58. an additional 'flags' parameter. Functions that share the same FunctionID
  59. can be assigned to a function variable through the rebind methods.
  60. A priority callback function is used to assess the most optimal function. }
  61. TFunctionRegistry = class(TPersistent)
  62. private
  63. FItems: TList;
  64. FBindings: TList;
  65. FName: string;
  66. FNeedRebind: boolean;
  67. procedure SetName(const Value: string);
  68. function GetItems(Index: Integer): PFunctionInfo;
  69. procedure SetItems(Index: Integer; const Value: PFunctionInfo);
  70. public
  71. constructor Create; virtual;
  72. destructor Destroy; override;
  73. procedure Clear;
  74. procedure Add(FunctionID: Integer; Proc: Pointer; CPUFeatures: TCPUFeatures = [];
  75. Flags: Integer = 0; Priority: Integer = 0);
  76. // function rebinding support
  77. procedure RegisterBinding(FunctionID: Integer; BindVariable: PPointer);
  78. procedure RebindAll(AForce: boolean; PriorityCallback: TFunctionPriority = nil); overload;
  79. procedure RebindAll(PriorityCallback: TFunctionPriority = nil); overload;
  80. function Rebind(FunctionID: Integer; PriorityCallback: TFunctionPriority = nil): boolean;
  81. function FindFunction(FunctionID: Integer; PriorityCallback: TFunctionPriority = nil): Pointer;
  82. property Items[Index: Integer]: PFunctionInfo read GetItems write SetItems;
  83. published
  84. property Name: string read FName write SetName;
  85. end;
  86. function NewRegistry(const Name: string = ''): TFunctionRegistry;
  87. function DefaultPriorityProc(Info: PFunctionInfo): Integer;
  88. var
  89. DefaultPriority: TFunctionPriority = DefaultPriorityProc;
  90. const
  91. INVALID_PRIORITY: Integer = MaxInt;
  92. implementation
  93. uses
  94. Math;
  95. var
  96. Registers: TList;
  97. function NewRegistry(const Name: string): TFunctionRegistry;
  98. begin
  99. if Registers = nil then
  100. Registers := TList.Create;
  101. Result := TFunctionRegistry.Create;
  102. {$IFDEF NEXTGEN}
  103. Result.__ObjAddRef;
  104. {$ENDIF}
  105. Result.Name := Name;
  106. Registers.Add(Result);
  107. end;
  108. function DefaultPriorityProc(Info: PFunctionInfo): Integer;
  109. begin
  110. if (Info^.CPUFeatures <= GR32_System.CPUFeatures) then
  111. Result := Info^.Priority
  112. else
  113. Result := INVALID_PRIORITY;
  114. end;
  115. { TFunctionRegistry }
  116. procedure TFunctionRegistry.Add(FunctionID: Integer; Proc: Pointer;
  117. CPUFeatures: TCPUFeatures; Flags: Integer; Priority: Integer);
  118. var
  119. Info: PFunctionInfo;
  120. begin
  121. New(Info);
  122. Info^.FunctionID := FunctionID;
  123. Info^.Proc := Proc;
  124. Info^.CPUFeatures := CPUFeatures;
  125. Info^.Flags := Flags;
  126. Info^.Priority := Priority;
  127. FItems.Add(Info);
  128. FNeedRebind := True;
  129. end;
  130. procedure TFunctionRegistry.Clear;
  131. var
  132. I: Integer;
  133. begin
  134. for I := 0 to FItems.Count - 1 do
  135. Dispose(PFunctionInfo(FItems[I]));
  136. FItems.Clear;
  137. for I := 0 to FBindings.Count - 1 do
  138. Dispose(PFunctionBinding(FBindings[I]));
  139. FBindings.Clear;
  140. end;
  141. constructor TFunctionRegistry.Create;
  142. begin
  143. FItems := TList.Create;
  144. FBindings := TList.Create;
  145. end;
  146. destructor TFunctionRegistry.Destroy;
  147. begin
  148. Clear;
  149. FItems.Free;
  150. FBindings.Free;
  151. inherited;
  152. end;
  153. function TFunctionRegistry.FindFunction(FunctionID: Integer;
  154. PriorityCallback: TFunctionPriority): Pointer;
  155. var
  156. I, MinPriority, P: Integer;
  157. Info: PFunctionInfo;
  158. begin
  159. if not Assigned(PriorityCallback) then
  160. PriorityCallback := DefaultPriority;
  161. Result := nil;
  162. MinPriority := INVALID_PRIORITY;
  163. for I := FItems.Count - 1 downto 0 do
  164. begin
  165. Info := FItems[I];
  166. if (Info^.FunctionID = FunctionID) then
  167. begin
  168. P := PriorityCallback(Info);
  169. if P < MinPriority then
  170. begin
  171. Result := Info^.Proc;
  172. MinPriority := P;
  173. end;
  174. end;
  175. end;
  176. end;
  177. function TFunctionRegistry.GetItems(Index: Integer): PFunctionInfo;
  178. begin
  179. Result := FItems[Index];
  180. end;
  181. function TFunctionRegistry.Rebind(FunctionID: Integer;
  182. PriorityCallback: TFunctionPriority): boolean;
  183. var
  184. P: PFunctionBinding;
  185. I: Integer;
  186. begin
  187. Result := False;
  188. for I := 0 to FBindings.Count - 1 do
  189. begin
  190. P := PFunctionBinding(FBindings[I]);
  191. if P^.FunctionID = FunctionID then
  192. begin
  193. P^.BindVariable^ := FindFunction(FunctionID, PriorityCallback);
  194. Result := (P^.BindVariable^ <> nil);
  195. break;
  196. end;
  197. end;
  198. end;
  199. procedure TFunctionRegistry.RebindAll(AForce: boolean; PriorityCallback: TFunctionPriority);
  200. begin
  201. if AForce then
  202. FNeedRebind := True;
  203. RebindAll(PriorityCallback);
  204. end;
  205. procedure TFunctionRegistry.RebindAll(PriorityCallback: TFunctionPriority);
  206. var
  207. I: Integer;
  208. P: PFunctionBinding;
  209. begin
  210. if (not Assigned(PriorityCallback)) and (not FNeedRebind) then
  211. exit;
  212. for I := 0 to FBindings.Count - 1 do
  213. begin
  214. P := PFunctionBinding(FBindings[I]);
  215. P^.BindVariable^ := FindFunction(P^.FunctionID, PriorityCallback);
  216. end;
  217. FNeedRebind := False;
  218. end;
  219. procedure TFunctionRegistry.RegisterBinding(FunctionID: Integer;
  220. BindVariable: PPointer);
  221. var
  222. Binding: PFunctionBinding;
  223. begin
  224. New(Binding);
  225. Binding^.FunctionID := FunctionID;
  226. Binding^.BindVariable := BindVariable;
  227. FBindings.Add(Binding);
  228. FNeedRebind := True;
  229. end;
  230. procedure TFunctionRegistry.SetItems(Index: Integer;
  231. const Value: PFunctionInfo);
  232. begin
  233. FItems[Index] := Value;
  234. FNeedRebind := True;
  235. end;
  236. procedure TFunctionRegistry.SetName(const Value: string);
  237. begin
  238. FName := Value;
  239. end;
  240. procedure FreeRegisters;
  241. var
  242. I: Integer;
  243. begin
  244. if Assigned(Registers) then
  245. begin
  246. for I := Registers.Count - 1 downto 0 do
  247. TFunctionRegistry(Registers[I]).Free;
  248. Registers.Free;
  249. Registers := nil;
  250. end;
  251. end;
  252. initialization
  253. finalization
  254. FreeRegisters;
  255. end.