| 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 <sys/types.h> | 
|  | 20 |  | 
|  | 21 | #include <cutils/properties.h> | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 22 | #include <cutils/native_handle.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 23 |  | 
|  | 24 | #include <utils/Errors.h> | 
|  | 25 | #include <utils/Log.h> | 
|  | 26 | #include <utils/StopWatch.h> | 
|  | 27 |  | 
| Mathias Agopian | 3330b20 | 2009-10-05 17:07:12 -0700 | [diff] [blame] | 28 | #include <ui/GraphicBuffer.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 29 | #include <ui/PixelFormat.h> | 
| Mathias Agopian | 9cce325 | 2010-02-09 17:46:37 -0800 | [diff] [blame] | 30 |  | 
|  | 31 | #include <surfaceflinger/Surface.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 32 |  | 
|  | 33 | #include "clz.h" | 
| Mathias Agopian | 1f7bec6 | 2010-06-25 18:02:21 -0700 | [diff] [blame] | 34 | #include "GLExtensions.h" | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 35 | #include "Layer.h" | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 36 | #include "SurfaceFlinger.h" | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 37 | #include "DisplayHardware/DisplayHardware.h" | 
| Mathias Agopian | a350ff9 | 2010-08-10 17:14:02 -0700 | [diff] [blame] | 38 | #include "DisplayHardware/HWComposer.h" | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 39 |  | 
|  | 40 |  | 
|  | 41 | #define DEBUG_RESIZE    0 | 
|  | 42 |  | 
|  | 43 |  | 
|  | 44 | namespace android { | 
|  | 45 |  | 
| Mathias Agopian | ca99fb8 | 2010-04-14 16:43:44 -0700 | [diff] [blame] | 46 | template <typename T> inline T min(T a, T b) { | 
|  | 47 | return a<b ? a : b; | 
|  | 48 | } | 
|  | 49 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 50 | // --------------------------------------------------------------------------- | 
|  | 51 |  | 
| Mathias Agopian | 96f0819 | 2010-06-02 23:28:45 -0700 | [diff] [blame] | 52 | Layer::Layer(SurfaceFlinger* flinger, | 
|  | 53 | DisplayID display, const sp<Client>& client) | 
|  | 54 | :   LayerBaseClient(flinger, display, client), | 
| Mathias Agopian | 1f7bec6 | 2010-06-25 18:02:21 -0700 | [diff] [blame] | 55 | mGLExtensions(GLExtensions::getInstance()), | 
| Mathias Agopian | 401c257 | 2009-09-23 19:16:27 -0700 | [diff] [blame] | 56 | mNeedsBlending(true), | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 57 | mNeedsDithering(false), | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 58 | mSecure(false), | 
| Mathias Agopian | 1f7bec6 | 2010-06-25 18:02:21 -0700 | [diff] [blame] | 59 | mTextureManager(), | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 60 | mBufferManager(mTextureManager), | 
| Mathias Agopian | 733189d | 2010-12-02 21:32:29 -0800 | [diff] [blame] | 61 | mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 62 | { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 63 | } | 
|  | 64 |  | 
|  | 65 | Layer::~Layer() | 
|  | 66 | { | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 67 | // FIXME: must be called from the main UI thread | 
|  | 68 | EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); | 
|  | 69 | mBufferManager.destroy(dpy); | 
|  | 70 |  | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 71 | // we can use getUserClientUnsafe here because we know we're | 
|  | 72 | // single-threaded at that point. | 
|  | 73 | sp<UserClient> ourClient(mUserClientRef.getUserClientUnsafe()); | 
|  | 74 | if (ourClient != 0) { | 
|  | 75 | ourClient->detachLayer(this); | 
|  | 76 | } | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 77 | } | 
|  | 78 |  | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 79 | status_t Layer::setToken(const sp<UserClient>& userClient, | 
|  | 80 | SharedClient* sharedClient, int32_t token) | 
| Mathias Agopian | 96f0819 | 2010-06-02 23:28:45 -0700 | [diff] [blame] | 81 | { | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 82 | sp<SharedBufferServer> lcblk = new SharedBufferServer( | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 83 | sharedClient, token, mBufferManager.getDefaultBufferCount(), | 
| Mathias Agopian | 96f0819 | 2010-06-02 23:28:45 -0700 | [diff] [blame] | 84 | getIdentity()); | 
|  | 85 |  | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 86 |  | 
| Mathias Agopian | dd17b3e | 2010-12-13 16:49:05 -0800 | [diff] [blame] | 87 | sp<UserClient> ourClient(mUserClientRef.getClient()); | 
|  | 88 |  | 
|  | 89 | /* | 
|  | 90 | *  Here it is guaranteed that userClient != ourClient | 
|  | 91 | *  (see UserClient::getTokenForSurface()). | 
|  | 92 | * | 
|  | 93 | *  We release the token used by this surface in ourClient below. | 
|  | 94 | *  This should be safe to do so now, since this layer won't be attached | 
|  | 95 | *  to this client, it should be okay to reuse that id. | 
|  | 96 | * | 
|  | 97 | *  If this causes problems, an other solution would be to keep a list | 
|  | 98 | *  of all the {UserClient, token} ever used and release them when the | 
|  | 99 | *  Layer is destroyed. | 
|  | 100 | * | 
|  | 101 | */ | 
|  | 102 |  | 
|  | 103 | if (ourClient != 0) { | 
|  | 104 | ourClient->detachLayer(this); | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | status_t err = mUserClientRef.setToken(userClient, lcblk, token); | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 108 | LOGE_IF(err != NO_ERROR, | 
|  | 109 | "ClientRef::setToken(%p, %p, %u) failed", | 
|  | 110 | userClient.get(), lcblk.get(), token); | 
|  | 111 |  | 
|  | 112 | if (err == NO_ERROR) { | 
|  | 113 | // we need to free the buffers associated with this surface | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 114 | } | 
|  | 115 |  | 
|  | 116 | return err; | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | int32_t Layer::getToken() const | 
|  | 120 | { | 
|  | 121 | return mUserClientRef.getToken(); | 
| Mathias Agopian | 96f0819 | 2010-06-02 23:28:45 -0700 | [diff] [blame] | 122 | } | 
|  | 123 |  | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 124 | sp<UserClient> Layer::getClient() const | 
|  | 125 | { | 
|  | 126 | return mUserClientRef.getClient(); | 
|  | 127 | } | 
|  | 128 |  | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 129 | // called with SurfaceFlinger::mStateLock as soon as the layer is entered | 
|  | 130 | // in the purgatory list | 
|  | 131 | void Layer::onRemoved() | 
|  | 132 | { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 133 | ClientRef::Access sharedClient(mUserClientRef); | 
|  | 134 | SharedBufferServer* lcblk(sharedClient.get()); | 
|  | 135 | if (lcblk) { | 
| Mathias Agopian | 96f0819 | 2010-06-02 23:28:45 -0700 | [diff] [blame] | 136 | // wake up the condition | 
|  | 137 | lcblk->setStatus(NO_INIT); | 
|  | 138 | } | 
| Mathias Agopian | 48d819a | 2009-09-10 19:41:18 -0700 | [diff] [blame] | 139 | } | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 140 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 141 | sp<LayerBaseClient::Surface> Layer::createSurface() const | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 142 | { | 
|  | 143 | return mSurface; | 
|  | 144 | } | 
|  | 145 |  | 
| Mathias Agopian | 9a11206 | 2009-04-17 19:36:26 -0700 | [diff] [blame] | 146 | status_t Layer::ditch() | 
|  | 147 | { | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 148 | // NOTE: Called from the main UI thread | 
|  | 149 |  | 
| Mathias Agopian | 0aa758d | 2009-04-22 15:23:34 -0700 | [diff] [blame] | 150 | // the layer is not on screen anymore. free as much resources as possible | 
| Mathias Agopian | f5430db | 2009-12-11 00:56:10 -0800 | [diff] [blame] | 151 | mFreezeLock.clear(); | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 152 |  | 
| Mathias Agopian | 3cc2677 | 2011-01-28 18:23:24 -0800 | [diff] [blame] | 153 | // Free our own reference to ISurface | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 154 | mSurface.clear(); | 
|  | 155 |  | 
|  | 156 | Mutex::Autolock _l(mLock); | 
|  | 157 | mWidth = mHeight = 0; | 
| Mathias Agopian | 9a11206 | 2009-04-17 19:36:26 -0700 | [diff] [blame] | 158 | return NO_ERROR; | 
|  | 159 | } | 
|  | 160 |  | 
| Mathias Agopian | f9d9327 | 2009-06-19 17:00:27 -0700 | [diff] [blame] | 161 | status_t Layer::setBuffers( uint32_t w, uint32_t h, | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 162 | PixelFormat format, uint32_t flags) | 
|  | 163 | { | 
| Mathias Agopian | 401c257 | 2009-09-23 19:16:27 -0700 | [diff] [blame] | 164 | // this surfaces pixel format | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 165 | PixelFormatInfo info; | 
|  | 166 | status_t err = getPixelFormatInfo(format, &info); | 
|  | 167 | if (err) return err; | 
|  | 168 |  | 
| Mathias Agopian | 401c257 | 2009-09-23 19:16:27 -0700 | [diff] [blame] | 169 | // the display's pixel format | 
|  | 170 | const DisplayHardware& hw(graphicPlane(0).displayHardware()); | 
| Mathias Agopian | ca99fb8 | 2010-04-14 16:43:44 -0700 | [diff] [blame] | 171 | uint32_t const maxSurfaceDims = min( | 
|  | 172 | hw.getMaxTextureSize(), hw.getMaxViewportDims()); | 
|  | 173 |  | 
|  | 174 | // never allow a surface larger than what our underlying GL implementation | 
|  | 175 | // can handle. | 
|  | 176 | if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) { | 
|  | 177 | return BAD_VALUE; | 
|  | 178 | } | 
|  | 179 |  | 
| Mathias Agopian | 401c257 | 2009-09-23 19:16:27 -0700 | [diff] [blame] | 180 | PixelFormatInfo displayInfo; | 
|  | 181 | getPixelFormatInfo(hw.getFormat(), &displayInfo); | 
| Mathias Agopian | a4b740e | 2009-10-05 18:20:39 -0700 | [diff] [blame] | 182 | const uint32_t hwFlags = hw.getFlags(); | 
|  | 183 |  | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 184 | mFormat = format; | 
| Mathias Agopian | ca99fb8 | 2010-04-14 16:43:44 -0700 | [diff] [blame] | 185 | mWidth  = w; | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 186 | mHeight = h; | 
| Mathias Agopian | eff062c | 2010-08-25 14:59:15 -0700 | [diff] [blame] | 187 |  | 
|  | 188 | mReqFormat = format; | 
|  | 189 | mReqWidth = w; | 
|  | 190 | mReqHeight = h; | 
|  | 191 |  | 
| Mathias Agopian | 3330b20 | 2009-10-05 17:07:12 -0700 | [diff] [blame] | 192 | mSecure = (flags & ISurfaceComposer::eSecure) ? true : false; | 
| Romain Guy | 3b996c9 | 2010-10-10 13:33:22 -0700 | [diff] [blame] | 193 | mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 && | 
|  | 194 | (flags & ISurfaceComposer::eOpaque) == 0; | 
| Mathias Agopian | ca99fb8 | 2010-04-14 16:43:44 -0700 | [diff] [blame] | 195 |  | 
| Mathias Agopian | 401c257 | 2009-09-23 19:16:27 -0700 | [diff] [blame] | 196 | // we use the red index | 
|  | 197 | int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED); | 
|  | 198 | int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED); | 
|  | 199 | mNeedsDithering = layerRedsize > displayRedSize; | 
|  | 200 |  | 
| Mathias Agopian | 96f0819 | 2010-06-02 23:28:45 -0700 | [diff] [blame] | 201 | mSurface = new SurfaceLayer(mFlinger, this); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 202 | return NO_ERROR; | 
|  | 203 | } | 
|  | 204 |  | 
| Mathias Agopian | a350ff9 | 2010-08-10 17:14:02 -0700 | [diff] [blame] | 205 | void Layer::setGeometry(hwc_layer_t* hwcl) | 
|  | 206 | { | 
|  | 207 | hwcl->compositionType = HWC_FRAMEBUFFER; | 
|  | 208 | hwcl->hints = 0; | 
|  | 209 | hwcl->flags = 0; | 
|  | 210 | hwcl->transform = 0; | 
|  | 211 | hwcl->blending = HWC_BLENDING_NONE; | 
|  | 212 |  | 
|  | 213 | // we can't do alpha-fade with the hwc HAL | 
|  | 214 | const State& s(drawingState()); | 
|  | 215 | if (s.alpha < 0xFF) { | 
|  | 216 | hwcl->flags = HWC_SKIP_LAYER; | 
|  | 217 | return; | 
|  | 218 | } | 
|  | 219 |  | 
|  | 220 | // we can only handle simple transformation | 
|  | 221 | if (mOrientation & Transform::ROT_INVALID) { | 
|  | 222 | hwcl->flags = HWC_SKIP_LAYER; | 
|  | 223 | return; | 
|  | 224 | } | 
|  | 225 |  | 
| Mathias Agopian | 86bdb2f | 2010-12-08 17:23:18 -0800 | [diff] [blame] | 226 | Transform tr(Transform(mOrientation) * Transform(mBufferTransform)); | 
|  | 227 | hwcl->transform = tr.getOrientation(); | 
| Mathias Agopian | a350ff9 | 2010-08-10 17:14:02 -0700 | [diff] [blame] | 228 |  | 
|  | 229 | if (needsBlending()) { | 
|  | 230 | hwcl->blending = mPremultipliedAlpha ? | 
|  | 231 | HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE; | 
|  | 232 | } | 
|  | 233 |  | 
|  | 234 | hwcl->displayFrame.left   = mTransformedBounds.left; | 
|  | 235 | hwcl->displayFrame.top    = mTransformedBounds.top; | 
|  | 236 | hwcl->displayFrame.right  = mTransformedBounds.right; | 
|  | 237 | hwcl->displayFrame.bottom = mTransformedBounds.bottom; | 
|  | 238 |  | 
|  | 239 | hwcl->visibleRegionScreen.rects = | 
|  | 240 | reinterpret_cast<hwc_rect_t const *>( | 
|  | 241 | visibleRegionScreen.getArray( | 
|  | 242 | &hwcl->visibleRegionScreen.numRects)); | 
|  | 243 | } | 
|  | 244 |  | 
|  | 245 | void Layer::setPerFrameData(hwc_layer_t* hwcl) { | 
|  | 246 | sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer()); | 
|  | 247 | if (buffer == NULL) { | 
| Mathias Agopian | da9584d | 2010-12-13 18:51:59 -0800 | [diff] [blame] | 248 | // this can happen if the client never drew into this layer yet, | 
|  | 249 | // or if we ran out of memory. In that case, don't let | 
|  | 250 | // HWC handle it. | 
|  | 251 | hwcl->flags |= HWC_SKIP_LAYER; | 
| Mathias Agopian | a350ff9 | 2010-08-10 17:14:02 -0700 | [diff] [blame] | 252 | hwcl->handle = NULL; | 
|  | 253 | return; | 
|  | 254 | } | 
| Louis Huemiller | 0404814 | 2010-12-01 12:29:36 -0800 | [diff] [blame] | 255 | hwcl->handle = buffer->handle; | 
| Mathias Agopian | f345069 | 2010-12-08 17:40:28 -0800 | [diff] [blame] | 256 |  | 
|  | 257 | if (!mBufferCrop.isEmpty()) { | 
|  | 258 | hwcl->sourceCrop.left   = mBufferCrop.left; | 
|  | 259 | hwcl->sourceCrop.top    = mBufferCrop.top; | 
|  | 260 | hwcl->sourceCrop.right  = mBufferCrop.right; | 
|  | 261 | hwcl->sourceCrop.bottom = mBufferCrop.bottom; | 
|  | 262 | } else { | 
|  | 263 | hwcl->sourceCrop.left   = 0; | 
|  | 264 | hwcl->sourceCrop.top    = 0; | 
|  | 265 | hwcl->sourceCrop.right  = buffer->width; | 
|  | 266 | hwcl->sourceCrop.bottom = buffer->height; | 
|  | 267 | } | 
| Mathias Agopian | a350ff9 | 2010-08-10 17:14:02 -0700 | [diff] [blame] | 268 | } | 
|  | 269 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 270 | void Layer::reloadTexture(const Region& dirty) | 
|  | 271 | { | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 272 | sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer()); | 
| Mathias Agopian | 8f03b47 | 2009-12-10 15:52:29 -0800 | [diff] [blame] | 273 | if (buffer == NULL) { | 
|  | 274 | // this situation can happen if we ran out of memory for instance. | 
|  | 275 | // not much we can do. continue to use whatever texture was bound | 
|  | 276 | // to this context. | 
|  | 277 | return; | 
|  | 278 | } | 
|  | 279 |  | 
| Mathias Agopian | 1f7bec6 | 2010-06-25 18:02:21 -0700 | [diff] [blame] | 280 | if (mGLExtensions.haveDirectTexture()) { | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 281 | EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); | 
|  | 282 | if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) { | 
|  | 283 | // not sure what we can do here... | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 284 | goto slowpath; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 285 | } | 
| Mathias Agopian | 1f7bec6 | 2010-06-25 18:02:21 -0700 | [diff] [blame] | 286 | } else { | 
| Mathias Agopian | fcfeb4b | 2010-03-08 11:14:20 -0800 | [diff] [blame] | 287 | slowpath: | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 288 | GGLSurface t; | 
| Mathias Agopian | f1b3824 | 2010-08-20 15:59:53 -0700 | [diff] [blame] | 289 | if (buffer->usage & GRALLOC_USAGE_SW_READ_MASK) { | 
|  | 290 | status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN); | 
|  | 291 | LOGE_IF(res, "error %d (%s) locking buffer %p", | 
|  | 292 | res, strerror(res), buffer.get()); | 
|  | 293 | if (res == NO_ERROR) { | 
|  | 294 | mBufferManager.loadTexture(dirty, t); | 
|  | 295 | buffer->unlock(); | 
|  | 296 | } | 
|  | 297 | } else { | 
|  | 298 | // we can't do anything | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 299 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 300 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 301 | } | 
|  | 302 |  | 
| Mathias Agopian | 74c40c0 | 2010-09-29 13:02:36 -0700 | [diff] [blame] | 303 | void Layer::drawForSreenShot() const | 
|  | 304 | { | 
| Mathias Agopian | 733189d | 2010-12-02 21:32:29 -0800 | [diff] [blame] | 305 | const bool currentFiltering = mNeedsFiltering; | 
|  | 306 | const_cast<Layer*>(this)->mNeedsFiltering = true; | 
| Mathias Agopian | 74c40c0 | 2010-09-29 13:02:36 -0700 | [diff] [blame] | 307 | LayerBase::drawForSreenShot(); | 
| Mathias Agopian | 733189d | 2010-12-02 21:32:29 -0800 | [diff] [blame] | 308 | const_cast<Layer*>(this)->mNeedsFiltering = currentFiltering; | 
| Mathias Agopian | 74c40c0 | 2010-09-29 13:02:36 -0700 | [diff] [blame] | 309 | } | 
|  | 310 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 311 | void Layer::onDraw(const Region& clip) const | 
|  | 312 | { | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 313 | Texture tex(mBufferManager.getActiveTexture()); | 
|  | 314 | if (tex.name == -1LU) { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 315 | // the texture has not been created yet, this Layer has | 
| Mathias Agopian | 179169e | 2010-05-06 20:21:45 -0700 | [diff] [blame] | 316 | // in fact never been drawn into. This happens frequently with | 
|  | 317 | // SurfaceView because the WindowManager can't know when the client | 
|  | 318 | // has drawn the first time. | 
|  | 319 |  | 
|  | 320 | // If there is nothing under us, we paint the screen in black, otherwise | 
|  | 321 | // we just skip this update. | 
|  | 322 |  | 
|  | 323 | // figure out if there is something below us | 
|  | 324 | Region under; | 
|  | 325 | const SurfaceFlinger::LayerVector& drawingLayers(mFlinger->mDrawingState.layersSortedByZ); | 
|  | 326 | const size_t count = drawingLayers.size(); | 
|  | 327 | for (size_t i=0 ; i<count ; ++i) { | 
|  | 328 | const sp<LayerBase>& layer(drawingLayers[i]); | 
|  | 329 | if (layer.get() == static_cast<LayerBase const*>(this)) | 
|  | 330 | break; | 
|  | 331 | under.orSelf(layer->visibleRegionScreen); | 
|  | 332 | } | 
|  | 333 | // if not everything below us is covered, we plug the holes! | 
|  | 334 | Region holes(clip.subtract(under)); | 
|  | 335 | if (!holes.isEmpty()) { | 
| Mathias Agopian | 0a91775 | 2010-06-14 21:20:00 -0700 | [diff] [blame] | 336 | clearWithOpenGL(holes, 0, 0, 0, 1); | 
| Mathias Agopian | 179169e | 2010-05-06 20:21:45 -0700 | [diff] [blame] | 337 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 338 | return; | 
|  | 339 | } | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 340 | drawWithOpenGL(clip, tex); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 341 | } | 
|  | 342 |  | 
| Mathias Agopian | a7f6692 | 2010-05-26 22:08:52 -0700 | [diff] [blame] | 343 | bool Layer::needsFiltering() const | 
|  | 344 | { | 
|  | 345 | if (!(mFlags & DisplayHardware::SLOW_CONFIG)) { | 
| Mathias Agopian | 733189d | 2010-12-02 21:32:29 -0800 | [diff] [blame] | 346 | // if our buffer is not the same size than ourselves, | 
|  | 347 | // we need filtering. | 
|  | 348 | Mutex::Autolock _l(mLock); | 
|  | 349 | if (mNeedsScaling) | 
| Mathias Agopian | a7f6692 | 2010-05-26 22:08:52 -0700 | [diff] [blame] | 350 | return true; | 
|  | 351 | } | 
|  | 352 | return LayerBase::needsFiltering(); | 
|  | 353 | } | 
|  | 354 |  | 
| Mathias Agopian | b5b7f26 | 2010-05-07 15:58:44 -0700 | [diff] [blame] | 355 |  | 
|  | 356 | status_t Layer::setBufferCount(int bufferCount) | 
|  | 357 | { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 358 | ClientRef::Access sharedClient(mUserClientRef); | 
|  | 359 | SharedBufferServer* lcblk(sharedClient.get()); | 
|  | 360 | if (!lcblk) { | 
| Mathias Agopian | b5b7f26 | 2010-05-07 15:58:44 -0700 | [diff] [blame] | 361 | // oops, the client is already gone | 
|  | 362 | return DEAD_OBJECT; | 
|  | 363 | } | 
|  | 364 |  | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 365 | // NOTE: lcblk->resize() is protected by an internal lock | 
|  | 366 | status_t err = lcblk->resize(bufferCount); | 
| Jamie Gennis | 54cc83e | 2010-11-02 11:51:32 -0700 | [diff] [blame] | 367 | if (err == NO_ERROR) { | 
|  | 368 | EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); | 
|  | 369 | mBufferManager.resize(bufferCount, mFlinger, dpy); | 
|  | 370 | } | 
| Mathias Agopian | b5b7f26 | 2010-05-07 15:58:44 -0700 | [diff] [blame] | 371 |  | 
|  | 372 | return err; | 
|  | 373 | } | 
|  | 374 |  | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 375 | sp<GraphicBuffer> Layer::requestBuffer(int index, | 
|  | 376 | uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat, | 
|  | 377 | uint32_t usage) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 378 | { | 
| Mathias Agopian | 3330b20 | 2009-10-05 17:07:12 -0700 | [diff] [blame] | 379 | sp<GraphicBuffer> buffer; | 
| Mathias Agopian | 48d819a | 2009-09-10 19:41:18 -0700 | [diff] [blame] | 380 |  | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 381 | if (int32_t(reqWidth | reqHeight | reqFormat) < 0) | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 382 | return buffer; | 
|  | 383 |  | 
|  | 384 | if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight)) | 
|  | 385 | return buffer; | 
|  | 386 |  | 
| Mathias Agopian | 48d819a | 2009-09-10 19:41:18 -0700 | [diff] [blame] | 387 | // this ensures our client doesn't go away while we're accessing | 
|  | 388 | // the shared area. | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 389 | ClientRef::Access sharedClient(mUserClientRef); | 
|  | 390 | SharedBufferServer* lcblk(sharedClient.get()); | 
|  | 391 | if (!lcblk) { | 
| Mathias Agopian | 48d819a | 2009-09-10 19:41:18 -0700 | [diff] [blame] | 392 | // oops, the client is already gone | 
|  | 393 | return buffer; | 
|  | 394 | } | 
|  | 395 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 396 | /* | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 397 | * This is called from the client's Surface::dequeue(). This can happen | 
|  | 398 | * at any time, especially while we're in the middle of using the | 
|  | 399 | * buffer 'index' as our front buffer. | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 400 | */ | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 401 |  | 
| Mathias Agopian | 208cb07 | 2010-07-27 20:11:35 -0700 | [diff] [blame] | 402 | status_t err = NO_ERROR; | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 403 | uint32_t w, h, f; | 
| Mathias Agopian | 48d819a | 2009-09-10 19:41:18 -0700 | [diff] [blame] | 404 | { // scope for the lock | 
|  | 405 | Mutex::Autolock _l(mLock); | 
| Mathias Agopian | eff062c | 2010-08-25 14:59:15 -0700 | [diff] [blame] | 406 |  | 
|  | 407 | // zero means default | 
| Mathias Agopian | e44d21a | 2010-09-21 10:52:42 -0700 | [diff] [blame] | 408 | const bool fixedSize = reqWidth && reqHeight; | 
| Mathias Agopian | eff062c | 2010-08-25 14:59:15 -0700 | [diff] [blame] | 409 | if (!reqFormat) reqFormat = mFormat; | 
|  | 410 | if (!reqWidth)  reqWidth = mWidth; | 
|  | 411 | if (!reqHeight) reqHeight = mHeight; | 
|  | 412 |  | 
|  | 413 | w = reqWidth; | 
|  | 414 | h = reqHeight; | 
|  | 415 | f = reqFormat; | 
|  | 416 |  | 
|  | 417 | if ((reqWidth != mReqWidth) || (reqHeight != mReqHeight) || | 
|  | 418 | (reqFormat != mReqFormat)) { | 
|  | 419 | mReqWidth  = reqWidth; | 
|  | 420 | mReqHeight = reqHeight; | 
|  | 421 | mReqFormat = reqFormat; | 
| Mathias Agopian | e44d21a | 2010-09-21 10:52:42 -0700 | [diff] [blame] | 422 | mFixedSize = fixedSize; | 
| Mathias Agopian | 733189d | 2010-12-02 21:32:29 -0800 | [diff] [blame] | 423 | mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight; | 
| Mathias Agopian | eff062c | 2010-08-25 14:59:15 -0700 | [diff] [blame] | 424 |  | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 425 | lcblk->reallocateAllExcept(index); | 
|  | 426 | } | 
| Mathias Agopian | 48d819a | 2009-09-10 19:41:18 -0700 | [diff] [blame] | 427 | } | 
|  | 428 |  | 
| Mathias Agopian | 208cb07 | 2010-07-27 20:11:35 -0700 | [diff] [blame] | 429 | // here we have to reallocate a new buffer because the buffer could be | 
|  | 430 | // used as the front buffer, or by a client in our process | 
|  | 431 | // (eg: status bar), and we can't release the handle under its feet. | 
| Mathias Agopian | 3330b20 | 2009-10-05 17:07:12 -0700 | [diff] [blame] | 432 | const uint32_t effectiveUsage = getEffectiveUsage(usage); | 
| Mathias Agopian | 208cb07 | 2010-07-27 20:11:35 -0700 | [diff] [blame] | 433 | buffer = new GraphicBuffer(w, h, f, effectiveUsage); | 
|  | 434 | err = buffer->initCheck(); | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 435 |  | 
|  | 436 | if (err || buffer->handle == 0) { | 
| Mathias Agopian | 678bdd6 | 2010-12-03 17:33:09 -0800 | [diff] [blame] | 437 | GraphicBuffer::dumpAllocationsToSystemLog(); | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 438 | LOGE_IF(err || buffer->handle == 0, | 
|  | 439 | "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)", | 
|  | 440 | this, index, w, h, strerror(-err)); | 
|  | 441 | } else { | 
|  | 442 | LOGD_IF(DEBUG_RESIZE, | 
| Mathias Agopian | 7e4a587 | 2009-09-29 22:39:22 -0700 | [diff] [blame] | 443 | "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d, handle=%p", | 
|  | 444 | this, index, w, h, buffer->handle); | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 445 | } | 
|  | 446 |  | 
|  | 447 | if (err == NO_ERROR && buffer->handle != 0) { | 
| Mathias Agopian | 48d819a | 2009-09-10 19:41:18 -0700 | [diff] [blame] | 448 | Mutex::Autolock _l(mLock); | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 449 | mBufferManager.attachBuffer(index, buffer); | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 450 | } | 
|  | 451 | return buffer; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 452 | } | 
|  | 453 |  | 
| Mathias Agopian | 3330b20 | 2009-10-05 17:07:12 -0700 | [diff] [blame] | 454 | uint32_t Layer::getEffectiveUsage(uint32_t usage) const | 
|  | 455 | { | 
|  | 456 | /* | 
|  | 457 | *  buffers used for software rendering, but h/w composition | 
|  | 458 | *  are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE | 
|  | 459 | * | 
|  | 460 | *  buffers used for h/w rendering and h/w composition | 
|  | 461 | *  are allocated with  HW_RENDER | HW_TEXTURE | 
|  | 462 | * | 
|  | 463 | *  buffers used with h/w rendering and either NPOT or no egl_image_ext | 
|  | 464 | *  are allocated with SW_READ_RARELY | HW_RENDER | 
|  | 465 | * | 
|  | 466 | */ | 
|  | 467 |  | 
|  | 468 | if (mSecure) { | 
|  | 469 | // secure buffer, don't store it into the GPU | 
|  | 470 | usage = GraphicBuffer::USAGE_SW_READ_OFTEN | | 
|  | 471 | GraphicBuffer::USAGE_SW_WRITE_OFTEN; | 
|  | 472 | } else { | 
|  | 473 | // it's allowed to modify the usage flags here, but generally | 
|  | 474 | // the requested flags should be honored. | 
| Mathias Agopian | 89141f9 | 2010-05-10 20:10:10 -0700 | [diff] [blame] | 475 | // request EGLImage for all buffers | 
|  | 476 | usage |= GraphicBuffer::USAGE_HW_TEXTURE; | 
| Mathias Agopian | 3330b20 | 2009-10-05 17:07:12 -0700 | [diff] [blame] | 477 | } | 
|  | 478 | return usage; | 
|  | 479 | } | 
|  | 480 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 481 | uint32_t Layer::doTransaction(uint32_t flags) | 
|  | 482 | { | 
|  | 483 | const Layer::State& front(drawingState()); | 
|  | 484 | const Layer::State& temp(currentState()); | 
|  | 485 |  | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 486 | const bool sizeChanged = (front.requested_w != temp.requested_w) || | 
|  | 487 | (front.requested_h != temp.requested_h); | 
|  | 488 |  | 
|  | 489 | if (sizeChanged) { | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 490 | // the size changed, we need to ask our client to request a new buffer | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 491 | LOGD_IF(DEBUG_RESIZE, | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 492 | "resize (layer=%p), requested (%dx%d), drawing (%d,%d)", | 
|  | 493 | this, | 
|  | 494 | int(temp.requested_w), int(temp.requested_h), | 
|  | 495 | int(front.requested_w), int(front.requested_h)); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 496 |  | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 497 | if (!isFixedSize()) { | 
|  | 498 | // we're being resized and there is a freeze display request, | 
|  | 499 | // acquire a freeze lock, so that the screen stays put | 
|  | 500 | // until we've redrawn at the new size; this is to avoid | 
|  | 501 | // glitches upon orientation changes. | 
|  | 502 | if (mFlinger->hasFreezeRequest()) { | 
|  | 503 | // if the surface is hidden, don't try to acquire the | 
|  | 504 | // freeze lock, since hidden surfaces may never redraw | 
|  | 505 | if (!(front.flags & ISurfaceComposer::eLayerHidden)) { | 
|  | 506 | mFreezeLock = mFlinger->getFreezeLock(); | 
|  | 507 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 508 | } | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 509 |  | 
|  | 510 | // this will make sure LayerBase::doTransaction doesn't update | 
|  | 511 | // the drawing state's size | 
|  | 512 | Layer::State& editDraw(mDrawingState); | 
|  | 513 | editDraw.requested_w = temp.requested_w; | 
|  | 514 | editDraw.requested_h = temp.requested_h; | 
|  | 515 |  | 
|  | 516 | // record the new size, form this point on, when the client request | 
|  | 517 | // a buffer, it'll get the new size. | 
|  | 518 | setBufferSize(temp.requested_w, temp.requested_h); | 
|  | 519 |  | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 520 | ClientRef::Access sharedClient(mUserClientRef); | 
|  | 521 | SharedBufferServer* lcblk(sharedClient.get()); | 
|  | 522 | if (lcblk) { | 
| Mathias Agopian | 96f0819 | 2010-06-02 23:28:45 -0700 | [diff] [blame] | 523 | // all buffers need reallocation | 
|  | 524 | lcblk->reallocateAll(); | 
|  | 525 | } | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 526 | } else { | 
|  | 527 | // record the new size | 
|  | 528 | setBufferSize(temp.requested_w, temp.requested_h); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 529 | } | 
|  | 530 | } | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 531 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 532 | if (temp.sequence != front.sequence) { | 
|  | 533 | if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) { | 
|  | 534 | // this surface is now hidden, so it shouldn't hold a freeze lock | 
|  | 535 | // (it may never redraw, which is fine if it is hidden) | 
|  | 536 | mFreezeLock.clear(); | 
|  | 537 | } | 
|  | 538 | } | 
|  | 539 |  | 
|  | 540 | return LayerBase::doTransaction(flags); | 
|  | 541 | } | 
|  | 542 |  | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 543 | void Layer::setBufferSize(uint32_t w, uint32_t h) { | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 544 | Mutex::Autolock _l(mLock); | 
|  | 545 | mWidth = w; | 
|  | 546 | mHeight = h; | 
| Mathias Agopian | 733189d | 2010-12-02 21:32:29 -0800 | [diff] [blame] | 547 | mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 548 | } | 
|  | 549 |  | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 550 | bool Layer::isFixedSize() const { | 
|  | 551 | Mutex::Autolock _l(mLock); | 
|  | 552 | return mFixedSize; | 
|  | 553 | } | 
|  | 554 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 555 | // ---------------------------------------------------------------------------- | 
|  | 556 | // pageflip handling... | 
|  | 557 | // ---------------------------------------------------------------------------- | 
|  | 558 |  | 
|  | 559 | void Layer::lockPageFlip(bool& recomputeVisibleRegions) | 
|  | 560 | { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 561 | ClientRef::Access sharedClient(mUserClientRef); | 
|  | 562 | SharedBufferServer* lcblk(sharedClient.get()); | 
|  | 563 | if (!lcblk) { | 
| Mathias Agopian | 96f0819 | 2010-06-02 23:28:45 -0700 | [diff] [blame] | 564 | // client died | 
|  | 565 | recomputeVisibleRegions = true; | 
|  | 566 | return; | 
|  | 567 | } | 
|  | 568 |  | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 569 | ssize_t buf = lcblk->retireAndLock(); | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 570 | if (buf == NOT_ENOUGH_DATA) { | 
|  | 571 | // NOTE: This is not an error, it simply means there is nothing to | 
|  | 572 | // retire. The buffer is locked because we will use it | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 573 | // for composition later in the loop | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 574 | return; | 
|  | 575 | } | 
| Mathias Agopian | d343e3d | 2010-03-15 18:15:20 -0700 | [diff] [blame] | 576 |  | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 577 | if (buf < NO_ERROR) { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 578 | LOGE("retireAndLock() buffer index (%d) out of range", int(buf)); | 
| Mathias Agopian | d343e3d | 2010-03-15 18:15:20 -0700 | [diff] [blame] | 579 | mPostedDirtyRegion.clear(); | 
|  | 580 | return; | 
|  | 581 | } | 
|  | 582 |  | 
| Mathias Agopian | cbb288b | 2009-09-07 16:32:45 -0700 | [diff] [blame] | 583 | // we retired a buffer, which becomes the new front buffer | 
| Mathias Agopian | da9584d | 2010-12-13 18:51:59 -0800 | [diff] [blame] | 584 |  | 
|  | 585 | const bool noActiveBuffer = !mBufferManager.hasActiveBuffer(); | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 586 | if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 587 | LOGE("retireAndLock() buffer index (%d) out of range", int(buf)); | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 588 | mPostedDirtyRegion.clear(); | 
|  | 589 | return; | 
|  | 590 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 591 |  | 
| Mathias Agopian | da9584d | 2010-12-13 18:51:59 -0800 | [diff] [blame] | 592 | if (noActiveBuffer) { | 
|  | 593 | // we didn't have an active buffer, we need to recompute | 
|  | 594 | // our visible region | 
|  | 595 | recomputeVisibleRegions = true; | 
|  | 596 | } | 
|  | 597 |  | 
| Mathias Agopian | 3330b20 | 2009-10-05 17:07:12 -0700 | [diff] [blame] | 598 | sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); | 
| Mathias Agopian | d343e3d | 2010-03-15 18:15:20 -0700 | [diff] [blame] | 599 | if (newFrontBuffer != NULL) { | 
| Mathias Agopian | b661d66 | 2010-08-19 17:01:19 -0700 | [diff] [blame] | 600 | // get the dirty region | 
| Mathias Agopian | d343e3d | 2010-03-15 18:15:20 -0700 | [diff] [blame] | 601 | // compute the posted region | 
|  | 602 | const Region dirty(lcblk->getDirtyRegion(buf)); | 
|  | 603 | mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() ); | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 604 |  | 
| Mathias Agopian | d343e3d | 2010-03-15 18:15:20 -0700 | [diff] [blame] | 605 | // update the layer size and release freeze-lock | 
|  | 606 | const Layer::State& front(drawingState()); | 
|  | 607 | if (newFrontBuffer->getWidth()  == front.requested_w && | 
|  | 608 | newFrontBuffer->getHeight() == front.requested_h) | 
| Mathias Agopian | df3e0b9 | 2009-09-30 14:07:22 -0700 | [diff] [blame] | 609 | { | 
| Mathias Agopian | d343e3d | 2010-03-15 18:15:20 -0700 | [diff] [blame] | 610 | if ((front.w != front.requested_w) || | 
|  | 611 | (front.h != front.requested_h)) | 
|  | 612 | { | 
|  | 613 | // Here we pretend the transaction happened by updating the | 
|  | 614 | // current and drawing states. Drawing state is only accessed | 
|  | 615 | // in this thread, no need to have it locked | 
|  | 616 | Layer::State& editDraw(mDrawingState); | 
|  | 617 | editDraw.w = editDraw.requested_w; | 
|  | 618 | editDraw.h = editDraw.requested_h; | 
| Mathias Agopian | df3e0b9 | 2009-09-30 14:07:22 -0700 | [diff] [blame] | 619 |  | 
| Mathias Agopian | d343e3d | 2010-03-15 18:15:20 -0700 | [diff] [blame] | 620 | // We also need to update the current state so that we don't | 
|  | 621 | // end-up doing too much work during the next transaction. | 
|  | 622 | // NOTE: We actually don't need hold the transaction lock here | 
|  | 623 | // because State::w and State::h are only accessed from | 
|  | 624 | // this thread | 
|  | 625 | Layer::State& editTemp(currentState()); | 
|  | 626 | editTemp.w = editDraw.w; | 
|  | 627 | editTemp.h = editDraw.h; | 
| Mathias Agopian | df3e0b9 | 2009-09-30 14:07:22 -0700 | [diff] [blame] | 628 |  | 
| Mathias Agopian | d343e3d | 2010-03-15 18:15:20 -0700 | [diff] [blame] | 629 | // recompute visible region | 
|  | 630 | recomputeVisibleRegions = true; | 
|  | 631 | } | 
|  | 632 |  | 
|  | 633 | // we now have the correct size, unfreeze the screen | 
|  | 634 | mFreezeLock.clear(); | 
| Mathias Agopian | df3e0b9 | 2009-09-30 14:07:22 -0700 | [diff] [blame] | 635 | } | 
| Mathias Agopian | b661d66 | 2010-08-19 17:01:19 -0700 | [diff] [blame] | 636 |  | 
|  | 637 | // get the crop region | 
|  | 638 | setBufferCrop( lcblk->getCrop(buf) ); | 
|  | 639 |  | 
|  | 640 | // get the transformation | 
|  | 641 | setBufferTransform( lcblk->getTransform(buf) ); | 
|  | 642 |  | 
| Mathias Agopian | d343e3d | 2010-03-15 18:15:20 -0700 | [diff] [blame] | 643 | } else { | 
|  | 644 | // this should not happen unless we ran out of memory while | 
|  | 645 | // allocating the buffer. we're hoping that things will get back | 
|  | 646 | // to normal the next time the app tries to draw into this buffer. | 
|  | 647 | // meanwhile, pretend the screen didn't update. | 
|  | 648 | mPostedDirtyRegion.clear(); | 
| Mathias Agopian | caa600c | 2009-09-16 18:27:24 -0700 | [diff] [blame] | 649 | } | 
|  | 650 |  | 
| Mathias Agopian | e700501 | 2009-10-07 16:44:10 -0700 | [diff] [blame] | 651 | if (lcblk->getQueuedCount()) { | 
|  | 652 | // signal an event if we have more buffers waiting | 
|  | 653 | mFlinger->signalEvent(); | 
|  | 654 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 655 |  | 
| Mathias Agopian | 245e4d7 | 2010-04-21 15:24:11 -0700 | [diff] [blame] | 656 | /* a buffer was posted, so we need to call reloadTexture(), which | 
|  | 657 | * will update our internal data structures (eg: EGLImageKHR or | 
|  | 658 | * texture names). we need to do this even if mPostedDirtyRegion is | 
|  | 659 | * empty -- it's orthogonal to the fact that a new buffer was posted, | 
|  | 660 | * for instance, a degenerate case could be that the user did an empty | 
|  | 661 | * update but repainted the buffer with appropriate content (after a | 
|  | 662 | * resize for instance). | 
|  | 663 | */ | 
|  | 664 | reloadTexture( mPostedDirtyRegion ); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 665 | } | 
|  | 666 |  | 
|  | 667 | void Layer::unlockPageFlip( | 
|  | 668 | const Transform& planeTransform, Region& outDirtyRegion) | 
|  | 669 | { | 
|  | 670 | Region dirtyRegion(mPostedDirtyRegion); | 
|  | 671 | if (!dirtyRegion.isEmpty()) { | 
|  | 672 | mPostedDirtyRegion.clear(); | 
|  | 673 | // The dirty region is given in the layer's coordinate space | 
|  | 674 | // transform the dirty region by the surface's transformation | 
|  | 675 | // and the global transformation. | 
|  | 676 | const Layer::State& s(drawingState()); | 
|  | 677 | const Transform tr(planeTransform * s.transform); | 
|  | 678 | dirtyRegion = tr.transform(dirtyRegion); | 
|  | 679 |  | 
|  | 680 | // At this point, the dirty region is in screen space. | 
|  | 681 | // Make sure it's constrained by the visible region (which | 
|  | 682 | // is in screen space as well). | 
|  | 683 | dirtyRegion.andSelf(visibleRegionScreen); | 
|  | 684 | outDirtyRegion.orSelf(dirtyRegion); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 685 | } | 
| Mathias Agopian | c61de17 | 2009-11-30 11:15:41 -0800 | [diff] [blame] | 686 | if (visibleRegionScreen.isEmpty()) { | 
|  | 687 | // an invisible layer should not hold a freeze-lock | 
| Mathias Agopian | 1b5e102 | 2010-04-20 17:55:49 -0700 | [diff] [blame] | 688 | // (because it may never be updated and therefore never release it) | 
| Mathias Agopian | c61de17 | 2009-11-30 11:15:41 -0800 | [diff] [blame] | 689 | mFreezeLock.clear(); | 
|  | 690 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 691 | } | 
|  | 692 |  | 
| Mathias Agopian | 1b5e102 | 2010-04-20 17:55:49 -0700 | [diff] [blame] | 693 | void Layer::dump(String8& result, char* buffer, size_t SIZE) const | 
|  | 694 | { | 
|  | 695 | LayerBaseClient::dump(result, buffer, SIZE); | 
|  | 696 |  | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 697 | ClientRef::Access sharedClient(mUserClientRef); | 
|  | 698 | SharedBufferServer* lcblk(sharedClient.get()); | 
|  | 699 | uint32_t totalTime = 0; | 
|  | 700 | if (lcblk) { | 
|  | 701 | SharedBufferStack::Statistics stats = lcblk->getStats(); | 
|  | 702 | totalTime= stats.totalTime; | 
|  | 703 | result.append( lcblk->dump("      ") ); | 
|  | 704 | } | 
|  | 705 |  | 
| Mathias Agopian | 1b5e102 | 2010-04-20 17:55:49 -0700 | [diff] [blame] | 706 | sp<const GraphicBuffer> buf0(getBuffer(0)); | 
|  | 707 | sp<const GraphicBuffer> buf1(getBuffer(1)); | 
|  | 708 | uint32_t w0=0, h0=0, s0=0; | 
|  | 709 | uint32_t w1=0, h1=0, s1=0; | 
|  | 710 | if (buf0 != 0) { | 
|  | 711 | w0 = buf0->getWidth(); | 
|  | 712 | h0 = buf0->getHeight(); | 
|  | 713 | s0 = buf0->getStride(); | 
|  | 714 | } | 
|  | 715 | if (buf1 != 0) { | 
|  | 716 | w1 = buf1->getWidth(); | 
|  | 717 | h1 = buf1->getHeight(); | 
|  | 718 | s1 = buf1->getStride(); | 
|  | 719 | } | 
|  | 720 | snprintf(buffer, SIZE, | 
|  | 721 | "      " | 
|  | 722 | "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u]," | 
|  | 723 | " freezeLock=%p, dq-q-time=%u us\n", | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 724 | mFormat, w0, h0, s0, w1, h1, s1, | 
|  | 725 | getFreezeLock().get(), totalTime); | 
| Mathias Agopian | 1b5e102 | 2010-04-20 17:55:49 -0700 | [diff] [blame] | 726 |  | 
|  | 727 | result.append(buffer); | 
|  | 728 | } | 
|  | 729 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 730 | // --------------------------------------------------------------------------- | 
|  | 731 |  | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 732 | Layer::ClientRef::ClientRef() | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 733 | : mControlBlock(0), mToken(-1) { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 734 | } | 
|  | 735 |  | 
|  | 736 | Layer::ClientRef::~ClientRef() { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 737 | } | 
|  | 738 |  | 
|  | 739 | int32_t Layer::ClientRef::getToken() const { | 
|  | 740 | Mutex::Autolock _l(mLock); | 
|  | 741 | return mToken; | 
|  | 742 | } | 
|  | 743 |  | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 744 | sp<UserClient> Layer::ClientRef::getClient() const { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 745 | Mutex::Autolock _l(mLock); | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 746 | return mUserClient.promote(); | 
|  | 747 | } | 
|  | 748 |  | 
|  | 749 | status_t Layer::ClientRef::setToken(const sp<UserClient>& uc, | 
|  | 750 | const sp<SharedBufferServer>& sharedClient, int32_t token) { | 
|  | 751 | Mutex::Autolock _l(mLock); | 
|  | 752 |  | 
|  | 753 | { // scope for strong mUserClient reference | 
|  | 754 | sp<UserClient> userClient(mUserClient.promote()); | 
|  | 755 | if (mUserClient != 0 && mControlBlock != 0) { | 
|  | 756 | mControlBlock->setStatus(NO_INIT); | 
|  | 757 | } | 
|  | 758 | } | 
|  | 759 |  | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 760 | mUserClient = uc; | 
|  | 761 | mToken = token; | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 762 | mControlBlock = sharedClient; | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 763 | return NO_ERROR; | 
|  | 764 | } | 
|  | 765 |  | 
|  | 766 | sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const { | 
|  | 767 | return mUserClient.promote(); | 
|  | 768 | } | 
|  | 769 |  | 
|  | 770 | // this class gives us access to SharedBufferServer safely | 
|  | 771 | // it makes sure the UserClient (and its associated shared memory) | 
|  | 772 | // won't go away while we're accessing it. | 
|  | 773 | Layer::ClientRef::Access::Access(const ClientRef& ref) | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 774 | : mControlBlock(0) | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 775 | { | 
|  | 776 | Mutex::Autolock _l(ref.mLock); | 
|  | 777 | mUserClientStrongRef = ref.mUserClient.promote(); | 
|  | 778 | if (mUserClientStrongRef != 0) | 
| Mathias Agopian | 579b3f8 | 2010-06-08 19:54:15 -0700 | [diff] [blame] | 779 | mControlBlock = ref.mControlBlock; | 
|  | 780 | } | 
|  | 781 |  | 
|  | 782 | Layer::ClientRef::Access::~Access() | 
|  | 783 | { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 784 | } | 
|  | 785 |  | 
|  | 786 | // --------------------------------------------------------------------------- | 
|  | 787 |  | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 788 | Layer::BufferManager::BufferManager(TextureManager& tm) | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 789 | : mNumBuffers(NUM_BUFFERS), mTextureManager(tm), | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 790 | mActiveBufferIndex(-1), mFailover(false) | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 791 | { | 
|  | 792 | } | 
|  | 793 |  | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 794 | Layer::BufferManager::~BufferManager() | 
|  | 795 | { | 
|  | 796 | } | 
|  | 797 |  | 
| Jamie Gennis | 54cc83e | 2010-11-02 11:51:32 -0700 | [diff] [blame] | 798 | status_t Layer::BufferManager::resize(size_t size, | 
|  | 799 | const sp<SurfaceFlinger>& flinger, EGLDisplay dpy) | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 800 | { | 
|  | 801 | Mutex::Autolock _l(mLock); | 
| Jamie Gennis | 54cc83e | 2010-11-02 11:51:32 -0700 | [diff] [blame] | 802 |  | 
|  | 803 | if (size < mNumBuffers) { | 
|  | 804 | // Move the active texture into slot 0 | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 805 | BufferData activeBufferData = mBufferData[mActiveBufferIndex]; | 
|  | 806 | mBufferData[mActiveBufferIndex] = mBufferData[0]; | 
| Jamie Gennis | 54cc83e | 2010-11-02 11:51:32 -0700 | [diff] [blame] | 807 | mBufferData[0] = activeBufferData; | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 808 | mActiveBufferIndex = 0; | 
| Jamie Gennis | 54cc83e | 2010-11-02 11:51:32 -0700 | [diff] [blame] | 809 |  | 
|  | 810 | // Free the buffers that are no longer needed. | 
|  | 811 | for (size_t i = size; i < mNumBuffers; i++) { | 
|  | 812 | mBufferData[i].buffer = 0; | 
|  | 813 |  | 
|  | 814 | // Create a message to destroy the textures on SurfaceFlinger's GL | 
|  | 815 | // thread. | 
|  | 816 | class MessageDestroyTexture : public MessageBase { | 
|  | 817 | Image mTexture; | 
|  | 818 | EGLDisplay mDpy; | 
|  | 819 | public: | 
|  | 820 | MessageDestroyTexture(const Image& texture, EGLDisplay dpy) | 
|  | 821 | : mTexture(texture), mDpy(dpy) { } | 
|  | 822 | virtual bool handler() { | 
|  | 823 | status_t err = Layer::BufferManager::destroyTexture( | 
|  | 824 | &mTexture, mDpy); | 
|  | 825 | LOGE_IF(err<0, "error destroying texture: %d (%s)", | 
|  | 826 | mTexture.name, strerror(-err)); | 
|  | 827 | return true; // XXX: err == 0;  ???? | 
|  | 828 | } | 
|  | 829 | }; | 
|  | 830 |  | 
|  | 831 | MessageDestroyTexture *msg = new MessageDestroyTexture( | 
|  | 832 | mBufferData[i].texture, dpy); | 
|  | 833 |  | 
|  | 834 | // Don't allow this texture to be cleaned up by | 
|  | 835 | // BufferManager::destroy. | 
|  | 836 | mBufferData[i].texture.name = -1U; | 
|  | 837 | mBufferData[i].texture.image = EGL_NO_IMAGE_KHR; | 
|  | 838 |  | 
|  | 839 | // Post the message to the SurfaceFlinger object. | 
|  | 840 | flinger->postMessageAsync(msg); | 
|  | 841 | } | 
|  | 842 | } | 
|  | 843 |  | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 844 | mNumBuffers = size; | 
|  | 845 | return NO_ERROR; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 846 | } | 
|  | 847 |  | 
|  | 848 | // only for debugging | 
|  | 849 | sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const { | 
|  | 850 | return mBufferData[index].buffer; | 
|  | 851 | } | 
|  | 852 |  | 
|  | 853 | status_t Layer::BufferManager::setActiveBufferIndex(size_t index) { | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 854 | BufferData const * const buffers = mBufferData; | 
|  | 855 | Mutex::Autolock _l(mLock); | 
|  | 856 | mActiveBuffer = buffers[index].buffer; | 
|  | 857 | mActiveBufferIndex = index; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 858 | return NO_ERROR; | 
|  | 859 | } | 
|  | 860 |  | 
|  | 861 | size_t Layer::BufferManager::getActiveBufferIndex() const { | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 862 | return mActiveBufferIndex; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 863 | } | 
|  | 864 |  | 
|  | 865 | Texture Layer::BufferManager::getActiveTexture() const { | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 866 | Texture res; | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 867 | if (mFailover || mActiveBufferIndex<0) { | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 868 | res = mFailoverTexture; | 
|  | 869 | } else { | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 870 | static_cast<Image&>(res) = mBufferData[mActiveBufferIndex].texture; | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 871 | } | 
|  | 872 | return res; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 873 | } | 
|  | 874 |  | 
|  | 875 | sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const { | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 876 | return mActiveBuffer; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 877 | } | 
|  | 878 |  | 
| Mathias Agopian | da9584d | 2010-12-13 18:51:59 -0800 | [diff] [blame] | 879 | bool Layer::BufferManager::hasActiveBuffer() const { | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 880 | return mActiveBufferIndex >= 0; | 
| Mathias Agopian | da9584d | 2010-12-13 18:51:59 -0800 | [diff] [blame] | 881 | } | 
|  | 882 |  | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 883 | sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index) | 
|  | 884 | { | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 885 | BufferData* const buffers = mBufferData; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 886 | sp<GraphicBuffer> buffer; | 
|  | 887 | Mutex::Autolock _l(mLock); | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 888 | buffer = buffers[index].buffer; | 
|  | 889 | buffers[index].buffer = 0; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 890 | return buffer; | 
|  | 891 | } | 
|  | 892 |  | 
|  | 893 | status_t Layer::BufferManager::attachBuffer(size_t index, | 
|  | 894 | const sp<GraphicBuffer>& buffer) | 
|  | 895 | { | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 896 | BufferData* const buffers = mBufferData; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 897 | Mutex::Autolock _l(mLock); | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 898 | buffers[index].buffer = buffer; | 
|  | 899 | buffers[index].texture.dirty = true; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 900 | return NO_ERROR; | 
|  | 901 | } | 
|  | 902 |  | 
|  | 903 | status_t Layer::BufferManager::destroy(EGLDisplay dpy) | 
|  | 904 | { | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 905 | BufferData* const buffers = mBufferData; | 
|  | 906 | size_t num; | 
|  | 907 | { // scope for the lock | 
|  | 908 | Mutex::Autolock _l(mLock); | 
|  | 909 | num = mNumBuffers; | 
|  | 910 | for (size_t i=0 ; i<num ; i++) { | 
|  | 911 | buffers[i].buffer = 0; | 
|  | 912 | } | 
|  | 913 | } | 
|  | 914 | for (size_t i=0 ; i<num ; i++) { | 
|  | 915 | destroyTexture(&buffers[i].texture, dpy); | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 916 | } | 
|  | 917 | destroyTexture(&mFailoverTexture, dpy); | 
|  | 918 | return NO_ERROR; | 
|  | 919 | } | 
|  | 920 |  | 
|  | 921 | status_t Layer::BufferManager::initEglImage(EGLDisplay dpy, | 
|  | 922 | const sp<GraphicBuffer>& buffer) | 
|  | 923 | { | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 924 | status_t err = NO_INIT; | 
| Mathias Agopian | 420a283 | 2010-12-14 20:30:37 -0800 | [diff] [blame] | 925 | ssize_t index = mActiveBufferIndex; | 
| Mathias Agopian | b7e930d | 2010-06-01 15:12:58 -0700 | [diff] [blame] | 926 | if (index >= 0) { | 
| Mathias Agopian | 1f7bec6 | 2010-06-25 18:02:21 -0700 | [diff] [blame] | 927 | if (!mFailover) { | 
|  | 928 | Image& texture(mBufferData[index].texture); | 
|  | 929 | err = mTextureManager.initEglImage(&texture, dpy, buffer); | 
|  | 930 | // if EGLImage fails, we switch to regular texture mode, and we | 
|  | 931 | // free all resources associated with using EGLImages. | 
|  | 932 | if (err == NO_ERROR) { | 
|  | 933 | mFailover = false; | 
|  | 934 | destroyTexture(&mFailoverTexture, dpy); | 
|  | 935 | } else { | 
|  | 936 | mFailover = true; | 
|  | 937 | const size_t num = mNumBuffers; | 
|  | 938 | for (size_t i=0 ; i<num ; i++) { | 
|  | 939 | destroyTexture(&mBufferData[i].texture, dpy); | 
|  | 940 | } | 
| Andreas Huber | e049a95 | 2010-06-25 09:25:19 -0700 | [diff] [blame] | 941 | } | 
| Mathias Agopian | 1f7bec6 | 2010-06-25 18:02:21 -0700 | [diff] [blame] | 942 | } else { | 
|  | 943 | // we failed once, don't try again | 
|  | 944 | err = BAD_VALUE; | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 945 | } | 
|  | 946 | } | 
|  | 947 | return err; | 
|  | 948 | } | 
|  | 949 |  | 
|  | 950 | status_t Layer::BufferManager::loadTexture( | 
|  | 951 | const Region& dirty, const GGLSurface& t) | 
|  | 952 | { | 
|  | 953 | return mTextureManager.loadTexture(&mFailoverTexture, dirty, t); | 
|  | 954 | } | 
|  | 955 |  | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 956 | status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy) | 
|  | 957 | { | 
|  | 958 | if (tex->name != -1U) { | 
|  | 959 | glDeleteTextures(1, &tex->name); | 
|  | 960 | tex->name = -1U; | 
|  | 961 | } | 
|  | 962 | if (tex->image != EGL_NO_IMAGE_KHR) { | 
|  | 963 | eglDestroyImageKHR(dpy, tex->image); | 
|  | 964 | tex->image = EGL_NO_IMAGE_KHR; | 
|  | 965 | } | 
|  | 966 | return NO_ERROR; | 
|  | 967 | } | 
|  | 968 |  | 
| Mathias Agopian | d606de6 | 2010-05-10 20:06:11 -0700 | [diff] [blame] | 969 | // --------------------------------------------------------------------------- | 
|  | 970 |  | 
| Mathias Agopian | 9a11206 | 2009-04-17 19:36:26 -0700 | [diff] [blame] | 971 | Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger, | 
| Mathias Agopian | 96f0819 | 2010-06-02 23:28:45 -0700 | [diff] [blame] | 972 | const sp<Layer>& owner) | 
|  | 973 | : Surface(flinger, owner->getIdentity(), owner) | 
| Mathias Agopian | 9a11206 | 2009-04-17 19:36:26 -0700 | [diff] [blame] | 974 | { | 
|  | 975 | } | 
|  | 976 |  | 
|  | 977 | Layer::SurfaceLayer::~SurfaceLayer() | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 978 | { | 
|  | 979 | } | 
|  | 980 |  | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 981 | sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, | 
|  | 982 | uint32_t w, uint32_t h, uint32_t format, uint32_t usage) | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 983 | { | 
| Mathias Agopian | 3330b20 | 2009-10-05 17:07:12 -0700 | [diff] [blame] | 984 | sp<GraphicBuffer> buffer; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 985 | sp<Layer> owner(getOwner()); | 
|  | 986 | if (owner != 0) { | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 987 | /* | 
|  | 988 | * requestBuffer() cannot be called from the main thread | 
|  | 989 | * as it could cause a dead-lock, since it may have to wait | 
|  | 990 | * on conditions updated my the main thread. | 
|  | 991 | */ | 
| Mathias Agopian | a138f89 | 2010-05-21 17:24:35 -0700 | [diff] [blame] | 992 | buffer = owner->requestBuffer(index, w, h, format, usage); | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 993 | } | 
|  | 994 | return buffer; | 
|  | 995 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 996 |  | 
| Mathias Agopian | b5b7f26 | 2010-05-07 15:58:44 -0700 | [diff] [blame] | 997 | status_t Layer::SurfaceLayer::setBufferCount(int bufferCount) | 
|  | 998 | { | 
|  | 999 | status_t err = DEAD_OBJECT; | 
|  | 1000 | sp<Layer> owner(getOwner()); | 
|  | 1001 | if (owner != 0) { | 
| Mathias Agopian | bb64124 | 2010-05-18 17:06:55 -0700 | [diff] [blame] | 1002 | /* | 
|  | 1003 | * setBufferCount() cannot be called from the main thread | 
|  | 1004 | * as it could cause a dead-lock, since it may have to wait | 
|  | 1005 | * on conditions updated my the main thread. | 
|  | 1006 | */ | 
| Mathias Agopian | b5b7f26 | 2010-05-07 15:58:44 -0700 | [diff] [blame] | 1007 | err = owner->setBufferCount(bufferCount); | 
|  | 1008 | } | 
|  | 1009 | return err; | 
|  | 1010 | } | 
|  | 1011 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1012 | // --------------------------------------------------------------------------- | 
|  | 1013 |  | 
|  | 1014 |  | 
|  | 1015 | }; // namespace android |