| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2007 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 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 17 | #include <stdlib.h> | 
|  | 18 | #include <stdint.h> | 
|  | 19 | #include <math.h> | 
|  | 20 | #include <sys/types.h> | 
|  | 21 |  | 
|  | 22 | #include <utils/Errors.h> | 
|  | 23 | #include <utils/Log.h> | 
|  | 24 | #include <utils/StopWatch.h> | 
|  | 25 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 26 | #include <ui/PixelFormat.h> | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 27 | #include <ui/FramebufferNativeWindow.h> | 
|  | 28 |  | 
|  | 29 | #include <hardware/copybit.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 30 |  | 
|  | 31 | #include "LayerBuffer.h" | 
|  | 32 | #include "SurfaceFlinger.h" | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 33 | #include "DisplayHardware/DisplayHardware.h" | 
|  | 34 |  | 
| Mathias Agopian | 5911aa9 | 2009-06-24 16:55:59 -0700 | [diff] [blame] | 35 | #include "gralloc_priv.h"   // needed for msm / copybit | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 36 |  | 
|  | 37 | namespace android { | 
|  | 38 |  | 
|  | 39 | // --------------------------------------------------------------------------- | 
|  | 40 |  | 
|  | 41 | const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20; | 
|  | 42 | const char* const LayerBuffer::typeID = "LayerBuffer"; | 
|  | 43 |  | 
|  | 44 | // --------------------------------------------------------------------------- | 
|  | 45 |  | 
|  | 46 | LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display, | 
| Mathias Agopian | f9d9327 | 2009-06-19 17:00:27 -0700 | [diff] [blame] | 47 | const sp<Client>& client, int32_t i) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 48 | : LayerBaseClient(flinger, display, client, i), | 
|  | 49 | mNeedsBlending(false) | 
|  | 50 | { | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | LayerBuffer::~LayerBuffer() | 
|  | 54 | { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 55 | } | 
|  | 56 |  | 
| Mathias Agopian | 9a11206 | 2009-04-17 19:36:26 -0700 | [diff] [blame] | 57 | void LayerBuffer::onFirstRef() | 
|  | 58 | { | 
| Mathias Agopian | 2e12324 | 2009-06-23 20:06:46 -0700 | [diff] [blame] | 59 | LayerBaseClient::onFirstRef(); | 
| Mathias Agopian | 9a11206 | 2009-04-17 19:36:26 -0700 | [diff] [blame] | 60 | mSurface = new SurfaceBuffer(mFlinger, clientIndex(), | 
|  | 61 | const_cast<LayerBuffer *>(this)); | 
|  | 62 | } | 
|  | 63 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 64 | sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 65 | { | 
| Mathias Agopian | 9a11206 | 2009-04-17 19:36:26 -0700 | [diff] [blame] | 66 | return mSurface; | 
|  | 67 | } | 
|  | 68 |  | 
|  | 69 | status_t LayerBuffer::ditch() | 
|  | 70 | { | 
|  | 71 | mSurface.clear(); | 
|  | 72 | return NO_ERROR; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 73 | } | 
|  | 74 |  | 
|  | 75 | bool LayerBuffer::needsBlending() const { | 
|  | 76 | return mNeedsBlending; | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | void LayerBuffer::setNeedsBlending(bool blending) { | 
|  | 80 | mNeedsBlending = blending; | 
|  | 81 | } | 
|  | 82 |  | 
|  | 83 | void LayerBuffer::postBuffer(ssize_t offset) | 
|  | 84 | { | 
|  | 85 | sp<Source> source(getSource()); | 
|  | 86 | if (source != 0) | 
|  | 87 | source->postBuffer(offset); | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | void LayerBuffer::unregisterBuffers() | 
|  | 91 | { | 
|  | 92 | sp<Source> source(clearSource()); | 
|  | 93 | if (source != 0) | 
|  | 94 | source->unregisterBuffers(); | 
|  | 95 | } | 
|  | 96 |  | 
|  | 97 | uint32_t LayerBuffer::doTransaction(uint32_t flags) | 
|  | 98 | { | 
|  | 99 | sp<Source> source(getSource()); | 
|  | 100 | if (source != 0) | 
|  | 101 | source->onTransaction(flags); | 
|  | 102 | return LayerBase::doTransaction(flags); | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | void LayerBuffer::unlockPageFlip(const Transform& planeTransform, | 
|  | 106 | Region& outDirtyRegion) | 
|  | 107 | { | 
|  | 108 | // this code-path must be as tight as possible, it's called each time | 
|  | 109 | // the screen is composited. | 
|  | 110 | sp<Source> source(getSource()); | 
|  | 111 | if (source != 0) | 
|  | 112 | source->onVisibilityResolved(planeTransform); | 
|  | 113 | LayerBase::unlockPageFlip(planeTransform, outDirtyRegion); | 
|  | 114 | } | 
|  | 115 |  | 
|  | 116 | void LayerBuffer::onDraw(const Region& clip) const | 
|  | 117 | { | 
|  | 118 | sp<Source> source(getSource()); | 
|  | 119 | if (LIKELY(source != 0)) { | 
|  | 120 | source->onDraw(clip); | 
|  | 121 | } else { | 
|  | 122 | clearWithOpenGL(clip); | 
|  | 123 | } | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | bool LayerBuffer::transformed() const | 
|  | 127 | { | 
|  | 128 | sp<Source> source(getSource()); | 
|  | 129 | if (LIKELY(source != 0)) | 
|  | 130 | return source->transformed(); | 
|  | 131 | return false; | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | /** | 
|  | 135 | * This creates a "buffer" source for this surface | 
|  | 136 | */ | 
|  | 137 | status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers) | 
|  | 138 | { | 
|  | 139 | Mutex::Autolock _l(mLock); | 
|  | 140 | if (mSource != 0) | 
|  | 141 | return INVALID_OPERATION; | 
|  | 142 |  | 
|  | 143 | sp<BufferSource> source = new BufferSource(*this, buffers); | 
|  | 144 |  | 
|  | 145 | status_t result = source->getStatus(); | 
|  | 146 | if (result == NO_ERROR) { | 
|  | 147 | mSource = source; | 
|  | 148 | } | 
|  | 149 | return result; | 
|  | 150 | } | 
|  | 151 |  | 
|  | 152 | /** | 
|  | 153 | * This creates an "overlay" source for this surface | 
|  | 154 | */ | 
|  | 155 | sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f) | 
|  | 156 | { | 
|  | 157 | sp<OverlayRef> result; | 
|  | 158 | Mutex::Autolock _l(mLock); | 
|  | 159 | if (mSource != 0) | 
|  | 160 | return result; | 
|  | 161 |  | 
|  | 162 | sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f); | 
|  | 163 | if (result != 0) { | 
|  | 164 | mSource = source; | 
|  | 165 | } | 
|  | 166 | return result; | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | sp<LayerBuffer::Source> LayerBuffer::getSource() const { | 
|  | 170 | Mutex::Autolock _l(mLock); | 
|  | 171 | return mSource; | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | sp<LayerBuffer::Source> LayerBuffer::clearSource() { | 
|  | 175 | sp<Source> source; | 
|  | 176 | Mutex::Autolock _l(mLock); | 
|  | 177 | source = mSource; | 
|  | 178 | mSource.clear(); | 
|  | 179 | return source; | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 | // ============================================================================ | 
|  | 183 | // LayerBuffer::SurfaceBuffer | 
|  | 184 | // ============================================================================ | 
|  | 185 |  | 
| Mathias Agopian | 9a11206 | 2009-04-17 19:36:26 -0700 | [diff] [blame] | 186 | LayerBuffer::SurfaceBuffer::SurfaceBuffer(const sp<SurfaceFlinger>& flinger, | 
|  | 187 | SurfaceID id, const sp<LayerBuffer>& owner) | 
|  | 188 | : LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 189 | { | 
|  | 190 | } | 
|  | 191 |  | 
|  | 192 | LayerBuffer::SurfaceBuffer::~SurfaceBuffer() | 
|  | 193 | { | 
|  | 194 | unregisterBuffers(); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 195 | } | 
|  | 196 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 197 | status_t LayerBuffer::SurfaceBuffer::registerBuffers( | 
|  | 198 | const ISurface::BufferHeap& buffers) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 199 | { | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 200 | sp<LayerBuffer> owner(getOwner()); | 
|  | 201 | if (owner != 0) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 202 | return owner->registerBuffers(buffers); | 
|  | 203 | return NO_INIT; | 
|  | 204 | } | 
|  | 205 |  | 
|  | 206 | void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset) | 
|  | 207 | { | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 208 | sp<LayerBuffer> owner(getOwner()); | 
|  | 209 | if (owner != 0) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 210 | owner->postBuffer(offset); | 
|  | 211 | } | 
|  | 212 |  | 
|  | 213 | void LayerBuffer::SurfaceBuffer::unregisterBuffers() | 
|  | 214 | { | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 215 | sp<LayerBuffer> owner(getOwner()); | 
|  | 216 | if (owner != 0) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 217 | owner->unregisterBuffers(); | 
|  | 218 | } | 
|  | 219 |  | 
|  | 220 | sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay( | 
|  | 221 | uint32_t w, uint32_t h, int32_t format) { | 
|  | 222 | sp<OverlayRef> result; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 223 | sp<LayerBuffer> owner(getOwner()); | 
|  | 224 | if (owner != 0) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 225 | result = owner->createOverlay(w, h, format); | 
|  | 226 | return result; | 
|  | 227 | } | 
|  | 228 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 229 | // ============================================================================ | 
|  | 230 | // LayerBuffer::Buffer | 
|  | 231 | // ============================================================================ | 
|  | 232 |  | 
|  | 233 | LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset) | 
|  | 234 | : mBufferHeap(buffers) | 
|  | 235 | { | 
|  | 236 | NativeBuffer& src(mNativeBuffer); | 
| Mathias Agopian | 5911aa9 | 2009-06-24 16:55:59 -0700 | [diff] [blame] | 237 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 238 | src.crop.l = 0; | 
|  | 239 | src.crop.t = 0; | 
|  | 240 | src.crop.r = buffers.w; | 
|  | 241 | src.crop.b = buffers.h; | 
| Mathias Agopian | 5911aa9 | 2009-06-24 16:55:59 -0700 | [diff] [blame] | 242 |  | 
|  | 243 | src.img.w       = buffers.hor_stride ?: buffers.w; | 
|  | 244 | src.img.h       = buffers.ver_stride ?: buffers.h; | 
|  | 245 | src.img.format  = buffers.format; | 
|  | 246 | src.img.base    = (void*)(intptr_t(buffers.heap->base()) + offset); | 
|  | 247 |  | 
| Mathias Agopian | d512f23 | 2009-06-25 17:41:12 -0700 | [diff] [blame] | 248 | // FIXME: gross hack, we should never access private_handle_t from here, | 
|  | 249 | // but this is needed by msm drivers | 
| Mathias Agopian | 5911aa9 | 2009-06-24 16:55:59 -0700 | [diff] [blame] | 250 | private_handle_t* hnd = new private_handle_t( | 
|  | 251 | buffers.heap->heapID(), buffers.heap->getSize(), 0); | 
|  | 252 | hnd->offset = offset; | 
|  | 253 | src.img.handle = hnd; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 254 | } | 
|  | 255 |  | 
|  | 256 | LayerBuffer::Buffer::~Buffer() | 
|  | 257 | { | 
| Mathias Agopian | 5911aa9 | 2009-06-24 16:55:59 -0700 | [diff] [blame] | 258 | NativeBuffer& src(mNativeBuffer); | 
|  | 259 | if (src.img.handle) | 
|  | 260 | delete (private_handle_t*)src.img.handle; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 261 | } | 
|  | 262 |  | 
|  | 263 | // ============================================================================ | 
|  | 264 | // LayerBuffer::Source | 
|  | 265 | // LayerBuffer::BufferSource | 
|  | 266 | // LayerBuffer::OverlaySource | 
|  | 267 | // ============================================================================ | 
|  | 268 |  | 
|  | 269 | LayerBuffer::Source::Source(LayerBuffer& layer) | 
|  | 270 | : mLayer(layer) | 
|  | 271 | { | 
|  | 272 | } | 
|  | 273 | LayerBuffer::Source::~Source() { | 
|  | 274 | } | 
|  | 275 | void LayerBuffer::Source::onDraw(const Region& clip) const { | 
|  | 276 | } | 
|  | 277 | void LayerBuffer::Source::onTransaction(uint32_t flags) { | 
|  | 278 | } | 
|  | 279 | void LayerBuffer::Source::onVisibilityResolved( | 
|  | 280 | const Transform& planeTransform) { | 
|  | 281 | } | 
|  | 282 | void LayerBuffer::Source::postBuffer(ssize_t offset) { | 
|  | 283 | } | 
|  | 284 | void LayerBuffer::Source::unregisterBuffers() { | 
|  | 285 | } | 
|  | 286 | bool LayerBuffer::Source::transformed() const { | 
|  | 287 | return mLayer.mTransformed; | 
|  | 288 | } | 
|  | 289 |  | 
|  | 290 | // --------------------------------------------------------------------------- | 
|  | 291 |  | 
|  | 292 | LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer, | 
|  | 293 | const ISurface::BufferHeap& buffers) | 
| Mathias Agopian | 1fed11c | 2009-06-23 18:08:22 -0700 | [diff] [blame] | 294 | : Source(layer), mStatus(NO_ERROR), mBufferSize(0) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 295 | { | 
|  | 296 | if (buffers.heap == NULL) { | 
|  | 297 | // this is allowed, but in this case, it is illegal to receive | 
|  | 298 | // postBuffer(). The surface just erases the framebuffer with | 
|  | 299 | // fully transparent pixels. | 
|  | 300 | mBufferHeap = buffers; | 
|  | 301 | mLayer.setNeedsBlending(false); | 
|  | 302 | return; | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT; | 
|  | 306 | if (err != NO_ERROR) { | 
|  | 307 | LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err)); | 
|  | 308 | mStatus = err; | 
|  | 309 | return; | 
|  | 310 | } | 
|  | 311 |  | 
|  | 312 | PixelFormatInfo info; | 
|  | 313 | err = getPixelFormatInfo(buffers.format, &info); | 
|  | 314 | if (err != NO_ERROR) { | 
|  | 315 | LOGE("LayerBuffer::BufferSource: invalid format %d (%s)", | 
|  | 316 | buffers.format, strerror(err)); | 
|  | 317 | mStatus = err; | 
|  | 318 | return; | 
|  | 319 | } | 
|  | 320 |  | 
|  | 321 | if (buffers.hor_stride<0 || buffers.ver_stride<0) { | 
|  | 322 | LOGE("LayerBuffer::BufferSource: invalid parameters " | 
|  | 323 | "(w=%d, h=%d, xs=%d, ys=%d)", | 
|  | 324 | buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride); | 
|  | 325 | mStatus = BAD_VALUE; | 
|  | 326 | return; | 
|  | 327 | } | 
|  | 328 |  | 
|  | 329 | mBufferHeap = buffers; | 
|  | 330 | mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0); | 
|  | 331 | mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride; | 
|  | 332 | mLayer.forceVisibilityTransaction(); | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 333 |  | 
|  | 334 | hw_module_t const* module; | 
|  | 335 | mBlitEngine = NULL; | 
|  | 336 | if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { | 
|  | 337 | copybit_open(module, &mBlitEngine); | 
|  | 338 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 339 | } | 
|  | 340 |  | 
|  | 341 | LayerBuffer::BufferSource::~BufferSource() | 
|  | 342 | { | 
| Mathias Agopian | 1fed11c | 2009-06-23 18:08:22 -0700 | [diff] [blame] | 343 | if (mTexture.name != -1U) { | 
|  | 344 | glDeleteTextures(1, &mTexture.name); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 345 | } | 
| Mathias Agopian | 240c9fe | 2009-06-25 15:39:25 -0700 | [diff] [blame] | 346 | if (mBlitEngine) { | 
|  | 347 | copybit_close(mBlitEngine); | 
|  | 348 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 349 | } | 
|  | 350 |  | 
|  | 351 | void LayerBuffer::BufferSource::postBuffer(ssize_t offset) | 
|  | 352 | { | 
|  | 353 | ISurface::BufferHeap buffers; | 
|  | 354 | { // scope for the lock | 
|  | 355 | Mutex::Autolock _l(mLock); | 
|  | 356 | buffers = mBufferHeap; | 
|  | 357 | if (buffers.heap != 0) { | 
|  | 358 | const size_t memorySize = buffers.heap->getSize(); | 
|  | 359 | if ((size_t(offset) + mBufferSize) > memorySize) { | 
|  | 360 | LOGE("LayerBuffer::BufferSource::postBuffer() " | 
|  | 361 | "invalid buffer (offset=%d, size=%d, heap-size=%d", | 
|  | 362 | int(offset), int(mBufferSize), int(memorySize)); | 
|  | 363 | return; | 
|  | 364 | } | 
|  | 365 | } | 
|  | 366 | } | 
|  | 367 |  | 
|  | 368 | sp<Buffer> buffer; | 
|  | 369 | if (buffers.heap != 0) { | 
|  | 370 | buffer = new LayerBuffer::Buffer(buffers, offset); | 
|  | 371 | if (buffer->getStatus() != NO_ERROR) | 
|  | 372 | buffer.clear(); | 
|  | 373 | setBuffer(buffer); | 
|  | 374 | mLayer.invalidate(); | 
|  | 375 | } | 
|  | 376 | } | 
|  | 377 |  | 
|  | 378 | void LayerBuffer::BufferSource::unregisterBuffers() | 
|  | 379 | { | 
|  | 380 | Mutex::Autolock _l(mLock); | 
|  | 381 | mBufferHeap.heap.clear(); | 
|  | 382 | mBuffer.clear(); | 
|  | 383 | mLayer.invalidate(); | 
|  | 384 | } | 
|  | 385 |  | 
|  | 386 | sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const | 
|  | 387 | { | 
|  | 388 | Mutex::Autolock _l(mLock); | 
|  | 389 | return mBuffer; | 
|  | 390 | } | 
|  | 391 |  | 
|  | 392 | void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer) | 
|  | 393 | { | 
|  | 394 | Mutex::Autolock _l(mLock); | 
|  | 395 | mBuffer = buffer; | 
|  | 396 | } | 
|  | 397 |  | 
|  | 398 | bool LayerBuffer::BufferSource::transformed() const | 
|  | 399 | { | 
|  | 400 | return mBufferHeap.transform ? true : Source::transformed(); | 
|  | 401 | } | 
|  | 402 |  | 
|  | 403 | void LayerBuffer::BufferSource::onDraw(const Region& clip) const | 
|  | 404 | { | 
| Mathias Agopian | 1fed11c | 2009-06-23 18:08:22 -0700 | [diff] [blame] | 405 | sp<Buffer> ourBuffer(getBuffer()); | 
|  | 406 | if (UNLIKELY(ourBuffer == 0))  { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 407 | // nothing to do, we don't have a buffer | 
|  | 408 | mLayer.clearWithOpenGL(clip); | 
|  | 409 | return; | 
|  | 410 | } | 
|  | 411 |  | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 412 | status_t err = NO_ERROR; | 
|  | 413 | NativeBuffer src(ourBuffer->getBuffer()); | 
|  | 414 | const Rect& transformedBounds = mLayer.getTransformedBounds(); | 
|  | 415 | copybit_device_t* copybit = mBlitEngine; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 416 |  | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 417 | if (copybit)  { | 
|  | 418 | const int src_width  = src.crop.r - src.crop.l; | 
|  | 419 | const int src_height = src.crop.b - src.crop.t; | 
|  | 420 | int W = transformedBounds.width(); | 
|  | 421 | int H = transformedBounds.height(); | 
|  | 422 | if (mLayer.getOrientation() & Transform::ROT_90) { | 
|  | 423 | int t(W); W=H; H=t; | 
|  | 424 | } | 
|  | 425 |  | 
| Mathias Agopian | 2ab55a4 | 2009-06-24 22:39:26 -0700 | [diff] [blame] | 426 | #ifdef EGL_ANDROID_get_render_buffer | 
|  | 427 | EGLDisplay dpy = eglGetCurrentDisplay(); | 
|  | 428 | EGLSurface draw = eglGetCurrentSurface(EGL_DRAW); | 
|  | 429 | EGLClientBuffer clientBuf = eglGetRenderBufferANDROID(dpy, draw); | 
|  | 430 | android_native_buffer_t* nb = (android_native_buffer_t*)clientBuf; | 
|  | 431 | if (nb == 0) { | 
|  | 432 | err = BAD_VALUE; | 
|  | 433 | } else { | 
|  | 434 | copybit_image_t dst; | 
|  | 435 | dst.w       = nb->width; | 
|  | 436 | dst.h       = nb->height; | 
|  | 437 | dst.format  = nb->format; | 
|  | 438 | dst.base    = NULL; // unused by copybit on msm7k | 
|  | 439 | dst.handle  = (native_handle_t *)nb->handle; | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 440 |  | 
| Mathias Agopian | d512f23 | 2009-06-25 17:41:12 -0700 | [diff] [blame] | 441 | /* With LayerBuffer, it is likely that we'll have to rescale the | 
|  | 442 | * surface, because this is often used for video playback or | 
|  | 443 | * camera-preview. Since we want these operation as fast as possible | 
|  | 444 | * we make sure we can use the 2D H/W even if it doesn't support | 
|  | 445 | * the requested scale factor, in which case we perform the scaling | 
|  | 446 | * in several passes. */ | 
|  | 447 |  | 
|  | 448 | const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT); | 
|  | 449 | const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT); | 
|  | 450 |  | 
|  | 451 | float xscale = 1.0f; | 
|  | 452 | if (src_width > W*min)          xscale = 1.0f / min; | 
|  | 453 | else if (src_width*mag < W)     xscale = mag; | 
|  | 454 |  | 
|  | 455 | float yscale = 1.0f; | 
|  | 456 | if (src_height > H*min)         yscale = 1.0f / min; | 
|  | 457 | else if (src_height*mag < H)    yscale = mag; | 
|  | 458 |  | 
|  | 459 | if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) { | 
|  | 460 | const int tmp_w = floorf(src_width  * xscale); | 
|  | 461 | const int tmp_h = floorf(src_height * yscale); | 
|  | 462 |  | 
|  | 463 | if (mTempBitmap==0 || | 
|  | 464 | mTempBitmap->getWidth() < tmp_w || | 
|  | 465 | mTempBitmap->getHeight() < tmp_h) { | 
|  | 466 | mTempBitmap.clear(); | 
|  | 467 | mTempBitmap = new android::Buffer(tmp_w, tmp_h, src.img.format); | 
|  | 468 | err = mTempBitmap->initCheck(); | 
|  | 469 | } | 
|  | 470 |  | 
|  | 471 | if (LIKELY(err == NO_ERROR)) { | 
|  | 472 | NativeBuffer tmp; | 
|  | 473 | tmp.img.w = tmp_w; | 
|  | 474 | tmp.img.h = tmp_h; | 
|  | 475 | tmp.img.format = src.img.format; | 
|  | 476 | tmp.img.handle = (native_handle_t*)mTempBitmap->getNativeBuffer()->handle; | 
|  | 477 | tmp.crop.l = 0; | 
|  | 478 | tmp.crop.t = 0; | 
|  | 479 | tmp.crop.r = tmp.img.w; | 
|  | 480 | tmp.crop.b = tmp.img.h; | 
|  | 481 |  | 
|  | 482 | region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b))); | 
|  | 483 | copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); | 
|  | 484 | copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); | 
|  | 485 | copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); | 
|  | 486 | err = copybit->stretch(copybit, | 
|  | 487 | &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it); | 
|  | 488 | src = tmp; | 
|  | 489 | } | 
|  | 490 | } | 
|  | 491 |  | 
| Mathias Agopian | 2ab55a4 | 2009-06-24 22:39:26 -0700 | [diff] [blame] | 492 | const Rect& transformedBounds = mLayer.getTransformedBounds(); | 
| Mathias Agopian | d512f23 | 2009-06-25 17:41:12 -0700 | [diff] [blame] | 493 | const copybit_rect_t& drect = | 
|  | 494 | reinterpret_cast<const copybit_rect_t&>(transformedBounds); | 
| Mathias Agopian | 2ab55a4 | 2009-06-24 22:39:26 -0700 | [diff] [blame] | 495 | const State& s(mLayer.drawingState()); | 
|  | 496 | region_iterator it(clip); | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 497 |  | 
| Mathias Agopian | 2ab55a4 | 2009-06-24 22:39:26 -0700 | [diff] [blame] | 498 | // pick the right orientation for this buffer | 
|  | 499 | int orientation = mLayer.getOrientation(); | 
|  | 500 | if (UNLIKELY(mBufferHeap.transform)) { | 
|  | 501 | Transform rot90; | 
|  | 502 | GraphicPlane::orientationToTransfrom( | 
|  | 503 | ISurfaceComposer::eOrientation90, 0, 0, &rot90); | 
|  | 504 | const Transform& planeTransform(mLayer.graphicPlane(0).transform()); | 
|  | 505 | const Layer::State& s(mLayer.drawingState()); | 
|  | 506 | Transform tr(planeTransform * s.transform * rot90); | 
|  | 507 | orientation = tr.getOrientation(); | 
|  | 508 | } | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 509 |  | 
| Mathias Agopian | 2ab55a4 | 2009-06-24 22:39:26 -0700 | [diff] [blame] | 510 | copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation); | 
|  | 511 | copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha); | 
|  | 512 | copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE); | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 513 |  | 
| Mathias Agopian | 2ab55a4 | 2009-06-24 22:39:26 -0700 | [diff] [blame] | 514 | err = copybit->stretch(copybit, | 
|  | 515 | &dst, &src.img, &drect, &src.crop, &it); | 
|  | 516 | if (err != NO_ERROR) { | 
|  | 517 | LOGE("copybit failed (%s)", strerror(err)); | 
|  | 518 | } | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 519 | } | 
|  | 520 | } | 
| Mathias Agopian | 2ab55a4 | 2009-06-24 22:39:26 -0700 | [diff] [blame] | 521 | #endif | 
|  | 522 |  | 
| Mathias Agopian | 69029eb | 2009-06-23 21:11:43 -0700 | [diff] [blame] | 523 | if (!copybit || err) | 
| Mathias Agopian | 1fed11c | 2009-06-23 18:08:22 -0700 | [diff] [blame] | 524 | { | 
|  | 525 | // OpenGL fall-back | 
|  | 526 | if (UNLIKELY(mTexture.name == -1LU)) { | 
|  | 527 | mTexture.name = mLayer.createTexture(); | 
|  | 528 | } | 
| Mathias Agopian | 0926f50 | 2009-05-04 14:17:04 -0700 | [diff] [blame] | 529 | GLuint w = 0; | 
|  | 530 | GLuint h = 0; | 
| Mathias Agopian | 1fed11c | 2009-06-23 18:08:22 -0700 | [diff] [blame] | 531 | GGLSurface t; | 
|  | 532 | t.version = sizeof(GGLSurface); | 
|  | 533 | t.width  = src.crop.r; | 
|  | 534 | t.height = src.crop.b; | 
|  | 535 | t.stride = src.img.w; | 
|  | 536 | t.vstride= src.img.h; | 
|  | 537 | t.format = src.img.format; | 
| Mathias Agopian | 5911aa9 | 2009-06-24 16:55:59 -0700 | [diff] [blame] | 538 | t.data = (GGLubyte*)src.img.base; | 
| Mathias Agopian | 1fed11c | 2009-06-23 18:08:22 -0700 | [diff] [blame] | 539 | const Region dirty(Rect(t.width, t.height)); | 
|  | 540 | mLayer.loadTexture(&mTexture, mTexture.name, dirty, t); | 
|  | 541 | mTexture.transform = mBufferHeap.transform; | 
|  | 542 | mLayer.drawWithOpenGL(clip, mTexture); | 
| Mathias Agopian | 0926f50 | 2009-05-04 14:17:04 -0700 | [diff] [blame] | 543 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 544 | } | 
|  | 545 |  | 
|  | 546 |  | 
|  | 547 | // --------------------------------------------------------------------------- | 
|  | 548 |  | 
|  | 549 | LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer, | 
|  | 550 | sp<OverlayRef>* overlayRef, | 
|  | 551 | uint32_t w, uint32_t h, int32_t format) | 
|  | 552 | : Source(layer), mVisibilityChanged(false), | 
|  | 553 | mOverlay(0), mOverlayHandle(0), mOverlayDevice(0) | 
|  | 554 | { | 
|  | 555 | overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine(); | 
|  | 556 | if (overlay_dev == NULL) { | 
|  | 557 | // overlays not supported | 
|  | 558 | return; | 
|  | 559 | } | 
|  | 560 |  | 
|  | 561 | mOverlayDevice = overlay_dev; | 
|  | 562 | overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format); | 
|  | 563 | if (overlay == NULL) { | 
|  | 564 | // couldn't create the overlay (no memory? no more overlays?) | 
|  | 565 | return; | 
|  | 566 | } | 
|  | 567 |  | 
|  | 568 | // enable dithering... | 
|  | 569 | overlay_dev->setParameter(overlay_dev, overlay, | 
|  | 570 | OVERLAY_DITHER, OVERLAY_ENABLE); | 
|  | 571 |  | 
|  | 572 | mOverlay = overlay; | 
|  | 573 | mWidth = overlay->w; | 
|  | 574 | mHeight = overlay->h; | 
|  | 575 | mFormat = overlay->format; | 
|  | 576 | mWidthStride = overlay->w_stride; | 
|  | 577 | mHeightStride = overlay->h_stride; | 
| Rebecca Schultz Zavin | 1000170 | 2009-07-21 16:17:59 -0700 | [diff] [blame] | 578 | mInitialized = false; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 579 |  | 
|  | 580 | mOverlayHandle = overlay->getHandleRef(overlay); | 
|  | 581 |  | 
|  | 582 | // NOTE: here it's okay to acquire a reference to "this"m as long as | 
|  | 583 | // the reference is not released before we leave the ctor. | 
|  | 584 | sp<OverlayChannel> channel = new OverlayChannel(this); | 
|  | 585 |  | 
|  | 586 | *overlayRef = new OverlayRef(mOverlayHandle, channel, | 
|  | 587 | mWidth, mHeight, mFormat, mWidthStride, mHeightStride); | 
|  | 588 | } | 
|  | 589 |  | 
|  | 590 | LayerBuffer::OverlaySource::~OverlaySource() | 
|  | 591 | { | 
|  | 592 | if (mOverlay && mOverlayDevice) { | 
|  | 593 | overlay_control_device_t* overlay_dev = mOverlayDevice; | 
|  | 594 | overlay_dev->destroyOverlay(overlay_dev, mOverlay); | 
|  | 595 | } | 
|  | 596 | } | 
|  | 597 |  | 
| Rebecca Schultz Zavin | 96df49b | 2009-07-20 21:18:04 -0700 | [diff] [blame] | 598 | void LayerBuffer::OverlaySource::onDraw(const Region& clip) const | 
|  | 599 | { | 
|  | 600 | mLayer.clearWithOpenGL(clip); | 
|  | 601 | } | 
|  | 602 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 603 | void LayerBuffer::OverlaySource::onTransaction(uint32_t flags) | 
|  | 604 | { | 
|  | 605 | const Layer::State& front(mLayer.drawingState()); | 
|  | 606 | const Layer::State& temp(mLayer.currentState()); | 
|  | 607 | if (temp.sequence != front.sequence) { | 
|  | 608 | mVisibilityChanged = true; | 
|  | 609 | } | 
|  | 610 | } | 
|  | 611 |  | 
|  | 612 | void LayerBuffer::OverlaySource::onVisibilityResolved( | 
|  | 613 | const Transform& planeTransform) | 
|  | 614 | { | 
|  | 615 | // this code-path must be as tight as possible, it's called each time | 
|  | 616 | // the screen is composited. | 
|  | 617 | if (UNLIKELY(mOverlay != 0)) { | 
| Rebecca Schultz Zavin | 1000170 | 2009-07-21 16:17:59 -0700 | [diff] [blame] | 618 | if (mVisibilityChanged || !mInitialized) { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 619 | mVisibilityChanged = false; | 
| Rebecca Schultz Zavin | 1000170 | 2009-07-21 16:17:59 -0700 | [diff] [blame] | 620 | mInitialized = true; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 621 | const Rect& bounds = mLayer.getTransformedBounds(); | 
|  | 622 | int x = bounds.left; | 
|  | 623 | int y = bounds.top; | 
|  | 624 | int w = bounds.width(); | 
|  | 625 | int h = bounds.height(); | 
|  | 626 |  | 
|  | 627 | // we need a lock here to protect "destroy" | 
|  | 628 | Mutex::Autolock _l(mLock); | 
|  | 629 | if (mOverlay) { | 
|  | 630 | overlay_control_device_t* overlay_dev = mOverlayDevice; | 
|  | 631 | overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h); | 
| Rebecca Schultz Zavin | 1000170 | 2009-07-21 16:17:59 -0700 | [diff] [blame] | 632 | overlay_dev->setParameter(overlay_dev, mOverlay, | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 633 | OVERLAY_TRANSFORM, mLayer.getOrientation()); | 
| Rebecca Schultz Zavin | 96df49b | 2009-07-20 21:18:04 -0700 | [diff] [blame] | 634 | overlay_dev->commit(overlay_dev, mOverlay); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 635 | } | 
|  | 636 | } | 
|  | 637 | } | 
|  | 638 | } | 
|  | 639 |  | 
|  | 640 | void LayerBuffer::OverlaySource::serverDestroy() | 
|  | 641 | { | 
|  | 642 | mLayer.clearSource(); | 
|  | 643 | destroyOverlay(); | 
|  | 644 | } | 
|  | 645 |  | 
|  | 646 | void LayerBuffer::OverlaySource::destroyOverlay() | 
|  | 647 | { | 
|  | 648 | // we need a lock here to protect "onVisibilityResolved" | 
|  | 649 | Mutex::Autolock _l(mLock); | 
|  | 650 | if (mOverlay) { | 
|  | 651 | overlay_control_device_t* overlay_dev = mOverlayDevice; | 
|  | 652 | overlay_dev->destroyOverlay(overlay_dev, mOverlay); | 
|  | 653 | mOverlay = 0; | 
|  | 654 | } | 
|  | 655 | } | 
|  | 656 |  | 
|  | 657 | // --------------------------------------------------------------------------- | 
|  | 658 | }; // namespace android |