Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 2bb113d

Browse files
committed
[[ ThreadedRendering ]] Changed LockImageFrame to return a retained GImage inside MCGImageFrame rather than a pointer to the internal MCGImageFrame - thus making it more multi-thread friendly.
[[ ThreadedRendering ]] Made Release/Retain of MCImageRep thread-safe [[ ThreadedRendering ]] Tweaked release methods to ensure thread-safety.
1 parent 1aaee1e commit 2bb113d

File tree

13 files changed

+105
-153
lines changed

13 files changed

+105
-153
lines changed

engine/src/globals.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ Boolean MCallowdatagrambroadcasts = False;
499499
// MM-2014-07-31: [[ ThreadedRendering ]] Used to ensure only a single animation message is sent per redraw
500500
MCThreadMutexRef MCanimationmutex = NULL;
501501
MCThreadMutexRef MCpatternmutex = NULL;
502+
MCThreadMutexRef MCimagerepmutex = NULL;
502503

503504
////////////////////////////////////////////////////////////////////////////////
504505

@@ -826,6 +827,7 @@ void X_clear_globals(void)
826827
// MM-2014-07-31: [[ ThreadedRendering ]]
827828
MCanimationmutex = NULL;
828829
MCpatternmutex = NULL;
830+
MCimagerepmutex = NULL;
829831

830832
#ifdef _ANDROID_MOBILE
831833
// MM-2012-02-22: Initialize up any static variables as Android static vars are preserved between sessions
@@ -865,6 +867,7 @@ bool X_open(int argc, char *argv[], char *envp[])
865867
MCStackTileInitialize();
866868
MCThreadMutexCreate(MCanimationmutex);
867869
MCThreadMutexCreate(MCpatternmutex);
870+
MCThreadMutexCreate(MCimagerepmutex);
868871

869872
////
870873

@@ -1227,6 +1230,7 @@ int X_close(void)
12271230
MCStackTileFinalize();
12281231
MCThreadMutexRelease(MCanimationmutex);
12291232
MCThreadMutexRelease(MCpatternmutex);
1233+
MCThreadMutexRelease(MCimagerepmutex);
12301234

12311235
#ifdef _ANDROID_MOBILE
12321236
// MM-2012-02-22: Clean up any static variables as Android static vars are preserved between sessions

engine/src/globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ extern Boolean MCallowdatagrambroadcasts;
414414
// MM-2014-07-31: [[ ThreadedRendering ]] Used to ensure only a single animation message is sent per redraw
415415
extern MCThreadMutexRef MCanimationmutex;
416416
extern MCThreadMutexRef MCpatternmutex;
417+
extern MCThreadMutexRef MCimagerepmutex;
417418

418419

419420
///////////////////////////////////////////////////////////////////////////////

engine/src/idraw.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ void MCImage::drawme(MCDC *dc, int2 sx, int2 sy, uint2 sw, uint2 sh, int2 dx, in
9090
// source images from flushing everything else out of the cache.
9191
bool t_success = true;
9292

93-
MCGImageFrame *t_frame = nil;
93+
MCGImageFrame t_frame;
9494

9595
bool t_printer = dc->gettype() == CONTEXT_TYPE_PRINTER;
9696
bool t_update = !((state & CS_SIZE) && (state & CS_EDITED));
@@ -163,12 +163,12 @@ void MCImage::drawme(MCDC *dc, int2 sx, int2 sy, uint2 sw, uint2 sh, int2 dx, in
163163

164164
// IM-2013-07-19: [[ ResIndependence ]] set scale factor so hi-res image draws at the right size
165165
// IM-2013-10-30: [[ FullscreenMode ]] Get scale factor from the returned frame
166-
t_image.scale_factor = t_frame->density;
166+
t_image.scale_factor = t_frame.density;
167167

168168
// MM-2014-01-27: [[ UpdateImageFilters ]] Updated to use new libgraphics image filter types.
169169
t_image.filter = getimagefilter();
170170

171-
t_image . image = t_frame->image;
171+
t_image . image = t_frame.image;
172172

173173
if (t_printer && m_rep->GetType() == kMCImageRepResident)
174174
{
@@ -205,12 +205,13 @@ void MCImage::drawme(MCDC *dc, int2 sx, int2 sy, uint2 sw, uint2 sh, int2 dx, in
205205
drawnodata(dc, drect, sw, sh, dx, dy, dw, dh);
206206
}
207207

208-
t_rep->UnlockImageFrame(currentframe, t_frame);
208+
if (t_success)
209+
t_rep->UnlockImageFrame(currentframe, t_frame);
209210
}
210211

211212
if (state & CS_DO_START)
212213
{
213-
MCGImageFrame *t_frame = nil;
214+
MCGImageFrame t_frame;
214215
if (m_rep->LockImageFrame(currentframe, getdevicescale(), t_frame))
215216
{
216217

@@ -221,7 +222,7 @@ void MCImage::drawme(MCDC *dc, int2 sx, int2 sy, uint2 sw, uint2 sh, int2 dx, in
221222
if (!m_animate_posted)
222223
{
223224
m_animate_posted = true;
224-
MCscreen->addtimer(this, MCM_internal, t_frame->duration);
225+
MCscreen->addtimer(this, MCM_internal, t_frame.duration);
225226
}
226227
MCThreadMutexUnlock(MCanimationmutex);
227228
}

engine/src/ifile.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -188,18 +188,20 @@ bool MCImage::decompressbrush(MCGImageRef &r_brush)
188188

189189
bool t_success = true;
190190

191-
MCGImageFrame *t_frame = nil;
191+
MCGImageFrame t_frame;
192192

193193
// IM-2013-10-30: [[ FullscreenMode ]] REVISIT: We try here to acquire the brush
194194
// bitmap at 1.0 scale, but currently ignore the set density value of the returned frame.
195195
// We may have to add support for hi-res brushes OR scale the resulting bitmap appropriately.
196196
t_success = m_rep->LockImageFrame(0, 1.0, t_frame);
197197

198198
if (t_success)
199-
r_brush = MCGImageRetain(t_frame->image);
200-
201-
m_rep->UnlockImageFrame(0, t_frame);
199+
{
200+
r_brush = MCGImageRetain(t_frame.image);
202201

202+
m_rep->UnlockImageFrame(0, t_frame);
203+
}
204+
203205
return t_success;
204206
}
205207

@@ -210,9 +212,9 @@ void MCImagePrepareRepForDisplayAtDensity(MCImageRep *p_rep, MCGFloat p_density)
210212
/* OVERHAUL - REVISIT: for the moment, prepared images are premultiplied
211213
* as we expect them to be rendered, but if not then this is actually
212214
* causing more work to be done than needed */
213-
MCGImageFrame *t_frame = nil;
214-
p_rep->LockImageFrame(0, p_density, t_frame);
215-
p_rep->UnlockImageFrame(0, t_frame);
215+
MCGImageFrame t_frame;
216+
if (p_rep->LockImageFrame(0, p_density, t_frame))
217+
p_rep->UnlockImageFrame(0, t_frame);
216218
}
217219
}
218220

engine/src/image.cpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -509,10 +509,10 @@ void MCImage::timer(MCNameRef mptr, MCParameter *params)
509509
advanceframe();
510510
if (irepeatcount)
511511
{
512-
MCGImageFrame *t_frame = nil;
512+
MCGImageFrame t_frame;
513513
if (m_rep->LockImageFrame(currentframe, getdevicescale(), t_frame))
514514
{
515-
MCscreen->addtimer(this, MCM_internal, t_frame->duration);
515+
MCscreen->addtimer(this, MCM_internal, t_frame.duration);
516516
m_rep->UnlockImageFrame(currentframe, t_frame);
517517
}
518518
}
@@ -945,10 +945,10 @@ Exec_stat MCImage::setprop(uint4 parid, Properties p, MCExecPoint &ep, Boolean e
945945
}
946946
if (isvisible() && !wasvisible && m_rep != nil && m_rep->GetFrameCount() > 1)
947947
{
948-
MCGImageFrame *t_frame = nil;
948+
MCGImageFrame t_frame;
949949
if (m_rep->LockImageFrame(currentframe, getdevicescale(), t_frame))
950950
{
951-
MCscreen->addtimer(this, MCM_internal, t_frame->duration);
951+
MCscreen->addtimer(this, MCM_internal, t_frame.duration);
952952
m_rep->UnlockImageFrame(currentframe, t_frame);
953953
}
954954
}
@@ -1094,10 +1094,10 @@ Exec_stat MCImage::setprop(uint4 parid, Properties p, MCExecPoint &ep, Boolean e
10941094
if (opened && m_rep != nil && m_rep->GetFrameCount() > 1 && repeatcount != 0)
10951095
{
10961096
setframe(currentframe == m_rep->GetFrameCount() - 1 ? 0 : currentframe + 1);
1097-
MCGImageFrame *t_frame = nil;
1097+
MCGImageFrame t_frame;
10981098
if (m_rep->LockImageFrame(currentframe, getdevicescale(), t_frame))
10991099
{
1100-
MCscreen->addtimer(this, MCM_internal, t_frame->duration);
1100+
MCscreen->addtimer(this, MCM_internal, t_frame.duration);
11011101
m_rep->UnlockImageFrame(currentframe, t_frame);
11021102
}
11031103
}
@@ -1409,7 +1409,7 @@ Boolean MCImage::maskrect(const MCRectangle &srect)
14091409
return True;
14101410

14111411
// MW-2007-09-11: [[ Bug 5177 ]] If the object is currently selected, make its mask the whole rectangle
1412-
MCGImageFrame *t_frame = nil;
1412+
MCGImageFrame t_frame;
14131413
if (!getstate(CS_SELECTED) && m_rep != nil && m_rep->LockImageFrame(currentframe, getdevicescale(), t_frame))
14141414
{
14151415
int32_t t_x = srect.x - rect.x;
@@ -1423,16 +1423,16 @@ Boolean MCImage::maskrect(const MCRectangle &srect)
14231423
}
14241424

14251425
// IM-2013-10-30: [[ FullscreenMode ]] Account for image density when locating pixel position
1426-
t_x = t_x * t_frame->density;
1427-
t_y = t_y * t_frame->density;
1426+
t_x = t_x * t_frame.density;
1427+
t_y = t_y * t_frame.density;
14281428

14291429
uint32_t t_width, t_height;
1430-
t_width = MCGImageGetWidth(t_frame->image);
1431-
t_height = MCGImageGetHeight(t_frame->image);
1430+
t_width = MCGImageGetWidth(t_frame.image);
1431+
t_height = MCGImageGetHeight(t_frame.image);
14321432

14331433
uint32_t t_pixel = 0;
14341434
if (t_x >= 0 && t_y >= 0 && t_x < t_width && t_y < t_height)
1435-
MCGImageGetPixel(t_frame->image, t_x, t_y, t_pixel);
1435+
MCGImageGetPixel(t_frame.image, t_x, t_y, t_pixel);
14361436

14371437
m_rep->UnlockImageFrame(currentframe, t_frame);
14381438
return MCGPixelGetNativeAlpha(t_pixel) != 0;
@@ -2608,32 +2608,30 @@ bool MCImage::lockbitmap(bool p_premultiplied, bool p_update_transform, MCGFloat
26082608
}
26092609
else if (t_copy_pixels && p_premultiplied)
26102610
{
2611-
MCGImageFrame *t_frame;
2612-
t_frame = nil;
2611+
MCGImageFrame t_frame;
26132612

26142613
t_success = t_rep->LockImageFrame(currentframe, t_src_density, t_frame);
26152614

26162615
if (t_success)
26172616
{
26182617
MCGRaster t_raster;
2619-
t_success = MCGImageGetRaster(t_frame->image, t_raster);
2618+
t_success = MCGImageGetRaster(t_frame.image, t_raster);
26202619

26212620
if (t_success)
26222621
t_success = MCMemoryNew(m_locked_bitmap);
26232622

26242623
if (t_success)
26252624
{
26262625
*m_locked_bitmap = MCImageBitmapFromMCGRaster(t_raster);
2627-
m_locked_image = MCGImageRetain(t_frame->image);
2626+
m_locked_image = MCGImageRetain(t_frame.image);
26282627
}
26292628

26302629
t_rep->UnlockImageFrame(currentframe, t_frame);
26312630
}
26322631
}
26332632
else
26342633
{
2635-
MCGImageFrame *t_frame;
2636-
t_frame = nil;
2634+
MCGImageFrame t_frame;
26372635

26382636
t_success = t_rep->LockImageFrame(currentframe, t_src_density, t_frame);
26392637

@@ -2644,7 +2642,7 @@ bool MCImage::lockbitmap(bool p_premultiplied, bool p_update_transform, MCGFloat
26442642
MCGImageFilter t_filter;
26452643
t_filter = getimagefilter();
26462644

2647-
t_success = MCImageBitmapCreateWithTransformedMCGImage(t_frame->image, t_transform, t_filter, m_locked_bitmap);
2645+
t_success = MCImageBitmapCreateWithTransformedMCGImage(t_frame.image, t_transform, t_filter, m_locked_bitmap);
26482646

26492647
if (t_success && !p_premultiplied)
26502648
MCImageBitmapUnpremultiply(m_locked_bitmap);

engine/src/image.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ class MCMutableImageRep : public MCImageRep
160160
bool LockBitmapFrame(uindex_t p_index, MCGFloat p_density, MCBitmapFrame *&r_frame);
161161
void UnlockBitmapFrame(uindex_t p_index, MCBitmapFrame *p_frame);
162162

163-
bool LockImageFrame(uindex_t p_index, MCGFloat p_density, MCGImageFrame *&r_frame);
164-
void UnlockImageFrame(uindex_t p_index, MCGImageFrame *p_frame);
163+
bool LockImageFrame(uindex_t p_index, MCGFloat p_density, MCGImageFrame& r_frame);
164+
void UnlockImageFrame(uindex_t p_index, MCGImageFrame& p_frame);
165165

166166
bool GetGeometry(uindex_t &r_width, uindex_t &r_height);
167167

engine/src/image_rep.cpp

Lines changed: 15 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,14 @@ MCImageRep::~MCImageRep()
3939

4040
MCImageRep *MCImageRep::Retain()
4141
{
42-
m_reference_count++;
42+
MCThreadAtomicInc((int32_t *)&m_reference_count);
4343
return this;
4444
}
4545

4646
void MCImageRep::Release()
4747
{
48-
if (m_reference_count > 1)
49-
{
50-
m_reference_count--;
51-
return;
52-
}
53-
54-
delete this;
48+
if (MCThreadAtomicDec((int32_t *)&m_reference_count) == 1)
49+
delete this;
5550
}
5651

5752
////////////////////////////////////////////////////////////////////////////////
@@ -74,17 +69,11 @@ MCLoadableImageRep::MCLoadableImageRep()
7469
m_frames_premultiplied = false;
7570

7671
m_next = m_prev = nil;
77-
78-
// MM-2014-07-31: [[ ThreadedRendering ]] Used to ensure only a single threrad locks an image frame at a time.
79-
/* UNCHECKED */ MCThreadMutexCreate(m_frame_lock);
8072
}
8173

8274
MCLoadableImageRep::~MCLoadableImageRep()
8375
{
8476
ReleaseFrames();
85-
86-
// MM-2014-07-31: [[ ThreadedRendering ]] Used to ensure only a single threrad locks an image frame at a time.
87-
MCThreadMutexRelease(m_frame_lock);
8877
}
8978

9079
////////////////////////////////////////////////////////////////////////////////
@@ -236,15 +225,15 @@ bool convert_to_mcbitmapframes(MCGImageFrame *p_frames, uint32_t p_frame_count,
236225
return t_success;
237226
}
238227

239-
bool MCLoadableImageRep::LockImageFrame(uindex_t p_frame, MCGFloat p_density, MCGImageFrame *&r_frame)
228+
bool MCLoadableImageRep::LockImageFrame(uindex_t p_frame, MCGFloat p_density, MCGImageFrame& r_frame)
240229
{
241230
// frame index check
242231
if (m_frame_count != 0 && p_frame >= m_frame_count)
243232
return false;
244233

245234
// MM-2014-07-31: [[ ThreadedRendering ]] Make sure only a single thread locks an image frame at a time.
246235
// This could potentially be improved to be less obtrusive and resource hungry (mutex per image)
247-
MCThreadMutexLock(m_frame_lock);
236+
MCThreadMutexLock(MCimagerepmutex);
248237

249238
if (m_frame_count != 0 && p_frame >= m_frame_count)
250239
return false;
@@ -255,19 +244,21 @@ bool MCLoadableImageRep::LockImageFrame(uindex_t p_frame, MCGFloat p_density, MC
255244
if (p_frame >= m_frame_count)
256245
return false;
257246

258-
// prevent data being removed by cache flush
259-
m_lock_count++;
260-
261-
// prevent deletion due to ImageRep::Release()
262-
Retain();
263-
264-
r_frame = &m_frames[p_frame];
247+
r_frame = m_frames[p_frame];
248+
MCGImageRetain(r_frame . image);
265249

266-
MCThreadMutexUnlock(m_frame_lock);
250+
MoveRepToHead(this);
251+
252+
MCThreadMutexUnlock(MCimagerepmutex);
267253

268254
return true;
269255
}
270256

257+
void MCLoadableImageRep::UnlockImageFrame(uindex_t p_index, MCGImageFrame& p_frame)
258+
{
259+
MCGImageRelease(p_frame . image);
260+
}
261+
271262
bool MCLoadableImageRep::LockBitmapFrame(uindex_t p_frame, MCGFloat p_density, MCBitmapFrame *&r_frame)
272263
{
273264
// frame index check
@@ -321,31 +312,6 @@ bool MCLoadableImageRep::LockBitmapFrame(uindex_t p_frame, MCGFloat p_density, M
321312
return t_success;
322313
}
323314

324-
void MCLoadableImageRep::UnlockImageFrame(uindex_t p_index, MCGImageFrame *p_frame)
325-
{
326-
if (p_frame == nil || m_lock_count == 0)
327-
return;
328-
329-
// MM-2014-07-31: [[ ThreadedRendering ]] Make sure only a single thread locks an image frame at a time.
330-
MCThreadMutexLock(m_frame_lock);
331-
332-
if (p_frame == nil || m_lock_count == 0)
333-
return;
334-
335-
if (p_index >= m_frame_count)
336-
return;
337-
338-
if (m_frames == nil || &m_frames[p_index] != p_frame)
339-
return;
340-
341-
m_lock_count--;
342-
Release();
343-
344-
MoveRepToHead(this);
345-
346-
MCThreadMutexUnlock(m_frame_lock);
347-
}
348-
349315
void MCLoadableImageRep::UnlockBitmapFrame(uindex_t p_index, MCBitmapFrame *p_frame)
350316
{
351317
if (p_frame == nil)

0 commit comments

Comments
 (0)