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 // TODO: Skia intends for SkPixelRef to be immutable, but this method
186 // modifies it. Find another way to support reusing the same pixel memory.
187 this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
188 }
189
Bitmap(void * address,size_t size,const SkImageInfo & info,size_t rowBytes)190 Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
191 : SkPixelRef(info.width(), info.height(), address, rowBytes)
192 , mInfo(validateAlpha(info))
193 , mPixelStorageType(PixelStorageType::Heap) {
194 mPixelStorage.heap.address = address;
195 mPixelStorage.heap.size = size;
196 }
197
Bitmap(void * address,void * context,FreeFunc freeFunc,const SkImageInfo & info,size_t rowBytes)198 Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
199 size_t rowBytes)
200 : SkPixelRef(info.width(), info.height(), address, rowBytes)
201 , mInfo(validateAlpha(info))
202 , mPixelStorageType(PixelStorageType::External) {
203 mPixelStorage.external.address = address;
204 mPixelStorage.external.context = context;
205 mPixelStorage.external.freeFunc = freeFunc;
206 }
207
Bitmap(void * address,int fd,size_t mappedSize,const SkImageInfo & info,size_t rowBytes)208 Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
209 : SkPixelRef(info.width(), info.height(), address, rowBytes)
210 , mInfo(validateAlpha(info))
211 , mPixelStorageType(PixelStorageType::Ashmem) {
212 mPixelStorage.ashmem.address = address;
213 mPixelStorage.ashmem.fd = fd;
214 mPixelStorage.ashmem.size = mappedSize;
215 }
216
Bitmap(GraphicBuffer * buffer,const SkImageInfo & info,BitmapPalette palette)217 Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette)
218 : SkPixelRef(info.width(), info.height(), nullptr,
219 bytesPerPixel(buffer->getPixelFormat()) * (buffer->getStride() > 0 ? buffer->getStride() : buffer->getWidth()))
220 , mInfo(validateAlpha(info))
221 , mPixelStorageType(PixelStorageType::Hardware)
222 , mPalette(palette)
223 , mPaletteGenerationId(getGenerationID()) {
224 mPixelStorage.hardware.buffer = buffer;
225 buffer->incStrong(buffer);
226 setImmutable(); // HW bitmaps are always immutable
227 mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
228 mInfo.alphaType(), mInfo.refColorSpace());
229 }
230
~Bitmap()231 Bitmap::~Bitmap() {
232 switch (mPixelStorageType) {
233 case PixelStorageType::External:
234 mPixelStorage.external.freeFunc(mPixelStorage.external.address,
235 mPixelStorage.external.context);
236 break;
237 case PixelStorageType::Ashmem:
238 munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
239 close(mPixelStorage.ashmem.fd);
240 break;
241 case PixelStorageType::Heap:
242 free(mPixelStorage.heap.address);
243 mallopt(M_PURGE, 0);
244 break;
245 case PixelStorageType::Hardware:
246 auto buffer = mPixelStorage.hardware.buffer;
247 buffer->decStrong(buffer);
248 mPixelStorage.hardware.buffer = nullptr;
249 break;
250 }
251 }
252
hasHardwareMipMap() const253 bool Bitmap::hasHardwareMipMap() const {
254 return mHasHardwareMipMap;
255 }
256
setHasHardwareMipMap(bool hasMipMap)257 void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
258 mHasHardwareMipMap = hasMipMap;
259 }
260
getStorage() const261 void* Bitmap::getStorage() const {
262 switch (mPixelStorageType) {
263 case PixelStorageType::External:
264 return mPixelStorage.external.address;
265 case PixelStorageType::Ashmem:
266 return mPixelStorage.ashmem.address;
267 case PixelStorageType::Heap:
268 return mPixelStorage.heap.address;
269 case PixelStorageType::Hardware:
270 return nullptr;
271 }
272 }
273
getAshmemFd() const274 int Bitmap::getAshmemFd() const {
275 switch (mPixelStorageType) {
276 case PixelStorageType::Ashmem:
277 return mPixelStorage.ashmem.fd;
278 default:
279 return -1;
280 }
281 }
282
getAllocationByteCount() const283 size_t Bitmap::getAllocationByteCount() const {
284 switch (mPixelStorageType) {
285 case PixelStorageType::Heap:
286 return mPixelStorage.heap.size;
287 case PixelStorageType::Ashmem:
288 return mPixelStorage.ashmem.size;
289 default:
290 return rowBytes() * height();
291 }
292 }
293
reconfigure(const SkImageInfo & info)294 void Bitmap::reconfigure(const SkImageInfo& info) {
295 reconfigure(info, info.minRowBytes());
296 }
297
setAlphaType(SkAlphaType alphaType)298 void Bitmap::setAlphaType(SkAlphaType alphaType) {
299 if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
300 return;
301 }
302
303 mInfo = mInfo.makeAlphaType(alphaType);
304 }
305
getSkBitmap(SkBitmap * outBitmap)306 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
307 if (isHardware()) {
308 outBitmap->allocPixels(mInfo);
309 uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap);
310 return;
311 }
312 outBitmap->setInfo(mInfo, rowBytes());
313 outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
314 }
315
getBounds(SkRect * bounds) const316 void Bitmap::getBounds(SkRect* bounds) const {
317 SkASSERT(bounds);
318 bounds->set(0, 0, SkIntToScalar(width()), SkIntToScalar(height()));
319 }
320
graphicBuffer()321 GraphicBuffer* Bitmap::graphicBuffer() {
322 if (isHardware()) {
323 return mPixelStorage.hardware.buffer;
324 }
325 return nullptr;
326 }
327
makeImage()328 sk_sp<SkImage> Bitmap::makeImage() {
329 sk_sp<SkImage> image = mImage;
330 if (!image) {
331 SkASSERT(!isHardware());
332 SkBitmap skiaBitmap;
333 skiaBitmap.setInfo(info(), rowBytes());
334 skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
335 // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
336 // internally and ~Bitmap won't be invoked.
337 // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
338 image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
339 }
340 return image;
341 }
342
343 class MinMaxAverage {
344 public:
add(float sample)345 void add(float sample) {
346 if (mCount == 0) {
347 mMin = sample;
348 mMax = sample;
349 } else {
350 mMin = std::min(mMin, sample);
351 mMax = std::max(mMax, sample);
352 }
353 mTotal += sample;
354 mCount++;
355 }
356
average()357 float average() { return mTotal / mCount; }
358
min()359 float min() { return mMin; }
360
max()361 float max() { return mMax; }
362
delta()363 float delta() { return mMax - mMin; }
364
365 private:
366 float mMin = 0.0f;
367 float mMax = 0.0f;
368 float mTotal = 0.0f;
369 int mCount = 0;
370 };
371
computePalette(const SkImageInfo & info,const void * addr,size_t rowBytes)372 BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes) {
373 ATRACE_CALL();
374
375 SkPixmap pixmap{info, addr, rowBytes};
376
377 // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
378 // Experiment with something simpler since we just want to figure out if it's "color-ful"
379 // and then the average perceptual lightness.
380
381 MinMaxAverage hue, saturation, value;
382 int sampledCount = 0;
383
384 // Sample a grid of 100 pixels to get an overall estimation of the colors in play
385 const int x_step = std::max(1, pixmap.width() / 10);
386 const int y_step = std::max(1, pixmap.height() / 10);
387 for (int x = 0; x < pixmap.width(); x += x_step) {
388 for (int y = 0; y < pixmap.height(); y += y_step) {
389 SkColor color = pixmap.getColor(x, y);
390 if (!info.isOpaque() && SkColorGetA(color) < 75) {
391 continue;
392 }
393
394 sampledCount++;
395 float hsv[3];
396 SkColorToHSV(color, hsv);
397 hue.add(hsv[0]);
398 saturation.add(hsv[1]);
399 value.add(hsv[2]);
400 }
401 }
402
403 // TODO: Tune the coverage threshold
404 if (sampledCount < 5) {
405 ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d",
406 sampledCount, info.width(), info.height(), (int)info.colorType(),
407 (int)info.alphaType());
408 return BitmapPalette::Unknown;
409 }
410
411 ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
412 "%f]",
413 sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
414 saturation.average());
415
416 if (hue.delta() <= 20 && saturation.delta() <= .1f) {
417 if (value.average() >= .5f) {
418 return BitmapPalette::Light;
419 } else {
420 return BitmapPalette::Dark;
421 }
422 }
423 return BitmapPalette::Unknown;
424 }
425
426 } // namespace android
427