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 "Caches.h"
19 #include "renderthread/EglManager.h"
20 #include "renderthread/RenderThread.h"
21 #include "renderthread/RenderProxy.h"
22 #include "utils/Color.h"
23
24 #include <sys/mman.h>
25
26 #include <log/log.h>
27 #include <cutils/ashmem.h>
28
29 #include <private/gui/ComposerService.h>
30 #include <binder/IServiceManager.h>
31 #include <ui/PixelFormat.h>
32
33 #include <SkCanvas.h>
34 #include <SkImagePriv.h>
35
36 namespace android {
37
computeAllocationSize(size_t rowBytes,int height,size_t * size)38 static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
39 int32_t rowBytes32 = SkToS32(rowBytes);
40 int64_t bigSize = (int64_t) height * rowBytes32;
41 if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
42 return false; // allocation will be too large
43 }
44
45 *size = sk_64_asS32(bigSize);
46 return true;
47 }
48
49 typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info,
50 size_t rowBytes);
51
allocateBitmap(SkBitmap * bitmap,AllocPixelRef alloc)52 static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
53 const SkImageInfo& info = bitmap->info();
54 if (info.colorType() == kUnknown_SkColorType) {
55 LOG_ALWAYS_FATAL("unknown bitmap configuration");
56 return nullptr;
57 }
58
59 size_t size;
60
61 // we must respect the rowBytes value already set on the bitmap instead of
62 // attempting to compute our own.
63 const size_t rowBytes = bitmap->rowBytes();
64 if (!computeAllocationSize(rowBytes, bitmap->height(), &size)) {
65 return nullptr;
66 }
67
68 auto wrapper = alloc(size, info, rowBytes);
69 if (wrapper) {
70 wrapper->getSkBitmap(bitmap);
71 }
72 return wrapper;
73 }
74
allocateAshmemBitmap(SkBitmap * bitmap)75 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
76 return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
77 }
78
allocateHeapBitmap(size_t size,const SkImageInfo & info,size_t rowBytes)79 static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
80 void* addr = calloc(size, 1);
81 if (!addr) {
82 return nullptr;
83 }
84 return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
85 }
86
allocateHardwareBitmap(SkBitmap & bitmap)87 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) {
88 return uirenderer::renderthread::RenderProxy::allocateHardwareBitmap(bitmap);
89 }
90
allocateHeapBitmap(SkBitmap * bitmap)91 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
92 return allocateBitmap(bitmap, &android::allocateHeapBitmap);
93 }
94
allocateHeapBitmap(const SkImageInfo & info)95 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
96 size_t size;
97 if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
98 LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
99 return nullptr;
100 }
101 return android::allocateHeapBitmap(size, info, info.minRowBytes());
102 }
103
allocateAshmemBitmap(size_t size,const SkImageInfo & info,size_t rowBytes)104 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
105 size_t rowBytes) {
106 // Create new ashmem region with read/write priv
107 int fd = ashmem_create_region("bitmap", size);
108 if (fd < 0) {
109 return nullptr;
110 }
111
112 void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
113 if (addr == MAP_FAILED) {
114 close(fd);
115 return nullptr;
116 }
117
118 if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
119 munmap(addr, size);
120 close(fd);
121 return nullptr;
122 }
123 return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
124 }
125
FreePixelRef(void * addr,void * context)126 void FreePixelRef(void* addr, void* context) {
127 auto pixelRef = (SkPixelRef*) context;
128 pixelRef->unref();
129 }
130
createFrom(const SkImageInfo & info,SkPixelRef & pixelRef)131 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
132 pixelRef.ref();
133 return sk_sp<Bitmap>(new Bitmap((void*) pixelRef.pixels(), (void*) &pixelRef, FreePixelRef,
134 info, pixelRef.rowBytes()));
135 }
136
createFrom(sp<GraphicBuffer> graphicBuffer)137 sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
138 PixelFormat format = graphicBuffer->getPixelFormat();
139 if (!graphicBuffer.get() ||
140 (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
141 return nullptr;
142 }
143 SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
144 kRGBA_8888_SkColorType, kPremul_SkAlphaType,
145 SkColorSpace::MakeSRGB());
146 return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
147 }
148
setColorSpace(sk_sp<SkColorSpace> colorSpace)149 void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
150 mInfo = mInfo.makeColorSpace(std::move(colorSpace));
151 }
152
validateAlpha(const SkImageInfo & info)153 static SkImageInfo validateAlpha(const SkImageInfo& info) {
154 // Need to validate the alpha type to filter against the color type
155 // to prevent things like a non-opaque RGB565 bitmap
156 SkAlphaType alphaType;
157 LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
158 info.colorType(), info.alphaType(), &alphaType),
159 "Failed to validate alpha type!");
160 return info.makeAlphaType(alphaType);
161 }
162
reconfigure(const SkImageInfo & newInfo,size_t rowBytes)163 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
164 mInfo = validateAlpha(newInfo);
165
166 // Dirty hack is dirty
167 // TODO: Figure something out here, Skia's current design makes this
168 // really hard to work with. Skia really, really wants immutable objects,
169 // but with the nested-ref-count hackery going on that's just not
170 // feasible without going insane trying to figure it out
171 this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
172 }
173
Bitmap(void * address,size_t size,const SkImageInfo & info,size_t rowBytes)174 Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
175 : SkPixelRef(info.width(), info.height(), address, rowBytes)
176 , mInfo(validateAlpha(info))
177 , mPixelStorageType(PixelStorageType::Heap) {
178 mPixelStorage.heap.address = address;
179 mPixelStorage.heap.size = size;
180 }
181
Bitmap(void * address,void * context,FreeFunc freeFunc,const SkImageInfo & info,size_t rowBytes)182 Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
183 const SkImageInfo& info, size_t rowBytes)
184 : SkPixelRef(info.width(), info.height(), address, rowBytes)
185 , mInfo(validateAlpha(info))
186 , mPixelStorageType(PixelStorageType::External) {
187 mPixelStorage.external.address = address;
188 mPixelStorage.external.context = context;
189 mPixelStorage.external.freeFunc = freeFunc;
190 }
191
Bitmap(void * address,int fd,size_t mappedSize,const SkImageInfo & info,size_t rowBytes)192 Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
193 const SkImageInfo& info, size_t rowBytes)
194 : SkPixelRef(info.width(), info.height(), address, rowBytes)
195 , mInfo(validateAlpha(info))
196 , mPixelStorageType(PixelStorageType::Ashmem) {
197 mPixelStorage.ashmem.address = address;
198 mPixelStorage.ashmem.fd = fd;
199 mPixelStorage.ashmem.size = mappedSize;
200 }
201
Bitmap(GraphicBuffer * buffer,const SkImageInfo & info)202 Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
203 : SkPixelRef(info.width(), info.height(), nullptr,
204 bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride())
205 , mInfo(validateAlpha(info))
206 , mPixelStorageType(PixelStorageType::Hardware) {
207 mPixelStorage.hardware.buffer = buffer;
208 buffer->incStrong(buffer);
209 setImmutable(); // HW bitmaps are always immutable
210 if (uirenderer::Properties::isSkiaEnabled()) {
211 // GraphicBuffer should be in the display color space (Bitmap::createFrom is always
212 // passing SRGB). The code that uploads into a GraphicBuffer should do color conversion if
213 // needed.
214 mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
215 mInfo.alphaType(), nullptr);
216 }
217 }
218
~Bitmap()219 Bitmap::~Bitmap() {
220 switch (mPixelStorageType) {
221 case PixelStorageType::External:
222 mPixelStorage.external.freeFunc(mPixelStorage.external.address,
223 mPixelStorage.external.context);
224 break;
225 case PixelStorageType::Ashmem:
226 munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
227 close(mPixelStorage.ashmem.fd);
228 break;
229 case PixelStorageType::Heap:
230 free(mPixelStorage.heap.address);
231 break;
232 case PixelStorageType::Hardware:
233 auto buffer = mPixelStorage.hardware.buffer;
234 buffer->decStrong(buffer);
235 mPixelStorage.hardware.buffer = nullptr;
236 break;
237
238 }
239
240 android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID());
241 }
242
hasHardwareMipMap() const243 bool Bitmap::hasHardwareMipMap() const {
244 return mHasHardwareMipMap;
245 }
246
setHasHardwareMipMap(bool hasMipMap)247 void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
248 mHasHardwareMipMap = hasMipMap;
249 }
250
getStorage() const251 void* Bitmap::getStorage() const {
252 switch (mPixelStorageType) {
253 case PixelStorageType::External:
254 return mPixelStorage.external.address;
255 case PixelStorageType::Ashmem:
256 return mPixelStorage.ashmem.address;
257 case PixelStorageType::Heap:
258 return mPixelStorage.heap.address;
259 case PixelStorageType::Hardware:
260 return nullptr;
261 }
262 }
263
getAshmemFd() const264 int Bitmap::getAshmemFd() const {
265 switch (mPixelStorageType) {
266 case PixelStorageType::Ashmem:
267 return mPixelStorage.ashmem.fd;
268 default:
269 return -1;
270 }
271 }
272
getAllocationByteCount() const273 size_t Bitmap::getAllocationByteCount() const {
274 switch (mPixelStorageType) {
275 case PixelStorageType::Heap:
276 return mPixelStorage.heap.size;
277 default:
278 return rowBytes() * height();
279 }
280 }
281
reconfigure(const SkImageInfo & info)282 void Bitmap::reconfigure(const SkImageInfo& info) {
283 reconfigure(info, info.minRowBytes());
284 }
285
setAlphaType(SkAlphaType alphaType)286 void Bitmap::setAlphaType(SkAlphaType alphaType) {
287 if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
288 return;
289 }
290
291 mInfo = mInfo.makeAlphaType(alphaType);
292 }
293
getSkBitmap(SkBitmap * outBitmap)294 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
295 outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
296 if (isHardware()) {
297 if (uirenderer::Properties::isSkiaEnabled()) {
298 outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
299 info().colorType(), info().alphaType(), nullptr));
300 } else {
301 outBitmap->allocPixels(info());
302 }
303 uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
304 return;
305 }
306 outBitmap->setInfo(mInfo, rowBytes());
307 outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
308 }
309
getBounds(SkRect * bounds) const310 void Bitmap::getBounds(SkRect* bounds) const {
311 SkASSERT(bounds);
312 bounds->set(0, 0, SkIntToScalar(width()), SkIntToScalar(height()));
313 }
314
graphicBuffer()315 GraphicBuffer* Bitmap::graphicBuffer() {
316 if (isHardware()) {
317 return mPixelStorage.hardware.buffer;
318 }
319 return nullptr;
320 }
321
makeImage()322 sk_sp<SkImage> Bitmap::makeImage() {
323 sk_sp<SkImage> image = mImage;
324 if (!image) {
325 SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled()));
326 SkBitmap skiaBitmap;
327 skiaBitmap.setInfo(info(), rowBytes());
328 skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
329 skiaBitmap.setHasHardwareMipMap(mHasHardwareMipMap);
330 // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
331 // internally and ~Bitmap won't be invoked.
332 // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
333 if (uirenderer::Properties::isSkiaEnabled()) {
334 image = SkMakeImageInColorSpace(skiaBitmap, SkColorSpace::MakeSRGB(),
335 skiaBitmap.getGenerationID(), kNever_SkCopyPixelsMode);
336 } else {
337 image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
338 }
339 }
340 return image;
341 }
342
343 } // namespace android
344