• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "Bitmap.h"
17 
18 #include "HardwareBitmapUploader.h"
19 #include "Properties.h"
20 #include "renderthread/RenderProxy.h"
21 #include "utils/Color.h"
22 #include <utils/Trace.h>
23 
24 #include <sys/mman.h>
25 
26 #include <cutils/ashmem.h>
27 #include <log/log.h>
28 
29 #include <binder/IServiceManager.h>
30 #include <private/gui/ComposerService.h>
31 #include <ui/PixelFormat.h>
32 
33 #include <SkCanvas.h>
34 #include <SkImagePriv.h>
35 
36 #include <SkHighContrastFilter.h>
37 #include <limits>
38 
39 namespace android {
40 
41 // returns true if rowBytes * height can be represented by a positive int32_t value
42 // and places that value in size.
computeAllocationSize(size_t rowBytes,int height,size_t * size)43 static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
44     return 0 <= height && height <= std::numeric_limits<size_t>::max() &&
45            !__builtin_mul_overflow(rowBytes, (size_t)height, size) &&
46            *size <= std::numeric_limits<int32_t>::max();
47 }
48 
49 typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes);
50 
allocateBitmap(SkBitmap * bitmap,AllocPixelRef alloc)51 static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
52     const SkImageInfo& info = bitmap->info();
53     if (info.colorType() == kUnknown_SkColorType) {
54         LOG_ALWAYS_FATAL("unknown bitmap configuration");
55         return nullptr;
56     }
57 
58     size_t size;
59 
60     // we must respect the rowBytes value already set on the bitmap instead of
61     // attempting to compute our own.
62     const size_t rowBytes = bitmap->rowBytes();
63     if (!computeAllocationSize(rowBytes, bitmap->height(), &size)) {
64         return nullptr;
65     }
66 
67     auto wrapper = alloc(size, info, rowBytes);
68     if (wrapper) {
69         wrapper->getSkBitmap(bitmap);
70     }
71     return wrapper;
72 }
73 
allocateAshmemBitmap(SkBitmap * bitmap)74 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
75     return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
76 }
77 
allocateAshmemBitmap(size_t size,const SkImageInfo & info,size_t rowBytes)78 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
79     // Create new ashmem region with read/write priv
80     int fd = ashmem_create_region("bitmap", size);
81     if (fd < 0) {
82         return nullptr;
83     }
84 
85     void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
86     if (addr == MAP_FAILED) {
87         close(fd);
88         return nullptr;
89     }
90 
91     if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
92         munmap(addr, size);
93         close(fd);
94         return nullptr;
95     }
96     return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
97 }
98 
allocateHardwareBitmap(const SkBitmap & bitmap)99 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
100     return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
101 }
102 
allocateHeapBitmap(SkBitmap * bitmap)103 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
104     return allocateBitmap(bitmap, &Bitmap::allocateHeapBitmap);
105 }
106 
allocateHeapBitmap(const SkImageInfo & info)107 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
108     size_t size;
109     if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
110         LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
111         return nullptr;
112     }
113     return allocateHeapBitmap(size, info, info.minRowBytes());
114 }
115 
allocateHeapBitmap(size_t size,const SkImageInfo & info,size_t rowBytes)116 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
117     void* addr = calloc(size, 1);
118     if (!addr) {
119         return nullptr;
120     }
121     return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
122 }
123 
FreePixelRef(void * addr,void * context)124 void FreePixelRef(void* addr, void* context) {
125     auto pixelRef = (SkPixelRef*)context;
126     pixelRef->unref();
127 }
128 
createFrom(const SkImageInfo & info,SkPixelRef & pixelRef)129 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
130     pixelRef.ref();
131     return sk_sp<Bitmap>(new Bitmap((void*)pixelRef.pixels(), (void*)&pixelRef, FreePixelRef, info,
132                                     pixelRef.rowBytes()));
133 }
134 
135 
createFrom(sp<GraphicBuffer> graphicBuffer,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,SkAlphaType alphaType,BitmapPalette palette)136 sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, SkColorType colorType,
137                                  sk_sp<SkColorSpace> colorSpace, SkAlphaType alphaType,
138                                  BitmapPalette palette) {
139     SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
140                                          colorType, alphaType, colorSpace);
141     return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info, palette));
142 }
143 
createFrom(const SkImageInfo & info,size_t rowBytes,int fd,void * addr,size_t size,bool readOnly)144 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr,
145                                  size_t size, bool readOnly) {
146     if (info.colorType() == kUnknown_SkColorType) {
147         LOG_ALWAYS_FATAL("unknown bitmap configuration");
148         return nullptr;
149     }
150 
151     if (!addr) {
152         // Map existing ashmem region if not already mapped.
153         int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
154         size = ashmem_get_size_region(fd);
155         addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0);
156         if (addr == MAP_FAILED) {
157             return nullptr;
158         }
159     }
160 
161     sk_sp<Bitmap> bitmap(new Bitmap(addr, fd, size, info, rowBytes));
162     if (readOnly) {
163         bitmap->setImmutable();
164     }
165     return bitmap;
166 }
167 
setColorSpace(sk_sp<SkColorSpace> colorSpace)168 void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
169     mInfo = mInfo.makeColorSpace(std::move(colorSpace));
170 }
171 
validateAlpha(const SkImageInfo & info)172 static SkImageInfo validateAlpha(const SkImageInfo& info) {
173     // Need to validate the alpha type to filter against the color type
174     // to prevent things like a non-opaque RGB565 bitmap
175     SkAlphaType alphaType;
176     LOG_ALWAYS_FATAL_IF(
177             !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
178             "Failed to validate alpha type!");
179     return info.makeAlphaType(alphaType);
180 }
181 
reconfigure(const SkImageInfo & newInfo,size_t rowBytes)182 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
183     mInfo = validateAlpha(newInfo);
184 
185     // Dirty hack is dirty
186     // TODO: Figure something out here, Skia's current design makes this
187     // really hard to work with. Skia really, really wants immutable objects,
188     // but with the nested-ref-count hackery going on that's just not
189     // feasible without going insane trying to figure it out
190     this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
191 }
192 
Bitmap(void * address,size_t size,const SkImageInfo & info,size_t rowBytes)193 Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
194         : SkPixelRef(info.width(), info.height(), address, rowBytes)
195         , mInfo(validateAlpha(info))
196         , mPixelStorageType(PixelStorageType::Heap) {
197     mPixelStorage.heap.address = address;
198     mPixelStorage.heap.size = size;
199 }
200 
Bitmap(void * address,void * context,FreeFunc freeFunc,const SkImageInfo & info,size_t rowBytes)201 Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
202                size_t rowBytes)
203         : SkPixelRef(info.width(), info.height(), address, rowBytes)
204         , mInfo(validateAlpha(info))
205         , mPixelStorageType(PixelStorageType::External) {
206     mPixelStorage.external.address = address;
207     mPixelStorage.external.context = context;
208     mPixelStorage.external.freeFunc = freeFunc;
209 }
210 
Bitmap(void * address,int fd,size_t mappedSize,const SkImageInfo & info,size_t rowBytes)211 Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
212         : SkPixelRef(info.width(), info.height(), address, rowBytes)
213         , mInfo(validateAlpha(info))
214         , mPixelStorageType(PixelStorageType::Ashmem) {
215     mPixelStorage.ashmem.address = address;
216     mPixelStorage.ashmem.fd = fd;
217     mPixelStorage.ashmem.size = mappedSize;
218 }
219 
Bitmap(GraphicBuffer * buffer,const SkImageInfo & info,BitmapPalette palette)220 Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette)
221         : SkPixelRef(info.width(), info.height(), nullptr,
222                      bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride())
223         , mInfo(validateAlpha(info))
224         , mPixelStorageType(PixelStorageType::Hardware)
225         , mPalette(palette)
226         , mPaletteGenerationId(getGenerationID()) {
227     mPixelStorage.hardware.buffer = buffer;
228     buffer->incStrong(buffer);
229     setImmutable();  // HW bitmaps are always immutable
230     mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
231                                               mInfo.alphaType(), mInfo.refColorSpace());
232 }
233 
~Bitmap()234 Bitmap::~Bitmap() {
235     switch (mPixelStorageType) {
236         case PixelStorageType::External:
237             mPixelStorage.external.freeFunc(mPixelStorage.external.address,
238                                             mPixelStorage.external.context);
239             break;
240         case PixelStorageType::Ashmem:
241             munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
242             close(mPixelStorage.ashmem.fd);
243             break;
244         case PixelStorageType::Heap:
245             free(mPixelStorage.heap.address);
246             mallopt(M_PURGE, 0);
247             break;
248         case PixelStorageType::Hardware:
249             auto buffer = mPixelStorage.hardware.buffer;
250             buffer->decStrong(buffer);
251             mPixelStorage.hardware.buffer = nullptr;
252             break;
253     }
254 }
255 
hasHardwareMipMap() const256 bool Bitmap::hasHardwareMipMap() const {
257     return mHasHardwareMipMap;
258 }
259 
setHasHardwareMipMap(bool hasMipMap)260 void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
261     mHasHardwareMipMap = hasMipMap;
262 }
263 
getStorage() const264 void* Bitmap::getStorage() const {
265     switch (mPixelStorageType) {
266         case PixelStorageType::External:
267             return mPixelStorage.external.address;
268         case PixelStorageType::Ashmem:
269             return mPixelStorage.ashmem.address;
270         case PixelStorageType::Heap:
271             return mPixelStorage.heap.address;
272         case PixelStorageType::Hardware:
273             return nullptr;
274     }
275 }
276 
getAshmemFd() const277 int Bitmap::getAshmemFd() const {
278     switch (mPixelStorageType) {
279         case PixelStorageType::Ashmem:
280             return mPixelStorage.ashmem.fd;
281         default:
282             return -1;
283     }
284 }
285 
getAllocationByteCount() const286 size_t Bitmap::getAllocationByteCount() const {
287     switch (mPixelStorageType) {
288         case PixelStorageType::Heap:
289             return mPixelStorage.heap.size;
290         case PixelStorageType::Ashmem:
291             return mPixelStorage.ashmem.size;
292         default:
293             return rowBytes() * height();
294     }
295 }
296 
reconfigure(const SkImageInfo & info)297 void Bitmap::reconfigure(const SkImageInfo& info) {
298     reconfigure(info, info.minRowBytes());
299 }
300 
setAlphaType(SkAlphaType alphaType)301 void Bitmap::setAlphaType(SkAlphaType alphaType) {
302     if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
303         return;
304     }
305 
306     mInfo = mInfo.makeAlphaType(alphaType);
307 }
308 
getSkBitmap(SkBitmap * outBitmap)309 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
310     if (isHardware()) {
311         outBitmap->allocPixels(mInfo);
312         uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap);
313         return;
314     }
315     outBitmap->setInfo(mInfo, rowBytes());
316     outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
317 }
318 
getBounds(SkRect * bounds) const319 void Bitmap::getBounds(SkRect* bounds) const {
320     SkASSERT(bounds);
321     bounds->set(0, 0, SkIntToScalar(width()), SkIntToScalar(height()));
322 }
323 
graphicBuffer()324 GraphicBuffer* Bitmap::graphicBuffer() {
325     if (isHardware()) {
326         return mPixelStorage.hardware.buffer;
327     }
328     return nullptr;
329 }
330 
makeImage()331 sk_sp<SkImage> Bitmap::makeImage() {
332     sk_sp<SkImage> image = mImage;
333     if (!image) {
334         SkASSERT(!isHardware());
335         SkBitmap skiaBitmap;
336         skiaBitmap.setInfo(info(), rowBytes());
337         skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
338         // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
339         // internally and ~Bitmap won't be invoked.
340         // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
341         image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
342     }
343     return image;
344 }
345 
346 class MinMaxAverage {
347 public:
add(float sample)348     void add(float sample) {
349         if (mCount == 0) {
350             mMin = sample;
351             mMax = sample;
352         } else {
353             mMin = std::min(mMin, sample);
354             mMax = std::max(mMax, sample);
355         }
356         mTotal += sample;
357         mCount++;
358     }
359 
average()360     float average() { return mTotal / mCount; }
361 
min()362     float min() { return mMin; }
363 
max()364     float max() { return mMax; }
365 
delta()366     float delta() { return mMax - mMin; }
367 
368 private:
369     float mMin = 0.0f;
370     float mMax = 0.0f;
371     float mTotal = 0.0f;
372     int mCount = 0;
373 };
374 
computePalette(const SkImageInfo & info,const void * addr,size_t rowBytes)375 BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes) {
376     ATRACE_CALL();
377 
378     SkPixmap pixmap{info, addr, rowBytes};
379 
380     // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
381     // Experiment with something simpler since we just want to figure out if it's "color-ful"
382     // and then the average perceptual lightness.
383 
384     MinMaxAverage hue, saturation, value;
385     int sampledCount = 0;
386 
387     // Sample a grid of 100 pixels to get an overall estimation of the colors in play
388     const int x_step = std::max(1, pixmap.width() / 10);
389     const int y_step = std::max(1, pixmap.height() / 10);
390     for (int x = 0; x < pixmap.width(); x += x_step) {
391         for (int y = 0; y < pixmap.height(); y += y_step) {
392             SkColor color = pixmap.getColor(x, y);
393             if (!info.isOpaque() && SkColorGetA(color) < 75) {
394                 continue;
395             }
396 
397             sampledCount++;
398             float hsv[3];
399             SkColorToHSV(color, hsv);
400             hue.add(hsv[0]);
401             saturation.add(hsv[1]);
402             value.add(hsv[2]);
403         }
404     }
405 
406     // TODO: Tune the coverage threshold
407     if (sampledCount < 5) {
408         ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d",
409               sampledCount, info.width(), info.height(), (int)info.colorType(),
410               (int)info.alphaType());
411         return BitmapPalette::Unknown;
412     }
413 
414     ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
415           "%f]",
416           sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
417           saturation.average());
418 
419     if (hue.delta() <= 20 && saturation.delta() <= .1f) {
420         if (value.average() >= .5f) {
421             return BitmapPalette::Light;
422         } else {
423             return BitmapPalette::Dark;
424         }
425     }
426     return BitmapPalette::Unknown;
427 }
428 
429 }  // namespace android
430