Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(518)

Unified Diff: third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp

Issue 1866243003: Revert of Eliminate copies of encoded image data (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
index 1decd0f70f6f26e911b59732117b69f7bffea6ac..312dba24c3dd11a02830bf9cf60c3f94ab0f24c4 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
@@ -26,6 +26,7 @@
#include "platform/graphics/ImageFrameGenerator.h"
#include "SkData.h"
+#include "platform/SharedBuffer.h"
#include "platform/TraceEvent.h"
#include "platform/graphics/ImageDecodingStore.h"
#include "platform/image-decoders/ImageDecoder.h"
@@ -51,7 +52,7 @@
// Creates a SkPixelRef such that the memory for pixels is given by an external body.
// This is used to write directly to the memory given by Skia during decoding.
-class ExternalMemoryAllocator final : public SkBitmap::Allocator {
+class ImageFrameGenerator::ExternalMemoryAllocator final : public SkBitmap::Allocator {
USING_FAST_MALLOC(ExternalMemoryAllocator);
WTF_MAKE_NONCOPYABLE(ExternalMemoryAllocator);
public:
@@ -100,38 +101,104 @@
return true;
}
-ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, bool isMultiFrame)
+ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived, bool isMultiFrame)
: m_fullSize(fullSize)
+ , m_data(adoptRef(new ThreadSafeDataTransport()))
, m_isMultiFrame(isMultiFrame)
, m_decodeFailed(false)
, m_yuvDecodingFailed(false)
, m_frameCount(0)
-{
+ , m_encodedData(nullptr)
+{
+ setData(data.get(), allDataReceived);
}
ImageFrameGenerator::~ImageFrameGenerator()
{
+ if (m_encodedData)
+ m_encodedData->unref();
ImageDecodingStore::instance().removeCacheIndexedByGenerator(this);
}
-bool ImageFrameGenerator::decodeAndScale(SegmentReader* data, bool allDataReceived, size_t index, const SkImageInfo& info, void* pixels, size_t rowBytes)
-{
+void ImageFrameGenerator::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived)
+{
+ m_data->setData(data.get(), allDataReceived);
+}
+
+static void sharedSkDataReleaseCallback(const void* address, void* context)
+{
+ // This gets called when m_encodedData reference count becomes 0 - and it could happen in
+ // ImageFrameGenerator destructor or later when m_encodedData gets dereferenced.
+ // In this method, we deref ThreadSafeDataTransport, as ThreadSafeDataTransport is the owner
+ // of data returned via refEncodedData.
+
+ ThreadSafeDataTransport* dataTransport = static_cast<ThreadSafeDataTransport*>(context);
+#if ENABLE(ASSERT)
+ ASSERT(dataTransport);
+ SharedBuffer* buffer = 0;
+ bool allDataReceived = false;
+ dataTransport->data(&buffer, &allDataReceived);
+ ASSERT(allDataReceived && buffer && buffer->data() == address);
+#endif
+ // Dereference m_data now.
+ dataTransport->deref();
+}
+
+SkData* ImageFrameGenerator::refEncodedData()
+{
+ // SkData is returned only when full image (encoded) data is received. This is important
+ // since DeferredImageDecoder::setData is called only once with allDataReceived set to true,
+ // and after that m_data->m_readBuffer.data() is not changed. See also RELEASE_ASSERT used in
+ // ThreadSafeDataTransport::data().
+ SharedBuffer* buffer = 0;
+ bool allDataReceived = false;
+ m_data->data(&buffer, &allDataReceived);
+ if (!allDataReceived)
+ return nullptr;
+
+ {
+ // Prevents concurrent access to m_encodedData creation.
+ MutexLocker lock(m_decodeMutex);
+ if (m_encodedData) {
+ m_encodedData->ref();
+ return m_encodedData;
+ }
+ // m_encodedData is created with initial reference count == 1. ImageFrameGenerator always holds one
+ // reference to m_encodedData, as it prevents write access in SkData::writable_data.
+ m_encodedData = SkData::NewWithProc(buffer->data(), buffer->size(), sharedSkDataReleaseCallback, m_data.get());
+ // While m_encodedData is referenced, prevent disposing m_data and its content.
+ // it is dereferenced in sharedSkDataReleaseCallback, called when m_encodedData gets dereferenced.
+ m_data->ref();
+ }
+ // Increase the reference, caller must decrease it. One reference is always kept by ImageFrameGenerator and released
+ // in destructor.
+ m_encodedData->ref();
+ return m_encodedData;
+}
+
+bool ImageFrameGenerator::decodeAndScale(size_t index, const SkImageInfo& info, void* pixels, size_t rowBytes)
+{
+ // Prevent concurrent decode or scale operations on the same image data.
+ MutexLocker lock(m_decodeMutex);
+
if (m_decodeFailed)
return false;
TRACE_EVENT1("blink", "ImageFrameGenerator::decodeAndScale", "frame index", static_cast<int>(index));
- RefPtr<ExternalMemoryAllocator> externalAllocator = adoptRef(new ExternalMemoryAllocator(info, pixels, rowBytes));
+ m_externalAllocator = adoptPtr(new ExternalMemoryAllocator(info, pixels, rowBytes));
// This implementation does not support scaling so check the requested size.
SkISize scaledSize = SkISize::Make(info.width(), info.height());
ASSERT(m_fullSize == scaledSize);
- // TODO (scroggo): Convert tryToResumeDecode() and decode() to take a
- // PassRefPtr<SkBitmap::Allocator> instead of a bare pointer.
- SkBitmap bitmap = tryToResumeDecode(data, allDataReceived, index, scaledSize, externalAllocator.get());
+ SkBitmap bitmap = tryToResumeDecode(index, scaledSize);
if (bitmap.isNull())
return false;
+
+ // Don't keep the allocator because it contains a pointer to memory
+ // that we do not own.
+ m_externalAllocator.clear();
// Check to see if the decoder has written directly to the pixel memory
// provided. If not, make a copy.
@@ -143,10 +210,11 @@
return true;
}
-bool ImageFrameGenerator::decodeToYUV(SegmentReader* data, size_t index, const SkISize componentSizes[3], void* planes[3], const size_t rowBytes[3])
-{
- // TODO (scroggo): The only interesting thing this uses from the ImageFrameGenerator is m_decodeFailed.
- // Move this into DecodingImageGenerator, which is the only class that calls it.
+bool ImageFrameGenerator::decodeToYUV(size_t index, const SkISize componentSizes[3], void* planes[3], const size_t rowBytes[3])
+{
+ // Prevent concurrent decode or scale operations on the same image data.
+ MutexLocker lock(m_decodeMutex);
+
if (m_decodeFailed)
return false;
@@ -157,11 +225,18 @@
return false;
}
+ SharedBuffer* data = 0;
+ bool allDataReceived = false;
+ m_data->data(&data, &allDataReceived);
+
+ // FIXME: YUV decoding does not currently support progressive decoding.
+ ASSERT(allDataReceived);
+
OwnPtr<ImageDecoder> decoder = ImageDecoder::create(*data, ImageDecoder::AlphaPremultiplied, ImageDecoder::GammaAndColorProfileApplied);
- // getYUVComponentSizes was already called and was successful, so ImageDecoder::create must succeed.
- ASSERT(decoder);
-
- decoder->setData(data, true);
+ if (!decoder)
+ return false;
+
+ decoder->setData(data, allDataReceived);
OwnPtr<ImagePlanes> imagePlanes = adoptPtr(new ImagePlanes(planes, rowBytes));
decoder->setImagePlanes(imagePlanes.release());
@@ -178,19 +253,16 @@
return false;
}
-SkBitmap ImageFrameGenerator::tryToResumeDecode(SegmentReader* data, bool allDataReceived, size_t index, const SkISize& scaledSize, SkBitmap::Allocator* allocator)
+SkBitmap ImageFrameGenerator::tryToResumeDecode(size_t index, const SkISize& scaledSize)
{
TRACE_EVENT1("blink", "ImageFrameGenerator::tryToResumeDecode", "frame index", static_cast<int>(index));
ImageDecoder* decoder = 0;
-
- // Lock the mutex, so only one thread can use the decoder at once.
- MutexLocker lock(m_decodeMutex);
const bool resumeDecoding = ImageDecodingStore::instance().lockDecoder(this, m_fullSize, &decoder);
ASSERT(!resumeDecoding || decoder);
SkBitmap fullSizeImage;
- bool complete = decode(data, allDataReceived, index, &decoder, &fullSizeImage, allocator);
+ bool complete = decode(index, &decoder, &fullSizeImage);
if (!decoder)
return SkBitmap();
@@ -250,10 +322,13 @@
m_hasAlpha[index] = hasAlpha;
}
-bool ImageFrameGenerator::decode(SegmentReader* data, bool allDataReceived, size_t index, ImageDecoder** decoder, SkBitmap* bitmap, SkBitmap::Allocator* allocator)
-{
- ASSERT(m_decodeMutex.locked());
+bool ImageFrameGenerator::decode(size_t index, ImageDecoder** decoder, SkBitmap* bitmap)
+{
TRACE_EVENT2("blink", "ImageFrameGenerator::decode", "width", m_fullSize.width(), "height", m_fullSize.height());
+
+ SharedBuffer* data = 0;
+ bool allDataReceived = false;
+ m_data->data(&data, &allDataReceived);
// Try to create an ImageDecoder if we are not given one.
ASSERT(decoder);
@@ -273,8 +348,8 @@
if (!m_isMultiFrame && newDecoder && allDataReceived) {
// If we're using an external memory allocator that means we're decoding
// directly into the output memory and we can save one memcpy.
- ASSERT(allocator);
- (*decoder)->setMemoryAllocator(allocator);
+ ASSERT(m_externalAllocator.get());
+ (*decoder)->setMemoryAllocator(m_externalAllocator.get());
}
(*decoder)->setData(data, allDataReceived);
@@ -287,7 +362,7 @@
if (allDataReceived)
m_frameCount = (*decoder)->frameCount();
- (*decoder)->setData(PassRefPtr<SegmentReader>(nullptr), false); // Unref SegmentReader from ImageDecoder.
+ (*decoder)->setData(0, false); // Unref SharedBuffer from ImageDecoder.
(*decoder)->clearCacheExceptFrame(index);
(*decoder)->setMemoryAllocator(0);
@@ -317,11 +392,19 @@
return true;
}
-bool ImageFrameGenerator::getYUVComponentSizes(SegmentReader* data, SkYUVSizeInfo* sizeInfo)
+bool ImageFrameGenerator::getYUVComponentSizes(SkYUVSizeInfo* sizeInfo)
{
TRACE_EVENT2("blink", "ImageFrameGenerator::getYUVComponentSizes", "width", m_fullSize.width(), "height", m_fullSize.height());
if (m_yuvDecodingFailed)
+ return false;
+
+ SharedBuffer* data = 0;
+ bool allDataReceived = false;
+ m_data->data(&data, &allDataReceived);
+
+ // FIXME: YUV decoding does not currently support progressive decoding.
+ if (!allDataReceived)
return false;
OwnPtr<ImageDecoder> decoder = ImageDecoder::create(*data, ImageDecoder::AlphaPremultiplied, ImageDecoder::GammaAndColorProfileApplied);
@@ -329,7 +412,7 @@
return false;
// Setting a dummy ImagePlanes object signals to the decoder that we want to do YUV decoding.
- decoder->setData(data, true);
+ decoder->setData(data, allDataReceived);
OwnPtr<ImagePlanes> dummyImagePlanes = adoptPtr(new ImagePlanes);
decoder->setImagePlanes(dummyImagePlanes.release());

Powered by Google App Engine
This is Rietveld 408576698