• 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 "Caches.h"
19 #include "renderthread/EglManager.h"
20 #include "renderthread/RenderProxy.h"
21 #include "renderthread/RenderThread.h"
22 #include "utils/Color.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 #include <SkToSRGBColorFilter.h>
36 
37 namespace android {
38 
computeAllocationSize(size_t rowBytes,int height,size_t * size)39 static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
40     int32_t rowBytes32 = SkToS32(rowBytes);
41     int64_t bigSize = (int64_t)height * rowBytes32;
42     if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
43         return false;  // allocation will be too large
44     }
45 
46     *size = sk_64_asS32(bigSize);
47     return true;
48 }
49 
50 typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, 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, size_t rowBytes) {
105     // Create new ashmem region with read/write priv
106     int fd = ashmem_create_region("bitmap", size);
107     if (fd < 0) {
108         return nullptr;
109     }
110 
111     void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
112     if (addr == MAP_FAILED) {
113         close(fd);
114         return nullptr;
115     }
116 
117     if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
118         munmap(addr, size);
119         close(fd);
120         return nullptr;
121     }
122     return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
123 }
124 
FreePixelRef(void * addr,void * context)125 void FreePixelRef(void* addr, void* context) {
126     auto pixelRef = (SkPixelRef*)context;
127     pixelRef->unref();
128 }
129 
createFrom(const SkImageInfo & info,SkPixelRef & pixelRef)130 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
131     pixelRef.ref();
132     return sk_sp<Bitmap>(new Bitmap((void*)pixelRef.pixels(), (void*)&pixelRef, FreePixelRef, info,
133                                     pixelRef.rowBytes()));
134 }
135 
createFrom(sp<GraphicBuffer> graphicBuffer)136 sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
137     PixelFormat format = graphicBuffer->getPixelFormat();
138     if (!graphicBuffer.get() ||
139         (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
140         return nullptr;
141     }
142     SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
143                                          kRGBA_8888_SkColorType, kPremul_SkAlphaType,
144                                          SkColorSpace::MakeSRGB());
145     return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
146 }
147 
setColorSpace(sk_sp<SkColorSpace> colorSpace)148 void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
149     mInfo = mInfo.makeColorSpace(std::move(colorSpace));
150 }
151 
validateAlpha(const SkImageInfo & info)152 static SkImageInfo validateAlpha(const SkImageInfo& info) {
153     // Need to validate the alpha type to filter against the color type
154     // to prevent things like a non-opaque RGB565 bitmap
155     SkAlphaType alphaType;
156     LOG_ALWAYS_FATAL_IF(
157             !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
158             "Failed to validate alpha type!");
159     return info.makeAlphaType(alphaType);
160 }
161 
reconfigure(const SkImageInfo & newInfo,size_t rowBytes)162 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
163     mInfo = validateAlpha(newInfo);
164 
165     // Dirty hack is dirty
166     // TODO: Figure something out here, Skia's current design makes this
167     // really hard to work with. Skia really, really wants immutable objects,
168     // but with the nested-ref-count hackery going on that's just not
169     // feasible without going insane trying to figure it out
170     this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
171 }
172 
Bitmap(void * address,size_t size,const SkImageInfo & info,size_t rowBytes)173 Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
174         : SkPixelRef(info.width(), info.height(), address, rowBytes)
175         , mInfo(validateAlpha(info))
176         , mPixelStorageType(PixelStorageType::Heap) {
177     mPixelStorage.heap.address = address;
178     mPixelStorage.heap.size = size;
179 }
180 
Bitmap(void * address,void * context,FreeFunc freeFunc,const SkImageInfo & info,size_t rowBytes)181 Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
182                size_t rowBytes)
183         : SkPixelRef(info.width(), info.height(), address, rowBytes)
184         , mInfo(validateAlpha(info))
185         , mPixelStorageType(PixelStorageType::External) {
186     mPixelStorage.external.address = address;
187     mPixelStorage.external.context = context;
188     mPixelStorage.external.freeFunc = freeFunc;
189 }
190 
Bitmap(void * address,int fd,size_t mappedSize,const SkImageInfo & info,size_t rowBytes)191 Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
192         : SkPixelRef(info.width(), info.height(), address, rowBytes)
193         , mInfo(validateAlpha(info))
194         , mPixelStorageType(PixelStorageType::Ashmem) {
195     mPixelStorage.ashmem.address = address;
196     mPixelStorage.ashmem.fd = fd;
197     mPixelStorage.ashmem.size = mappedSize;
198 }
199 
Bitmap(GraphicBuffer * buffer,const SkImageInfo & info)200 Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
201         : SkPixelRef(info.width(), info.height(), nullptr,
202                      bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride())
203         , mInfo(validateAlpha(info))
204         , mPixelStorageType(PixelStorageType::Hardware) {
205     mPixelStorage.hardware.buffer = buffer;
206     buffer->incStrong(buffer);
207     setImmutable();  // HW bitmaps are always immutable
208     if (uirenderer::Properties::isSkiaEnabled()) {
209         mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
210                                                   mInfo.alphaType(), mInfo.refColorSpace());
211     }
212 }
213 
~Bitmap()214 Bitmap::~Bitmap() {
215     switch (mPixelStorageType) {
216         case PixelStorageType::External:
217             mPixelStorage.external.freeFunc(mPixelStorage.external.address,
218                                             mPixelStorage.external.context);
219             break;
220         case PixelStorageType::Ashmem:
221             munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
222             close(mPixelStorage.ashmem.fd);
223             break;
224         case PixelStorageType::Heap:
225             free(mPixelStorage.heap.address);
226             break;
227         case PixelStorageType::Hardware:
228             auto buffer = mPixelStorage.hardware.buffer;
229             buffer->decStrong(buffer);
230             mPixelStorage.hardware.buffer = nullptr;
231             break;
232     }
233 
234     android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID());
235 }
236 
hasHardwareMipMap() const237 bool Bitmap::hasHardwareMipMap() const {
238     return mHasHardwareMipMap;
239 }
240 
setHasHardwareMipMap(bool hasMipMap)241 void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
242     mHasHardwareMipMap = hasMipMap;
243 }
244 
getStorage() const245 void* Bitmap::getStorage() const {
246     switch (mPixelStorageType) {
247         case PixelStorageType::External:
248             return mPixelStorage.external.address;
249         case PixelStorageType::Ashmem:
250             return mPixelStorage.ashmem.address;
251         case PixelStorageType::Heap:
252             return mPixelStorage.heap.address;
253         case PixelStorageType::Hardware:
254             return nullptr;
255     }
256 }
257 
getAshmemFd() const258 int Bitmap::getAshmemFd() const {
259     switch (mPixelStorageType) {
260         case PixelStorageType::Ashmem:
261             return mPixelStorage.ashmem.fd;
262         default:
263             return -1;
264     }
265 }
266 
getAllocationByteCount() const267 size_t Bitmap::getAllocationByteCount() const {
268     switch (mPixelStorageType) {
269         case PixelStorageType::Heap:
270             return mPixelStorage.heap.size;
271         default:
272             return rowBytes() * height();
273     }
274 }
275 
reconfigure(const SkImageInfo & info)276 void Bitmap::reconfigure(const SkImageInfo& info) {
277     reconfigure(info, info.minRowBytes());
278 }
279 
setAlphaType(SkAlphaType alphaType)280 void Bitmap::setAlphaType(SkAlphaType alphaType) {
281     if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
282         return;
283     }
284 
285     mInfo = mInfo.makeAlphaType(alphaType);
286 }
287 
getSkBitmap(SkBitmap * outBitmap)288 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
289     outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
290     if (isHardware()) {
291         if (uirenderer::Properties::isSkiaEnabled()) {
292             outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
293                                                      info().colorType(), info().alphaType(),
294                                                      nullptr));
295         } else {
296             outBitmap->allocPixels(info());
297         }
298         uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
299         if (mInfo.colorSpace()) {
300             sk_sp<SkPixelRef> pixelRef = sk_ref_sp(outBitmap->pixelRef());
301             outBitmap->setInfo(mInfo);
302             outBitmap->setPixelRef(std::move(pixelRef), 0, 0);
303         }
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(sk_sp<SkColorFilter> * outputColorFilter)322 sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) {
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         image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
334     }
335     if (uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr &&
336         !image->colorSpace()->isSRGB()) {
337         *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
338     }
339     return image;
340 }
341 
342 }  // namespace android
343