Skip to content

Commit 24ef98b

Browse files
committed
c interface: add opengl; controlled: refcounting example
1 parent 0fd25bb commit 24ef98b

File tree

4 files changed

+418
-7
lines changed

4 files changed

+418
-7
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
==========================================
2+
Refcounting Wrapper for External C Objects
3+
==========================================
4+
5+
-------
6+
Context
7+
-------
8+
9+
* From :url:`https://blog.adacore.com/the-road-to-a-thick-opengl-binding-for-ada-part-2`
10+
* OpenGL API create various objects like textures or vertex buffers
11+
* Creating them gives us an ID
12+
13+
- Can then be used to refer to the object
14+
15+
* Simple approach: Manually reclaiming them
16+
17+
- Could cause leaks
18+
19+
* Refcount approach: automatic ID management
20+
21+
- From an Ada wrapper
22+
- Automatic reclaim once the last reference vanishes
23+
24+
-----------------
25+
Wrapper Interface
26+
-----------------
27+
28+
* :ada:`type GL_Object is abstract tagged private`
29+
30+
- Implements smart pointer logic
31+
32+
.. code:: Ada
33+
34+
procedure Initialize_Id (Object : in out GL_Object);
35+
36+
procedure Clear (Object : in out GL_Object);
37+
38+
function Initialized (Object : GL_Object) return Boolean;
39+
40+
* Derived by the **actual** object types
41+
42+
.. code:: Ada
43+
44+
procedure Internal_Create_Id
45+
(Object : GL_Object; Id : out UInt) is abstract;
46+
47+
procedure Internal_Release_Id
48+
(Object : GL_Object; Id : UInt) is abstract;
49+
50+
* Example usage
51+
52+
.. code:: Ada
53+
54+
type Shader (Kind : Shader_Type) is new GL_Object with null record;
55+
56+
------------------------------------
57+
Wrapper Implementation: Private part
58+
------------------------------------
59+
60+
* Object ID's holder: :ada:`GL_Object_Reference`
61+
62+
- All derived types have a handle to this
63+
64+
.. code:: Ada
65+
66+
type GL_Object_Reference;
67+
type GL_Object_Reference_Access is access all GL_Object_Reference;
68+
69+
type GL_Object is abstract new Ada.Finalization.Controlled
70+
with record
71+
Reference : GL_Object_Reference_Access := null;
72+
end record;
73+
74+
* Controlled type implementing **ref-counting**
75+
76+
.. code:: Ada
77+
78+
overriding procedure Adjust (Object : in out GL_Object);
79+
-- Increases reference count.
80+
81+
overriding procedure Finalize (Object : in out GL_Object);
82+
-- Decreases reference count.
83+
-- Destroys underlying resource when it reaches zero.
84+
85+
------------------------------------
86+
Wrapper Implementation: Full Picture
87+
------------------------------------
88+
89+
.. image:: controlled_gl_object.svg
90+
91+
.. code:: Ada
92+
93+
type GL_Object_Reference is record
94+
GL_Id : UInt;
95+
Reference_Count : Natural;
96+
Is_Owner : Boolean;
97+
end record;
98+
99+
------------------------
100+
:ada:`Adjust` Completion
101+
------------------------
102+
103+
* :ada:`Adjust` is called every time a new reference is **created**
104+
* Increments the ref-counter
105+
106+
.. code:: Ada
107+
108+
overriding procedure Adjust (Object : in out GL_Object) is
109+
begin
110+
if Object.Reference /= null then
111+
Object.Reference.Reference_Count := @ + 1;
112+
end if;
113+
end Adjust;
114+
115+
--------------------------
116+
:ada:`Finalize` Completion
117+
--------------------------
118+
119+
.. note::
120+
121+
* :ada:`Finalize` should always be :dfn:`idempotent`
122+
123+
- Compiler might call it multiple times on the same object
124+
- In particular when **exceptions** occur
125+
126+
.. code:: Ada
127+
128+
overriding procedure Finalize (Object : in out GL_Object) is
129+
Ref : GL_Object_Reference_Access
130+
renames Object.Reference;
131+
begin
132+
133+
134+
.. warning::
135+
136+
Do **not** decrement the reference counter for every call
137+
138+
* A given object will own **only one** reference
139+
140+
.. code:: Ada
141+
142+
-- Idempotence: the next call to Finalize will have no effect
143+
Ref := null;
144+
145+
if Ref /= null then
146+
Ref.Reference_Count := @ - 1;
147+
if Ref.Reference_Count = 0 then
148+
Free (Ref.all); -- Call to user-defined primitive
149+
Unchecked_Free (Ref);
150+
end if;
151+
end if;

courses/fundamentals_of_ada/260_controlled_types/10-idiom_refcounting.rst

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Global Overview
1313
- Efficient
1414
- All :ada:`access` must then be using it
1515

16-
* A refcounted type derives from :ada:`Refcounted`
16+
* Any refcounted type **must** derive from :ada:`Refcounted`
1717

1818
- Tagged
1919
- Get a :ada:`Ref` through :ada:`Set`
@@ -45,14 +45,19 @@ Global Overview
4545
Implementation Details
4646
----------------------
4747

48-
* :ada:`Set` is safe
49-
48+
.. code:: Ada
49+
50+
procedure Set (Self : in out Ref; Data : Refcounted'Class)
51+
52+
.. tip::
53+
54+
This procedure is safe
55+
5056
- :ada:`Ref` default value is :ada:`null`
5157
- Clears up any previously used :ada:`Ref`
5258

5359
.. code:: Ada
54-
55-
procedure Set (Self : in out Ref; Data : Refcounted'Class) is
60+
is
5661
D : constant Refcounted_Access := new Refcounted'Class'(Data);
5762
begin
5863
if Self.Data /= null then
@@ -63,12 +68,23 @@ Implementation Details
6368
Adjust (Self); -- increment reference count (set to 1)
6469
end Set;
6570
66-
* :ada:`Adjust` called for all new references
71+
.. code:: Ada
72+
73+
overriding procedure Adjust (P : in out Ref)
74+
75+
.. note::
76+
77+
Called for all new references
78+
79+
.. warning::
80+
81+
:ada:`Data` might be :ada:`null`
6782

6883
.. code:: Ada
6984
70-
overriding procedure Adjust (P : in out Ref) is
85+
is
7186
begin
87+
7288
if P.Data /= null then
7389
P.Data.Refcount := P.Data.Refcount + 1;
7490
end if;

courses/fundamentals_of_ada/700_expert_resource_management.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,6 @@ Expert Resource Management
4040
.. include:: 140_access_types/11-idiom_constant_pointer.rst
4141
.. include:: 260_controlled_types/10-idiom_refcounting.rst
4242
.. include:: 260_controlled_types/11-example_logger.rst
43+
.. include:: 230_interfacing_with_c/10-example_refcount_wrap.rst
4344
.. include:: 240_tasking/21-gnat_semaphores.rst
4445
.. include:: 240_tasking/22-task_safe_interfaces.rst

0 commit comments

Comments
 (0)