Skip to content

Commit 52d669d

Browse files
Fix memory leak
1 parent 3dd9019 commit 52d669d

File tree

5 files changed

+118
-5
lines changed

5 files changed

+118
-5
lines changed

building-a-renderer.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ struct DrawCmd {
1616
in_drawstate_t state;
1717
in_blend_mode_t blendMode;
1818
in_mask_mode_t maskMode;
19+
uint32_t allocId;
1920
uint32_t vtxOffset;
2021
uint32_t idxOffset;
21-
uint type;
22+
uint32_t type;
2223
void[64] vars;
2324
}
2425
```

source/inochi2d/cffi/puppet.d

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ void in_puppet_free(in_puppet_t* obj) {
105105
import core.memory : GC;
106106
if (obj) {
107107
GC.removeRoot(cast(void*)obj);
108+
assumeNoGC(&destroy!(false, Puppet), cast(Puppet)obj);
109+
GC.free(obj);
108110
}
109111
}
110112

source/inochi2d/cffi/render.d

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ void in_texture_flip_vertically(in_texture_t* obj) {
131131
}
132132

133133
/**
134-
Pre-multiplies the alpha channel of the texture.
134+
Premultiplies the alpha channel of the texture.
135135
136136
Params:
137137
obj = The texture object.
@@ -140,6 +140,27 @@ void in_texture_premultiply(in_texture_t* obj) {
140140
(cast(Texture)obj).data.premultiply();
141141
}
142142

143+
/**
144+
Un-premultiplies the alpha channel of the texture.
145+
146+
Params:
147+
obj = The texture object.
148+
*/
149+
void in_texture_unpremultiply(in_texture_t* obj) {
150+
(cast(Texture)obj).data.unpremultiply();
151+
}
152+
153+
/**
154+
Pads the texture with a border.
155+
156+
Params:
157+
obj = The texture object.
158+
thickness = Thickness of the border in pixels.
159+
*/
160+
void in_texture_pad(in_texture_t* obj, uint thickness) {
161+
(cast(Texture)obj).data.pad(thickness);
162+
}
163+
143164
/**
144165
Gets the pixels of the texture.
145166
@@ -210,6 +231,7 @@ struct in_drawcmd_t {
210231
in_drawstate_t state;
211232
in_blend_mode_t blendMode;
212233
in_mask_mode_t maskMode;
234+
uint allocId;
213235
uint vtxOffset;
214236
uint idxOffset;
215237
uint elemCount;
@@ -225,6 +247,7 @@ struct in_drawalloc_t {
225247
uint idxOffset;
226248
uint idxCount;
227249
uint vtxCount;
250+
uint allocId;
228251
}
229252

230253
/**

source/inochi2d/core/render/drawlist.d

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ private:
4848

4949
public:
5050

51+
// Destructor
52+
~this() {
53+
_cmds.clear();
54+
_vtxs.clear();
55+
_idxs.clear();
56+
_allocs.clear();
57+
_targetsStack.clear();
58+
}
59+
5160
/**
5261
Whether to use base vertex specification.
5362
*/
@@ -111,6 +120,7 @@ public:
111120
_vtxp += vtx.length;
112121
_idxp += idx.length;
113122

123+
_call.allocId = _allp;
114124
_call.idxCount = cast(uint)idx.length;
115125
_call.vtxCount = cast(uint)vtx.length;
116126

@@ -181,6 +191,7 @@ public:
181191
void setMesh(DrawListAlloc* alloc) {
182192
if (!alloc) return;
183193

194+
_ccmd.allocId = alloc.allocId;
184195
_ccmd.idxOffset = alloc.idxOffset;
185196
_ccmd.vtxOffset = alloc.vtxOffset;
186197
_ccmd.elemCount = alloc.idxCount;
@@ -249,6 +260,11 @@ struct DrawListAlloc {
249260
Number of vertices.
250261
*/
251262
uint vtxCount;
263+
264+
/**
265+
Allocation ID.
266+
*/
267+
uint allocId;
252268
}
253269

254270
/**
@@ -318,6 +334,11 @@ struct DrawCmd {
318334
*/
319335
MaskingMode maskMode;
320336

337+
/**
338+
Allocation ID.
339+
*/
340+
uint allocId;
341+
321342
/**
322343
Vertex offset.
323344
*/

source/inochi2d/core/render/texture.d

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,52 @@ public:
198198
Premultiplies incoming color data.
199199
*/
200200
void premultiply() {
201+
final switch(format) {
202+
case TextureFormat.rgba8Unorm:
203+
ubyte[] dataView = cast(ubyte[])data;
204+
foreach(i; 0..data.length/4) {
205+
size_t offsetPixel = (i*4);
206+
207+
float r = (cast(float)dataView[offsetPixel+0]/255.0) * (cast(float)dataView[offsetPixel+3]/255.0);
208+
float g = (cast(float)dataView[offsetPixel+1]/255.0) * (cast(float)dataView[offsetPixel+3]/255.0);
209+
float b = (cast(float)dataView[offsetPixel+2]/255.0) * (cast(float)dataView[offsetPixel+3]/255.0);
210+
211+
dataView[offsetPixel+0] = cast(ubyte)(r*255.0);
212+
dataView[offsetPixel+1] = cast(ubyte)(g*255.0);
213+
dataView[offsetPixel+2] = cast(ubyte)(b*255.0);
214+
}
215+
return;
216+
217+
case TextureFormat.none:
218+
case TextureFormat.depthStencil:
219+
case TextureFormat.r8:
220+
return;
221+
}
222+
}
223+
224+
/**
225+
Un-premultiplies incoming color data.
226+
*/
227+
void unpremultiply() {
201228
final switch(format) {
202229
case TextureFormat.rgba8Unorm:
203230
ubyte[] dataView = cast(ubyte[])data;
204231
foreach(i; 0..data.length/4) {
205232

206233
size_t offsetPixel = (i*4);
207-
dataView[offsetPixel+0] = cast(ubyte)((cast(int)dataView[offsetPixel+0] * cast(int)dataView[offsetPixel+3])/255);
208-
dataView[offsetPixel+1] = cast(ubyte)((cast(int)dataView[offsetPixel+1] * cast(int)dataView[offsetPixel+3])/255);
209-
dataView[offsetPixel+2] = cast(ubyte)((cast(int)dataView[offsetPixel+2] * cast(int)dataView[offsetPixel+3])/255);
234+
235+
// Ensure no divide by zero happens.
236+
if (cast(float)dataView[offsetPixel+3] == 0) {
237+
dataView[offsetPixel..offsetPixel+3] = 0;
238+
continue;
239+
}
240+
241+
float r = (cast(float)dataView[offsetPixel+0]/255.0) / (cast(float)dataView[offsetPixel+3]/255.0);
242+
float g = (cast(float)dataView[offsetPixel+1]/255.0) / (cast(float)dataView[offsetPixel+3]/255.0);
243+
float b = (cast(float)dataView[offsetPixel+2]/255.0) / (cast(float)dataView[offsetPixel+3]/255.0);
244+
dataView[offsetPixel+0] = cast(ubyte)(r*255.0);
245+
dataView[offsetPixel+1] = cast(ubyte)(g*255.0);
246+
dataView[offsetPixel+2] = cast(ubyte)(b*255.0);
210247
}
211248
return;
212249

@@ -217,6 +254,35 @@ public:
217254
}
218255
}
219256

257+
/**
258+
Pads the texture with a 1-pixel wide border.
259+
260+
Params:
261+
thickness = The border thickness to generate.
262+
*/
263+
void pad(uint thickness) {
264+
if (data.length == 0)
265+
return;
266+
267+
uint totalPad = thickness*2;
268+
ubyte[] newData = nu_malloca!ubyte((width+totalPad)*(height+totalPad)*channels);
269+
newData[0..$] = 0;
270+
271+
size_t srcStride = width*channels;
272+
size_t dstStride = (width+totalPad)*channels;
273+
foreach(y; 0..height) {
274+
size_t start = (dstStride*(y+thickness))+(thickness*channels);
275+
size_t end = start + srcStride;
276+
newData[start..end] = cast(ubyte[])data[srcStride*y..(srcStride*y)+srcStride];
277+
}
278+
279+
// Update the texture
280+
nu_freea(data);
281+
this.data = newData;
282+
this.width = width+totalPad;
283+
this.height = height+totalPad;
284+
}
285+
220286
/**
221287
Dumps the image data to the specified file.
222288

0 commit comments

Comments
 (0)