blob: 5b9327dd619d05433de48360703afaf4dd9d297f [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
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
Jamie Gennis1c8e95c2012-02-23 19:27:23 -080017#define ATRACE_TAG ATRACE_TAG_GRAPHICS
18
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080019#include <stdlib.h>
20#include <stdint.h>
21#include <sys/types.h>
Mathias Agopian90ac7992012-02-25 18:48:35 -080022#include <math.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080023
Mathias Agopiana67932f2011-04-20 14:20:59 -070024#include <cutils/compiler.h>
Mathias Agopian076b1cc2009-04-10 14:24:30 -070025#include <cutils/native_handle.h>
Mathias Agopiana67932f2011-04-20 14:20:59 -070026#include <cutils/properties.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080027
28#include <utils/Errors.h>
29#include <utils/Log.h>
30#include <utils/StopWatch.h>
Jamie Gennis1c8e95c2012-02-23 19:27:23 -080031#include <utils/Trace.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080032
Mathias Agopian3330b202009-10-05 17:07:12 -070033#include <ui/GraphicBuffer.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080034#include <ui/PixelFormat.h>
Mathias Agopian9cce3252010-02-09 17:46:37 -080035
Mathias Agopian90ac7992012-02-25 18:48:35 -080036#include <gui/Surface.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080037
38#include "clz.h"
Mathias Agopian1b031492012-06-20 17:51:20 -070039#include "DisplayHardware.h"
Mathias Agopian1f7bec62010-06-25 18:02:21 -070040#include "GLExtensions.h"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080041#include "Layer.h"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080042#include "SurfaceFlinger.h"
Mathias Agopiana67932f2011-04-20 14:20:59 -070043#include "SurfaceTextureLayer.h"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080044
Mathias Agopian1b031492012-06-20 17:51:20 -070045#include "DisplayHardware/HWComposer.h"
46
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080047#define DEBUG_RESIZE 0
48
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080049namespace android {
50
51// ---------------------------------------------------------------------------
52
Mathias Agopian96f08192010-06-02 23:28:45 -070053Layer::Layer(SurfaceFlinger* flinger,
54 DisplayID display, const sp<Client>& client)
55 : LayerBaseClient(flinger, display, client),
Mathias Agopiana67932f2011-04-20 14:20:59 -070056 mTextureName(-1U),
57 mQueuedFrames(0),
58 mCurrentTransform(0),
Mathias Agopian933389f2011-07-18 16:15:08 -070059 mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
Mathias Agopiana67932f2011-04-20 14:20:59 -070060 mCurrentOpacity(true),
Mathias Agopian4d143ee2012-02-23 20:05:39 -080061 mRefreshPending(false),
Mathias Agopian82d7ab62012-01-19 18:34:40 -080062 mFrameLatencyNeeded(false),
Jesse Halldc5b4852012-06-29 15:21:18 -070063 mNeedHwcFence(false),
Mathias Agopian82d7ab62012-01-19 18:34:40 -080064 mFrameLatencyOffset(0),
Mathias Agopian5bf3abe2011-03-11 17:01:07 -080065 mFormat(PIXEL_FORMAT_NONE),
Mathias Agopian1f7bec62010-06-25 18:02:21 -070066 mGLExtensions(GLExtensions::getInstance()),
Mathias Agopiana67932f2011-04-20 14:20:59 -070067 mOpaqueLayer(true),
Mathias Agopianb7e930d2010-06-01 15:12:58 -070068 mSecure(false),
Mathias Agopian933389f2011-07-18 16:15:08 -070069 mProtectedByApp(false)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080070{
Mathias Agopiana67932f2011-04-20 14:20:59 -070071 mCurrentCrop.makeInvalid();
72 glGenTextures(1, &mTextureName);
Jamie Gennise8696a42012-01-15 18:54:57 -080073}
74
Jesse Hallef194142012-06-14 14:45:17 -070075void Layer::onLayerDisplayed(HWComposer::HWCLayerInterface* layer) {
76 if (layer) {
77 mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd());
78 }
79
Jamie Gennise8696a42012-01-15 18:54:57 -080080 if (mFrameLatencyNeeded) {
Mathias Agopian1b031492012-06-20 17:51:20 -070081 // we need a DisplayHardware for debugging only right now
82 // XXX: should this be called per DisplayHardware?
83 const DisplayHardware& hw(mFlinger->getDefaultDisplayHardware());
Mathias Agopian82d7ab62012-01-19 18:34:40 -080084 mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp();
85 mFrameStats[mFrameLatencyOffset].set = systemTime();
86 mFrameStats[mFrameLatencyOffset].vsync = hw.getRefreshTimestamp();
Jamie Gennise8696a42012-01-15 18:54:57 -080087 mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128;
88 mFrameLatencyNeeded = false;
89 }
Mathias Agopiand606de62010-05-10 20:06:11 -070090}
91
Mathias Agopiana67932f2011-04-20 14:20:59 -070092void Layer::onFirstRef()
Mathias Agopian96f08192010-06-02 23:28:45 -070093{
Mathias Agopiana67932f2011-04-20 14:20:59 -070094 LayerBaseClient::onFirstRef();
Mathias Agopianddc31c32011-06-12 18:05:53 -070095
Mathias Agopiana67932f2011-04-20 14:20:59 -070096 struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
97 FrameQueuedListener(Layer* layer) : mLayer(layer) { }
98 private:
99 wp<Layer> mLayer;
100 virtual void onFrameAvailable() {
101 sp<Layer> that(mLayer.promote());
102 if (that != 0) {
103 that->onFrameQueued();
104 }
105 }
106 };
Daniel Lamb2675792012-02-23 14:35:13 -0800107
108 // Creates a custom BufferQueue for SurfaceTexture to use
109 sp<BufferQueue> bq = new SurfaceTextureLayer();
110 mSurfaceTexture = new SurfaceTexture(mTextureName, true,
Mathias Agopiana0db3082012-04-23 13:59:36 -0700111 GL_TEXTURE_EXTERNAL_OES, false, bq);
Daniel Lamb2675792012-02-23 14:35:13 -0800112
Daniel Lamb2675792012-02-23 14:35:13 -0800113 mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));
Mathias Agopiana67932f2011-04-20 14:20:59 -0700114 mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
115 mSurfaceTexture->setSynchronousMode(true);
Daniel Lamb2675792012-02-23 14:35:13 -0800116
Mathias Agopian7f42a9c2012-04-23 20:00:16 -0700117#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
118#warning "disabling triple buffering"
Mathias Agopiana67932f2011-04-20 14:20:59 -0700119 mSurfaceTexture->setBufferCountServer(2);
Mathias Agopian7f42a9c2012-04-23 20:00:16 -0700120#else
121 mSurfaceTexture->setBufferCountServer(3);
Mathias Agopian303d5382012-02-05 01:49:16 -0800122#endif
Mathias Agopianb7e930d2010-06-01 15:12:58 -0700123}
124
Mathias Agopiana67932f2011-04-20 14:20:59 -0700125Layer::~Layer()
Mathias Agopianb7e930d2010-06-01 15:12:58 -0700126{
Mathias Agopian118d0242011-10-13 16:02:48 -0700127 mFlinger->postMessageAsync(
128 new SurfaceFlinger::MessageDestroyGLTexture(mTextureName) );
Mathias Agopian96f08192010-06-02 23:28:45 -0700129}
130
Mathias Agopiana67932f2011-04-20 14:20:59 -0700131void Layer::onFrameQueued() {
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700132 android_atomic_inc(&mQueuedFrames);
Mathias Agopian99ce5cd2012-01-31 18:24:27 -0800133 mFlinger->signalLayerUpdate();
Mathias Agopian579b3f82010-06-08 19:54:15 -0700134}
135
Mathias Agopiand606de62010-05-10 20:06:11 -0700136// called with SurfaceFlinger::mStateLock as soon as the layer is entered
137// in the purgatory list
138void Layer::onRemoved()
139{
Jamie Gennisdbe64862011-07-30 14:33:49 -0700140 mSurfaceTexture->abandon();
Mathias Agopian48d819a2009-09-10 19:41:18 -0700141}
Mathias Agopiancbb288b2009-09-07 16:32:45 -0700142
Jamie Gennisa249f2d2011-09-16 17:31:54 -0700143void Layer::setName(const String8& name) {
144 LayerBase::setName(name);
145 mSurfaceTexture->setName(name);
146}
147
Mathias Agopian1b031492012-06-20 17:51:20 -0700148void Layer::validateVisibility(const Transform& globalTransform, const DisplayHardware& hw) {
149 LayerBase::validateVisibility(globalTransform, hw);
Daniel Lamb2675792012-02-23 14:35:13 -0800150
151 // This optimization allows the SurfaceTexture to bake in
152 // the rotation so hardware overlays can be used
153 mSurfaceTexture->setTransformHint(getTransformHint());
154}
155
Mathias Agopiana67932f2011-04-20 14:20:59 -0700156sp<ISurface> Layer::createSurface()
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800157{
Mathias Agopiana67932f2011-04-20 14:20:59 -0700158 class BSurface : public BnSurface, public LayerCleaner {
159 wp<const Layer> mOwner;
160 virtual sp<ISurfaceTexture> getSurfaceTexture() const {
161 sp<ISurfaceTexture> res;
162 sp<const Layer> that( mOwner.promote() );
163 if (that != NULL) {
Daniel Lamb2675792012-02-23 14:35:13 -0800164 res = that->mSurfaceTexture->getBufferQueue();
Mathias Agopiana67932f2011-04-20 14:20:59 -0700165 }
166 return res;
167 }
168 public:
169 BSurface(const sp<SurfaceFlinger>& flinger,
170 const sp<Layer>& layer)
171 : LayerCleaner(flinger, layer), mOwner(layer) { }
172 };
173 sp<ISurface> sur(new BSurface(mFlinger, this));
Mathias Agopiana1f47b92011-02-15 19:01:06 -0800174 return sur;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800175}
176
Jamie Gennis582270d2011-08-17 18:19:00 -0700177wp<IBinder> Layer::getSurfaceTextureBinder() const
178{
Daniel Lamb2675792012-02-23 14:35:13 -0800179 return mSurfaceTexture->getBufferQueue()->asBinder();
Jamie Gennis582270d2011-08-17 18:19:00 -0700180}
181
Mathias Agopianf9d93272009-06-19 17:00:27 -0700182status_t Layer::setBuffers( uint32_t w, uint32_t h,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800183 PixelFormat format, uint32_t flags)
184{
Mathias Agopian401c2572009-09-23 19:16:27 -0700185 // this surfaces pixel format
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800186 PixelFormatInfo info;
187 status_t err = getPixelFormatInfo(format, &info);
Mathias Agopianff615cc2012-02-24 14:58:36 -0800188 if (err) {
189 ALOGE("unsupported pixelformat %d", format);
190 return err;
191 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800192
Mathias Agopian401c2572009-09-23 19:16:27 -0700193 // the display's pixel format
Mathias Agopian1b031492012-06-20 17:51:20 -0700194 // XXX: we shouldn't rely on the DisplayHardware to do this
195 const DisplayHardware& hw(mFlinger->getDefaultDisplayHardware());
Mathias Agopianca99fb82010-04-14 16:43:44 -0700196 uint32_t const maxSurfaceDims = min(
197 hw.getMaxTextureSize(), hw.getMaxViewportDims());
198
199 // never allow a surface larger than what our underlying GL implementation
200 // can handle.
201 if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) {
Mathias Agopianff615cc2012-02-24 14:58:36 -0800202 ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
Mathias Agopianca99fb82010-04-14 16:43:44 -0700203 return BAD_VALUE;
204 }
205
Mathias Agopiancbb288b2009-09-07 16:32:45 -0700206 mFormat = format;
Mathias Agopianeff062c2010-08-25 14:59:15 -0700207
Mathias Agopian3330b202009-10-05 17:07:12 -0700208 mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
Glenn Kasten16f04532011-01-19 15:27:27 -0800209 mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
Mathias Agopiana67932f2011-04-20 14:20:59 -0700210 mOpaqueLayer = (flags & ISurfaceComposer::eOpaque);
211 mCurrentOpacity = getOpacityForFormat(format);
212
213 mSurfaceTexture->setDefaultBufferSize(w, h);
214 mSurfaceTexture->setDefaultBufferFormat(format);
Daniel Lamb2675792012-02-23 14:35:13 -0800215 mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));
Mathias Agopianca99fb82010-04-14 16:43:44 -0700216
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800217 return NO_ERROR;
218}
219
Jamie Gennisf15a83f2012-05-10 20:43:55 -0700220Rect Layer::computeBufferCrop() const {
221 // Start with the SurfaceTexture's buffer crop...
222 Rect crop;
223 if (!mCurrentCrop.isEmpty()) {
224 crop = mCurrentCrop;
225 } else if (mActiveBuffer != NULL){
226 crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
227 } else {
228 crop = Rect(mTransformedBounds.width(), mTransformedBounds.height());
229 }
230
231 // ... then reduce that in the same proportions as the window crop reduces
232 // the window size.
233 const State& s(drawingState());
Mathias Agopian93ffb862012-05-16 17:07:49 -0700234 if (!s.active.crop.isEmpty()) {
Jamie Gennisf15a83f2012-05-10 20:43:55 -0700235 // Transform the window crop to match the buffer coordinate system,
236 // which means using the inverse of the current transform set on the
237 // SurfaceTexture.
238 uint32_t invTransform = mCurrentTransform;
Mathias Agopian93ffb862012-05-16 17:07:49 -0700239 int winWidth = s.active.w;
240 int winHeight = s.active.h;
Jamie Gennisf15a83f2012-05-10 20:43:55 -0700241 if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
242 invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
243 NATIVE_WINDOW_TRANSFORM_FLIP_H;
Mathias Agopian93ffb862012-05-16 17:07:49 -0700244 winWidth = s.active.h;
245 winHeight = s.active.w;
Jamie Gennisf15a83f2012-05-10 20:43:55 -0700246 }
Mathias Agopian93ffb862012-05-16 17:07:49 -0700247 Rect winCrop = s.active.crop.transform(invTransform,
248 s.active.w, s.active.h);
Jamie Gennisf15a83f2012-05-10 20:43:55 -0700249
250 float xScale = float(crop.width()) / float(winWidth);
251 float yScale = float(crop.height()) / float(winHeight);
Mathias Agopian93ffb862012-05-16 17:07:49 -0700252 crop.left += int(ceilf(float(winCrop.left) * xScale));
253 crop.top += int(ceilf(float(winCrop.top) * yScale));
254 crop.right -= int(ceilf(float(winWidth - winCrop.right) * xScale));
255 crop.bottom -= int(ceilf(float(winHeight - winCrop.bottom) * yScale));
Jamie Gennisf15a83f2012-05-10 20:43:55 -0700256 }
257
258 return crop;
259}
260
Mathias Agopian3e8b8532012-05-13 20:42:01 -0700261void Layer::setGeometry(HWComposer::HWCLayerInterface& layer)
Mathias Agopiana350ff92010-08-10 17:14:02 -0700262{
Mathias Agopian3e8b8532012-05-13 20:42:01 -0700263 LayerBaseClient::setGeometry(layer);
Mathias Agopiana537c0f2011-08-02 15:51:37 -0700264
Mathias Agopian3e8b8532012-05-13 20:42:01 -0700265 // enable this layer
266 layer.setSkip(false);
Mathias Agopiana350ff92010-08-10 17:14:02 -0700267
268 // we can't do alpha-fade with the hwc HAL
269 const State& s(drawingState());
270 if (s.alpha < 0xFF) {
Mathias Agopian3e8b8532012-05-13 20:42:01 -0700271 layer.setSkip(true);
Mathias Agopiana350ff92010-08-10 17:14:02 -0700272 }
273
Mathias Agopian29a367b2011-07-12 14:51:45 -0700274 /*
275 * Transformations are applied in this order:
276 * 1) buffer orientation/flip/mirror
277 * 2) state transformation (window manager)
278 * 3) layer orientation (screen orientation)
Mathias Agopiand992db32011-08-18 18:31:00 -0700279 * mTransform is already the composition of (2) and (3)
Mathias Agopian29a367b2011-07-12 14:51:45 -0700280 * (NOTE: the matrices are multiplied in reverse order)
281 */
282
283 const Transform bufferOrientation(mCurrentTransform);
Mathias Agopiand992db32011-08-18 18:31:00 -0700284 const Transform tr(mTransform * bufferOrientation);
Mathias Agopian29a367b2011-07-12 14:51:45 -0700285
286 // this gives us only the "orientation" component of the transform
287 const uint32_t finalTransform = tr.getOrientation();
288
Mathias Agopiana350ff92010-08-10 17:14:02 -0700289 // we can only handle simple transformation
Mathias Agopian29a367b2011-07-12 14:51:45 -0700290 if (finalTransform & Transform::ROT_INVALID) {
Mathias Agopian3e8b8532012-05-13 20:42:01 -0700291 layer.setSkip(true);
Mathias Agopiana537c0f2011-08-02 15:51:37 -0700292 } else {
Mathias Agopian3e8b8532012-05-13 20:42:01 -0700293 layer.setTransform(finalTransform);
Mathias Agopiana350ff92010-08-10 17:14:02 -0700294 }
Mathias Agopian3e8b8532012-05-13 20:42:01 -0700295 layer.setCrop(computeBufferCrop());
Mathias Agopiana350ff92010-08-10 17:14:02 -0700296}
297
Mathias Agopian3e8b8532012-05-13 20:42:01 -0700298void Layer::setPerFrameData(HWComposer::HWCLayerInterface& layer) {
Mathias Agopiana67932f2011-04-20 14:20:59 -0700299 const sp<GraphicBuffer>& buffer(mActiveBuffer);
Mathias Agopian3e8b8532012-05-13 20:42:01 -0700300 // NOTE: buffer can be NULL if the client never drew into this
301 // layer yet, or if we ran out of memory
302 layer.setBuffer(buffer);
Jesse Halldc5b4852012-06-29 15:21:18 -0700303
304 if (mNeedHwcFence) {
305 sp<Fence> fence = mSurfaceTexture->getCurrentFence();
306 if (fence.get()) {
307 int fenceFd = fence->dup();
308 if (fenceFd == -1) {
309 ALOGW("failed to dup layer fence, skipping sync: %d", errno);
310 }
311 layer.setAcquireFenceFd(fenceFd);
312 }
313 mNeedHwcFence = false;
314 } else {
315 layer.setAcquireFenceFd(-1);
316 }
Mathias Agopiana350ff92010-08-10 17:14:02 -0700317}
318
Mathias Agopian1b031492012-06-20 17:51:20 -0700319void Layer::onDraw(const DisplayHardware& hw, const Region& clip) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800320{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800321 ATRACE_CALL();
322
Mathias Agopiana67932f2011-04-20 14:20:59 -0700323 if (CC_UNLIKELY(mActiveBuffer == 0)) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800324 // the texture has not been created yet, this Layer has
Mathias Agopian179169e2010-05-06 20:21:45 -0700325 // in fact never been drawn into. This happens frequently with
326 // SurfaceView because the WindowManager can't know when the client
327 // has drawn the first time.
328
329 // If there is nothing under us, we paint the screen in black, otherwise
330 // we just skip this update.
331
332 // figure out if there is something below us
333 Region under;
Mathias Agopianf7ae69d2011-08-23 12:34:29 -0700334 const SurfaceFlinger::LayerVector& drawingLayers(
335 mFlinger->mDrawingState.layersSortedByZ);
Mathias Agopian179169e2010-05-06 20:21:45 -0700336 const size_t count = drawingLayers.size();
337 for (size_t i=0 ; i<count ; ++i) {
338 const sp<LayerBase>& layer(drawingLayers[i]);
339 if (layer.get() == static_cast<LayerBase const*>(this))
340 break;
341 under.orSelf(layer->visibleRegionScreen);
342 }
343 // if not everything below us is covered, we plug the holes!
344 Region holes(clip.subtract(under));
345 if (!holes.isEmpty()) {
Mathias Agopian1b031492012-06-20 17:51:20 -0700346 clearWithOpenGL(hw, holes, 0, 0, 0, 1);
Mathias Agopian179169e2010-05-06 20:21:45 -0700347 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800348 return;
349 }
Mathias Agopiana67932f2011-04-20 14:20:59 -0700350
Jesse Halldc5b4852012-06-29 15:21:18 -0700351 // TODO: replace this with a server-side wait
352 sp<Fence> fence = mSurfaceTexture->getCurrentFence();
353 if (fence.get()) {
354 status_t err = fence->wait(Fence::TIMEOUT_NEVER);
355 ALOGW_IF(err != OK, "Layer::onDraw: failed waiting for fence: %d", err);
356 // Go ahead and draw the buffer anyway; no matter what we do the screen
357 // is probably going to have something visibly wrong.
358 }
359
Jamie Gennis9575f602011-10-07 14:51:16 -0700360 if (!isProtected()) {
Jamie Genniscbb1a952012-05-08 17:05:52 -0700361 // TODO: we could be more subtle with isFixedSize()
362 const bool useFiltering = getFiltering() || needsFiltering() || isFixedSize();
363
364 // Query the texture matrix given our current filtering mode.
365 float textureMatrix[16];
366 mSurfaceTexture->setFilteringEnabled(useFiltering);
367 mSurfaceTexture->getTransformMatrix(textureMatrix);
368
369 // Set things up for texturing.
Mathias Agopianc492e672011-10-18 14:49:27 -0700370 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName);
371 GLenum filter = GL_NEAREST;
Jamie Genniscbb1a952012-05-08 17:05:52 -0700372 if (useFiltering) {
Mathias Agopianc492e672011-10-18 14:49:27 -0700373 filter = GL_LINEAR;
Jamie Gennis9575f602011-10-07 14:51:16 -0700374 }
Mathias Agopianc492e672011-10-18 14:49:27 -0700375 glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, filter);
376 glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, filter);
Jamie Gennis9575f602011-10-07 14:51:16 -0700377 glMatrixMode(GL_TEXTURE);
Jamie Genniscbb1a952012-05-08 17:05:52 -0700378 glLoadMatrixf(textureMatrix);
Jamie Gennis9575f602011-10-07 14:51:16 -0700379 glMatrixMode(GL_MODELVIEW);
Mathias Agopianc492e672011-10-18 14:49:27 -0700380 glDisable(GL_TEXTURE_2D);
Xavier Ducrohet4c4163b2011-10-21 16:18:48 -0700381 glEnable(GL_TEXTURE_EXTERNAL_OES);
Mathias Agopiana67932f2011-04-20 14:20:59 -0700382 } else {
Mathias Agopianc492e672011-10-18 14:49:27 -0700383 glBindTexture(GL_TEXTURE_2D, mFlinger->getProtectedTexName());
Jamie Gennis9575f602011-10-07 14:51:16 -0700384 glMatrixMode(GL_TEXTURE);
385 glLoadIdentity();
386 glMatrixMode(GL_MODELVIEW);
Mathias Agopianc492e672011-10-18 14:49:27 -0700387 glDisable(GL_TEXTURE_EXTERNAL_OES);
388 glEnable(GL_TEXTURE_2D);
Mathias Agopiana67932f2011-04-20 14:20:59 -0700389 }
Mathias Agopiana67932f2011-04-20 14:20:59 -0700390
Mathias Agopian1b031492012-06-20 17:51:20 -0700391 drawWithOpenGL(hw, clip);
Mathias Agopiana67932f2011-04-20 14:20:59 -0700392
Mathias Agopianc492e672011-10-18 14:49:27 -0700393 glDisable(GL_TEXTURE_EXTERNAL_OES);
394 glDisable(GL_TEXTURE_2D);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800395}
396
Eric Hassoldac45e6b2011-02-10 14:41:26 -0800397// As documented in libhardware header, formats in the range
398// 0x100 - 0x1FF are specific to the HAL implementation, and
399// are known to have no alpha channel
400// TODO: move definition for device-specific range into
401// hardware.h, instead of using hard-coded values here.
402#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
403
Mathias Agopiana67932f2011-04-20 14:20:59 -0700404bool Layer::getOpacityForFormat(uint32_t format)
Eric Hassoldac45e6b2011-02-10 14:41:26 -0800405{
Mathias Agopiana67932f2011-04-20 14:20:59 -0700406 if (HARDWARE_IS_DEVICE_FORMAT(format)) {
407 return true;
Eric Hassoldac45e6b2011-02-10 14:41:26 -0800408 }
Mathias Agopiana67932f2011-04-20 14:20:59 -0700409 PixelFormatInfo info;
410 status_t err = getPixelFormatInfo(PixelFormat(format), &info);
411 // in case of error (unknown format), we assume no blending
412 return (err || info.h_alpha <= info.l_alpha);
Eric Hassoldac45e6b2011-02-10 14:41:26 -0800413}
414
Eric Hassoldac45e6b2011-02-10 14:41:26 -0800415
Mathias Agopiana67932f2011-04-20 14:20:59 -0700416bool Layer::isOpaque() const
Mathias Agopiana7f66922010-05-26 22:08:52 -0700417{
Mathias Agopiana67932f2011-04-20 14:20:59 -0700418 // if we don't have a buffer yet, we're translucent regardless of the
419 // layer's opaque flag.
Jamie Gennisdb5230f2011-07-28 14:54:07 -0700420 if (mActiveBuffer == 0) {
Mathias Agopiana67932f2011-04-20 14:20:59 -0700421 return false;
Jamie Gennisdb5230f2011-07-28 14:54:07 -0700422 }
Mathias Agopiana67932f2011-04-20 14:20:59 -0700423
424 // if the layer has the opaque flag, then we're always opaque,
425 // otherwise we use the current buffer's format.
426 return mOpaqueLayer || mCurrentOpacity;
Mathias Agopiana7f66922010-05-26 22:08:52 -0700427}
428
Jamie Gennis7a4d0df2011-03-09 17:05:02 -0800429bool Layer::isProtected() const
430{
Mathias Agopiana67932f2011-04-20 14:20:59 -0700431 const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
Jamie Gennis7a4d0df2011-03-09 17:05:02 -0800432 return (activeBuffer != 0) &&
433 (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
434}
Mathias Agopianb5b7f262010-05-07 15:58:44 -0700435
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800436uint32_t Layer::doTransaction(uint32_t flags)
437{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800438 ATRACE_CALL();
439
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800440 const Layer::State& front(drawingState());
441 const Layer::State& temp(currentState());
442
Mathias Agopian4824d402012-06-04 18:16:30 -0700443 const bool sizeChanged = (temp.requested.w != front.requested.w) ||
444 (temp.requested.h != front.requested.h);
Mathias Agopiana138f892010-05-21 17:24:35 -0700445
446 if (sizeChanged) {
Mathias Agopiancbb288b2009-09-07 16:32:45 -0700447 // the size changed, we need to ask our client to request a new buffer
Steve Block9d453682011-12-20 16:23:08 +0000448 ALOGD_IF(DEBUG_RESIZE,
Mathias Agopian419e1962012-05-23 14:34:07 -0700449 "doTransaction: geometry (layer=%p), scalingMode=%d\n"
450 " current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
451 " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n"
452 " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
453 " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n",
454 this, mCurrentScalingMode,
455 temp.active.w, temp.active.h,
456 temp.active.crop.left,
457 temp.active.crop.top,
458 temp.active.crop.right,
459 temp.active.crop.bottom,
460 temp.active.crop.getWidth(),
461 temp.active.crop.getHeight(),
462 temp.requested.w, temp.requested.h,
Mathias Agopianb30c4152012-05-16 18:21:32 -0700463 temp.requested.crop.left,
464 temp.requested.crop.top,
465 temp.requested.crop.right,
466 temp.requested.crop.bottom,
467 temp.requested.crop.getWidth(),
468 temp.requested.crop.getHeight(),
Mathias Agopian419e1962012-05-23 14:34:07 -0700469 front.active.w, front.active.h,
470 front.active.crop.left,
471 front.active.crop.top,
472 front.active.crop.right,
473 front.active.crop.bottom,
474 front.active.crop.getWidth(),
475 front.active.crop.getHeight(),
476 front.requested.w, front.requested.h,
Mathias Agopianb30c4152012-05-16 18:21:32 -0700477 front.requested.crop.left,
478 front.requested.crop.top,
479 front.requested.crop.right,
480 front.requested.crop.bottom,
481 front.requested.crop.getWidth(),
Mathias Agopian419e1962012-05-23 14:34:07 -0700482 front.requested.crop.getHeight());
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800483
Jamie Gennis2a0d5b62011-09-26 16:54:44 -0700484 // record the new size, form this point on, when the client request
485 // a buffer, it'll get the new size.
Mathias Agopianb30c4152012-05-16 18:21:32 -0700486 mSurfaceTexture->setDefaultBufferSize(
487 temp.requested.w, temp.requested.h);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800488 }
Mathias Agopiancbb288b2009-09-07 16:32:45 -0700489
Mathias Agopian0cd545f2012-06-07 14:18:55 -0700490 if (!isFixedSize()) {
491
492 const bool resizePending = (temp.requested.w != temp.active.w) ||
493 (temp.requested.h != temp.active.h);
494
495 if (resizePending) {
496 // don't let LayerBase::doTransaction update the drawing state
497 // if we have a pending resize, unless we are in fixed-size mode.
498 // the drawing state will be updated only once we receive a buffer
499 // with the correct size.
500 //
501 // in particular, we want to make sure the clip (which is part
502 // of the geometry state) is latched together with the size but is
503 // latched immediately when no resizing is involved.
504
505 flags |= eDontUpdateGeometryState;
506 }
507 }
508
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800509 return LayerBase::doTransaction(flags);
510}
511
Mathias Agopiana138f892010-05-21 17:24:35 -0700512bool Layer::isFixedSize() const {
Mathias Agopian933389f2011-07-18 16:15:08 -0700513 return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
Mathias Agopiana67932f2011-04-20 14:20:59 -0700514}
515
516bool Layer::isCropped() const {
517 return !mCurrentCrop.isEmpty();
518}
519
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800520// ----------------------------------------------------------------------------
521// pageflip handling...
522// ----------------------------------------------------------------------------
523
Mathias Agopian4d143ee2012-02-23 20:05:39 -0800524bool Layer::onPreComposition() {
525 mRefreshPending = false;
526 return mQueuedFrames > 0;
Mathias Agopian99ce5cd2012-01-31 18:24:27 -0800527}
528
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800529void Layer::lockPageFlip(bool& recomputeVisibleRegions)
530{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800531 ATRACE_CALL();
532
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700533 if (mQueuedFrames > 0) {
Mathias Agopian99ce5cd2012-01-31 18:24:27 -0800534
535 // if we've already called updateTexImage() without going through
536 // a composition step, we have to skip this layer at this point
537 // because we cannot call updateTeximage() without a corresponding
538 // compositionComplete() call.
539 // we'll trigger an update in onPreComposition().
Mathias Agopian4d143ee2012-02-23 20:05:39 -0800540 if (mRefreshPending) {
541 mPostedDirtyRegion.clear();
Mathias Agopian99ce5cd2012-01-31 18:24:27 -0800542 return;
543 }
544
Jamie Gennis351a5132011-09-14 18:23:37 -0700545 // Capture the old state of the layer for comparisons later
Jamie Gennisdb5230f2011-07-28 14:54:07 -0700546 const bool oldOpacity = isOpaque();
Jamie Gennis351a5132011-09-14 18:23:37 -0700547 sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
Jamie Gennisdb5230f2011-07-28 14:54:07 -0700548
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700549 // signal another event if we have more frames pending
550 if (android_atomic_dec(&mQueuedFrames) > 1) {
Mathias Agopian99ce5cd2012-01-31 18:24:27 -0800551 mFlinger->signalLayerUpdate();
Jamie Gennis3d8063b2011-06-26 18:27:47 -0700552 }
553
Mathias Agopian2c8207e2012-05-23 17:56:42 -0700554 struct Reject : public SurfaceTexture::BufferRejecter {
555 Layer::State& front;
556 Layer::State& current;
557 bool& recomputeVisibleRegions;
558 Reject(Layer::State& front, Layer::State& current,
559 bool& recomputeVisibleRegions)
560 : front(front), current(current),
561 recomputeVisibleRegions(recomputeVisibleRegions) {
562 }
563
564 virtual bool reject(const sp<GraphicBuffer>& buf,
565 const BufferQueue::BufferItem& item) {
566 if (buf == NULL) {
567 return false;
568 }
569
570 uint32_t bufWidth = buf->getWidth();
571 uint32_t bufHeight = buf->getHeight();
572
573 // check that we received a buffer of the right size
574 // (Take the buffer's orientation into account)
575 if (item.mTransform & Transform::ROT_90) {
576 swap(bufWidth, bufHeight);
577 }
578
579
580 bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
581 if (front.active != front.requested) {
582
583 if (isFixedSize ||
584 (bufWidth == front.requested.w &&
585 bufHeight == front.requested.h))
586 {
587 // Here we pretend the transaction happened by updating the
588 // current and drawing states. Drawing state is only accessed
589 // in this thread, no need to have it locked
590 front.active = front.requested;
591
592 // We also need to update the current state so that
593 // we don't end-up overwriting the drawing state with
594 // this stale current state during the next transaction
595 //
596 // NOTE: We don't need to hold the transaction lock here
597 // because State::active is only accessed from this thread.
598 current.active = front.active;
599
600 // recompute visible region
601 recomputeVisibleRegions = true;
602 }
603
604 ALOGD_IF(DEBUG_RESIZE,
605 "lockPageFlip: (layer=%p), buffer (%ux%u, tr=%02x), scalingMode=%d\n"
606 " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
607 " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n",
608 this, bufWidth, bufHeight, item.mTransform, item.mScalingMode,
609 front.active.w, front.active.h,
610 front.active.crop.left,
611 front.active.crop.top,
612 front.active.crop.right,
613 front.active.crop.bottom,
614 front.active.crop.getWidth(),
615 front.active.crop.getHeight(),
616 front.requested.w, front.requested.h,
617 front.requested.crop.left,
618 front.requested.crop.top,
619 front.requested.crop.right,
620 front.requested.crop.bottom,
621 front.requested.crop.getWidth(),
622 front.requested.crop.getHeight());
623 }
624
625 if (!isFixedSize) {
626 if (front.active.w != bufWidth ||
627 front.active.h != bufHeight) {
Mathias Agopian4824d402012-06-04 18:16:30 -0700628 // reject this buffer
Mathias Agopian2c8207e2012-05-23 17:56:42 -0700629 return true;
630 }
631 }
632 return false;
633 }
634 };
635
636
637 Reject r(mDrawingState, currentState(), recomputeVisibleRegions);
638
639 if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) {
Mathias Agopiana67932f2011-04-20 14:20:59 -0700640 // something happened!
641 recomputeVisibleRegions = true;
642 return;
643 }
Mathias Agopian96f08192010-06-02 23:28:45 -0700644
Jamie Gennis351a5132011-09-14 18:23:37 -0700645 // update the active buffer
646 mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
Mathias Agopiane31564d2012-05-29 20:41:03 -0700647 if (mActiveBuffer == NULL) {
648 // this can only happen if the very first buffer was rejected.
649 return;
650 }
Mathias Agopianda9584d2010-12-13 18:51:59 -0800651
Mathias Agopian4824d402012-06-04 18:16:30 -0700652 mRefreshPending = true;
Mathias Agopian2c8207e2012-05-23 17:56:42 -0700653 mFrameLatencyNeeded = true;
Jesse Halldc5b4852012-06-29 15:21:18 -0700654 mNeedHwcFence = true;
Mathias Agopiane31564d2012-05-29 20:41:03 -0700655 if (oldActiveBuffer == NULL) {
Mathias Agopian2c8207e2012-05-23 17:56:42 -0700656 // the first time we receive a buffer, we need to trigger a
657 // geometry invalidation.
658 mFlinger->invalidateHwcGeometry();
659 }
660
Mathias Agopian702634a2012-05-23 17:50:31 -0700661 Rect crop(mSurfaceTexture->getCurrentCrop());
Mathias Agopian2c8207e2012-05-23 17:56:42 -0700662 const uint32_t transform(mSurfaceTexture->getCurrentTransform());
663 const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
Mathias Agopian702634a2012-05-23 17:50:31 -0700664 if ((crop != mCurrentCrop) ||
665 (transform != mCurrentTransform) ||
666 (scalingMode != mCurrentScalingMode))
667 {
668 mCurrentCrop = crop;
669 mCurrentTransform = transform;
670 mCurrentScalingMode = scalingMode;
671 mFlinger->invalidateHwcGeometry();
672 }
673
674 if (oldActiveBuffer != NULL) {
Mathias Agopiane31564d2012-05-29 20:41:03 -0700675 uint32_t bufWidth = mActiveBuffer->getWidth();
676 uint32_t bufHeight = mActiveBuffer->getHeight();
Mathias Agopian702634a2012-05-23 17:50:31 -0700677 if (bufWidth != uint32_t(oldActiveBuffer->width) ||
678 bufHeight != uint32_t(oldActiveBuffer->height)) {
679 mFlinger->invalidateHwcGeometry();
680 }
681 }
682
683 mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
684 if (oldOpacity != isOpaque()) {
685 recomputeVisibleRegions = true;
686 }
687
688 // FIXME: mPostedDirtyRegion = dirty & bounds
Mathias Agopian2c8207e2012-05-23 17:56:42 -0700689 const Layer::State& front(drawingState());
Mathias Agopian702634a2012-05-23 17:50:31 -0700690 mPostedDirtyRegion.set(front.active.w, front.active.h);
691
692 glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
693 glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
Mathias Agopiancaa600c2009-09-16 18:27:24 -0700694 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800695}
696
697void Layer::unlockPageFlip(
698 const Transform& planeTransform, Region& outDirtyRegion)
699{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800700 ATRACE_CALL();
701
Mathias Agopian4d143ee2012-02-23 20:05:39 -0800702 Region postedRegion(mPostedDirtyRegion);
703 if (!postedRegion.isEmpty()) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800704 mPostedDirtyRegion.clear();
Mathias Agopian4d143ee2012-02-23 20:05:39 -0800705 if (!visibleRegionScreen.isEmpty()) {
706 // The dirty region is given in the layer's coordinate space
707 // transform the dirty region by the surface's transformation
708 // and the global transformation.
709 const Layer::State& s(drawingState());
710 const Transform tr(planeTransform * s.transform);
711 postedRegion = tr.transform(postedRegion);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800712
Mathias Agopian4d143ee2012-02-23 20:05:39 -0800713 // At this point, the dirty region is in screen space.
714 // Make sure it's constrained by the visible region (which
715 // is in screen space as well).
716 postedRegion.andSelf(visibleRegionScreen);
717 outDirtyRegion.orSelf(postedRegion);
718 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800719 }
720}
721
Mathias Agopian1b5e1022010-04-20 17:55:49 -0700722void Layer::dump(String8& result, char* buffer, size_t SIZE) const
723{
724 LayerBaseClient::dump(result, buffer, SIZE);
725
Mathias Agopiana67932f2011-04-20 14:20:59 -0700726 sp<const GraphicBuffer> buf0(mActiveBuffer);
727 uint32_t w0=0, h0=0, s0=0, f0=0;
Mathias Agopian1b5e1022010-04-20 17:55:49 -0700728 if (buf0 != 0) {
729 w0 = buf0->getWidth();
730 h0 = buf0->getHeight();
731 s0 = buf0->getStride();
Mathias Agopiana67932f2011-04-20 14:20:59 -0700732 f0 = buf0->format;
Mathias Agopian1b5e1022010-04-20 17:55:49 -0700733 }
734 snprintf(buffer, SIZE,
735 " "
Mathias Agopianad795ba2011-08-08 16:02:13 -0700736 "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
Mathias Agopian99ce5cd2012-01-31 18:24:27 -0800737 " transform-hint=0x%02x, queued-frames=%d, mRefreshPending=%d\n",
Mathias Agopiana67932f2011-04-20 14:20:59 -0700738 mFormat, w0, h0, s0,f0,
Mathias Agopian99ce5cd2012-01-31 18:24:27 -0800739 getTransformHint(), mQueuedFrames, mRefreshPending);
Mathias Agopian1b5e1022010-04-20 17:55:49 -0700740
741 result.append(buffer);
Mathias Agopian1b5e1022010-04-20 17:55:49 -0700742
Mathias Agopiana67932f2011-04-20 14:20:59 -0700743 if (mSurfaceTexture != 0) {
744 mSurfaceTexture->dump(result, " ", buffer, SIZE);
Mathias Agopian579b3f82010-06-08 19:54:15 -0700745 }
Mathias Agopianb7e930d2010-06-01 15:12:58 -0700746}
747
Mathias Agopian82d7ab62012-01-19 18:34:40 -0800748void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const
749{
750 LayerBaseClient::dumpStats(result, buffer, SIZE);
751 const size_t o = mFrameLatencyOffset;
Mathias Agopian1b031492012-06-20 17:51:20 -0700752 const DisplayHardware& hw(mFlinger->getDefaultDisplayHardware());
Mathias Agopian82d7ab62012-01-19 18:34:40 -0800753 const nsecs_t period = hw.getRefreshPeriod();
754 result.appendFormat("%lld\n", period);
755 for (size_t i=0 ; i<128 ; i++) {
756 const size_t index = (o+i) % 128;
757 const nsecs_t time_app = mFrameStats[index].timestamp;
758 const nsecs_t time_set = mFrameStats[index].set;
759 const nsecs_t time_vsync = mFrameStats[index].vsync;
760 result.appendFormat("%lld\t%lld\t%lld\n",
761 time_app,
762 time_vsync,
763 time_set);
764 }
765 result.append("\n");
766}
767
Mathias Agopian25e66fc2012-01-28 22:31:55 -0800768void Layer::clearStats()
769{
770 LayerBaseClient::clearStats();
771 memset(mFrameStats, 0, sizeof(mFrameStats));
772}
773
Mathias Agopiana67932f2011-04-20 14:20:59 -0700774uint32_t Layer::getEffectiveUsage(uint32_t usage) const
Mathias Agopianb7e930d2010-06-01 15:12:58 -0700775{
Mathias Agopiana67932f2011-04-20 14:20:59 -0700776 // TODO: should we do something special if mSecure is set?
777 if (mProtectedByApp) {
778 // need a hardware-protected path to external video sink
779 usage |= GraphicBuffer::USAGE_PROTECTED;
Jamie Gennis54cc83e2010-11-02 11:51:32 -0700780 }
Jamie Gennis3599bf22011-08-10 11:48:07 -0700781 usage |= GraphicBuffer::USAGE_HW_COMPOSER;
Mathias Agopiana67932f2011-04-20 14:20:59 -0700782 return usage;
Mathias Agopianb5b7f262010-05-07 15:58:44 -0700783}
784
Mathias Agopiana4583642011-08-23 18:03:18 -0700785uint32_t Layer::getTransformHint() const {
786 uint32_t orientation = 0;
787 if (!mFlinger->mDebugDisableTransformHint) {
Jamie Gennis8d91b422011-09-23 15:54:34 -0700788 orientation = getPlaneOrientation();
Mathias Agopiana4583642011-08-23 18:03:18 -0700789 if (orientation & Transform::ROT_INVALID) {
790 orientation = 0;
791 }
792 }
793 return orientation;
794}
795
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800796// ---------------------------------------------------------------------------
797
798
799}; // namespace android