Merge "Allow blaming a single uid for work done" into klp-dev
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 75ee30c..a5fdfb9 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -273,7 +273,7 @@
private:
// createImage creates a new EGLImage from a GraphicBuffer.
EGLImageKHR createImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& graphicBuffer);
+ const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
// freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in that
@@ -386,6 +386,10 @@
// mEglImage is the EGLImage created from mGraphicBuffer.
EGLImageKHR mEglImage;
+ // mCropRect is the crop rectangle passed to EGL when mEglImage was
+ // created.
+ Rect mCropRect;
+
// mFence is the EGL sync object that must signal before the buffer
// associated with this buffer slot may be dequeued. It is initialized
// to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index ac67f94..de3aeb1 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -89,6 +89,31 @@
buffer_handle_t pHandle;
};
+// A pointer to this struct is passed to OMX_SetParameter() when the extension
+// index "OMX.google.android.index.prepareForAdaptivePlayback" is given.
+//
+// This method is used to signal a video decoder, that the user has requested
+// seamless resolution change support (if bEnable is set to OMX_TRUE).
+// nMaxFrameWidth and nMaxFrameHeight are the dimensions of the largest
+// anticipated frames in the video. If bEnable is OMX_FALSE, no resolution
+// change is expected, and the nMaxFrameWidth/Height fields are unused.
+//
+// If the decoder supports dynamic output buffers, it may ignore this
+// request. Otherwise, it shall request resources in such a way so that it
+// avoids full port-reconfiguration (due to output port-definition change)
+// during resolution changes.
+//
+// DO NOT USE THIS STRUCTURE AS IT WILL BE REMOVED. INSTEAD, IMPLEMENT
+// METADATA SUPPORT FOR VIDEO DECODERS.
+struct PrepareForAdaptivePlaybackParams {
+ OMX_U32 nSize;
+ OMX_VERSIONTYPE nVersion;
+ OMX_U32 nPortIndex;
+ OMX_BOOL bEnable;
+ OMX_U32 nMaxFrameWidth;
+ OMX_U32 nMaxFrameHeight;
+};
+
// A pointer to this struct is passed to OMX_SetParameter when the extension
// index for the 'OMX.google.android.index.useAndroidNativeBuffer' extension is
// given. This call will only be performed if a prior call was made with the
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 87d66e2..c165a68 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -668,11 +668,15 @@
mConnectedApi = api;
output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size());
- // set-up a death notification so that we can disconnect automatically
- // when/if the remote producer dies.
- // This will fail with INVALID_OPERATION if the "token" is local to our process.
- if (token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)) == NO_ERROR) {
- mConnectedProducerToken = token;
+ // set-up a death notification so that we can disconnect
+ // automatically when/if the remote producer dies.
+ if (token != NULL && token->remoteBinder() != NULL) {
+ status_t err = token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
+ if (err == NO_ERROR) {
+ mConnectedProducerToken = token;
+ } else {
+ ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err);
+ }
}
}
break;
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index cf3f12a..7ee3081 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -41,6 +41,9 @@
#include <utils/String8.h>
#include <utils/Trace.h>
+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+#define CROP_EXT_STR "EGL_ANDROID_image_crop"
+
namespace android {
// Macros for including the GLConsumer name in log messages
@@ -89,6 +92,30 @@
Mutex GLConsumer::sStaticInitLock;
sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
+static bool hasEglAndroidImageCropImpl() {
+ EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
+ size_t cropExtLen = strlen(CROP_EXT_STR);
+ size_t extsLen = strlen(exts);
+ bool equal = !strcmp(CROP_EXT_STR, exts);
+ bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
+ bool atEnd = (cropExtLen+1) < extsLen &&
+ !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
+ bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
+ return equal || atStart || atEnd || inMiddle;
+}
+
+static bool hasEglAndroidImageCrop() {
+ // Only compute whether the extension is present once the first time this
+ // function is called.
+ static bool hasIt = hasEglAndroidImageCropImpl();
+ return hasIt;
+}
+
+static bool isEglImageCroppable(const Rect& crop) {
+ return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
+}
+
GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
ConsumerBase(bq, isControlledByApp),
@@ -279,19 +306,30 @@
}
int slot = item->mBuf;
- if (item->mGraphicBuffer != NULL) {
- // This buffer has not been acquired before, so we must assume
- // that any EGLImage in mEglSlots is stale.
- if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
- if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
- ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
- slot);
- // keep going
- }
- mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
+ bool destroyEglImage = false;
+
+ if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
+ if (item->mGraphicBuffer != NULL) {
+ // This buffer has not been acquired before, so we must assume
+ // that any EGLImage in mEglSlots is stale.
+ destroyEglImage = true;
+ } else if (mEglSlots[slot].mCropRect != item->mCrop) {
+ // We've already seen this buffer before, but it now has a
+ // different crop rect, so we'll need to recreate the EGLImage if
+ // we're using the EGL_ANDROID_image_crop extension.
+ destroyEglImage = hasEglAndroidImageCrop();
}
}
+ if (destroyEglImage) {
+ if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
+ ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
+ slot);
+ // keep going
+ }
+ mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
+ }
+
return NO_ERROR;
}
@@ -334,13 +372,15 @@
// EGLImage when detaching from a context but the buffer has not been
// re-allocated.
if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) {
- EGLImageKHR image = createImage(mEglDisplay, mSlots[buf].mGraphicBuffer);
+ EGLImageKHR image = createImage(mEglDisplay,
+ mSlots[buf].mGraphicBuffer, item.mCrop);
if (image == EGL_NO_IMAGE_KHR) {
ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
mEglDisplay, buf);
return UNKNOWN_ERROR;
}
mEglSlots[buf].mEglImage = image;
+ mEglSlots[buf].mCropRect = item.mCrop;
}
// Do whatever sync ops we need to do before releasing the old slot.
@@ -581,7 +621,8 @@
mCurrentTexture, mCurrentTextureBuf.get());
// Create a temporary EGLImageKHR.
- EGLImageKHR image = createImage(dpy, mCurrentTextureBuf);
+ Rect crop;
+ EGLImageKHR image = createImage(dpy, mCurrentTextureBuf, mCurrentCrop);
if (image == EGL_NO_IMAGE_KHR) {
return UNKNOWN_ERROR;
}
@@ -753,60 +794,66 @@
ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
}
- Rect cropRect = mCurrentCrop;
- float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
- float bufferWidth = buf->getWidth();
- float bufferHeight = buf->getHeight();
- if (!cropRect.isEmpty()) {
- float shrinkAmount = 0.0f;
- if (mFilteringEnabled) {
- // In order to prevent bilinear sampling beyond the edge of the
- // crop rectangle we may need to shrink it by 2 texels in each
- // dimension. Normally this would just need to take 1/2 a texel
- // off each end, but because the chroma channels of YUV420 images
- // are subsampled we may need to shrink the crop region by a whole
- // texel on each side.
- switch (buf->getPixelFormat()) {
- case PIXEL_FORMAT_RGBA_8888:
- case PIXEL_FORMAT_RGBX_8888:
- case PIXEL_FORMAT_RGB_888:
- case PIXEL_FORMAT_RGB_565:
- case PIXEL_FORMAT_BGRA_8888:
- // We know there's no subsampling of any channels, so we
- // only need to shrink by a half a pixel.
- shrinkAmount = 0.5;
- break;
+ float mtxBeforeFlipV[16];
+ if (!isEglImageCroppable(mCurrentCrop)) {
+ Rect cropRect = mCurrentCrop;
+ float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
+ float bufferWidth = buf->getWidth();
+ float bufferHeight = buf->getHeight();
+ if (!cropRect.isEmpty()) {
+ float shrinkAmount = 0.0f;
+ if (mFilteringEnabled) {
+ // In order to prevent bilinear sampling beyond the edge of the
+ // crop rectangle we may need to shrink it by 2 texels in each
+ // dimension. Normally this would just need to take 1/2 a texel
+ // off each end, but because the chroma channels of YUV420 images
+ // are subsampled we may need to shrink the crop region by a whole
+ // texel on each side.
+ switch (buf->getPixelFormat()) {
+ case PIXEL_FORMAT_RGBA_8888:
+ case PIXEL_FORMAT_RGBX_8888:
+ case PIXEL_FORMAT_RGB_888:
+ case PIXEL_FORMAT_RGB_565:
+ case PIXEL_FORMAT_BGRA_8888:
+ // We know there's no subsampling of any channels, so we
+ // only need to shrink by a half a pixel.
+ shrinkAmount = 0.5;
+ break;
- default:
- // If we don't recognize the format, we must assume the
- // worst case (that we care about), which is YUV420.
- shrinkAmount = 1.0;
- break;
+ default:
+ // If we don't recognize the format, we must assume the
+ // worst case (that we care about), which is YUV420.
+ shrinkAmount = 1.0;
+ break;
+ }
+ }
+
+ // Only shrink the dimensions that are not the size of the buffer.
+ if (cropRect.width() < bufferWidth) {
+ tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
+ sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
+ bufferWidth;
+ }
+ if (cropRect.height() < bufferHeight) {
+ ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
+ bufferHeight;
+ sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
+ bufferHeight;
}
}
+ float crop[16] = {
+ sx, 0, 0, 0,
+ 0, sy, 0, 0,
+ 0, 0, 1, 0,
+ tx, ty, 0, 1,
+ };
- // Only shrink the dimensions that are not the size of the buffer.
- if (cropRect.width() < bufferWidth) {
- tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
- sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
- bufferWidth;
- }
- if (cropRect.height() < bufferHeight) {
- ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
- bufferHeight;
- sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
- bufferHeight;
+ mtxMul(mtxBeforeFlipV, crop, xform);
+ } else {
+ for (int i = 0; i < 16; i++) {
+ mtxBeforeFlipV[i] = xform[i];
}
}
- float crop[16] = {
- sx, 0, 0, 0,
- 0, sy, 0, 0,
- 0, 0, 1, 0,
- tx, ty, 0, 1,
- };
-
- float mtxBeforeFlipV[16];
- mtxMul(mtxBeforeFlipV, crop, xform);
// SurfaceFlinger expects the top of its window textures to be at a Y
// coordinate of 0, so GLConsumer must behave the same way. We don't
@@ -828,12 +875,26 @@
}
EGLImageKHR GLConsumer::createImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& graphicBuffer) {
+ const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
EGLint attrs[] = {
- EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_IMAGE_CROP_LEFT_ANDROID, crop.left,
+ EGL_IMAGE_CROP_TOP_ANDROID, crop.top,
+ EGL_IMAGE_CROP_RIGHT_ANDROID, crop.right,
+ EGL_IMAGE_CROP_BOTTOM_ANDROID, crop.bottom,
EGL_NONE,
};
+ if (!crop.isValid()) {
+ // No crop rect to set, so terminate the attrib array before the crop.
+ attrs[2] = EGL_NONE;
+ } else if (!isEglImageCroppable(crop)) {
+ // The crop rect is not at the origin, so we can't set the crop on the
+ // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
+ // extension. In the future we can add a layered extension that
+ // removes this restriction if there is hardware that can support it.
+ attrs[2] = EGL_NONE;
+ }
EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
if (image == EGL_NO_IMAGE_KHR) {
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 6c505ed..3b2984a 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -494,6 +494,14 @@
#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
#endif
+#ifndef EGL_ANDROID_image_crop
+#define EGL_ANDROID_image_crop 1
+#define EGL_IMAGE_CROP_LEFT_ANDROID 0x3148
+#define EGL_IMAGE_CROP_TOP_ANDROID 0x3149
+#define EGL_IMAGE_CROP_RIGHT_ANDROID 0x314A
+#define EGL_IMAGE_CROP_BOTTOM_ANDROID 0x314B
+#endif
+
#ifndef EGL_ANDROID_blob_cache
#define EGL_ANDROID_blob_cache 1
typedef khronos_ssize_t EGLsizeiANDROID;
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 04d5f45..0cc5265 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -99,6 +99,7 @@
"EGL_NV_system_time "
"EGL_ANDROID_image_native_buffer " // mandatory
"EGL_KHR_wait_sync " // strongly recommended
+ "EGL_ANDROID_recordable " // mandatory
;
// extensions not exposed to applications but used by the ANDROID system
@@ -106,8 +107,7 @@
// "EGL_IMG_hibernate_process " // optional
// "EGL_ANDROID_native_fence_sync " // strongly recommended
// "EGL_ANDROID_framebuffer_target " // mandatory for HWC 1.1
-// "EGL_ANDROID_recordable " // mandatory
-
+// "EGL_ANDROID_image_crop " // optional
/*
* EGL Extensions entry-points exposed to 3rd party applications
diff --git a/opengl/specs/README b/opengl/specs/README
index eb86869..f4de1b3 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -14,4 +14,8 @@
0x3145 EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync)
0x3146 EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync)
0x3147 EGL_FRAMEBUFFER_TARGET_ANDROID (EGL_ANDROID_framebuffer_target)
-0x3148 - 0x314F (unused)
+0x3148 EGL_IMAGE_CROP_LEFT_ANDROID (EGL_ANDROID_image_crop)
+0x3149 EGL_IMAGE_CROP_TOP_ANDROID (EGL_ANDROID_image_crop)
+0x314A EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
+0x314B EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
+0x314C - 0x314F (unused)
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c851a2c..7132b2f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -611,6 +611,10 @@
// here we're just making sure that "skip" layers are set
// to HWC_FRAMEBUFFER and we're also counting how many layers
// we have of each type.
+ //
+ // If there are no window layers, we treat the display has having FB
+ // composition, because SurfaceFlinger will use GLES to draw the
+ // wormhole region.
for (size_t i=0 ; i<mNumDisplays ; i++) {
DisplayData& disp(mDisplayData[i]);
disp.hasFbComp = false;
@@ -632,6 +636,11 @@
disp.hasOvComp = true;
}
}
+ if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
+ disp.hasFbComp = true;
+ }
+ } else {
+ disp.hasFbComp = true;
}
}
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 88ef392..c5a14b0 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -147,6 +147,10 @@
mFbProducerSlot, fbBuffer.get(),
mOutputProducerSlot, outBuffer.get());
+ // At this point we know the output buffer acquire fence,
+ // so update HWC state with it.
+ mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer);
+
return mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
}
@@ -415,7 +419,11 @@
return result;
mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
- result = mHwc.setOutputBuffer(mDisplayId, mOutputFence,
+ // On GLES-only frames, we don't have the right output buffer acquire fence
+ // until after GLES calls queueBuffer(). So here we just set the buffer
+ // (for use in HWC prepare) but not the fence; we'll call this again with
+ // the proper fence once we have it.
+ result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE,
mProducerBuffers[mOutputProducerSlot]);
return result;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f83cc06..e374548 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -366,12 +366,10 @@
operator EGLint const* () const { return &mList.keyAt(0).v; }
};
-EGLConfig SurfaceFlinger::selectEGLConfig(EGLDisplay display, EGLint nativeVisualId,
- EGLint renderableType) {
+status_t SurfaceFlinger::selectEGLConfig(EGLDisplay display, EGLint nativeVisualId,
+ EGLint renderableType, EGLConfig* config) {
// select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
// it is to be used with WIFI displays
- EGLConfig config;
- EGLint dummy;
status_t err;
EGLint wantedAttribute;
EGLint wantedAttributeValue;
@@ -390,22 +388,18 @@
} else {
// if no renderable type specified, fallback to a simplified query
- attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
wantedAttribute = EGL_NATIVE_VISUAL_ID;
wantedAttributeValue = nativeVisualId;
}
err = selectConfigForAttribute(display, attribs, wantedAttribute,
- wantedAttributeValue, &config);
- if (!err)
- goto success;
-
- return 0;
-
-success:
- if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy))
- ALOGW_IF(dummy == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
- return config;
+ wantedAttributeValue, config);
+ if (err == NO_ERROR) {
+ EGLint caveat;
+ if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
+ ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
+ }
+ return err;
}
void SurfaceFlinger::init() {
@@ -413,6 +407,7 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
+ status_t err;
Mutex::Autolock _l(mStateLock);
// initialize EGL for the default display
@@ -425,21 +420,23 @@
*static_cast<HWComposer::EventHandler *>(this));
// First try to get an ES2 config
- mEGLConfig = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), EGL_OPENGL_ES2_BIT);
+ err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), EGL_OPENGL_ES2_BIT,
+ &mEGLConfig);
- if (!mEGLConfig) {
+ if (err != NO_ERROR) {
// If ES2 fails, try ES1
- mEGLConfig = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), EGL_OPENGL_ES_BIT);
+ err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(),
+ EGL_OPENGL_ES_BIT, &mEGLConfig);
}
- if (!mEGLConfig) {
+ if (err != NO_ERROR) {
// still didn't work, probably because we're on the emulator...
// try a simplified query
ALOGW("no suitable EGLConfig found, trying a simpler query");
- mEGLConfig = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), 0);
+ err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), 0, &mEGLConfig);
}
- if (!mEGLConfig) {
+ if (err != NO_ERROR) {
// this EGL is too lame for android
LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
}
@@ -1527,7 +1524,7 @@
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
- const bool hasGlesComposition = hwc.hasGlesComposition(id) || (cur==end);
+ bool hasGlesComposition = hwc.hasGlesComposition(id);
if (hasGlesComposition) {
if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) {
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
@@ -1600,9 +1597,10 @@
if (!clip.isEmpty()) {
switch (cur->getCompositionType()) {
case HWC_OVERLAY: {
+ const Layer::State& state(layer->getDrawingState());
if ((cur->getHints() & HWC_HINT_CLEAR_FB)
&& i
- && layer->isOpaque()
+ && layer->isOpaque() && (state.alpha == 0xFF)
&& hasGlesComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 989e439..0e9955c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -317,8 +317,8 @@
*/
static status_t selectConfigForAttribute(EGLDisplay dpy,
EGLint const* attrs, EGLint attribute, EGLint value, EGLConfig* outConfig);
- static EGLConfig selectEGLConfig(EGLDisplay disp, EGLint visualId,
- EGLint renderableType);
+ static status_t selectEGLConfig(EGLDisplay disp, EGLint visualId,
+ EGLint renderableType, EGLConfig* config);
size_t getMaxTextureSize() const;
size_t getMaxViewportDims() const;