blob: 8344a86923ee14b25f0fae7d4525119559cc0527 [file] [log] [blame]
sergeyv163f8812016-10-07 16:57:29 -07001/*
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 */
sergeyvc1c54062016-10-19 18:47:26 -070016#include "Bitmap.h"
sergeyv163f8812016-10-07 16:57:29 -070017
John Recke170fb62018-05-07 08:12:07 -070018#include "HardwareBitmapUploader.h"
John Reck339cf9b2018-07-18 16:32:27 -070019#include "Properties.h"
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010020#ifdef __ANDROID__ // Layoutlib does not support render thread
John Reckac175cc2023-05-05 16:29:14 -040021#include <private/android/AHardwareBufferHelpers.h>
22#include <ui/GraphicBuffer.h>
23#include <ui/GraphicBufferMapper.h>
24
sergeyv694d4992016-10-27 10:23:13 -070025#include "renderthread/RenderProxy.h"
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010026#endif
Romain Guycaaaa662017-03-27 00:40:21 -070027#include "utils/Color.h"
Stan Iliev564ca3e2018-09-04 22:00:00 +000028#include <utils/Trace.h>
sergeyv163f8812016-10-07 16:57:29 -070029
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010030#ifndef _WIN32
sergeyv163f8812016-10-07 16:57:29 -070031#include <sys/mman.h>
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010032#endif
Mark Salyzyn6f773a02016-09-28 16:15:30 -070033
sergeyv163f8812016-10-07 16:57:29 -070034#include <cutils/ashmem.h>
John Reck1bcacfd2017-11-03 10:12:19 -070035#include <log/log.h>
sergeyv163f8812016-10-07 16:57:29 -070036
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010037#ifndef _WIN32
sergeyv694d4992016-10-27 10:23:13 -070038#include <binder/IServiceManager.h>
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010039#endif
sergeyv694d4992016-10-27 10:23:13 -070040
John Reck5bd537e2023-01-24 20:13:45 -050041#include <Gainmap.h>
sergeyv694d4992016-10-27 10:23:13 -070042#include <SkCanvas.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050043#include <SkColor.h>
44#include <SkEncodedImageFormat.h>
John Reck339cf9b2018-07-18 16:32:27 -070045#include <SkHighContrastFilter.h>
Kevin Lubickdd8b2ea2023-03-17 19:55:58 +000046#include <SkImage.h>
Kevin Lubick93671082023-03-13 18:30:55 +000047#include <SkImageAndroid.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050048#include <SkImagePriv.h>
John Reck340620d2023-02-01 22:26:00 -050049#include <SkJpegGainmapEncoder.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050050#include <SkPixmap.h>
51#include <SkRect.h>
52#include <SkStream.h>
Kevin Lubickfb9aa402023-04-12 18:48:49 +000053#include <SkJpegEncoder.h>
54#include <SkPngEncoder.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050055#include <SkWebpEncoder.h>
John Reck5bd537e2023-01-24 20:13:45 -050056
John Reck8f45d4a2018-08-15 10:17:12 -070057#include <limits>
Ben Wagnerdbbc74c2018-05-18 17:46:48 -040058
sergeyv163f8812016-10-07 16:57:29 -070059namespace android {
60
John Reckac175cc2023-05-05 16:29:14 -040061#ifdef __ANDROID__
62static uint64_t AHardwareBuffer_getAllocationSize(AHardwareBuffer* aHardwareBuffer) {
63 GraphicBuffer* buffer = AHardwareBuffer_to_GraphicBuffer(aHardwareBuffer);
64 auto& mapper = GraphicBufferMapper::get();
65 uint64_t size = 0;
66 auto err = mapper.getAllocationSize(buffer->handle, &size);
67 if (err == OK) {
68 if (size > 0) {
69 return size;
70 } else {
71 ALOGW("Mapper returned size = 0 for buffer format: 0x%x size: %d x %d", buffer->format,
72 buffer->width, buffer->height);
73 // Fall-through to estimate
74 }
75 }
76
77 // Estimation time!
78 // Stride could be = 0 if it's ill-defined (eg, compressed buffer), in which case we use the
79 // width of the buffer instead
80 size = std::max(buffer->width, buffer->stride) * buffer->height;
81 // Require bpp to be at least 1. This is too low for many formats, but it's better than 0
82 // Also while we could make increasingly better estimates, the reality is that mapper@4
83 // should be common enough at this point that we won't ever hit this anyway
84 size *= std::max(1u, bytesPerPixel(buffer->format));
85 return size;
86}
87#endif
88
Leon Scroggins III753a56f2019-12-11 11:02:15 -050089bool Bitmap::computeAllocationSize(size_t rowBytes, int height, size_t* size) {
Ben Wagnerdbbc74c2018-05-18 17:46:48 -040090 return 0 <= height && height <= std::numeric_limits<size_t>::max() &&
91 !__builtin_mul_overflow(rowBytes, (size_t)height, size) &&
92 *size <= std::numeric_limits<int32_t>::max();
sergeyvc36bd6c2016-10-11 15:49:16 -070093}
94
John Reck1bcacfd2017-11-03 10:12:19 -070095typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes);
sergeyvc36bd6c2016-10-11 15:49:16 -070096
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -040097static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
sergeyvc36bd6c2016-10-11 15:49:16 -070098 const SkImageInfo& info = bitmap->info();
99 if (info.colorType() == kUnknown_SkColorType) {
100 LOG_ALWAYS_FATAL("unknown bitmap configuration");
101 return nullptr;
102 }
103
104 size_t size;
sergeyvc36bd6c2016-10-11 15:49:16 -0700105
106 // we must respect the rowBytes value already set on the bitmap instead of
107 // attempting to compute our own.
108 const size_t rowBytes = bitmap->rowBytes();
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500109 if (!Bitmap::computeAllocationSize(rowBytes, bitmap->height(), &size)) {
sergeyvfc9999502016-10-17 13:07:38 -0700110 return nullptr;
111 }
112
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400113 auto wrapper = alloc(size, info, rowBytes);
sergeyvc36bd6c2016-10-11 15:49:16 -0700114 if (wrapper) {
115 wrapper->getSkBitmap(bitmap);
sergeyvc36bd6c2016-10-11 15:49:16 -0700116 }
117 return wrapper;
118}
119
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400120sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
John Reck1bcacfd2017-11-03 10:12:19 -0700121 return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
sergeyvc36bd6c2016-10-11 15:49:16 -0700122}
123
John Reck1bcacfd2017-11-03 10:12:19 -0700124sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100125#ifdef __ANDROID__
sergeyvc36bd6c2016-10-11 15:49:16 -0700126 // Create new ashmem region with read/write priv
127 int fd = ashmem_create_region("bitmap", size);
128 if (fd < 0) {
129 return nullptr;
130 }
131
132 void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
133 if (addr == MAP_FAILED) {
134 close(fd);
135 return nullptr;
136 }
137
138 if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
139 munmap(addr, size);
140 close(fd);
141 return nullptr;
142 }
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400143 return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100144#else
145 return Bitmap::allocateHeapBitmap(size, info, rowBytes);
146#endif
sergeyvc36bd6c2016-10-11 15:49:16 -0700147}
148
Derek Sollenbergere2169482018-11-20 10:57:20 -0500149sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100150#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500151 if (bitmap.colorType() == kAlpha_8_SkColorType &&
152 !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
153 return nullptr;
154 }
Derek Sollenbergere2169482018-11-20 10:57:20 -0500155 return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100156#else
157 return Bitmap::allocateHeapBitmap(bitmap.info());
158#endif
Derek Sollenbergere2169482018-11-20 10:57:20 -0500159}
160
161sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
162 return allocateBitmap(bitmap, &Bitmap::allocateHeapBitmap);
163}
164
165sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
166 size_t size;
167 if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
168 LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
169 return nullptr;
170 }
171 return allocateHeapBitmap(size, info, info.minRowBytes());
172}
173
174sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
175 void* addr = calloc(size, 1);
176 if (!addr) {
177 return nullptr;
178 }
179 return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
180}
181
sergeyvaed7f582016-10-14 16:30:21 -0700182sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
John Reckd0a79552020-06-01 14:21:44 -0700183 return sk_sp<Bitmap>(new Bitmap(pixelRef, info));
sergeyvaed7f582016-10-14 16:30:21 -0700184}
185
Derek Sollenbergere2169482018-11-20 10:57:20 -0500186
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100187#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400188sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, sk_sp<SkColorSpace> colorSpace,
189 BitmapPalette palette) {
190 AHardwareBuffer_Desc bufferDesc;
191 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
192 SkImageInfo info = uirenderer::BufferDescriptionToImageInfo(bufferDesc, colorSpace);
Leon Scroggins III3d334d82020-02-19 16:38:24 -0500193 return createFrom(hardwareBuffer, info, bufferDesc, palette);
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400194}
195
196sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, SkColorType colorType,
Derek Sollenberger6e35e632019-01-22 13:56:25 -0500197 sk_sp<SkColorSpace> colorSpace, SkAlphaType alphaType,
198 BitmapPalette palette) {
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400199 AHardwareBuffer_Desc bufferDesc;
200 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
201 SkImageInfo info = SkImageInfo::Make(bufferDesc.width, bufferDesc.height,
Derek Sollenberger6e35e632019-01-22 13:56:25 -0500202 colorType, alphaType, colorSpace);
Leon Scroggins III3d334d82020-02-19 16:38:24 -0500203 return createFrom(hardwareBuffer, info, bufferDesc, palette);
204}
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400205
Leon Scroggins III3d334d82020-02-19 16:38:24 -0500206sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, const SkImageInfo& info,
207 const AHardwareBuffer_Desc& bufferDesc, BitmapPalette palette) {
208 // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
209 const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
210 const size_t rowBytes = info.bytesPerPixel() * bufferStride;
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400211 return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
rennb2e9f522018-09-26 10:49:00 -0700212}
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100213#endif
rennb2e9f522018-09-26 10:49:00 -0700214
Derek Sollenbergere2169482018-11-20 10:57:20 -0500215sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr,
216 size_t size, bool readOnly) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100217#ifdef _WIN32 // ashmem not implemented on Windows
218 return nullptr;
219#else
Derek Sollenbergere2169482018-11-20 10:57:20 -0500220 if (info.colorType() == kUnknown_SkColorType) {
221 LOG_ALWAYS_FATAL("unknown bitmap configuration");
222 return nullptr;
223 }
224
225 if (!addr) {
226 // Map existing ashmem region if not already mapped.
227 int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
228 size = ashmem_get_size_region(fd);
229 addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0);
230 if (addr == MAP_FAILED) {
231 return nullptr;
232 }
233 }
234
235 sk_sp<Bitmap> bitmap(new Bitmap(addr, fd, size, info, rowBytes));
236 if (readOnly) {
237 bitmap->setImmutable();
238 }
239 return bitmap;
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100240#endif
sergeyv9a029872016-11-29 10:13:28 -0800241}
242
Romain Guy82426562017-04-04 19:38:50 -0700243void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
Matt Sarett489cfff2017-04-21 18:08:40 -0400244 mInfo = mInfo.makeColorSpace(std::move(colorSpace));
245}
246
247static SkImageInfo validateAlpha(const SkImageInfo& info) {
248 // Need to validate the alpha type to filter against the color type
249 // to prevent things like a non-opaque RGB565 bitmap
250 SkAlphaType alphaType;
John Reck1bcacfd2017-11-03 10:12:19 -0700251 LOG_ALWAYS_FATAL_IF(
252 !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
Matt Sarett489cfff2017-04-21 18:08:40 -0400253 "Failed to validate alpha type!");
254 return info.makeAlphaType(alphaType);
Romain Guy82426562017-04-04 19:38:50 -0700255}
256
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400257void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
Matt Sarett489cfff2017-04-21 18:08:40 -0400258 mInfo = validateAlpha(newInfo);
sergeyv163f8812016-10-07 16:57:29 -0700259
Leon Scroggins IIIf6631822020-07-22 12:40:06 -0400260 // TODO: Skia intends for SkPixelRef to be immutable, but this method
261 // modifies it. Find another way to support reusing the same pixel memory.
Mike Reed81397c42017-07-18 17:04:16 -0400262 this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
sergeyv163f8812016-10-07 16:57:29 -0700263}
264
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400265Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
John Reck1bcacfd2017-11-03 10:12:19 -0700266 : SkPixelRef(info.width(), info.height(), address, rowBytes)
267 , mInfo(validateAlpha(info))
268 , mPixelStorageType(PixelStorageType::Heap) {
sergeyv163f8812016-10-07 16:57:29 -0700269 mPixelStorage.heap.address = address;
270 mPixelStorage.heap.size = size;
sergeyv163f8812016-10-07 16:57:29 -0700271}
272
John Reckd0a79552020-06-01 14:21:44 -0700273Bitmap::Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info)
274 : SkPixelRef(info.width(), info.height(), pixelRef.pixels(), pixelRef.rowBytes())
John Reck1bcacfd2017-11-03 10:12:19 -0700275 , mInfo(validateAlpha(info))
John Reckd0a79552020-06-01 14:21:44 -0700276 , mPixelStorageType(PixelStorageType::WrappedPixelRef) {
277 pixelRef.ref();
278 mPixelStorage.wrapped.pixelRef = &pixelRef;
sergeyv163f8812016-10-07 16:57:29 -0700279}
280
John Reck1bcacfd2017-11-03 10:12:19 -0700281Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
282 : SkPixelRef(info.width(), info.height(), address, rowBytes)
283 , mInfo(validateAlpha(info))
284 , mPixelStorageType(PixelStorageType::Ashmem) {
sergeyv163f8812016-10-07 16:57:29 -0700285 mPixelStorage.ashmem.address = address;
286 mPixelStorage.ashmem.fd = fd;
287 mPixelStorage.ashmem.size = mappedSize;
sergeyv163f8812016-10-07 16:57:29 -0700288}
289
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100290#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400291Bitmap::Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes,
292 BitmapPalette palette)
293 : SkPixelRef(info.width(), info.height(), nullptr, rowBytes)
Matt Sarett489cfff2017-04-21 18:08:40 -0400294 , mInfo(validateAlpha(info))
John Reck339cf9b2018-07-18 16:32:27 -0700295 , mPixelStorageType(PixelStorageType::Hardware)
296 , mPalette(palette)
297 , mPaletteGenerationId(getGenerationID()) {
sergeyv9a029872016-11-29 10:13:28 -0800298 mPixelStorage.hardware.buffer = buffer;
John Reckac175cc2023-05-05 16:29:14 -0400299 mPixelStorage.hardware.size = AHardwareBuffer_getAllocationSize(buffer);
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400300 AHardwareBuffer_acquire(buffer);
John Reck1bcacfd2017-11-03 10:12:19 -0700301 setImmutable(); // HW bitmaps are always immutable
Kevin Lubickdd8b2ea2023-03-17 19:55:58 +0000302 mImage = SkImages::DeferredFromAHardwareBuffer(buffer, mInfo.alphaType(),
303 mInfo.refColorSpace());
sergeyv694d4992016-10-27 10:23:13 -0700304}
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100305#endif
sergeyv9a029872016-11-29 10:13:28 -0800306
sergeyvc1c54062016-10-19 18:47:26 -0700307Bitmap::~Bitmap() {
sergeyv163f8812016-10-07 16:57:29 -0700308 switch (mPixelStorageType) {
John Reckd0a79552020-06-01 14:21:44 -0700309 case PixelStorageType::WrappedPixelRef:
310 mPixelStorage.wrapped.pixelRef->unref();
John Reck1bcacfd2017-11-03 10:12:19 -0700311 break;
312 case PixelStorageType::Ashmem:
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100313#ifndef _WIN32 // ashmem not implemented on Windows
John Reck1bcacfd2017-11-03 10:12:19 -0700314 munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100315#endif
John Reck1bcacfd2017-11-03 10:12:19 -0700316 close(mPixelStorage.ashmem.fd);
317 break;
318 case PixelStorageType::Heap:
319 free(mPixelStorage.heap.address);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100320#ifdef __ANDROID__
Tim Murraye0b5e842018-10-15 16:29:15 -0700321 mallopt(M_PURGE, 0);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100322#endif
John Reck1bcacfd2017-11-03 10:12:19 -0700323 break;
324 case PixelStorageType::Hardware:
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100325#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
John Reck1bcacfd2017-11-03 10:12:19 -0700326 auto buffer = mPixelStorage.hardware.buffer;
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400327 AHardwareBuffer_release(buffer);
John Reck1bcacfd2017-11-03 10:12:19 -0700328 mPixelStorage.hardware.buffer = nullptr;
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100329#endif
John Reck1bcacfd2017-11-03 10:12:19 -0700330 break;
sergeyv163f8812016-10-07 16:57:29 -0700331 }
sergeyv163f8812016-10-07 16:57:29 -0700332}
333
sergeyvc1c54062016-10-19 18:47:26 -0700334bool Bitmap::hasHardwareMipMap() const {
sergeyv163f8812016-10-07 16:57:29 -0700335 return mHasHardwareMipMap;
336}
337
sergeyvc1c54062016-10-19 18:47:26 -0700338void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
sergeyv163f8812016-10-07 16:57:29 -0700339 mHasHardwareMipMap = hasMipMap;
340}
341
sergeyvc1c54062016-10-19 18:47:26 -0700342int Bitmap::getAshmemFd() const {
sergeyv163f8812016-10-07 16:57:29 -0700343 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700344 case PixelStorageType::Ashmem:
345 return mPixelStorage.ashmem.fd;
346 default:
347 return -1;
sergeyv163f8812016-10-07 16:57:29 -0700348 }
349}
350
sergeyvc1c54062016-10-19 18:47:26 -0700351size_t Bitmap::getAllocationByteCount() const {
sergeyv163f8812016-10-07 16:57:29 -0700352 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700353 case PixelStorageType::Heap:
354 return mPixelStorage.heap.size;
Leon Scroggins IIIbbdb7312019-01-31 14:35:54 -0500355 case PixelStorageType::Ashmem:
356 return mPixelStorage.ashmem.size;
John Reckac175cc2023-05-05 16:29:14 -0400357#ifdef __ANDROID__
358 case PixelStorageType::Hardware:
359 return mPixelStorage.hardware.size;
360#endif
John Reck1bcacfd2017-11-03 10:12:19 -0700361 default:
362 return rowBytes() * height();
sergeyv163f8812016-10-07 16:57:29 -0700363 }
364}
365
sergeyvc1c54062016-10-19 18:47:26 -0700366void Bitmap::reconfigure(const SkImageInfo& info) {
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400367 reconfigure(info, info.minRowBytes());
sergeyv163f8812016-10-07 16:57:29 -0700368}
369
sergeyvc1c54062016-10-19 18:47:26 -0700370void Bitmap::setAlphaType(SkAlphaType alphaType) {
sergeyv163f8812016-10-07 16:57:29 -0700371 if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
372 return;
373 }
374
Matt Sarett489cfff2017-04-21 18:08:40 -0400375 mInfo = mInfo.makeAlphaType(alphaType);
sergeyv163f8812016-10-07 16:57:29 -0700376}
377
sergeyvc1c54062016-10-19 18:47:26 -0700378void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100379#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
sergeyv694d4992016-10-27 10:23:13 -0700380 if (isHardware()) {
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400381 outBitmap->allocPixels(mInfo);
Stan Iliev1a025a72018-09-05 16:35:11 -0400382 uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap);
sergeyv694d4992016-10-27 10:23:13 -0700383 return;
384 }
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100385#endif
Matt Sarett489cfff2017-04-21 18:08:40 -0400386 outBitmap->setInfo(mInfo, rowBytes());
Mike Reed826deef2017-04-04 15:32:04 -0400387 outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
sergeyv163f8812016-10-07 16:57:29 -0700388}
389
sergeyvec4a4b12016-10-20 18:39:04 -0700390void Bitmap::getBounds(SkRect* bounds) const {
391 SkASSERT(bounds);
Mike Reed39adc882019-08-22 11:53:05 -0400392 bounds->setIWH(width(), height());
sergeyvec4a4b12016-10-20 18:39:04 -0700393}
394
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100395#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Derek Sollenbergere78f7c92019-07-31 15:18:47 -0400396AHardwareBuffer* Bitmap::hardwareBuffer() {
sergeyv694d4992016-10-27 10:23:13 -0700397 if (isHardware()) {
398 return mPixelStorage.hardware.buffer;
399 }
400 return nullptr;
401}
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100402#endif
sergeyv694d4992016-10-27 10:23:13 -0700403
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400404sk_sp<SkImage> Bitmap::makeImage() {
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400405 sk_sp<SkImage> image = mImage;
406 if (!image) {
John Reck1072fff2018-04-12 15:20:09 -0700407 SkASSERT(!isHardware());
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400408 SkBitmap skiaBitmap;
409 skiaBitmap.setInfo(info(), rowBytes());
410 skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400411 // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
412 // internally and ~Bitmap won't be invoked.
413 // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
Kevin Lubick93671082023-03-13 18:30:55 +0000414#ifdef __ANDROID__
415 // pinnable images are only supported with the Ganesh GPU backend compiled in.
Kevin Lubickdd8b2ea2023-03-17 19:55:58 +0000416 image = SkImages::PinnableRasterFromBitmap(skiaBitmap);
Kevin Lubick93671082023-03-13 18:30:55 +0000417#else
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400418 image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
Kevin Lubick93671082023-03-13 18:30:55 +0000419#endif
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400420 }
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400421 return image;
422}
423
John Reck339cf9b2018-07-18 16:32:27 -0700424class MinMaxAverage {
425public:
John Reck339cf9b2018-07-18 16:32:27 -0700426 void add(float sample) {
427 if (mCount == 0) {
428 mMin = sample;
429 mMax = sample;
430 } else {
431 mMin = std::min(mMin, sample);
432 mMax = std::max(mMax, sample);
433 }
434 mTotal += sample;
435 mCount++;
436 }
437
John Reck8f45d4a2018-08-15 10:17:12 -0700438 float average() { return mTotal / mCount; }
John Reck339cf9b2018-07-18 16:32:27 -0700439
John Reck8f45d4a2018-08-15 10:17:12 -0700440 float min() { return mMin; }
John Reck339cf9b2018-07-18 16:32:27 -0700441
John Reck8f45d4a2018-08-15 10:17:12 -0700442 float max() { return mMax; }
John Reck339cf9b2018-07-18 16:32:27 -0700443
John Reck8f45d4a2018-08-15 10:17:12 -0700444 float delta() { return mMax - mMin; }
John Reck339cf9b2018-07-18 16:32:27 -0700445
446private:
447 float mMin = 0.0f;
448 float mMax = 0.0f;
449 float mTotal = 0.0f;
450 int mCount = 0;
451};
452
453BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes) {
454 ATRACE_CALL();
455
456 SkPixmap pixmap{info, addr, rowBytes};
457
458 // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
459 // Experiment with something simpler since we just want to figure out if it's "color-ful"
460 // and then the average perceptual lightness.
461
462 MinMaxAverage hue, saturation, value;
463 int sampledCount = 0;
464
465 // Sample a grid of 100 pixels to get an overall estimation of the colors in play
466 const int x_step = std::max(1, pixmap.width() / 10);
467 const int y_step = std::max(1, pixmap.height() / 10);
468 for (int x = 0; x < pixmap.width(); x += x_step) {
469 for (int y = 0; y < pixmap.height(); y += y_step) {
470 SkColor color = pixmap.getColor(x, y);
471 if (!info.isOpaque() && SkColorGetA(color) < 75) {
472 continue;
473 }
474
475 sampledCount++;
476 float hsv[3];
477 SkColorToHSV(color, hsv);
478 hue.add(hsv[0]);
479 saturation.add(hsv[1]);
480 value.add(hsv[2]);
481 }
482 }
483
484 // TODO: Tune the coverage threshold
485 if (sampledCount < 5) {
486 ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d",
John Reck8f45d4a2018-08-15 10:17:12 -0700487 sampledCount, info.width(), info.height(), (int)info.colorType(),
488 (int)info.alphaType());
John Reck339cf9b2018-07-18 16:32:27 -0700489 return BitmapPalette::Unknown;
490 }
491
John Reck8f45d4a2018-08-15 10:17:12 -0700492 ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
493 "%f]",
494 sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
495 saturation.average());
John Reck339cf9b2018-07-18 16:32:27 -0700496
497 if (hue.delta() <= 20 && saturation.delta() <= .1f) {
498 if (value.average() >= .5f) {
499 return BitmapPalette::Light;
500 } else {
501 return BitmapPalette::Dark;
502 }
503 }
504 return BitmapPalette::Unknown;
505}
506
Leon Scroggins III949c6002020-01-23 16:20:39 -0500507bool Bitmap::compress(JavaCompressFormat format, int32_t quality, SkWStream* stream) {
John Reck340620d2023-02-01 22:26:00 -0500508#ifdef __ANDROID__ // TODO: This isn't built for host for some reason?
509 if (hasGainmap() && format == JavaCompressFormat::Jpeg) {
510 SkBitmap baseBitmap = getSkBitmap();
511 SkBitmap gainmapBitmap = gainmap()->bitmap->getSkBitmap();
John Reck280b4402023-02-27 18:10:25 -0500512 if (gainmapBitmap.colorType() == SkColorType::kAlpha_8_SkColorType) {
513 SkBitmap greyGainmap;
514 auto greyInfo = gainmapBitmap.info().makeColorType(SkColorType::kGray_8_SkColorType);
515 greyGainmap.setInfo(greyInfo, gainmapBitmap.rowBytes());
516 greyGainmap.setPixelRef(sk_ref_sp(gainmapBitmap.pixelRef()), 0, 0);
517 gainmapBitmap = std::move(greyGainmap);
518 }
John Reck340620d2023-02-01 22:26:00 -0500519 SkJpegEncoder::Options options{.fQuality = quality};
John Reck9eb77792023-02-16 21:53:50 -0500520 return SkJpegGainmapEncoder::EncodeHDRGM(stream, baseBitmap.pixmap(), options,
John Reck340620d2023-02-01 22:26:00 -0500521 gainmapBitmap.pixmap(), options, gainmap()->info);
522 }
523#endif
524
Leon Scroggins III9010e8b2019-08-20 11:27:17 -0400525 SkBitmap skbitmap;
526 getSkBitmap(&skbitmap);
527 return compress(skbitmap, format, quality, stream);
528}
529
Leon Scroggins III949c6002020-01-23 16:20:39 -0500530bool Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format,
531 int32_t quality, SkWStream* stream) {
Leon Scroggins III9f49a7c2020-01-29 14:51:26 -0500532 if (bitmap.colorType() == kAlpha_8_SkColorType) {
533 // None of the JavaCompressFormats have a sensible way to compress an
534 // ALPHA_8 Bitmap. SkPngEncoder will compress one, but it uses a non-
535 // standard format that most decoders do not understand, so this is
536 // likely not useful.
537 return false;
538 }
539
Leon Scroggins III9010e8b2019-08-20 11:27:17 -0400540 switch (format) {
Kevin Lubickfb9aa402023-04-12 18:48:49 +0000541 case JavaCompressFormat::Jpeg: {
542 SkJpegEncoder::Options options;
543 options.fQuality = quality;
544 return SkJpegEncoder::Encode(stream, bitmap.pixmap(), options);
545 }
Leon Scroggins III9010e8b2019-08-20 11:27:17 -0400546 case JavaCompressFormat::Png:
Kevin Lubickfb9aa402023-04-12 18:48:49 +0000547 return SkPngEncoder::Encode(stream, bitmap.pixmap(), {});
548 case JavaCompressFormat::Webp: {
549 SkWebpEncoder::Options options;
550 if (quality >= 100) {
551 options.fCompression = SkWebpEncoder::Compression::kLossless;
552 options.fQuality = 75; // This is effort to compress
553 } else {
554 options.fCompression = SkWebpEncoder::Compression::kLossy;
555 options.fQuality = quality;
556 }
557 return SkWebpEncoder::Encode(stream, bitmap.pixmap(), options);
558 }
Leon Scroggins III9010e8b2019-08-20 11:27:17 -0400559 case JavaCompressFormat::WebpLossy:
560 case JavaCompressFormat::WebpLossless: {
561 SkWebpEncoder::Options options;
562 options.fQuality = quality;
563 options.fCompression = format == JavaCompressFormat::WebpLossy ?
564 SkWebpEncoder::Compression::kLossy : SkWebpEncoder::Compression::kLossless;
Leon Scroggins III949c6002020-01-23 16:20:39 -0500565 return SkWebpEncoder::Encode(stream, bitmap.pixmap(), options);
Leon Scroggins III9010e8b2019-08-20 11:27:17 -0400566 }
567 }
Leon Scroggins III9010e8b2019-08-20 11:27:17 -0400568}
John Reck5bd537e2023-01-24 20:13:45 -0500569
570sp<uirenderer::Gainmap> Bitmap::gainmap() const {
571 LOG_ALWAYS_FATAL_IF(!hasGainmap(), "Bitmap doesn't have a gainmap");
572 return mGainmap;
573}
574
575void Bitmap::setGainmap(sp<uirenderer::Gainmap>&& gainmap) {
576 mGainmap = std::move(gainmap);
577}
578
John Reck1bcacfd2017-11-03 10:12:19 -0700579} // namespace android