2
0

GLS.CUDAContext.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLS.CUDAContext;
  5. (* CUDA context *)
  6. interface
  7. {$I GLScene.inc}
  8. uses
  9. System.Classes,
  10. System.SysUtils,
  11. GLS.Strings,
  12. GLBaseClasses,
  13. GLContext,
  14. GLS.Generics,
  15. GLS.Logger,
  16. GLS.CUDARunTime,
  17. GLS.CUDAApi;
  18. type
  19. TCUDADimensions = class(TGLUpdateAbleObject)
  20. private
  21. FXYZ: TDim3;
  22. FMaxXYZ: TDim3;
  23. FReadOnly: Boolean;
  24. function GetDimComponent(index: Integer): Integer;
  25. procedure SetDimComponent(index: Integer; Value: Integer);
  26. function GetMaxDimComponent(index: Integer): Integer;
  27. procedure SetMaxDimComponent(index: Integer; Value: Integer);
  28. public
  29. constructor Create(AOwner: TPersistent); override;
  30. procedure Assign(Source: TPersistent); override;
  31. property MaxSizeX: Integer index 0 read GetMaxDimComponent
  32. write SetMaxDimComponent;
  33. property MaxSizeY: Integer index 1 read GetMaxDimComponent
  34. write SetMaxDimComponent;
  35. property MaxSizeZ: Integer index 2 read GetMaxDimComponent
  36. write SetMaxDimComponent;
  37. property ReadOnlyValue: Boolean read FReadOnly write FReadOnly;
  38. published
  39. { Published Properties }
  40. property SizeX: Integer index 0 read GetDimComponent write SetDimComponent
  41. default 1;
  42. property SizeY: Integer index 1 read GetDimComponent write SetDimComponent
  43. default 1;
  44. property SizeZ: Integer index 2 read GetDimComponent write SetDimComponent
  45. default 1;
  46. end;
  47. TCUDAContext = class;
  48. TOnOpenGLInteropInit = procedure(out Context: TGLContext) of object;
  49. TCUDADevice = class(TPersistent)
  50. private
  51. fID: Integer;
  52. fHandle: TCUdevice;
  53. fGFlops: Integer;
  54. fDeviceProperties: TCudaDeviceProp;
  55. FSuitable: Boolean;
  56. FUsed: Boolean;
  57. fMaxThreadsDim: TCUDADimensions;
  58. fMaxGridSize: TCUDADimensions;
  59. protected
  60. function GetName: string;
  61. public
  62. constructor Create; reintroduce;
  63. destructor Destroy; override;
  64. procedure Assign(Source: TPersistent); override;
  65. { Returns in bytes the total amount of memory
  66. available on the device dev in bytes. }
  67. function TotalMemory: Cardinal;
  68. published
  69. property Name: string read GetName;
  70. property TotalGlobalMem: NativeUInt read fDeviceProperties.TotalGlobalMem;
  71. property SharedMemPerBlock: NativeUInt read fDeviceProperties.SharedMemPerBlock;
  72. property RegsPerBlock: Integer read fDeviceProperties.RegsPerBlock;
  73. property WarpSize: Integer read fDeviceProperties.WarpSize;
  74. property MemPitch: NativeUInt read fDeviceProperties.MemPitch;
  75. property MaxThreadsPerBlock: Integer
  76. read fDeviceProperties.MaxThreadsPerBlock;
  77. property MaxThreadsDim: TCUDADimensions read fMaxThreadsDim;
  78. property MaxGridSize: TCUDADimensions read fMaxGridSize;
  79. property ClockRate: Integer read fDeviceProperties.ClockRate;
  80. property TotalConstMem: NativeUInt read fDeviceProperties.TotalConstMem;
  81. property Major: Integer read fDeviceProperties.Major;
  82. property Minor: Integer read fDeviceProperties.Minor;
  83. property TextureAlignment: NativeUInt read fDeviceProperties.TextureAlignment;
  84. property DeviceOverlap: Integer read fDeviceProperties.DeviceOverlap;
  85. property MultiProcessorCount: Integer
  86. read fDeviceProperties.MultiProcessorCount;
  87. end;
  88. TGLSCUDADevice = class(TComponent)
  89. private
  90. FSelectDeviceName: string;
  91. function GetDevice: TCUDADevice;
  92. procedure SetDevice(AValue: TCUDADevice);
  93. procedure SetDeviceName(const AName: string);
  94. public
  95. constructor Create(AOwner: TComponent); override;
  96. destructor Destroy; override;
  97. function Suitable: Boolean;
  98. published
  99. property SelectDevice: string read FSelectDeviceName write SetDeviceName;
  100. property Device: TCUDADevice read GetDevice write SetDevice;
  101. end;
  102. TCUDAHandlesMaster = class(TComponent)
  103. protected
  104. function GetContext: TCUDAContext; virtual; abstract;
  105. procedure AllocateHandles; virtual;
  106. procedure DestroyHandles; virtual;
  107. end;
  108. TCUDAHandleList = GThreadList<TCUDAHandlesMaster>;
  109. TCUDAContext = class(TObject)
  110. private
  111. fHandle: PCUcontext;
  112. FDevice: TCUDADevice;
  113. FOnOpenGLInteropInit: TOnOpenGLInteropInit;
  114. FHandleList: TCUDAHandleList;
  115. procedure SetDevice(ADevice: TCUDADevice);
  116. public
  117. constructor Create;
  118. destructor Destroy; override;
  119. { Destroy all handles based of this context. }
  120. procedure DestroyAllHandles;
  121. { Pushes context onto CPU thread’s stack of current contexts. }
  122. procedure Requires;
  123. { Pops context from current CPU thread. }
  124. procedure Release;
  125. function IsValid: Boolean; inline;
  126. property Device: TCUDADevice read FDevice write SetDevice;
  127. property OnOpenGLInteropInit: TOnOpenGLInteropInit read FOnOpenGLInteropInit
  128. write FOnOpenGLInteropInit;
  129. end;
  130. TCUDADeviceList = GList<TCUDADevice>;
  131. TCUDAContextList = GList<TCUDAContext>;
  132. { Static class of CUDA contexts manager. }
  133. CUDAContextManager = class
  134. private
  135. class var fDeviceList: TCUDADeviceList;
  136. class var fContextList: TCUDAContextList;
  137. class var FContextStacks: array of TCUDAContextList;
  138. protected
  139. class function GetDevice(i: Integer): TCUDADevice;
  140. class function GetNextUnusedDevice: TCUDADevice;
  141. class procedure RegisterContext(aContext: TCUDAContext);
  142. class procedure UnRegisterContext(aContext: TCUDAContext);
  143. class function GetThreadStack: TCUDAContextList;
  144. class function GetContext(i: Integer): TCUDAContext;
  145. public
  146. // Management
  147. class procedure Init;
  148. class procedure Done;
  149. class procedure CreateContext(aContext: TCUDAContext);
  150. class procedure DestroyContext(aContext: TCUDAContext);
  151. class procedure CreateContextOf(ADevice: TCUDADevice);
  152. class procedure DestroyContextOf(ADevice: TCUDADevice);
  153. class procedure PushContext(aContext: TCUDAContext);
  154. class function PopContext: TCUDAContext;
  155. // Fill unused device list to show its in property.
  156. class procedure FillUnusedDeviceList(var AList: TStringList);
  157. // Return device by name.
  158. class function GetDeviceByName(const AName: string): TCUDADevice;
  159. // Returns the number of CUDA compatiable devices.
  160. class function DeviceCount: Integer;
  161. // Access to devices list.
  162. property Devices[i: Integer]: TCUDADevice read GetDevice;
  163. // Returns a device that has a maximum Giga flops.
  164. class function GetMaxGflopsDevice: TCUDADevice;
  165. // Returns the number of TCUDAcontext object.
  166. class function ContextCount: Integer;
  167. // Return CUDA context of current thread.
  168. class function GetCurrentThreadContext: TCUDAContext;
  169. { Access to contexts list. }
  170. property Contexts[i: Integer]: TCUDAContext read GetContext;
  171. end;
  172. //---------------------------------------------------------------------
  173. implementation
  174. //---------------------------------------------------------------------
  175. threadvar
  176. vStackIndex: Cardinal;
  177. // ------------------
  178. // ------------------ TCUDADimensions ------------------
  179. // ------------------
  180. constructor TCUDADimensions.Create(AOwner: TPersistent);
  181. const
  182. cXYZone: TDim3 = (1, 1, 1);
  183. cXYZmax: TDim3 = (MaxInt, MaxInt, MaxInt);
  184. begin
  185. inherited Create(AOwner);
  186. FReadOnly := False;
  187. FXYZ := cXYZone;
  188. FMaxXYZ := cXYZmax;
  189. end;
  190. procedure TCUDADimensions.Assign(Source: TPersistent);
  191. begin
  192. if Source is TCUDADimensions then
  193. begin
  194. FMaxXYZ[0] := TCUDADimensions(Source).FMaxXYZ[0];
  195. FMaxXYZ[1] := TCUDADimensions(Source).FMaxXYZ[1];
  196. FMaxXYZ[2] := TCUDADimensions(Source).FMaxXYZ[2];
  197. FXYZ[0] := TCUDADimensions(Source).FXYZ[0];
  198. FXYZ[1] := TCUDADimensions(Source).FXYZ[1];
  199. FXYZ[2] := TCUDADimensions(Source).FXYZ[2];
  200. NotifyChange(Self);
  201. end;
  202. inherited Assign(Source);
  203. end;
  204. function TCUDADimensions.GetDimComponent(index: Integer): Integer;
  205. begin
  206. Result := FXYZ[index];
  207. end;
  208. procedure TCUDADimensions.SetDimComponent(index: Integer; Value: Integer);
  209. var
  210. v: LongWord;
  211. begin
  212. if not FReadOnly then
  213. begin
  214. if Value < 1 then
  215. v := 1
  216. else
  217. v := LongWord(Value);
  218. if v > FMaxXYZ[index] then
  219. v := FMaxXYZ[index];
  220. FXYZ[index] := v;
  221. NotifyChange(Self);
  222. end;
  223. end;
  224. function TCUDADimensions.GetMaxDimComponent(index: Integer): Integer;
  225. begin
  226. Result := FMaxXYZ[index];
  227. end;
  228. procedure TCUDADimensions.SetMaxDimComponent(index: Integer; Value: Integer);
  229. begin
  230. if not FReadOnly then
  231. begin
  232. if Value > 0 then
  233. begin
  234. FMaxXYZ[index] := LongWord(Value);
  235. if FXYZ[index] > FMaxXYZ[index] then
  236. FXYZ[index] := FMaxXYZ[index];
  237. NotifyChange(Self);
  238. end;
  239. end;
  240. end;
  241. // ------------------
  242. // ------------------ TCUDADevice ------------------
  243. // ------------------
  244. constructor TCUDADevice.Create;
  245. begin
  246. fMaxThreadsDim := TCUDADimensions.Create(Self);
  247. fMaxThreadsDim.ReadOnlyValue := True;
  248. fMaxGridSize := TCUDADimensions.Create(Self);
  249. fMaxGridSize.ReadOnlyValue := True;
  250. if IsCUDAInitialized then
  251. begin
  252. fID := CUDAContextManager.fDeviceList.Count;
  253. FUsed := False;
  254. FSuitable := cuDeviceGet(fHandle, fID) = CUDA_SUCCESS;
  255. if FSuitable then
  256. begin
  257. cuDeviceGetName(@fDeviceProperties.name[0], SizeOf(fDeviceProperties.name), fHandle);
  258. cuDeviceTotalMem(@fDeviceProperties.TotalGlobalMem, fHandle);
  259. cuDeviceGetAttribute(@fDeviceProperties.SharedMemPerBlock, CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK, fHandle);
  260. cuDeviceGetAttribute(@fDeviceProperties.RegsPerBlock, CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK, fHandle);
  261. cuDeviceGetAttribute(@fDeviceProperties.WarpSize, CU_DEVICE_ATTRIBUTE_WARP_SIZE, fHandle);
  262. cuDeviceGetAttribute(@fDeviceProperties.MemPitch, CU_DEVICE_ATTRIBUTE_MAX_PITCH, fHandle);
  263. cuDeviceGetAttribute(@fDeviceProperties.MaxThreadsPerBlock, CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK, fHandle);
  264. cuDeviceGetAttribute(@fDeviceProperties.MaxThreadsDim[0], CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X, fHandle);
  265. cuDeviceGetAttribute(@fDeviceProperties.MaxThreadsDim[1], CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y, fHandle);
  266. cuDeviceGetAttribute(@fDeviceProperties.MaxThreadsDim[2], CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z, fHandle);
  267. cuDeviceGetAttribute(@fDeviceProperties.MaxGridSize[0], CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X, fHandle);
  268. cuDeviceGetAttribute(@fDeviceProperties.MaxGridSize[1], CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y, fHandle);
  269. cuDeviceGetAttribute(@fDeviceProperties.MaxGridSize[2], CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z, fHandle);
  270. cuDeviceGetAttribute(@fDeviceProperties.ClockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, fHandle);
  271. cuDeviceGetAttribute(@fDeviceProperties.TotalConstMem, CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY, fHandle);
  272. cuDeviceComputeCapability(fDeviceProperties.Major, fDeviceProperties.Minor, fHandle);
  273. cuDeviceGetAttribute(@fDeviceProperties.TextureAlignment, CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT, fHandle);
  274. cuDeviceGetAttribute(@fDeviceProperties.DeviceOverlap, CU_DEVICE_ATTRIBUTE_GPU_OVERLAP, fHandle);
  275. cuDeviceGetAttribute(@fDeviceProperties.DeviceOverlap, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, fHandle);
  276. fGFlops := fDeviceProperties.MultiProcessorCount *
  277. fDeviceProperties.ClockRate;
  278. fMaxThreadsDim.FXYZ[0] := fDeviceProperties.MaxThreadsDim[0];
  279. fMaxThreadsDim.FXYZ[1] := fDeviceProperties.MaxThreadsDim[1];
  280. fMaxThreadsDim.FXYZ[2] := fDeviceProperties.MaxThreadsDim[2];
  281. fMaxGridSize.FXYZ[0] := fDeviceProperties.MaxGridSize[0];
  282. fMaxGridSize.FXYZ[1] := fDeviceProperties.MaxGridSize[1];
  283. fMaxGridSize.FXYZ[2] := fDeviceProperties.MaxGridSize[2];
  284. end;
  285. end;
  286. end;
  287. destructor TCUDADevice.Destroy;
  288. begin
  289. fMaxThreadsDim.Destroy;
  290. fMaxGridSize.Destroy;
  291. inherited;
  292. end;
  293. procedure TCUDADevice.Assign(Source: TPersistent);
  294. var
  295. dev: TCUDADevice;
  296. begin
  297. if Source is TCUDADevice then
  298. begin
  299. dev := TCUDADevice(Source);
  300. fID := dev.fID;
  301. fHandle := dev.fHandle;
  302. fGFlops := dev.fGFlops;
  303. fDeviceProperties := dev.fDeviceProperties;
  304. FSuitable := dev.FSuitable;
  305. fMaxThreadsDim.Assign(dev.fMaxThreadsDim);
  306. fMaxGridSize.Assign(dev.fMaxGridSize);
  307. end;
  308. inherited Assign(Source);
  309. end;
  310. function TCUDADevice.GetName: string;
  311. begin
  312. Result := Format('%s (%d)', [string(fDeviceProperties.name), fID + 1]);
  313. end;
  314. function TCUDADevice.TotalMemory: Cardinal;
  315. begin
  316. cuDeviceTotalMem(@fDeviceProperties.TotalGlobalMem, fHandle);
  317. Result := fDeviceProperties.TotalGlobalMem;
  318. end;
  319. // ------------------
  320. // ------------------ TGLSCUDADevice ------------------
  321. // ------------------
  322. constructor TGLSCUDADevice.Create(AOwner: TComponent);
  323. var
  324. LDevice: TCUDADevice;
  325. begin
  326. inherited Create(AOwner);
  327. LDevice := CUDAContextManager.GetNextUnusedDevice;
  328. if Assigned(LDevice) and LDevice.FSuitable then
  329. begin
  330. FSelectDeviceName := LDevice.name;
  331. LDevice.FUsed := True;
  332. end
  333. else
  334. begin
  335. FSelectDeviceName := '';
  336. end;
  337. end;
  338. destructor TGLSCUDADevice.Destroy;
  339. var
  340. Device: TCUDADevice;
  341. begin
  342. inherited;
  343. Device := CUDAContextManager.GetDeviceByName(FSelectDeviceName);
  344. if Assigned(Device) then
  345. Device.FUsed := False;
  346. end;
  347. function TGLSCUDADevice.GetDevice: TCUDADevice;
  348. begin
  349. Result := CUDAContextManager.GetDeviceByName(FSelectDeviceName);
  350. end;
  351. function TGLSCUDADevice.Suitable: Boolean;
  352. var
  353. LDevice: TCUDADevice;
  354. begin
  355. LDevice := GetDevice;
  356. Result := Assigned(LDevice);
  357. if Result then
  358. Result := LDevice.FSuitable;
  359. end;
  360. procedure TGLSCUDADevice.SetDevice(AValue: TCUDADevice);
  361. begin
  362. end;
  363. procedure TGLSCUDADevice.SetDeviceName(const AName: string);
  364. begin
  365. if FSelectDeviceName <> AName then
  366. begin
  367. CUDAContextManager.DestroyContextOf(Self.Device);
  368. FSelectDeviceName := AName;
  369. CUDAContextManager.CreateContextOf(Self.Device);
  370. end;
  371. end;
  372. // ------------------
  373. // ------------------ TCUDAContextManager ------------------
  374. // ------------------
  375. class procedure CUDAContextManager.Init;
  376. var
  377. dCount: Integer;
  378. status: TCUresult;
  379. i: Integer;
  380. begin
  381. if InitCUDA and not Assigned(fDeviceList) then
  382. begin
  383. fDeviceList := TCUDADeviceList.Create;
  384. fContextList := TCUDAContextList.Create;
  385. dCount := 0;
  386. status := cuInit(0);
  387. if status = CUDA_SUCCESS then
  388. cuDeviceGetCount(dCount);
  389. // Fill devices list
  390. for i := 0 to dCount - 1 do
  391. fDeviceList.Add(TCUDADevice.Create);
  392. end;
  393. end;
  394. class procedure CUDAContextManager.Done;
  395. var
  396. I, J: Integer;
  397. begin
  398. if Assigned(fDeviceList) then
  399. for i := 0 to fDeviceList.Count - 1 do
  400. fDeviceList[i].Free;
  401. for I := 0 to High(FContextStacks) do
  402. begin
  403. if FContextStacks[I].Count > 0 then
  404. begin
  405. GLSLogger.LogError(strUnbalansedUsage);
  406. for J := FContextStacks[I].Count - 1 to 0 do
  407. FContextStacks[I][J].Release;
  408. end;
  409. FContextStacks[I].Destroy;
  410. end;
  411. fDeviceList.Free;
  412. fContextList.Free;
  413. CloseCUDA;
  414. end;
  415. class procedure CUDAContextManager.RegisterContext(aContext: TCUDAContext);
  416. begin
  417. if fContextList.IndexOf(aContext) >= 0 then
  418. begin
  419. GLSLogger.LogError(strInvalidContextReg);
  420. Abort;
  421. end
  422. else
  423. fContextList.Add(aContext);
  424. end;
  425. class procedure CUDAContextManager.UnRegisterContext(aContext: TCUDAContext);
  426. begin
  427. if fContextList.IndexOf(aContext) < 0 then
  428. begin
  429. GLSLogger.LogError(strInvalidContextReg);
  430. Abort;
  431. end
  432. else
  433. begin
  434. fContextList.Remove(aContext);
  435. end;
  436. end;
  437. class function CUDAContextManager.ContextCount: Integer;
  438. begin
  439. Result := fContextList.Count;
  440. end;
  441. class function CUDAContextManager.DeviceCount: Integer;
  442. begin
  443. Result := fDeviceList.Count;
  444. end;
  445. class function CUDAContextManager.GetDevice(i: Integer): TCUDADevice;
  446. begin
  447. Result := nil;
  448. if i < fDeviceList.Count then
  449. Result := fDeviceList[i];
  450. end;
  451. class function CUDAContextManager.GetContext(i: Integer): TCUDAContext;
  452. begin
  453. Result := nil;
  454. if i < fContextList.Count then
  455. Result := fContextList[i];
  456. end;
  457. class procedure CUDAContextManager.FillUnusedDeviceList(var AList: TStringList);
  458. var
  459. i: Integer;
  460. begin
  461. if not Assigned(AList) then
  462. AList := TStringList.Create
  463. else
  464. AList.Clear;
  465. for i := 0 to fDeviceList.Count - 1 do
  466. if not fDeviceList[i].FUsed then
  467. AList.Add(fDeviceList[i].name);
  468. end;
  469. class function CUDAContextManager.GetDeviceByName(const AName: string)
  470. : TCUDADevice;
  471. var
  472. i: Integer;
  473. Device: TCUDADevice;
  474. begin
  475. Result := nil;
  476. if Length(AName) = 0 then
  477. exit;
  478. for i := 0 to fDeviceList.Count - 1 do
  479. begin
  480. Device := fDeviceList[i];
  481. if Device.name = AName then
  482. begin
  483. Result := Device;
  484. exit;
  485. end;
  486. end;
  487. end;
  488. class function CUDAContextManager.GetMaxGflopsDevice: TCUDADevice;
  489. var
  490. max_gflops: Integer;
  491. i: Integer;
  492. Device: TCUDADevice;
  493. begin
  494. Device := nil;
  495. max_gflops := 0;
  496. for i := 0 to fDeviceList.Count - 1 do
  497. begin
  498. if max_gflops < fDeviceList.Items[i].fGFlops then
  499. begin
  500. Device := fDeviceList.Items[i];
  501. max_gflops := Device.fGFlops;
  502. end;
  503. end;
  504. Result := Device;
  505. end;
  506. class function CUDAContextManager.GetNextUnusedDevice: TCUDADevice;
  507. var
  508. i: Integer;
  509. Device: TCUDADevice;
  510. begin
  511. Result := nil;
  512. for i := 0 to fDeviceList.Count - 1 do
  513. begin
  514. Device := fDeviceList[i];
  515. if not Device.FUsed then
  516. begin
  517. Result := Device;
  518. exit;
  519. end;
  520. end;
  521. end;
  522. class procedure CUDAContextManager.CreateContext(aContext: TCUDAContext);
  523. var
  524. status: TCUresult;
  525. cuOldContext, cuContext: PCUcontext;
  526. LGLContext: TGLContext;
  527. LStack: TCUDAContextList;
  528. begin
  529. if not Assigned(aContext.FDevice)
  530. or not aContext.FDevice.FSuitable then
  531. begin
  532. GLSLogger.LogError(strNoDeviceToCreate);
  533. Abort;
  534. end;
  535. if GetThreadStack.Count > 0 then
  536. begin
  537. if cuCtxPopCurrent(cuOldContext) <> CUDA_SUCCESS then
  538. begin
  539. GLSLogger.LogError(strThreadBusy);
  540. Abort;
  541. end;
  542. end
  543. else
  544. cuOldContext := nil;
  545. if aContext.IsValid then
  546. DestroyContext(aContext);
  547. RegisterContext(aContext);
  548. status := CUDA_SUCCESS;
  549. if Assigned(aContext.FOnOpenGLInteropInit) then
  550. begin
  551. aContext.FOnOpenGLInteropInit(LGLContext);
  552. if Assigned(LGLContext) and LGLContext.IsValid then
  553. begin
  554. LGLContext.Activate;
  555. cuContext := nil;
  556. status := cuGLCtxCreate(cuContext, 0, aContext.FDevice.fHandle);
  557. LGLContext.Deactivate;
  558. end
  559. else
  560. begin
  561. GLSLogger.LogError(strInvalidGLContext);
  562. UnRegisterContext(aContext);
  563. Abort;
  564. end;
  565. end
  566. else
  567. begin
  568. status := cuCtxCreate(cuContext, 0, aContext.FDevice.fHandle);
  569. end;
  570. if (status <> CUDA_SUCCESS) then
  571. begin
  572. GLSLogger.LogError(cudaGetLastErrorString);
  573. UnRegisterContext(aContext);
  574. cuCtxDetach(cuContext);
  575. Abort;
  576. end;
  577. aContext.fHandle := cuContext;
  578. // Make context be floating to use it in different thread
  579. if cuCtxPopCurrent(cuContext) <> CUDA_SUCCESS then
  580. begin
  581. LStack := GetThreadStack;
  582. LStack.Insert(LStack.Count - 1, aContext);
  583. GLSLogger.LogWarning(strMakeFloatingFail);
  584. end;
  585. if Assigned(cuOldContext) then
  586. cuCtxPushCurrent(cuOldContext);
  587. end;
  588. class procedure CUDAContextManager.CreateContextOf(ADevice: TCUDADevice);
  589. var
  590. i: Integer;
  591. begin
  592. if Assigned(ADevice) and ADevice.FSuitable then
  593. begin
  594. for i := 0 to fContextList.Count do
  595. if fContextList[i].FDevice = ADevice then
  596. CreateContext(fContextList[i]);
  597. end;
  598. end;
  599. class procedure CUDAContextManager.DestroyContext(aContext: TCUDAContext);
  600. begin
  601. if aContext.IsValid then
  602. begin
  603. aContext.DestroyAllHandles;
  604. cuCtxDestroy(aContext.fHandle);
  605. aContext.fHandle := nil;
  606. CUDAContextManager.UnRegisterContext(aContext);
  607. end;
  608. end;
  609. class procedure CUDAContextManager.DestroyContextOf(ADevice: TCUDADevice);
  610. var
  611. i: Integer;
  612. begin
  613. if Assigned(ADevice) and ADevice.FSuitable then
  614. begin
  615. for i := 0 to fContextList.Count - 1 do
  616. if fContextList[i].FDevice = ADevice then
  617. DestroyContext(fContextList[i]);
  618. end;
  619. end;
  620. class function CUDAContextManager.GetThreadStack: TCUDAContextList;
  621. begin
  622. if vStackIndex = 0 then
  623. begin
  624. SetLength(FContextStacks, Length(FContextStacks)+1);
  625. FContextStacks[High(FContextStacks)] := TCUDAContextList.Create;
  626. vStackIndex := High(FContextStacks)+1;
  627. end;
  628. Result := FContextStacks[vStackIndex-1];
  629. end;
  630. class function CUDAContextManager.GetCurrentThreadContext: TCUDAContext;
  631. begin
  632. if GetThreadStack.Count > 0 then
  633. Result := GetThreadStack.Last
  634. else
  635. Result := nil;
  636. end;
  637. class procedure CUDAContextManager.PushContext(aContext: TCUDAContext);
  638. var
  639. LContext: TCUDAContext;
  640. cuContext: PCUcontext;
  641. begin
  642. LContext := GetCurrentThreadContext;
  643. if LContext <> aContext then
  644. begin
  645. // Pop current
  646. if Assigned(LContext) then
  647. if cuCtxPopCurrent(cuContext) = CUDA_SUCCESS then
  648. begin
  649. if LContext.fHandle <> cuContext then
  650. begin
  651. GLSLogger.LogError(strUnbalansedUsage);
  652. Abort;
  653. end;
  654. end
  655. else
  656. Abort;
  657. // Push required
  658. if cuCtxPushCurrent(aContext.fHandle) <> CUDA_SUCCESS then
  659. Abort;
  660. end;
  661. GetThreadStack.Add(aContext);
  662. end;
  663. class function CUDAContextManager.PopContext: TCUDAContext;
  664. var
  665. C: Integer;
  666. LContext: TCUDAContext;
  667. cuContext: PCUcontext;
  668. begin
  669. C := GetThreadStack.Count;
  670. if C = 0 then
  671. begin
  672. GLSLogger.LogError(strUnbalansedUsage);
  673. Abort;
  674. end;
  675. Result := GetThreadStack.Last;
  676. GetThreadStack.Delete(C - 1);
  677. LContext := GetCurrentThreadContext;
  678. if Result <> LContext then
  679. begin
  680. if cuCtxPopCurrent(cuContext) = CUDA_SUCCESS then
  681. begin
  682. if Result.fHandle <> cuContext then
  683. begin
  684. GLSLogger.LogError(strUnbalansedUsage);
  685. Abort;
  686. end;
  687. end
  688. else
  689. Abort;
  690. if Assigned(LContext)
  691. and (cuCtxPushCurrent(LContext.fHandle) <> CUDA_SUCCESS) then
  692. Abort;
  693. end;
  694. end;
  695. // ------------------
  696. // ------------------ TCUDAHandlesMaster ------------------
  697. // ------------------
  698. procedure TCUDAHandlesMaster.AllocateHandles;
  699. var
  700. LList: TCUDAHandleList.TLockableList;
  701. begin
  702. LList := GetContext.FHandleList.LockList;
  703. if LList.IndexOf(Self) < 0 then
  704. LList.Add(Self);
  705. GetContext.FHandleList.UnlockList;
  706. end;
  707. procedure TCUDAHandlesMaster.DestroyHandles;
  708. begin
  709. GetContext.FHandleList.Remove(Self);
  710. end;
  711. // ------------------
  712. // ------------------ TCUDAContext ------------------
  713. // ------------------
  714. constructor TCUDAContext.Create;
  715. begin
  716. inherited Create;
  717. fHandle := nil;
  718. FDevice := nil;
  719. FHandleList := TCUDAHandleList.Create;
  720. end;
  721. destructor TCUDAContext.Destroy;
  722. begin
  723. DestroyAllHandles;
  724. CUDAContextManager.DestroyContext(Self);
  725. FHandleList.Destroy;
  726. inherited;
  727. end;
  728. procedure TCUDAContext.SetDevice(ADevice: TCUDADevice);
  729. begin
  730. if FDevice <> ADevice then
  731. begin
  732. CUDAContextManager.DestroyContext(Self);
  733. FDevice := ADevice;
  734. end;
  735. end;
  736. procedure TCUDAContext.Requires;
  737. begin
  738. if not IsValid then
  739. begin
  740. GLSLogger.LogError(strContextNotInit);
  741. Abort;
  742. end;
  743. CUDAContextManager.PushContext(Self);
  744. end;
  745. procedure TCUDAContext.Release;
  746. begin
  747. CUDAContextManager.PopContext;
  748. end;
  749. procedure TCUDAContext.DestroyAllHandles;
  750. var
  751. i: Integer;
  752. LList: TCUDAHandleList.TLockableList;
  753. begin
  754. Requires;
  755. LList := FHandleList.LockList;
  756. try
  757. for i := LList.Count - 1 downto 0 do
  758. LList[i].DestroyHandles;
  759. finally
  760. FHandleList.Clear;
  761. FHandleList.UnlockList;
  762. Release;
  763. end;
  764. end;
  765. function TCUDAContext.IsValid: Boolean;
  766. begin
  767. Result := Assigned(fHandle);
  768. end;
  769. // ------------------------------------------------------------------
  770. initialization
  771. // ------------------------------------------------------------------
  772. RegisterClasses([TGLSCUDADevice]);
  773. CUDAContextManager.Init;
  774. finalization
  775. CUDAContextManager.Done;
  776. end.