GR32_Bindings.pas 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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. end;
  48. TFunctionPriority = function (Info: PFunctionInfo): Integer;
  49. PFunctionBinding = ^TFunctionBinding;
  50. TFunctionBinding = record
  51. FunctionID: Integer;
  52. BindVariable: PPointer;
  53. end;
  54. { TFunctionRegistry }
  55. { This class fascilitates a registry that allows multiple function to be
  56. registered together with information about their CPU requirements and
  57. an additional 'flags' parameter. Functions that share the same FunctionID
  58. can be assigned to a function variable through the rebind methods.
  59. A priority callback function is used to assess the most optimal function. }
  60. TFunctionRegistry = class(TPersistent)
  61. private
  62. FItems: TList;
  63. FBindings: TList;
  64. FName: string;
  65. procedure SetName(const Value: string);
  66. function GetItems(Index: Integer): PFunctionInfo;
  67. procedure SetItems(Index: Integer; const Value: PFunctionInfo);
  68. public
  69. constructor Create; virtual;
  70. destructor Destroy; override;
  71. procedure Clear;
  72. procedure Add(FunctionID: Integer; Proc: Pointer; CPUFeatures: TCPUFeatures = []; Flags: Integer = 0);
  73. // function rebinding support
  74. procedure RegisterBinding(FunctionID: Integer; BindVariable: PPointer);
  75. procedure RebindAll(PriorityCallback: TFunctionPriority = nil);
  76. procedure Rebind(FunctionID: Integer; PriorityCallback: TFunctionPriority = nil);
  77. function FindFunction(FunctionID: Integer; PriorityCallback: TFunctionPriority = nil): Pointer;
  78. property Items[Index: Integer]: PFunctionInfo read GetItems write SetItems;
  79. published
  80. property Name: string read FName write SetName;
  81. end;
  82. function NewRegistry(const Name: string = ''): TFunctionRegistry;
  83. function DefaultPriorityProc(Info: PFunctionInfo): Integer;
  84. var
  85. DefaultPriority: TFunctionPriority = DefaultPriorityProc;
  86. const
  87. INVALID_PRIORITY: Integer = MaxInt;
  88. implementation
  89. uses
  90. Math;
  91. var
  92. Registers: TList;
  93. function NewRegistry(const Name: string): TFunctionRegistry;
  94. begin
  95. if Registers = nil then
  96. Registers := TList.Create;
  97. Result := TFunctionRegistry.Create;
  98. Result.Name := Name;
  99. Registers.Add(Result);
  100. end;
  101. function DefaultPriorityProc(Info: PFunctionInfo): Integer;
  102. begin
  103. Result := IfThen(Info^.CPUFeatures <= GR32_System.CPUFeatures, 0, INVALID_PRIORITY);
  104. end;
  105. { TFunctionRegistry }
  106. procedure TFunctionRegistry.Add(FunctionID: Integer; Proc: Pointer;
  107. CPUFeatures: TCPUFeatures; Flags: Integer);
  108. var
  109. Info: PFunctionInfo;
  110. begin
  111. New(Info);
  112. Info^.FunctionID := FunctionID;
  113. Info^.Proc := Proc;
  114. Info^.CPUFeatures := CPUFeatures;
  115. Info^.Flags := Flags;
  116. FItems.Add(Info);
  117. end;
  118. procedure TFunctionRegistry.Clear;
  119. var
  120. I: Integer;
  121. begin
  122. for I := 0 to FItems.Count - 1 do
  123. Dispose(PFunctionInfo(FItems[I]));
  124. FItems.Clear;
  125. for I := 0 to FBindings.Count - 1 do
  126. Dispose(PFunctionBinding(FBindings[I]));
  127. FBindings.Clear;
  128. end;
  129. constructor TFunctionRegistry.Create;
  130. begin
  131. FItems := TList.Create;
  132. FBindings := TList.Create;
  133. end;
  134. destructor TFunctionRegistry.Destroy;
  135. begin
  136. Clear;
  137. FItems.Free;
  138. FBindings.Free;
  139. inherited;
  140. end;
  141. function TFunctionRegistry.FindFunction(FunctionID: Integer;
  142. PriorityCallback: TFunctionPriority): Pointer;
  143. var
  144. I, MinPriority, P: Integer;
  145. Info: PFunctionInfo;
  146. begin
  147. if not Assigned(PriorityCallback) then PriorityCallback := DefaultPriority;
  148. Result := nil;
  149. MinPriority := INVALID_PRIORITY;
  150. for I := FItems.Count - 1 downto 0 do
  151. begin
  152. Info := FItems[I];
  153. if (Info^.FunctionID = FunctionID) then
  154. begin
  155. P := PriorityCallback(Info);
  156. if P < MinPriority then
  157. begin
  158. Result := Info^.Proc;
  159. MinPriority := P;
  160. end;
  161. end;
  162. end;
  163. end;
  164. function TFunctionRegistry.GetItems(Index: Integer): PFunctionInfo;
  165. begin
  166. Result := FItems[Index];
  167. end;
  168. procedure TFunctionRegistry.Rebind(FunctionID: Integer;
  169. PriorityCallback: TFunctionPriority);
  170. var
  171. P: PFunctionBinding;
  172. I: Integer;
  173. begin
  174. for I := 0 to FBindings.Count - 1 do
  175. begin
  176. P := PFunctionBinding(FBindings[I]);
  177. if P^.FunctionID = FunctionID then
  178. P^.BindVariable^ := FindFunction(FunctionID, PriorityCallback);
  179. end;
  180. end;
  181. procedure TFunctionRegistry.RebindAll(PriorityCallback: TFunctionPriority);
  182. var
  183. I: Integer;
  184. P: PFunctionBinding;
  185. begin
  186. for I := 0 to FBindings.Count - 1 do
  187. begin
  188. P := PFunctionBinding(FBindings[I]);
  189. P^.BindVariable^ := FindFunction(P^.FunctionID, PriorityCallback);
  190. end;
  191. end;
  192. procedure TFunctionRegistry.RegisterBinding(FunctionID: Integer;
  193. BindVariable: PPointer);
  194. var
  195. Binding: PFunctionBinding;
  196. begin
  197. New(Binding);
  198. Binding^.FunctionID := FunctionID;
  199. Binding^.BindVariable := BindVariable;
  200. FBindings.Add(Binding);
  201. end;
  202. procedure TFunctionRegistry.SetItems(Index: Integer;
  203. const Value: PFunctionInfo);
  204. begin
  205. FItems[Index] := Value;
  206. end;
  207. procedure TFunctionRegistry.SetName(const Value: string);
  208. begin
  209. FName := Value;
  210. end;
  211. procedure FreeRegisters;
  212. var
  213. I: Integer;
  214. begin
  215. if Assigned(Registers) then
  216. begin
  217. for I := Registers.Count - 1 downto 0 do
  218. TFunctionRegistry(Registers[I]).Free;
  219. Registers.Free;
  220. Registers := nil;
  221. end;
  222. end;
  223. initialization
  224. finalization
  225. FreeRegisters;
  226. end.