From b66f78bacff656fbb0dcf7f86d74567443de8081 Mon Sep 17 00:00:00 2001 From: Tom Poole Date: Wed, 3 Oct 2018 12:47:41 +0100 Subject: [PATCH] Fixed some CoreGraphics image issues in the latest iOS and MacOS SDKs --- modules/juce_graphics/images/juce_Image.cpp | 4 +- .../native/juce_mac_CoreGraphicsContext.mm | 79 ++++++++++++++++++- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/modules/juce_graphics/images/juce_Image.cpp b/modules/juce_graphics/images/juce_Image.cpp index 4bb9262e7a..0f3b1290b2 100644 --- a/modules/juce_graphics/images/juce_Image.cpp +++ b/modules/juce_graphics/images/juce_Image.cpp @@ -252,13 +252,13 @@ Image& Image::operator= (const Image& other) } Image::Image (Image&& other) noexcept - : image (static_cast (other.image)) + : image (std::move (other.image)) { } Image& Image::operator= (Image&& other) noexcept { - image = static_cast (other.image); + image = std::move (other.image); return *this; } diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm index d89822c4f4..9d41590fce 100644 --- a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm +++ b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm @@ -27,6 +27,61 @@ namespace juce { +#if (JUCE_IOS && defined (__IPHONE_12_0)) + #define JUCE_CORE_GRAPHICS_NEEDS_DELAYED_GARBAGE_COLLECTION 1 +#endif + +#if JUCE_CORE_GRAPHICS_NEEDS_DELAYED_GARBAGE_COLLECTION +class CoreGraphicsImageGarbageCollector : public Timer, + public DeletedAtShutdown +{ +public: + CoreGraphicsImageGarbageCollector() + { + // TODO: Add an assertion here telling JUCE developers to move to the + // latest SDK if/when the CoreGraphics memory handling is fixed. + } + + ~CoreGraphicsImageGarbageCollector() + { + clearSingletonInstance(); + } + + JUCE_DECLARE_SINGLETON (CoreGraphicsImageGarbageCollector, false) + + void addItem (HeapBlock&& data) + { + ScopedLock lock (queueLock); + + queue.emplace_back (Time::getApproximateMillisecondCounter(), std::move (data)); + + if (! isTimerRunning()) + startTimer (timeDelta); + } + + void timerCallback() override + { + ScopedLock lock (queueLock); + + auto cutoffTime = Time::getApproximateMillisecondCounter() - timeDelta; + + auto it = std::find_if (queue.begin(), queue.end(), + [cutoffTime](const std::pair>& x) { return x.first > cutoffTime; }); + queue.erase (queue.begin(), it); + + queue.empty() ? stopTimer() : startTimer (timeDelta); + } + +private: + CriticalSection queueLock; + std::vector>> queue; + static constexpr int timeDelta = 50; +}; + +JUCE_IMPLEMENT_SINGLETON (CoreGraphicsImageGarbageCollector) +#endif + +//============================================================================== class CoreGraphicsImage : public ImagePixelData { public: @@ -36,7 +91,16 @@ public: pixelStride = format == Image::RGB ? 3 : ((format == Image::ARGB) ? 4 : 1); lineStride = (pixelStride * jmax (1, width) + 3) & ~3; - imageData.allocate ((size_t) lineStride * (size_t) jmax (1, height), clearImage); + auto numComponents = (size_t) lineStride * (size_t) jmax (1, height); + + # if JUCE_MAC && defined (__MAC_10_14) + // This version of the SDK intermittently requires a bit of extra space + // at the end of the image data. This feels like something has gone + // wrong in Apple's code. + numComponents += (size_t) lineStride; + #endif + + imageData.allocate (numComponents, clearImage); CGColorSpaceRef colourSpace = (format == Image::SingleChannel) ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); @@ -51,6 +115,10 @@ public: { freeCachedImageRef(); CGContextRelease (context); + + #if JUCE_CORE_GRAPHICS_NEEDS_DELAYED_GARBAGE_COLLECTION + CoreGraphicsImageGarbageCollector::getInstance()->addItem (std::move (imageData)); + #endif } LowLevelGraphicsContext* createLowLevelContext() override @@ -123,7 +191,8 @@ public: CGImageRef imageRef = CGImageCreate ((size_t) srcData.width, (size_t) srcData.height, - 8, (size_t) srcData.pixelStride * 8, + 8, + (size_t) srcData.pixelStride * 8, (size_t) srcData.lineStride, colourSpace, getCGImageFlags (juceImage.getFormat()), provider, 0, true, kCGRenderingIntentDefault); @@ -493,8 +562,10 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans { auto iw = sourceImage.getWidth(); auto ih = sourceImage.getHeight(); - CGImageRef image = CoreGraphicsImage::getCachedImageRef (sourceImage, sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace - : rgbColourSpace); + + auto colourSpace = sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace + : rgbColourSpace; + CGImageRef image = CoreGraphicsImage::getCachedImageRef (sourceImage, colourSpace); CGContextSaveGState (context); CGContextSetAlpha (context, state->fillType.getOpacity());