| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "SurfaceFlinger" |
| |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include <sys/types.h> |
| |
| #include <cutils/memory.h> |
| #include <utils/Errors.h> |
| #include <utils/Log.h> |
| #include <utils/MemoryDealer.h> |
| #include <utils/IMemory.h> |
| #include <ui/PixelFormat.h> |
| #include <pixelflinger/pixelflinger.h> |
| |
| #include "LayerBitmap.h" |
| #include "SurfaceFlinger.h" |
| #include "VRamHeap.h" |
| |
| |
| namespace android { |
| |
| // --------------------------------------------------------------------------- |
| |
| LayerBitmap::LayerBitmap() |
| : mAllocFlags(0), mOffset(0), mSize(-1U), mAlignment(2) |
| { |
| memset(&mSurface, 0, sizeof(mSurface)); |
| } |
| |
| LayerBitmap::~LayerBitmap() |
| { |
| mSurface.data = 0; |
| } |
| |
| status_t LayerBitmap::init(const sp<MemoryDealer>& allocator) |
| { |
| if (mAllocator != NULL) |
| return BAD_VALUE; |
| mAllocator = allocator; |
| return NO_ERROR; |
| } |
| |
| status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment, |
| PixelFormat format, uint32_t flags) |
| { |
| const sp<MemoryDealer>& allocator(mAllocator); |
| if (allocator == NULL) |
| return NO_INIT; |
| |
| if (UNLIKELY(w == mSurface.width && h == mSurface.height && |
| format == mSurface.format)) |
| { // same format and size, do nothing. |
| return NO_ERROR; |
| } |
| |
| PixelFormatInfo info; |
| getPixelFormatInfo(format, &info); |
| |
| uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED; |
| const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT |
| const uint32_t Bpp = info.bytesPerPixel; |
| uint32_t stride = (w + (alignment-1)) & ~(alignment-1); |
| stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp; |
| size_t size = info.getScanlineSize(stride) * h; |
| if (allocFlags & MemoryDealer::PAGE_ALIGNED) { |
| size_t pagesize = getpagesize(); |
| size = (size + (pagesize-1)) & ~(pagesize-1); |
| } |
| |
| /* FIXME: we should be able to have a h/v stride because the user of the |
| * surface might have stride limitation (for instance h/w codecs often do) |
| */ |
| int32_t vstride = 0; |
| |
| mAlignment = alignment; |
| mAllocFlags = allocFlags; |
| mOffset = 0; |
| if (mSize != size) { |
| // would be nice to have a reallocate() api |
| mBitsMemory.clear(); // free-memory |
| mBitsMemory = allocator->allocate(size, allocFlags); |
| mSize = size; |
| } else { |
| // don't erase memory if we didn't have to reallocate |
| flags &= ~SECURE_BITS; |
| } |
| if (mBitsMemory != 0) { |
| mOffset = mBitsMemory->offset(); |
| mSurface.data = static_cast<GGLubyte*>(mBitsMemory->pointer()); |
| mSurface.version = sizeof(GGLSurface); |
| mSurface.width = w; |
| mSurface.height = h; |
| mSurface.stride = stride; |
| mSurface.vstride = vstride; |
| mSurface.format = format; |
| if (flags & SECURE_BITS) |
| clear(); |
| } |
| |
| if (mBitsMemory==0 || mSurface.data==0) { |
| LOGE("not enough memory for layer bitmap " |
| "size=%u (w=%d, h=%d, stride=%d, format=%d)", |
| size, int(w), int(h), int(stride), int(format)); |
| allocator->dump("LayerBitmap"); |
| mSurface.data = 0; |
| mSize = -1U; |
| return NO_MEMORY; |
| } |
| return NO_ERROR; |
| } |
| |
| void LayerBitmap::clear() |
| { |
| // NOTE: this memset should not be necessary, at least for |
| // opaque surface. However, for security reasons it's better to keep it |
| // (in the case of pmem, it's possible that the memory contains old |
| // data) |
| if (mSurface.data) { |
| memset(mSurface.data, 0, mSize); |
| //if (bytesPerPixel(mSurface.format) == 4) { |
| // android_memset32((uint32_t*)mSurface.data, 0xFF0000FF, mSize); |
| //} else { |
| // android_memset16((uint16_t*)mSurface.data, 0xF800, mSize); |
| //} |
| } |
| } |
| |
| status_t LayerBitmap::getInfo(surface_info_t* info) const |
| { |
| if (mSurface.data == 0) { |
| memset(info, 0, sizeof(surface_info_t)); |
| info->bits_offset = NO_MEMORY; |
| return NO_MEMORY; |
| } |
| info->w = uint16_t(width()); |
| info->h = uint16_t(height()); |
| info->stride= uint16_t(stride()); |
| info->bpr = uint16_t(stride() * bytesPerPixel(pixelFormat())); |
| info->format= uint8_t(pixelFormat()); |
| info->flags = surface_info_t::eBufferDirty; |
| info->bits_offset = ssize_t(mOffset); |
| return NO_ERROR; |
| } |
| |
| status_t LayerBitmap::resize(uint32_t w, uint32_t h) |
| { |
| int err = setBits(w, h, mAlignment, pixelFormat(), SECURE_BITS); |
| return err; |
| } |
| |
| size_t LayerBitmap::size() const |
| { |
| return mSize; |
| } |
| |
| void LayerBitmap::getBitmapSurface(copybit_image_t* img) const |
| { |
| const sp<IMemoryHeap>& mh(getAllocator()->getMemoryHeap()); |
| void* sbase = mh->base(); |
| const GGLSurface& t(surface()); |
| img->w = t.stride ?: t.width; |
| img->h = t.vstride ?: t.height; |
| img->format = t.format; |
| img->offset = intptr_t(t.data) - intptr_t(sbase); |
| img->base = sbase; |
| img->fd = mh->heapID(); |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| }; // namespace android |