GLS.CUDA.Context.pas 23 KB

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