Merge "Background modifications trigger callbacks (BufferStateLayer)"
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 62d2fa1..d398559 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -222,9 +222,9 @@
}
bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
- sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0);
+ const sp<IBinder> dpy = mSurfaceComposerClient->getInternalDisplayToken();
if (dpy == nullptr) {
- fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n");
+ fprintf(stderr, "SurfaceComposer::getInternalDisplayToken failed.\n");
return false;
}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index b8c6cfe..337308b 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -152,6 +152,20 @@
mDriverPath = path;
}
+void GraphicsEnv::setGpuStats(const std::string driverPackageName,
+ const std::string driverVersionName, const uint64_t driverVersionCode,
+ const std::string appPackageName) {
+ ALOGV("setGpuStats: drvPkgName[%s], drvVerName[%s], drvVerCode[%lld], appPkgName[%s]",
+ driverPackageName.c_str(), driverVersionName.c_str(), (long long)driverVersionCode,
+ appPackageName.c_str());
+ mGpuStats = {
+ .driverPackageName = driverPackageName,
+ .driverVersionName = driverVersionName,
+ .driverVersionCode = driverVersionCode,
+ .appPackageName = appPackageName,
+ };
+}
+
void* GraphicsEnv::loadLibrary(std::string name) {
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index ed08882..a247bec 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -28,6 +28,13 @@
struct NativeLoaderNamespace;
class GraphicsEnv {
+ struct GpuStats {
+ std::string driverPackageName;
+ std::string driverVersionName;
+ uint64_t driverVersionCode;
+ std::string appPackageName;
+ };
+
public:
static GraphicsEnv& getInstance();
@@ -40,6 +47,8 @@
// /data/app/com.example.driver/base.apk!/lib/arm64-v8a
void setDriverPath(const std::string path);
android_namespace_t* getDriverNamespace();
+ void setGpuStats(const std::string driverPackageName, const std::string driverVersionName,
+ const uint64_t versionCode, const std::string appPackageName);
bool shouldUseAngle(std::string appName);
bool shouldUseAngle();
@@ -70,6 +79,7 @@
GraphicsEnv() = default;
std::string mDriverPath;
+ GpuStats mGpuStats;
std::string mAnglePath;
std::string mAngleAppName;
std::string mAngleDeveloperOptIn;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index fd30e3b..fc9185d 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -275,12 +275,25 @@
remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
}
- virtual sp<IBinder> getBuiltInDisplay(int32_t id)
- {
+ virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeInt32(id);
- remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply);
+ if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
+ NO_ERROR) {
+ std::vector<PhysicalDisplayId> displayIds;
+ if (reply.readUint64Vector(&displayIds) == NO_ERROR) {
+ return displayIds;
+ }
+ }
+
+ return {};
+ }
+
+ virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeUint64(displayId);
+ remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply);
return reply.readStrongBinder();
}
@@ -896,10 +909,10 @@
destroyDisplay(display);
return NO_ERROR;
}
- case GET_BUILT_IN_DISPLAY: {
+ case GET_PHYSICAL_DISPLAY_TOKEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int32_t id = data.readInt32();
- sp<IBinder> display(getBuiltInDisplay(id));
+ PhysicalDisplayId displayId = data.readUint64();
+ sp<IBinder> display = getPhysicalDisplayToken(displayId);
reply->writeStrongBinder(display);
return NO_ERROR;
}
@@ -1216,12 +1229,14 @@
}
return error;
}
+ case GET_PHYSICAL_DISPLAY_IDS: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ return reply->writeUint64Vector(getPhysicalDisplayIds());
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
}
}
-// ----------------------------------------------------------------------------
-
-};
+} // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1f726b2..3affa23 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -321,8 +321,11 @@
status_t Surface::getWideColorSupport(bool* supported) {
ATRACE_CALL();
- sp<IBinder> display(
- composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ if (display == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+
*supported = false;
status_t error = composerService()->isWideColorDisplay(display, supported);
return error;
@@ -331,8 +334,11 @@
status_t Surface::getHdrSupport(bool* supported) {
ATRACE_CALL();
- sp<IBinder> display(
- composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ if (display == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+
HdrCapabilities hdrCapabilities;
status_t err =
composerService()->getHdrCapabilities(display, &hdrCapabilities);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 92b5588..46b9128 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -484,8 +484,20 @@
return ComposerService::getComposerService()->destroyDisplay(display);
}
-sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
- return ComposerService::getComposerService()->getBuiltInDisplay(id);
+std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() {
+ return ComposerService::getComposerService()->getPhysicalDisplayIds();
+}
+
+std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
+ return ComposerService::getComposerService()->getInternalDisplayId();
+}
+
+sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
+ return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId);
+}
+
+sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
+ return ComposerService::getComposerService()->getInternalDisplayToken();
}
void SurfaceComposerClient::Transaction::setAnimationTransaction() {
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 008f520..55488da 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -63,23 +63,25 @@
SurfaceControl::~SurfaceControl()
{
+ // Avoid reparenting the server-side surface to null if we are not the owner of it,
+ // meaning that we retrieved it from another process.
if (mClient != nullptr && mHandle != nullptr && mOwned) {
SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient());
}
- mClient.clear();
- mHandle.clear();
- mGraphicBufferProducer.clear();
- IPCThreadState::self()->flushCommands();
+ release();
}
void SurfaceControl::destroy()
{
- // Avoid destroying the server-side surface if we are not the owner of it, meaning that we
- // retrieved it from another process.
- if (isValid() && mOwned) {
+ if (isValid()) {
SurfaceComposerClient::Transaction().reparent(this, nullptr).apply();
}
- // clear all references and trigger an IPC now, to make sure things
+ release();
+}
+
+void SurfaceControl::release()
+{
+ // Trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
mClient.clear();
mHandle.clear();
@@ -87,17 +89,6 @@
IPCThreadState::self()->flushCommands();
}
-void SurfaceControl::clear()
-{
- // here, the window manager tells us explicitly that we should destroy
- // the surface's resource. Soon after this call, it will also release
- // its last reference (which will call the dtor); however, it is possible
- // that a client living in the same process still holds references which
- // would delay the call to the dtor -- that is why we need this explicit
- // "clear()" call.
- destroy();
-}
-
void SurfaceControl::disconnect() {
if (mGraphicBufferProducer != nullptr) {
mGraphicBufferProducer->disconnect(
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index a4102df..8c3f463 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -58,7 +58,7 @@
struct Header {
uint32_t type;
- uint32_t id;
+ PhysicalDisplayId displayId;
nsecs_t timestamp __attribute__((aligned(8)));
};
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 7146b7d..a2db7bc 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -34,6 +34,7 @@
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
+#include <optional>
#include <vector>
namespace android {
@@ -71,11 +72,6 @@
eEarlyWakeup = 0x04
};
- enum {
- eDisplayIdMain = 0,
- eDisplayIdHdmi = 1
- };
-
enum Rotation {
eRotateNone = 0,
eRotate90 = 1,
@@ -88,7 +84,7 @@
eVsyncSourceSurfaceFlinger = 1
};
- /*
+ /*
* Create a connection with SurfaceFlinger.
*/
virtual sp<ISurfaceComposerClient> createConnection() = 0;
@@ -108,10 +104,26 @@
*/
virtual void destroyDisplay(const sp<IBinder>& display) = 0;
- /* get the token for the existing default displays. possible values
- * for id are eDisplayIdMain and eDisplayIdHdmi.
+ /* get stable IDs for connected physical displays.
*/
- virtual sp<IBinder> getBuiltInDisplay(int32_t id) = 0;
+ virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+ const auto displayIds = getPhysicalDisplayIds();
+ return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
+ }
+
+ /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
+ * DisplayEventReceiver hotplug event.
+ */
+ virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const = 0;
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+ }
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual void setTransactionState(const Vector<ComposerState>& state,
@@ -341,7 +353,7 @@
CREATE_DISPLAY_EVENT_CONNECTION,
CREATE_DISPLAY,
DESTROY_DISPLAY,
- GET_BUILT_IN_DISPLAY,
+ GET_PHYSICAL_DISPLAY_TOKEN,
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
GET_SUPPORTED_FRAME_TIMESTAMPS,
@@ -370,6 +382,7 @@
GET_PROTECTED_CONTENT_SUPPORT,
IS_WIDE_COLOR_DISPLAY,
GET_DISPLAY_NATIVE_PRIMARIES,
+ GET_PHYSICAL_DISPLAY_IDS,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 044106d..aa99bd2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -196,9 +196,13 @@
//! Destroy a virtual display
static void destroyDisplay(const sp<IBinder>& display);
- //! Get the token for the existing default displays.
- //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
- static sp<IBinder> getBuiltInDisplay(int32_t id);
+ //! Get stable IDs for connected physical displays
+ static std::vector<PhysicalDisplayId> getPhysicalDisplayIds();
+ static std::optional<PhysicalDisplayId> getInternalDisplayId();
+
+ //! Get token for a physical display given its stable ID
+ static sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId);
+ static sp<IBinder> getInternalDisplayToken();
static status_t enableVSyncInjections(bool enable);
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index b584f36..55efcbf 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -58,8 +58,12 @@
static bool isSameSurface(
const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
- // release surface data from java
- void clear();
+ // Release the handles assosciated with the SurfaceControl, without reparenting
+ // them off-screen. At the moment if this isn't executed before ~SurfaceControl
+ // is called then the destructor will reparent the layer off-screen for you.
+ void release();
+ // Reparent off-screen and release. This is invoked by the destructor.
+ void destroy();
// disconnect any api that's connected
void disconnect();
@@ -98,7 +102,6 @@
sp<Surface> generateSurfaceLocked() const;
status_t validate() const;
- void destroy();
sp<SurfaceComposerClient> mClient;
sp<IBinder> mHandle;
diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp
index 5443812..b647aab 100644
--- a/libs/gui/tests/DisplayedContentSampling_test.cpp
+++ b/libs/gui/tests/DisplayedContentSampling_test.cpp
@@ -32,7 +32,7 @@
void SetUp() {
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(OK, mComposerClient->initCheck());
- mDisplayToken = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ mDisplayToken = mComposerClient->getInternalDisplayToken();
ASSERT_TRUE(mDisplayToken);
}
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index ac97733..4a78480 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -233,9 +233,11 @@
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+ const auto display = mComposerClient->getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- auto display = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info));
// After a new buffer is queued, SurfaceFlinger is notified and will
// latch the new buffer on next vsync. Let's heuristically wait for 3
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8bd589d..bec9299 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -131,8 +131,10 @@
// Verify the screenshot works with no protected buffers.
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> display(sf->getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+
+ const sp<IBinder> display = sf->getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
sp<GraphicBuffer> outBuffer;
ASSERT_EQ(NO_ERROR,
sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
@@ -552,7 +554,8 @@
sp<IBinder> createDisplay(const String8& /*displayName*/,
bool /*secure*/) override { return nullptr; }
void destroyDisplay(const sp<IBinder>& /*display */) override {}
- sp<IBinder> getBuiltInDisplay(int32_t /*id*/) override { return nullptr; }
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
+ sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
void setTransactionState(const Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
const sp<IBinder>& /*applyToken*/,
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 6ea1270..8ef4896 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -263,8 +263,17 @@
if (!desc) return 0;
if (!AHardwareBuffer_isValidDescription(desc, /*log=*/false)) return 0;
- // Make a trial allocation.
- // TODO(b/115660272): add implementation that uses a HAL query.
+ bool supported = false;
+ GraphicBuffer* gBuffer = new GraphicBuffer();
+ status_t err = gBuffer->isSupported(desc->width, desc->height, desc->format, desc->layers,
+ desc->usage, &supported);
+
+ if (err == NO_ERROR) {
+ return supported;
+ }
+
+ // function isSupported is not implemented on device or an error occurred during HAL
+ // query. Make a trial allocation.
AHardwareBuffer_Desc trialDesc = *desc;
trialDesc.width = 4;
trialDesc.height = desc->format == AHARDWAREBUFFER_FORMAT_BLOB ? 1 : 4;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index c5a9942..3d6ac8f 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -449,6 +449,7 @@
}
base::unique_fd GLESRenderEngine::flush() {
+ ATRACE_CALL();
if (!GLExtensions::getInstance().hasNativeFenceSync()) {
return base::unique_fd();
}
@@ -479,6 +480,7 @@
}
bool GLESRenderEngine::finish() {
+ ATRACE_CALL();
if (!GLExtensions::getInstance().hasFenceSync()) {
ALOGW("no synchronization support");
return false;
@@ -544,6 +546,8 @@
}
void GLESRenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+ ATRACE_CALL();
+ glDisable(GL_BLEND);
glClearColor(red, green, blue, alpha);
glClear(GL_COLOR_BUFFER_BIT);
}
@@ -594,6 +598,7 @@
}
void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) {
+ ATRACE_CALL();
const GLImage& glImage = static_cast<const GLImage&>(image);
const GLenum target = GL_TEXTURE_EXTERNAL_OES;
@@ -608,8 +613,15 @@
}
status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
+ sp<Fence> bufferFence, bool readCache) {
+ return bindExternalTextureBuffer(texName, buffer, bufferFence, readCache,
+ /*persistCache=*/false);
+}
+
+status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
sp<Fence> bufferFence, bool readCache,
bool persistCache) {
+ ATRACE_CALL();
if (readCache) {
auto cachedImage = mImageCache.find(buffer->getId());
@@ -655,7 +667,7 @@
}
// We don't always want to persist to the cache, e.g. on older devices we
- // might bind for synchronization purpoeses, but that might leak if we never
+ // might bind for synchronization purposes, but that might leak if we never
// call drawLayers again, so it's just better to recreate the image again
// if needed when we draw.
if (persistCache) {
@@ -703,6 +715,7 @@
}
status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
+ ATRACE_CALL();
GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
EGLImageKHR eglImage = glFramebuffer->getEGLImage();
uint32_t textureName = glFramebuffer->getTextureName();
@@ -770,6 +783,7 @@
const std::vector<LayerSettings>& layers,
ANativeWindowBuffer* const buffer,
base::unique_fd* drawFence) {
+ ATRACE_CALL();
if (layers.empty()) {
ALOGV("Drawing empty layer stack");
return NO_ERROR;
@@ -786,6 +800,13 @@
evictImages(layers);
+ // clear the entire buffer, sometimes when we reuse buffers we'd persist
+ // ghost images otherwise.
+ // we also require a full transparent framebuffer for overlays. This is
+ // probably not quite efficient on all GPUs, since we could filter out
+ // opaque layers.
+ clearWithColor(0.0, 0.0, 0.0, 0.0);
+
setViewportAndProjection(display.physicalDisplay, display.clip);
setOutputDataSpace(display.outputDataspace);
@@ -794,6 +815,7 @@
mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
mState.projectionMatrix = projectionMatrix;
if (!display.clearRegion.isEmpty()) {
+ glDisable(GL_BLEND);
fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0);
}
@@ -813,9 +835,11 @@
bool usePremultipliedAlpha = true;
bool disableTexture = true;
+ bool isOpaque = false;
if (layer.source.buffer.buffer != nullptr) {
disableTexture = false;
+ isOpaque = layer.source.buffer.isOpaque;
sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
@@ -825,17 +849,19 @@
usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
- texture.setMatrix(layer.source.buffer.textureTransform.asArray());
+ mat4 texMatrix = layer.source.buffer.textureTransform;
+
+ texture.setMatrix(texMatrix.asArray());
texture.setFiltering(layer.source.buffer.useTextureFiltering);
texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
setSourceY410BT2020(layer.source.buffer.isY410BT2020);
renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
- texCoords[0] = vec2(0.0, 1.0);
- texCoords[1] = vec2(0.0, 0.0);
- texCoords[2] = vec2(1.0, 0.0);
- texCoords[3] = vec2(1.0, 1.0);
+ texCoords[0] = vec2(0.0, 0.0);
+ texCoords[1] = vec2(0.0, 1.0);
+ texCoords[2] = vec2(1.0, 1.0);
+ texCoords[3] = vec2(1.0, 0.0);
setupLayerTexturing(texture);
}
@@ -843,8 +869,11 @@
const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
// Buffer sources will have a black solid color ignored in the shader,
// so in that scenario the solid color passed here is arbitrary.
- setupLayerBlending(usePremultipliedAlpha, layer.source.buffer.isOpaque, disableTexture,
- color, layer.geometry.roundedCornersRadius);
+ setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
+ layer.geometry.roundedCornersRadius);
+ if (layer.disableBlending) {
+ glDisable(GL_BLEND);
+ }
setSourceDataSpace(layer.sourceDataspace);
drawMesh(mesh);
@@ -903,6 +932,7 @@
}
void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
+ ATRACE_CALL();
mVpWidth = viewport.getWidth();
mVpHeight = viewport.getHeight();
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index e094860..34187f1 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -71,6 +71,8 @@
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
void bindExternalTextureImage(uint32_t texName, const Image& image) override;
+ status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence,
+ bool readCache);
status_t bindFrameBuffer(Framebuffer* framebuffer) override;
void unbindFrameBuffer(Framebuffer* framebuffer) override;
void checkErrors() const override;
@@ -184,6 +186,9 @@
const bool mUseColorManagement = false;
// Cache of GL images that we'll store per GraphicBuffer ID
+ // TODO: Layer should call back on destruction instead to clean this up,
+ // as it has better system utilization at the potential expense of a
+ // more complicated interface.
std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache;
class FlushTracer {
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index 4a519bb..0e3b405 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "GLFramebuffer.h"
#include <GLES/gl.h>
@@ -21,6 +23,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <nativebase/nativebase.h>
+#include <utils/Trace.h>
#include "GLESRenderEngine.h"
namespace android {
@@ -40,6 +43,7 @@
}
bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) {
+ ATRACE_CALL();
if (mEGLImage != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(mEGLDisplay, mEGLImage);
mEGLImage = EGL_NO_IMAGE_KHR;
diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp
index 587cb31..77e648e 100644
--- a/libs/renderengine/gl/GLImage.cpp
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "GLImage.h"
#include <vector>
#include <log/log.h>
+#include <utils/Trace.h>
#include "GLESRenderEngine.h"
#include "GLExtensions.h"
@@ -50,6 +53,7 @@
}
bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) {
+ ATRACE_CALL();
if (mEGLImage != EGL_NO_IMAGE_KHR) {
if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
ALOGE("failed to destroy image: %#x", eglGetError());
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 56ac714..aa45ed8 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -126,6 +126,9 @@
// Additional layer-specific color transform to be applied before the global
// transform.
mat4 colorTransform = mat4();
+
+ // True if blending will be forced to be disabled.
+ bool disableBlending = false;
};
} // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 20dd996..bc1a4da 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -108,6 +108,8 @@
virtual void genTextures(size_t count, uint32_t* names) = 0;
virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
+ virtual status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
+ sp<Fence> fence, bool cleanCache) = 0;
// When binding a native buffer, it must be done before setViewportAndProjection
// Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index b4c7c96..4b86cfe 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -52,6 +52,7 @@
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
+ MOCK_METHOD4(bindExternalTextureBuffer, status_t(uint32_t, sp<GraphicBuffer>, sp<Fence>, bool));
MOCK_CONST_METHOD0(checkErrors, void());
MOCK_METHOD4(setViewportAndProjection,
void(size_t, size_t, Rect, ui::Transform::orientation_flags));
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index bef25a8..f82beeb 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -178,6 +178,9 @@
template <typename SourceVariant>
void fillBufferWithRoundedCorners();
+ template <typename SourceVariant>
+ void overlayCorners();
+
void fillRedBufferTextureTransform();
void fillBufferTextureTransform();
@@ -194,7 +197,7 @@
void clearLeftRegion();
- void fillBufferThenClearRegion();
+ void clearRegion();
// Dumb hack to get aroud the fact that tear-down for renderengine isn't
// well defined right now, so we can't create multiple instances
@@ -543,6 +546,44 @@
255);
}
+template <typename SourceVariant>
+void RenderEngineTest::overlayCorners() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ std::vector<renderengine::LayerSettings> layersFirst;
+
+ renderengine::LayerSettings layerOne;
+ layerOne.geometry.boundaries =
+ FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0);
+ SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
+ layerOne.alpha = 0.2;
+
+ layersFirst.push_back(layerOne);
+ invokeDraw(settings, layersFirst, mBuffer);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 0, 0, 0, 0);
+
+ std::vector<renderengine::LayerSettings> layersSecond;
+ renderengine::LayerSettings layerTwo;
+ layerTwo.geometry.boundaries =
+ FloatRect(DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
+ SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
+ layerTwo.alpha = 1.0f;
+
+ layersSecond.push_back(layerTwo);
+ invokeDraw(settings, layersSecond, mBuffer);
+
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 0, 255, 0, 255);
+}
+
void RenderEngineTest::fillRedBufferTextureTransform() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
@@ -685,14 +726,13 @@
invokeDraw(settings, layers, mBuffer);
}
-void RenderEngineTest::fillBufferThenClearRegion() {
- fillGreenBuffer<ColorSourceVariant>();
+void RenderEngineTest::clearRegion() {
// Reuse mBuffer
clearLeftRegion();
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 255);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT),
- 0, 255, 0, 255);
+ 0, 0, 0, 0);
}
TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
@@ -747,6 +787,10 @@
fillBufferWithRoundedCorners<ColorSourceVariant>();
}
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
+ overlayCorners<ColorSourceVariant>();
+}
+
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
@@ -795,6 +839,10 @@
fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
+ overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
@@ -843,6 +891,10 @@
fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
+ overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
TEST_F(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
fillBufferTextureTransform();
}
@@ -855,8 +907,8 @@
fillBufferWithoutPremultiplyAlpha();
}
-TEST_F(RenderEngineTest, drawLayers_fillBufferThenClearRegion) {
- fillBufferThenClearRegion();
+TEST_F(RenderEngineTest, drawLayers_clearRegion) {
+ clearRegion();
}
} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index e678c58..41ae253 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -286,22 +286,22 @@
return res;
}
-status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd)
-{
+status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
const Rect lockBounds(width, height);
- status_t res = lockAsync(inUsage, lockBounds, vaddr, fenceFd);
+ status_t res =
+ lockAsync(inUsage, lockBounds, vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
return res;
}
-status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect,
- void** vaddr, int fenceFd)
-{
- return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd);
+status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
+ return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
}
-status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage,
- uint64_t inConsumerUsage, const Rect& rect, void** vaddr, int fenceFd)
-{
+status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
+ const Rect& rect, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
if (rect.left < 0 || rect.right > width ||
rect.top < 0 || rect.bottom > height) {
ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
@@ -310,9 +310,9 @@
return BAD_VALUE;
}
- int32_t bytesPerPixel, bytesPerStride;
status_t res = getBufferMapper().lockAsync(handle, inProducerUsage, inConsumerUsage, rect,
- vaddr, fenceFd, &bytesPerPixel, &bytesPerStride);
+ vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
+
return res;
}
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 7d88c58..4d4ee68 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -180,11 +180,15 @@
status_t lockYCbCr(uint32_t inUsage, const Rect& rect,
android_ycbcr *ycbcr);
status_t unlock();
- status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd);
- status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr,
- int fenceFd);
- status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
- const Rect& rect, void** vaddr, int fenceFd);
+ // For the following three lockAsync functions, if bytesPerStride or bytesPerPixel
+ // are unknown or variable, -1 will be returned
+ status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+ status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+ status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage, const Rect& rect,
+ void** vaddr, int fenceFd, int32_t* outBytesPerPixel = nullptr,
+ int32_t* outBytesPerStride = nullptr);
status_t lockAsyncYCbCr(uint32_t inUsage, android_ycbcr *ycbcr,
int fenceFd);
status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index 4b03e44..5dc56c8 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -16,13 +16,21 @@
#pragma once
+#include <cinttypes>
+#include <cstdint>
+
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/common/1.2/types.h>
#include <system/graphics.h>
+#define ANDROID_PHYSICAL_DISPLAY_ID_FORMAT PRIu64
+
+namespace android {
+
+using PhysicalDisplayId = uint64_t;
+
// android::ui::* in this header file will alias different types as
// the HIDL interface is updated.
-namespace android {
namespace ui {
using android::hardware::graphics::common::V1_1::RenderIntent;
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 79166a7..872631f 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -954,6 +954,22 @@
egl_context_t* const c = get_context(share_list);
share_list = c->context;
}
+ // b/111083885 - If we are presenting EGL 1.4 interface to apps
+ // error out on robust access attributes that are invalid
+ // in EGL 1.4 as the driver may be fine with them but dEQP expects
+ // tests to fail according to spec.
+ if (attrib_list && (cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0))) {
+ const EGLint* attrib_ptr = attrib_list;
+ while (*attrib_ptr != EGL_NONE) {
+ GLint attr = *attrib_ptr++;
+ GLint value = *attrib_ptr++;
+ if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR) {
+ // We are GL ES context with EGL 1.4, this is an invalid
+ // attribute
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
+ }
+ };
+ }
EGLContext context = cnx->egl.eglCreateContext(
dp->disp.dpy, config, share_list, attrib_list);
if (context != EGL_NO_CONTEXT) {
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index b06422a..a0bd4e2 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -34,8 +34,12 @@
}
// Get main display parameters.
- sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain);
+ const auto mainDpy = SurfaceComposerClient::getInternalDisplayToken();
+ if (mainDpy == nullptr) {
+ fprintf(stderr, "ERROR: no display\n");
+ return;
+ }
+
DisplayInfo mainDpyInfo;
err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
if (err != NO_ERROR) {
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 65308a6..63748bf 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -57,8 +57,6 @@
compositionengine::LayerCreationArgs{this})} {
ALOGV("Creating Layer %s", args.name.string());
- mTexture.init(renderengine::Texture::TEXTURE_EXTERNAL, mTextureName);
-
mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
@@ -129,13 +127,11 @@
return inverse(tr);
}
-/*
- * onDraw will draw the current layer onto the presentable buffer
- */
-void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) {
+bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform, Region& clearRegion,
+ renderengine::LayerSettings& layer) {
ATRACE_CALL();
-
+ Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
if (CC_UNLIKELY(mActiveBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
@@ -153,30 +149,27 @@
finished = true;
return;
}
- under.orSelf(renderArea.getTransform().transform(layer->visibleRegion));
+ under.orSelf(layer->visibleRegion);
});
// if not everything below us is covered, we plug the holes!
Region holes(clip.subtract(under));
if (!holes.isEmpty()) {
- clearWithOpenGL(renderArea, 0, 0, 0, 1);
+ clearRegion.orSelf(holes);
}
- return;
+ return false;
}
-
- // Bind the current buffer to the GL texture, and wait for it to be
- // ready for us to draw into.
- status_t err = bindTextureImage();
- if (err != NO_ERROR) {
- ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
- // Go ahead and draw the buffer anyway; no matter what we do the screen
- // is probably going to have something visibly wrong.
- }
-
bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
-
- auto& engine(mFlinger->getRenderEngine());
-
+ const State& s(getDrawingState());
if (!blackOutLayer) {
+ layer.source.buffer.buffer = mActiveBuffer;
+ layer.source.buffer.isOpaque = isOpaque(s);
+ layer.source.buffer.fence = mActiveBufferFence;
+ layer.source.buffer.cacheHint = useCachedBufferForClientComposition()
+ ? renderengine::Buffer::CachingHint::USE_CACHE
+ : renderengine::Buffer::CachingHint::NO_CACHE;
+ layer.source.buffer.textureName = mTextureName;
+ layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
+ layer.source.buffer.isY410BT2020 = isHdrY410();
// TODO: we could be more subtle with isFixedSize()
const bool useFiltering = needsFiltering() || renderArea.needsFiltering() || isFixedSize();
@@ -213,17 +206,31 @@
memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
}
- // Set things up for texturing.
- mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
- mTexture.setFiltering(useFiltering);
- mTexture.setMatrix(textureMatrix);
+ const Rect win{computeBounds()};
+ const float bufferWidth = getBufferSize(s).getWidth();
+ const float bufferHeight = getBufferSize(s).getHeight();
- engine.setupLayerTexturing(mTexture);
+ const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
+ const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
+ const float translateY = float(win.top) / bufferHeight;
+ const float translateX = float(win.left) / bufferWidth;
+
+ // Flip y-coordinates because GLConsumer expects OpenGL convention.
+ mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
+ mat4::translate(vec4(-.5, -.5, 0, 1)) *
+ mat4::translate(vec4(translateX, translateY, 0, 1)) *
+ mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0));
+
+ layer.source.buffer.useTextureFiltering = useFiltering;
+ layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
} else {
- engine.setupLayerBlackedOut();
+ // If layer is blacked out, force alpha to 1 so that we draw a black color
+ // layer.
+ layer.source.buffer.buffer = nullptr;
+ layer.alpha = 1.0;
}
- drawWithOpenGL(renderArea, useIdentityTransform);
- engine.disableTexturing();
+
+ return true;
}
bool BufferLayer::isHdrY410() const {
@@ -365,20 +372,18 @@
return true;
}
-Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) {
+bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ const sp<Fence>& releaseFence) {
ATRACE_CALL();
- std::optional<Region> sidebandStreamDirtyRegion = latchSidebandStream(recomputeVisibleRegions);
+ bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
- if (sidebandStreamDirtyRegion) {
- return *sidebandStreamDirtyRegion;
+ if (refreshRequired) {
+ return refreshRequired;
}
- Region dirtyRegion;
-
if (!hasReadyFrame()) {
- return dirtyRegion;
+ return false;
}
// if we've already called updateTexImage() without going through
@@ -387,14 +392,14 @@
// compositionComplete() call.
// we'll trigger an update in onPreComposition().
if (mRefreshPending) {
- return dirtyRegion;
+ return false;
}
// If the head buffer's acquire fence hasn't signaled yet, return and
// try again later
if (!fenceHasSignaled()) {
mFlinger->signalLayerUpdate();
- return dirtyRegion;
+ return false;
}
// Capture the old state of the layer for comparisons later
@@ -404,24 +409,24 @@
if (!allTransactionsSignaled()) {
mFlinger->signalLayerUpdate();
- return dirtyRegion;
+ return false;
}
status_t err = updateTexImage(recomputeVisibleRegions, latchTime, releaseFence);
if (err != NO_ERROR) {
- return dirtyRegion;
+ return false;
}
err = updateActiveBuffer();
if (err != NO_ERROR) {
- return dirtyRegion;
+ return false;
}
mBufferLatched = true;
err = updateFrameNumber(latchTime);
if (err != NO_ERROR) {
- return dirtyRegion;
+ return false;
}
mRefreshPending = true;
@@ -461,11 +466,14 @@
Rect crop(getDrawingCrop());
const uint32_t transform(getDrawingTransform());
const uint32_t scalingMode(getDrawingScalingMode());
+ const bool transformToDisplayInverse(getTransformToDisplayInverse());
if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
- (scalingMode != mCurrentScalingMode)) {
+ (scalingMode != mCurrentScalingMode) ||
+ (transformToDisplayInverse != mTransformToDisplayInverse)) {
mCurrentCrop = crop;
mCurrentTransform = transform;
mCurrentScalingMode = scalingMode;
+ mTransformToDisplayInverse = transformToDisplayInverse;
recomputeVisibleRegions = true;
}
@@ -502,9 +510,7 @@
}
}
- // FIXME: postedRegion should be dirty & bounds
- // transform the dirty region to window-manager space
- return getTransform().transform(Region(getBufferSize(s)));
+ return true;
}
// transaction
@@ -606,67 +612,6 @@
sourceCrop.getWidth() != displayFrame.getWidth();
}
-void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
- ATRACE_CALL();
- const State& s(getDrawingState());
-
- computeGeometry(renderArea, getBE().mMesh, useIdentityTransform);
-
- /*
- * NOTE: the way we compute the texture coordinates here produces
- * different results than when we take the HWC path -- in the later case
- * the "source crop" is rounded to texel boundaries.
- * This can produce significantly different results when the texture
- * is scaled by a large amount.
- *
- * The GL code below is more logical (imho), and the difference with
- * HWC is due to a limitation of the HWC API to integers -- a question
- * is suspend is whether we should ignore this problem or revert to
- * GL composition when a buffer scaling is applied (maybe with some
- * minimal value)? Or, we could make GL behave like HWC -- but this feel
- * like more of a hack.
- */
- const Rect bounds{computeBounds()}; // Rounds from FloatRect
-
- Rect win = bounds;
- const int bufferWidth = getBufferSize(s).getWidth();
- const int bufferHeight = getBufferSize(s).getHeight();
-
- const float left = float(win.left) / float(bufferWidth);
- const float top = float(win.top) / float(bufferHeight);
- const float right = float(win.right) / float(bufferWidth);
- const float bottom = float(win.bottom) / float(bufferHeight);
-
- // TODO: we probably want to generate the texture coords with the mesh
- // here we assume that we only have 4 vertices
- renderengine::Mesh::VertexArray<vec2> texCoords(getBE().mMesh.getTexCoordArray<vec2>());
- // flip texcoords vertically because BufferLayerConsumer expects them to be in GL convention
- texCoords[0] = vec2(left, 1.0f - top);
- texCoords[1] = vec2(left, 1.0f - bottom);
- texCoords[2] = vec2(right, 1.0f - bottom);
- texCoords[3] = vec2(right, 1.0f - top);
-
- const auto roundedCornerState = getRoundedCornerState();
- const auto cropRect = roundedCornerState.cropRect;
- setupRoundedCornersCropCoordinates(win, cropRect);
-
- auto& engine(mFlinger->getRenderEngine());
- engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
- getColor(), roundedCornerState.radius);
- engine.setSourceDataSpace(mCurrentDataSpace);
-
- if (isHdrY410()) {
- engine.setSourceY410BT2020(true);
- }
-
- engine.setupCornerRadiusCropSize(cropRect.getWidth(), cropRect.getHeight());
-
- engine.drawMesh(getBE().mMesh);
- engine.disableBlending();
-
- engine.setSourceY410BT2020(false);
-}
-
uint64_t BufferLayer::getHeadFrameNumber() const {
if (hasFrameUpdate()) {
return getFrameNumber();
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 8158d6c..c118b78 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -22,6 +22,7 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
+#include <renderengine/Image.h>
#include <renderengine/Mesh.h>
#include <renderengine/Texture.h>
#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE
@@ -77,10 +78,6 @@
// isFixedSize - true if content has a fixed size
bool isFixedSize() const override;
- // onDraw - draws the surface.
- void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) override;
-
bool isHdrY410() const override;
void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
@@ -99,8 +96,8 @@
// If there was a GL composition step rendering the previous frame, then
// releaseFence will be populated with a native fence that fires when
// composition has completed.
- Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) override;
+ bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ const sp<Fence>& releaseFence) override;
bool isBufferLatched() const override { return mRefreshPending; }
@@ -137,7 +134,8 @@
virtual bool getAutoRefresh() const = 0;
virtual bool getSidebandStreamChanged() const = 0;
- virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
+ // Latch sideband stream and returns true if the dirty region should be updated.
+ virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
virtual bool hasFrameUpdate() const = 0;
@@ -168,23 +166,28 @@
bool mRefreshPending{false};
+ // Returns true if, when drawing the active buffer during gpu compositon, we
+ // should use a cached buffer or not.
+ virtual bool useCachedBufferForClientComposition() const = 0;
+
+ // prepareClientLayer - constructs a RenderEngine layer for GPU composition.
+ bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform, Region& clearRegion,
+ renderengine::LayerSettings& layer);
+
private:
// Returns true if this layer requires filtering
bool needsFiltering() const;
- // drawing
- void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
-
uint64_t getHeadFrameNumber() const;
uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
+ bool mTransformToDisplayInverse{false};
+
// main thread.
bool mBufferLatched{false}; // TODO: Use mActiveBuffer?
- // The texture used to draw the layer in GLES composition mode
- mutable renderengine::Texture mTexture;
-
Rect getBufferSize(const State& s) const override;
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 6826050..7ed8184 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -272,6 +272,7 @@
// Update the BufferLayerConsumer state.
mCurrentTexture = slot;
mCurrentTextureBuffer = nextTextureBuffer;
+ mCurrentTextureBufferStaleForGpu = false;
mCurrentTextureImageFreed = nullptr;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
@@ -294,48 +295,7 @@
status_t BufferLayerConsumer::bindTextureImageLocked() {
ATRACE_CALL();
- mRE.checkErrors();
-
- // It is possible for the current slot's buffer to be freed before a new one
- // is bound. In that scenario we still want to bind the image.
- if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureBuffer == nullptr) {
- BLC_LOGE("bindTextureImage: no currently-bound texture");
- mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
- return NO_INIT;
- }
-
- renderengine::Image* imageToRender;
-
- // mCurrentTextureImageFreed is non-null iff mCurrentTexture ==
- // BufferQueue::INVALID_BUFFER_SLOT, so we can omit that check.
- if (mCurrentTextureImageFreed) {
- imageToRender = mCurrentTextureImageFreed.get();
- } else if (mImages[mCurrentTexture]) {
- imageToRender = mImages[mCurrentTexture].get();
- } else {
- std::unique_ptr<renderengine::Image> image = mRE.createImage();
- bool success = image->setNativeWindowBuffer(mCurrentTextureBuffer->getNativeBuffer(),
- mCurrentTextureBuffer->getUsage() &
- GRALLOC_USAGE_PROTECTED);
- if (!success) {
- BLC_LOGE("bindTextureImage: Failed to create image. size=%ux%u st=%u usage=%#" PRIx64
- " fmt=%d",
- mCurrentTextureBuffer->getWidth(), mCurrentTextureBuffer->getHeight(),
- mCurrentTextureBuffer->getStride(), mCurrentTextureBuffer->getUsage(),
- mCurrentTextureBuffer->getPixelFormat());
- BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
- mRE.bindExternalTextureImage(mTexName, *image);
- return UNKNOWN_ERROR;
- }
- imageToRender = image.get();
- // Cache the image here so that we can reuse it.
- mImages[mCurrentTexture] = std::move(image);
- }
-
- mRE.bindExternalTextureImage(mTexName, *imageToRender);
-
- // Wait for the new buffer to be ready.
- return doFenceWaitLocked();
+ return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer, mCurrentFence, false);
}
status_t BufferLayerConsumer::syncForReleaseLocked(const sp<Fence>& releaseFence) {
@@ -433,16 +393,29 @@
return mCurrentApi;
}
-sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
+sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp<Fence>* outFence) const {
Mutex::Autolock lock(mMutex);
if (outSlot != nullptr) {
*outSlot = mCurrentTexture;
}
+ if (outFence != nullptr) {
+ *outFence = mCurrentFence;
+ }
+
return mCurrentTextureBuffer;
}
+bool BufferLayerConsumer::getAndSetCurrentBufferCacheHint() {
+ Mutex::Autolock lock(mMutex);
+ bool useCache = mCurrentTextureBufferStaleForGpu;
+ // Set the staleness bit here, as this function is only called during a
+ // client composition path.
+ mCurrentTextureBufferStaleForGpu = true;
+ return useCache;
+}
+
Rect BufferLayerConsumer::getCurrentCrop() const {
Mutex::Autolock lock(mMutex);
return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index ea46245..e2ef399 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -150,10 +150,16 @@
// for use with bilinear filtering.
void setFilteringEnabled(bool enabled);
+ // Sets mCurrentTextureBufferStaleForGpu to true to indicate that the
+ // buffer is now "stale" for GPU composition, and returns the old staleness
+ // bit as a caching hint.
+ bool getAndSetCurrentBufferCacheHint();
+
// getCurrentBuffer returns the buffer associated with the current image.
// When outSlot is not nullptr, the current buffer slot index is also
- // returned.
- sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr) const;
+ // returned. Simiarly, when outFence is not nullptr, the current output
+ // fence is returned.
+ sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const;
// getCurrentCrop returns the cropping rectangle of the current buffer.
Rect getCurrentCrop() const;
@@ -255,6 +261,10 @@
// must track it separately in order to support the getCurrentBuffer method.
sp<GraphicBuffer> mCurrentTextureBuffer;
+ // True if the buffer was used for the previous client composition frame,
+ // and false otherwise.
+ bool mCurrentTextureBufferStaleForGpu;
+
// mCurrentCrop is the crop rectangle that applies to the current texture.
// It gets set each time updateTexImage is called.
Rect mCurrentCrop;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 42021d1..93b2b99 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -190,7 +190,7 @@
return mSidebandStreamChanged;
}
-std::optional<Region> BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
bool sidebandStreamChanged = true;
if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
// mSidebandStreamChanged was changed to false
@@ -202,10 +202,9 @@
}
recomputeVisibleRegions = true;
- const State& s(getDrawingState());
- return getTransform().transform(Region(Rect(s.active_legacy.w, s.active_legacy.h)));
+ return true;
}
- return {};
+ return false;
}
bool BufferQueueLayer::hasFrameUpdate() const {
@@ -306,7 +305,7 @@
status_t BufferQueueLayer::updateActiveBuffer() {
// update the active buffer
- mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot);
+ mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
getBE().compositionInfo.mBuffer = mActiveBuffer;
getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
@@ -317,6 +316,10 @@
return NO_ERROR;
}
+bool BufferQueueLayer::useCachedBufferForClientComposition() const {
+ return mConsumer->getAndSetCurrentBufferCacheHint();
+}
+
status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mConsumer->getFrameNumber();
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index d7c3f6a..d392a69 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -62,6 +62,9 @@
public:
bool fenceHasSignaled() const override;
+protected:
+ bool useCachedBufferForClientComposition() const override;
+
private:
nsecs_t getDesiredPresentTime() override;
std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
@@ -81,7 +84,7 @@
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
- std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+ bool latchSidebandStream(bool& recomputeVisibleRegions) override;
bool hasFrameUpdate() const override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c0997a0..b95cd2e 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -421,7 +421,7 @@
return mSidebandStreamChanged.load();
}
-std::optional<Region> BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
if (mSidebandStreamChanged.exchange(false)) {
const State& s(getDrawingState());
// mSidebandStreamChanged was true
@@ -433,9 +433,9 @@
}
recomputeVisibleRegions = true;
- return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
+ return true;
}
- return {};
+ return false;
}
bool BufferStateLayer::hasFrameUpdate() const {
@@ -452,46 +452,7 @@
const State& s(getDrawingState());
auto& engine(mFlinger->getRenderEngine());
- engine.checkErrors();
-
- // TODO(marissaw): once buffers are cached, don't create a new image everytime
- mTextureImage = engine.createImage();
-
- bool created =
- mTextureImage->setNativeWindowBuffer(s.buffer->getNativeBuffer(),
- s.buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
- if (!created) {
- ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
- s.buffer->getWidth(), s.buffer->getHeight(), s.buffer->getStride(),
- s.buffer->getUsage(), s.buffer->getPixelFormat());
- engine.bindExternalTextureImage(mTextureName, *engine.createImage());
- return NO_INIT;
- }
-
- engine.bindExternalTextureImage(mTextureName, *mTextureImage);
-
- // Wait for the new buffer to be ready.
- if (s.acquireFence->isValid()) {
- if (SyncFeatures::getInstance().useWaitSync()) {
- base::unique_fd fenceFd(s.acquireFence->dup());
- if (fenceFd == -1) {
- ALOGE("error dup'ing fence fd: %d", errno);
- return -errno;
- }
- if (!engine.waitFence(std::move(fenceFd))) {
- ALOGE("failed to wait on fence fd");
- return UNKNOWN_ERROR;
- }
- } else {
- status_t err = s.acquireFence->waitForever("BufferStateLayer::bindTextureImage");
- if (err != NO_ERROR) {
- ALOGE("error waiting for fence: %d", err);
- return err;
- }
- }
- }
-
- return NO_ERROR;
+ return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence, false);
}
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
@@ -619,12 +580,18 @@
}
mActiveBuffer = s.buffer;
+ mActiveBufferFence = s.acquireFence;
getBE().compositionInfo.mBuffer = mActiveBuffer;
getBE().compositionInfo.mBufferSlot = 0;
return NO_ERROR;
}
+bool BufferStateLayer::useCachedBufferForClientComposition() const {
+ // TODO: Store a proper staleness bit to support EGLImage caching.
+ return false;
+}
+
status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
// TODO(marissaw): support frame history events
mCurrentFrameNumber = mFrameNumber;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 3f891d3..ef287b9 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -95,6 +95,9 @@
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
+protected:
+ bool useCachedBufferForClientComposition() const override;
+
private:
nsecs_t getDesiredPresentTime() override;
std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
@@ -114,7 +117,7 @@
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
- std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+ bool latchSidebandStream(bool& recomputeVisibleRegions) override;
bool hasFrameUpdate() const override;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index b4e9d17..d82ff0e 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -44,28 +44,14 @@
ColorLayer::~ColorLayer() = default;
-void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
- bool useIdentityTransform) {
- half4 color = getColor();
- if (color.a > 0) {
- renderengine::Mesh mesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2);
- computeGeometry(renderArea, mesh, useIdentityTransform);
- auto& engine(mFlinger->getRenderEngine());
-
- Rect win{computeBounds()};
-
- const auto roundedCornerState = getRoundedCornerState();
- const auto cropRect = roundedCornerState.cropRect;
- setupRoundedCornersCropCoordinates(win, cropRect);
-
- engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
- true /* disableTexture */, color, roundedCornerState.radius);
-
- engine.setSourceDataSpace(mCurrentDataSpace);
- engine.setupCornerRadiusCropSize(cropRect.getWidth(), cropRect.getHeight());
- engine.drawMesh(mesh);
- engine.disableBlending();
- }
+bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform, Region& clearRegion,
+ renderengine::LayerSettings& layer) {
+ Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
+ half4 color(getColor());
+ half3 solidColor(color.r, color.g, color.b);
+ layer.source.solidColor = solidColor;
+ return true;
}
bool ColorLayer::isVisible() const {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 3b98e8c..ed4c2d8 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -31,8 +31,6 @@
std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override;
virtual const char* getTypeId() const { return "ColorLayer"; }
- virtual void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform);
bool isVisible() const override;
bool setColor(const half3& color) override;
@@ -44,6 +42,9 @@
protected:
FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
+ virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform, Region& clearRegion,
+ renderengine::LayerSettings& layer);
private:
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index a7ab472..84b2423 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -97,10 +97,9 @@
// TODO(lpique): Make this protected once it is only internally called.
virtual OutputCompositionState& editState() = 0;
- // Gets the physical space dirty region. If repaintEverything is true, this
- // will be the full display bounds. Internally the dirty region is stored in
- // logical (aka layer stack) space.
- virtual Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const = 0;
+ // Gets the dirty region in layer stack space.
+ // If repaintEverything is true, this will be the full display bounds.
+ virtual Region getDirtyRegion(bool repaintEverything) const = 0;
// Tests whether a given layerStackId belongs in this output.
// A layer belongs to the output if its layerStackId matches the of the output layerStackId,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index dd01b05..ddeb730 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -75,16 +75,13 @@
// Allocates a buffer as scratch space for GPU composition
virtual sp<GraphicBuffer> dequeueBuffer() = 0;
- // Queues the drawn buffer for consumption by HWC
- virtual void queueBuffer() = 0;
+ // Queues the drawn buffer for consumption by HWC. readyFence is the fence
+ // which will fire when the buffer is ready for consumption.
+ virtual void queueBuffer(base::unique_fd&& readyFence) = 0;
// Called after the HWC calls are made to present the display
virtual void onPresentDisplayCompleted() = 0;
- // Marks the current buffer has finished, so that it can be presented and
- // swapped out
- virtual void finishBuffer() = 0;
-
// Called to set the viewport and projection state for rendering into this
// surface
virtual void setViewportAndProjection() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index d876c03..3fd057c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -61,7 +61,7 @@
const OutputCompositionState& getState() const override;
OutputCompositionState& editState() override;
- Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const override;
+ Region getDirtyRegion(bool repaintEverything) const override;
bool belongsInOutput(uint32_t, bool) const override;
compositionengine::OutputLayer* getOutputLayerForLayer(
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 0489310..2f0fceb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -53,9 +53,8 @@
status_t beginFrame(bool mustRecompose) override;
status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override;
sp<GraphicBuffer> dequeueBuffer() override;
- void queueBuffer() override;
+ void queueBuffer(base::unique_fd&& readyFence) override;
void onPresentDisplayCompleted() override;
- void finishBuffer() override;
void setViewportAndProjection() override;
void flip() override;
@@ -77,9 +76,6 @@
const sp<ANativeWindow> mNativeWindow;
// Current buffer being rendered into
sp<GraphicBuffer> mGraphicBuffer;
- // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
- // that drawing to the buffer is now complete.
- base::unique_fd mBufferReady;
const sp<DisplaySurface> mDisplaySurface;
ui::Size mSize;
std::uint32_t mPageFlipCount{0};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index e79a44c..2972ad7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -56,7 +56,7 @@
MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
MOCK_METHOD0(editState, OutputCompositionState&());
- MOCK_CONST_METHOD1(getPhysicalSpaceDirtyRegion, Region(bool));
+ MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
MOCK_CONST_METHOD2(belongsInOutput, bool(uint32_t, bool));
MOCK_CONST_METHOD1(getOutputLayerForLayer,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 2269e57..e9ff330 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -39,9 +39,8 @@
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData));
MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
- MOCK_METHOD0(queueBuffer, void());
+ MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
MOCK_METHOD0(onPresentDisplayCompleted, void());
- MOCK_METHOD0(finishBuffer, void());
MOCK_METHOD0(setViewportAndProjection, void());
MOCK_METHOD0(flip, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6d5147d..e103ebe 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -90,13 +90,25 @@
void Output::setColorTransform(const mat4& transform) {
const bool isIdentity = (transform == mat4());
-
- mState.colorTransform =
+ const auto newColorTransform =
isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+
+ if (mState.colorTransform == newColorTransform) {
+ return;
+ }
+
+ mState.colorTransform = newColorTransform;
+
+ dirtyEntireOutput();
}
void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
ui::RenderIntent renderIntent) {
+ if (mState.colorMode == mode && mState.dataspace == dataspace &&
+ mState.renderIntent == renderIntent) {
+ return;
+ }
+
mState.colorMode = mode;
mState.dataspace = dataspace;
mState.renderIntent = renderIntent;
@@ -106,6 +118,8 @@
ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
renderIntent);
+
+ dirtyEntireOutput();
}
void Output::dump(std::string& out) const {
@@ -170,13 +184,10 @@
return mState;
}
-Region Output::getPhysicalSpaceDirtyRegion(bool repaintEverything) const {
- Region dirty;
- if (repaintEverything) {
- dirty.set(mState.bounds);
- } else {
- dirty = mState.transform.transform(mState.dirtyRegion);
- dirty.andSelf(mState.bounds);
+Region Output::getDirtyRegion(bool repaintEverything) const {
+ Region dirty(mState.viewport);
+ if (!repaintEverything) {
+ dirty.andSelf(mState.dirtyRegion);
}
return dirty;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index d546fc8..3f841d2 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -156,7 +156,7 @@
return mGraphicBuffer;
}
-void RenderSurface::queueBuffer() {
+void RenderSurface::queueBuffer(base::unique_fd&& readyFence) {
auto& hwc = mCompositionEngine.getHwComposer();
const auto id = mDisplay.getId();
@@ -178,9 +178,9 @@
if (mGraphicBuffer == nullptr) {
ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str());
} else {
- status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(),
- dup(mBufferReady));
+ status_t result =
+ mNativeWindow->queueBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(), dup(readyFence));
if (result != NO_ERROR) {
ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
result);
@@ -190,12 +190,10 @@
LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
} else {
mNativeWindow->cancelBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(),
- dup(mBufferReady));
+ mGraphicBuffer->getNativeBuffer(), dup(readyFence));
}
}
- mBufferReady.reset();
mGraphicBuffer = nullptr;
}
}
@@ -217,14 +215,6 @@
ui::Transform::ROT_0);
}
-void RenderSurface::finishBuffer() {
- auto& renderEngine = mCompositionEngine.getRenderEngine();
- mBufferReady = renderEngine.flush();
- if (mBufferReady.get() < 0) {
- renderEngine.finish();
- }
-}
-
void RenderSurface::flip() {
mPageFlipCount++;
}
@@ -263,9 +253,5 @@
return mGraphicBuffer;
}
-base::unique_fd& RenderSurface::mutableBufferReadyForTest() {
- return mBufferReady;
-}
-
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 8cb6936..cd2d454 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -156,17 +156,17 @@
EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
// Otherwise if the values are different, updates happen
- EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+ EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
EXPECT_CALL(mHwComposer,
- setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::BT2100_PQ,
+ setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::DISPLAY_P3,
ui::RenderIntent::TONE_MAP_COLORIMETRIC))
.Times(1);
- mDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
ui::RenderIntent::TONE_MAP_COLORIMETRIC);
- EXPECT_EQ(ui::ColorMode::BT2100_PQ, mDisplay.getState().colorMode);
- EXPECT_EQ(ui::Dataspace::SRGB, mDisplay.getState().dataspace);
+ EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent);
}
@@ -174,7 +174,7 @@
impl::Display virtualDisplay{mCompositionEngine,
DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
- virtualDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
ui::RenderIntent::TONE_MAP_COLORIMETRIC);
EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index cc1211b..cb71821 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -43,15 +43,21 @@
mOutput.setDisplayColorProfileForTest(
std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+
+ mOutput.editState().bounds = kDefaultDisplaySize;
}
~OutputTest() override = default;
+ static const Rect kDefaultDisplaySize;
+
StrictMock<mock::CompositionEngine> mCompositionEngine;
mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
impl::Output mOutput{mCompositionEngine};
};
+const Rect OutputTest::kDefaultDisplaySize{100, 200};
+
/* ------------------------------------------------------------------------
* Basic construction
*/
@@ -76,8 +82,6 @@
*/
TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
mOutput.editState().isEnabled = true;
mOutput.setCompositionEnabled(true);
@@ -87,25 +91,21 @@
}
TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
mOutput.editState().isEnabled = false;
mOutput.setCompositionEnabled(true);
EXPECT_TRUE(mOutput.getState().isEnabled);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
mOutput.editState().isEnabled = true;
mOutput.setCompositionEnabled(false);
EXPECT_FALSE(mOutput.getState().isEnabled);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
/* ------------------------------------------------------------------------
@@ -135,7 +135,7 @@
*/
TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
- const ui::Size displaySize{100, 200};
+ const ui::Size displaySize{200, 400};
EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
@@ -152,16 +152,13 @@
*/
TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
-
const uint32_t layerStack = 123u;
mOutput.setLayerStackFilter(layerStack, true);
EXPECT_TRUE(mOutput.getState().layerStackInternal);
EXPECT_EQ(layerStack, mOutput.getState().layerStackId);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
/* ------------------------------------------------------------------------
@@ -176,27 +173,45 @@
EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
+ // Since identity is the default, the dirty region should be unchanged (empty)
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+
// Non-identity matrix sets a non-identity state value
const mat4 nonIdentity = mat4() * 2;
mOutput.setColorTransform(nonIdentity);
EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+
+ // Since this is a state change, the entire output should now be dirty.
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
/* ------------------------------------------------------------------------
* Output::setColorMode
*/
-TEST_F(OutputTest, setColorModeSetsModeUnlessNoChange) {
- EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) {
+ EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
- mOutput.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
ui::RenderIntent::TONE_MAP_COLORIMETRIC);
- EXPECT_EQ(ui::ColorMode::BT2100_PQ, mOutput.getState().colorMode);
- EXPECT_EQ(ui::Dataspace::SRGB, mOutput.getState().dataspace);
+ EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+}
+
+TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) {
+ mOutput.editState().colorMode = ui::ColorMode::DISPLAY_P3;
+ mOutput.editState().dataspace = ui::Dataspace::DISPLAY_P3;
+ mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC;
+
+ mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
}
/* ------------------------------------------------------------------------
@@ -215,52 +230,32 @@
}
/* ------------------------------------------------------------------------
- * Output::getPhysicalSpaceDirtyRegion()
+ * Output::getDirtyRegion()
*/
-TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingTrue) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
+TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) {
+ const Rect viewport{100, 200};
+ mOutput.editState().viewport = viewport;
mOutput.editState().dirtyRegion.set(50, 300);
{
- Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
+ Region result = mOutput.getDirtyRegion(true);
- EXPECT_THAT(result, RegionEq(Region(displaySize)));
- }
-
- // For repaint everything == true, the returned value does not depend on the display
- // rotation.
- mOutput.editState().transform.set(ui::Transform::ROT_90, 0, 0);
-
- {
- Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
-
- EXPECT_THAT(result, RegionEq(Region(displaySize)));
+ EXPECT_THAT(result, RegionEq(Region(viewport)));
}
}
-TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingFalse) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
+TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) {
+ const Rect viewport{100, 200};
+ mOutput.editState().viewport = viewport;
mOutput.editState().dirtyRegion.set(50, 300);
{
- Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
+ Region result = mOutput.getDirtyRegion(false);
// The dirtyRegion should be clipped to the display bounds.
EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
}
-
- mOutput.editState().transform.set(ui::Transform::ROT_90, displaySize.getWidth(),
- displaySize.getHeight());
-
- {
- Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
-
- // The dirtyRegion should be rotated and clipped to the display bounds.
- EXPECT_THAT(result, RegionEq(Region(Rect(100, 50))));
- }
}
/* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 13cc663..c56d92a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -373,7 +373,7 @@
.WillOnce(Return(false));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer();
+ mSurface.queueBuffer(base::unique_fd());
EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
}
@@ -387,7 +387,7 @@
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer();
+ mSurface.queueBuffer(base::unique_fd());
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
@@ -402,7 +402,7 @@
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer();
+ mSurface.queueBuffer(base::unique_fd());
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
@@ -419,7 +419,7 @@
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer();
+ mSurface.queueBuffer(base::unique_fd());
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
@@ -436,7 +436,7 @@
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
- mSurface.queueBuffer();
+ mSurface.queueBuffer(base::unique_fd());
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
@@ -452,29 +452,6 @@
}
/* ------------------------------------------------------------------------
- * RenderSurface::finishBuffer()
- */
-
-TEST_F(RenderSurfaceTest, finishBufferJustFlushesRenderEngine) {
- int fd = dup(1);
-
- EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(fd))));
-
- mSurface.finishBuffer();
-
- EXPECT_EQ(fd, mSurface.mutableBufferReadyForTest().release());
-}
-
-TEST_F(RenderSurfaceTest, finishBufferFlushesAndFinishesRenderEngine) {
- EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(-2))));
- EXPECT_CALL(mRenderEngine, finish()).Times(1);
-
- mSurface.finishBuffer();
-
- EXPECT_EQ(-2, mSurface.mutableBufferReadyForTest().release());
-}
-
-/* ------------------------------------------------------------------------
* RenderSurface::setViewportAndProjection()
*/
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index ca49f6c..941b4ad 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,9 +26,16 @@
ContainerLayer::~ContainerLayer() = default;
-void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) {}
+bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&,
+ renderengine::LayerSettings&) {
+ return false;
+}
bool ContainerLayer::isVisible() const {
+ return false;
+}
+
+bool ContainerLayer::canReceiveInput() const {
return !isHiddenByPolicy();
}
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 413844b..fec82d7 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -29,16 +29,21 @@
~ContainerLayer() override;
const char* getTypeId() const override { return "ContainerLayer"; }
- void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) override;
bool isVisible() const override;
+ bool canReceiveInput() const override;
+
void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
int32_t supportedPerFrameMetadata) override;
bool isCreatedFromMainThread() const override { return true; }
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
+
+protected:
+ bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform, Region& clearRegion,
+ renderengine::LayerSettings& layer);
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 1599995..d63cd79 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -23,10 +23,12 @@
#include <string_view>
#include <vector>
+#include <ui/GraphicTypes.h>
+
namespace android {
struct DisplayId {
- using Type = uint64_t;
+ using Type = PhysicalDisplayId;
Type value;
uint16_t manufacturerId() const;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e76cbd3..93a7acf 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -639,7 +639,7 @@
* Here we cancel out the orientation component of the WM transform.
* The scaling and translate components are already included in our bounds
* computation so it's enough to just omit it in the composition.
- * See comment in onDraw with ref to b/36727915 for why.
+ * See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why.
*/
transform = ui::Transform(invTransform) * tr * bufferOrientation;
}
@@ -707,12 +707,51 @@
// drawing...
// ---------------------------------------------------------------------------
-void Layer::draw(const RenderArea& renderArea, const Region& clip) {
- onDraw(renderArea, clip, false);
+bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+ Region& clearRegion, renderengine::LayerSettings& layer) {
+ return prepareClientLayer(renderArea, clip, false, clearRegion, layer);
}
-void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) {
- onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform);
+bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
+ Region& clearRegion, renderengine::LayerSettings& layer) {
+ return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
+ clearRegion, layer);
+}
+
+bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
+ bool useIdentityTransform, Region& /*clearRegion*/,
+ renderengine::LayerSettings& layer) {
+ FloatRect bounds = computeBounds();
+ half alpha = getAlpha();
+ layer.geometry.boundaries = bounds;
+ if (useIdentityTransform) {
+ layer.geometry.positionTransform = mat4();
+ } else {
+ const ui::Transform transform = getTransform();
+ mat4 m;
+ m[0][0] = transform[0][0];
+ m[0][1] = transform[0][1];
+ m[0][3] = transform[0][2];
+ m[1][0] = transform[1][0];
+ m[1][1] = transform[1][1];
+ m[1][3] = transform[1][2];
+ m[3][0] = transform[2][0];
+ m[3][1] = transform[2][1];
+ m[3][3] = transform[2][2];
+ layer.geometry.positionTransform = m;
+ }
+
+ if (hasColorTransform()) {
+ layer.colorTransform = getColorTransform();
+ }
+
+ const auto roundedCornerState = getRoundedCornerState();
+ layer.geometry.roundedCornersRadius = roundedCornerState.radius;
+ layer.geometry.roundedCornersCrop = roundedCornerState.cropRect;
+
+ layer.alpha = alpha;
+ layer.sourceDataspace = mCurrentDataSpace;
+ return true;
}
void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue,
@@ -2211,7 +2250,7 @@
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
- info.visible = isVisible();
+ info.visible = canReceiveInput();
return info;
}
@@ -2223,6 +2262,10 @@
return nullptr;
}
+bool Layer::canReceiveInput() const {
+ return isVisible();
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f099df6..8b6d4c7 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -387,6 +387,11 @@
bool isHiddenByPolicy() const;
/*
+ * Returns whether this layer can receive input.
+ */
+ virtual bool canReceiveInput() const;
+
+ /*
* isProtected - true if the layer may contain protected content in the
* GRALLOC_USAGE_PROTECTED sense.
*/
@@ -421,11 +426,9 @@
virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
protected:
- /*
- * onDraw - draws the surface.
- */
- virtual void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) = 0;
+ virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform, Region& clearRegion,
+ renderengine::LayerSettings& layer) = 0;
public:
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
@@ -475,11 +478,14 @@
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
/*
- * draw - performs some global clipping optimizations
- * and calls onDraw().
+ * prepareClientLayer - populates a renderengine::LayerSettings to passed to
+ * RenderEngine::drawLayers. Returns true if the layer can be used, and
+ * false otherwise.
*/
- void draw(const RenderArea& renderArea, const Region& clip);
- void draw(const RenderArea& renderArea, bool useIdentityTransform);
+ bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
+ renderengine::LayerSettings& layer);
+ bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
+ Region& clearRegion, renderengine::LayerSettings& layer);
/*
* doTransaction - process the transaction. This is a good place to figure
@@ -517,8 +523,8 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- virtual Region latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
- const sp<Fence>& /*releaseFence*/) {
+ virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
+ const sp<Fence>& /*releaseFence*/) {
return {};
}
@@ -810,7 +816,13 @@
FenceTimeline mReleaseTimeline;
// main thread
+ // Active buffer fields
sp<GraphicBuffer> mActiveBuffer;
+ sp<Fence> mActiveBufferFence;
+ // False if the buffer and its contents have been previously used for GPU
+ // composition, true otherwise.
+ bool mIsActiveBufferUpdatedForGpu = true;
+
ui::Dataspace mCurrentDataSpace = ui::Dataspace::UNKNOWN;
Rect mCurrentCrop;
uint32_t mCurrentTransform{0};
@@ -866,7 +878,6 @@
const LayerVector::Visitor& visitor);
LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet,
const std::vector<Layer*>& layersInTree);
-
/**
* Retuns the child bounds in layer space cropped to its bounds as well all its parent bounds.
* The cropped bounds must be transformed back from parent layer space to child layer space by
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 52abe9c..91ae087 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -69,24 +69,28 @@
std::string toString(const DisplayEventReceiver::Event& event) {
switch (event.header.type) {
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
- return StringPrintf("Hotplug{displayId=%u, %s}", event.header.id,
+ return StringPrintf("Hotplug{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", %s}",
+ event.header.displayId,
event.hotplug.connected ? "connected" : "disconnected");
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- return StringPrintf("VSync{displayId=%u, count=%u}", event.header.id,
- event.vsync.count);
+ return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+ ", count=%u}",
+ event.header.displayId, event.vsync.count);
default:
return "Event{}";
}
}
-DisplayEventReceiver::Event makeHotplug(uint32_t displayId, nsecs_t timestamp, bool connected) {
+DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t timestamp,
+ bool connected) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, displayId, timestamp};
event.hotplug.connected = connected;
return event;
}
-DisplayEventReceiver::Event makeVSync(uint32_t displayId, nsecs_t timestamp, uint32_t count) {
+DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
+ uint32_t count) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
event.vsync.count = count;
@@ -290,10 +294,9 @@
mCondition.notify_all();
}
-void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
+void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) {
std::lock_guard<std::mutex> lock(mMutex);
- const uint32_t displayId = displayType == DisplayType::Primary ? 0 : 1;
mPendingEvents.push_back(makeHotplug(displayId, systemTime(), connected));
mCondition.notify_all();
}
@@ -312,9 +315,9 @@
switch (event->header.type) {
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
if (event->hotplug.connected && !mVSyncState) {
- mVSyncState.emplace(event->header.id);
+ mVSyncState.emplace(event->header.displayId);
} else if (!event->hotplug.connected && mVSyncState &&
- mVSyncState->displayId == event->header.id) {
+ mVSyncState->displayId == event->header.displayId) {
mVSyncState.reset();
}
break;
@@ -440,8 +443,9 @@
StringAppendF(&result, "%s: state=%s VSyncState=", mThreadName, toCString(mState));
if (mVSyncState) {
- StringAppendF(&result, "{displayId=%u, count=%u%s}\n", mVSyncState->displayId,
- mVSyncState->count, mVSyncState->synthetic ? ", synthetic" : "");
+ StringAppendF(&result, "{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%u%s}\n",
+ mVSyncState->displayId, mVSyncState->count,
+ mVSyncState->synthetic ? ", synthetic" : "");
} else {
StringAppendF(&result, "none\n");
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 89b799e..62b6a8b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -94,9 +94,6 @@
class EventThread {
public:
- // TODO: Remove once stable display IDs are plumbed through SF/WM interface.
- enum class DisplayType { Primary, External };
-
virtual ~EventThread();
virtual sp<EventThreadConnection> createEventConnection(
@@ -108,8 +105,7 @@
// called after the screen is turned on from main thread
virtual void onScreenAcquired() = 0;
- // called when receiving a hotplug event
- virtual void onHotplugReceived(DisplayType displayType, bool connected) = 0;
+ virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
virtual void dump(std::string& result) const = 0;
@@ -151,8 +147,7 @@
// called after the screen is turned on from main thread
void onScreenAcquired() override;
- // called when receiving a hotplug event
- void onHotplugReceived(DisplayType displayType, bool connected) override;
+ void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
void dump(std::string& result) const override;
@@ -199,9 +194,9 @@
// VSYNC state of connected display.
struct VSyncState {
- explicit VSyncState(uint32_t displayId) : displayId(displayId) {}
+ explicit VSyncState(PhysicalDisplayId displayId) : displayId(displayId) {}
- const uint32_t displayId;
+ const PhysicalDisplayId displayId;
// Number of VSYNC events since display was connected.
uint32_t count = 0;
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/IdleTimer.cpp
index 5a76dbc..e975e65 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.cpp
+++ b/services/surfaceflinger/Scheduler/IdleTimer.cpp
@@ -54,18 +54,24 @@
if (mState == TimerState::IDLE) {
mCondition.wait(mMutex);
} else if (mState == TimerState::RESET) {
+ auto triggerTime = std::chrono::steady_clock::now() + mInterval;
mState = TimerState::WAITING;
- if (mCondition.wait_for(mMutex, mInterval) == std::cv_status::timeout) {
- if (mTimeoutCallback) {
- mTimeoutCallback();
+ while (mState == TimerState::WAITING) {
+ constexpr auto zero = std::chrono::steady_clock::duration::zero();
+ auto waitTime = triggerTime - std::chrono::steady_clock::now();
+ if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
+ if (mState == TimerState::WAITING &&
+ (triggerTime - std::chrono::steady_clock::now()) <= zero) {
+ if (mTimeoutCallback) {
+ mTimeoutCallback();
+ }
+
+ mState = TimerState::IDLE;
}
}
- if (mState == TimerState::WAITING) {
- mState = TimerState::IDLE;
- }
}
}
-}
+} // namespace scheduler
void IdleTimer::reset() {
{
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 00820f1..3060f1d 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -29,7 +29,6 @@
#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
-#include <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -81,7 +80,10 @@
}
}
-Scheduler::~Scheduler() = default;
+Scheduler::~Scheduler() {
+ // Ensure the IdleTimer thread is joined before we start destroying state.
+ mIdleTimer.reset();
+}
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
@@ -128,9 +130,9 @@
}
void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
- EventThread::DisplayType displayType, bool connected) {
+ PhysicalDisplayId displayId, bool connected) {
RETURN_IF_INVALID();
- mConnections[handle->id]->thread->onHotplugReceived(displayType, connected);
+ mConnections[handle->id]->thread->onHotplugReceived(displayId, connected);
}
void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index b717605..e77dc06 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -19,8 +19,8 @@
#include <cstdint>
#include <memory>
-#include <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
+#include <ui/GraphicTypes.h>
#include "DispSync.h"
#include "EventControlThread.h"
@@ -85,7 +85,7 @@
sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle);
// Should be called when receiving a hotplug event.
- void hotplugReceived(const sp<ConnectionHandle>& handle, EventThread::DisplayType displayType,
+ void hotplugReceived(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
bool connected);
// Should be called after the screen is turned on.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d54a1d5..aeaeb9f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// #define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <sys/types.h>
@@ -492,21 +492,30 @@
setTransactionFlags(eDisplayTransactionNeeded);
}
-sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
- std::optional<DisplayId> displayId;
+std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const {
+ Mutex::Autolock lock(mStateLock);
- if (id == HWC_DISPLAY_PRIMARY) {
- displayId = getInternalDisplayId();
- } else if (id == HWC_DISPLAY_EXTERNAL) {
- displayId = getExternalDisplayId();
+ const auto internalDisplayId = getInternalDisplayIdLocked();
+ if (!internalDisplayId) {
+ return {};
}
- if (!displayId) {
- ALOGE("%s: Invalid display %d", __FUNCTION__, id);
- return nullptr;
+ std::vector<PhysicalDisplayId> displayIds;
+ displayIds.reserve(mPhysicalDisplayTokens.size());
+ displayIds.push_back(internalDisplayId->value);
+
+ for (const auto& [id, token] : mPhysicalDisplayTokens) {
+ if (id != *internalDisplayId) {
+ displayIds.push_back(id.value);
+ }
}
- return getPhysicalDisplayToken(*displayId);
+ return displayIds;
+}
+
+sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
+ Mutex::Autolock lock(mStateLock);
+ return getPhysicalDisplayTokenLocked(DisplayId{displayId});
}
status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const {
@@ -610,9 +619,9 @@
// start the EventThread
if (mUseScheduler) {
- mScheduler = getFactory().createScheduler([this](bool enabled) {
- setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
- });
+ mScheduler = getFactory().createScheduler(
+ [this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
+
// TODO(b/113612090): Currently we assume that if scheduler is turned on, then the refresh
// rate is 90. Once b/122905403 is completed, this should be updated accordingly.
mPhaseOffsets->setRefreshRateType(
@@ -701,7 +710,7 @@
}
mEventControlThread = getFactory().createEventControlThread(
- [this](bool enabled) { setVsyncEnabled(EventThread::DisplayType::Primary, enabled); });
+ [this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -818,7 +827,9 @@
return BAD_VALUE;
}
- const auto displayId = getPhysicalDisplayId(displayToken);
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
if (!displayId) {
return NAME_NOT_FOUND;
}
@@ -842,8 +853,6 @@
configs->clear();
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
DisplayInfo info = DisplayInfo();
@@ -856,7 +865,7 @@
info.viewportW = info.w;
info.viewportH = info.h;
- if (displayId == getInternalDisplayId()) {
+ if (displayId == getInternalDisplayIdLocked()) {
// The density of the device is provided by a build property
float density = Density::getBuildDensity() / 160.0f;
if (density == 0) {
@@ -912,7 +921,7 @@
// All non-virtual displays are currently considered secure.
info.secure = true;
- if (displayId == getInternalDisplayId() &&
+ if (displayId == getInternalDisplayIdLocked() &&
primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
std::swap(info.w, info.h);
}
@@ -1010,15 +1019,15 @@
return BAD_VALUE;
}
- const auto displayId = getPhysicalDisplayId(displayToken);
- if (!displayId) {
- return NAME_NOT_FOUND;
- }
-
std::vector<ColorMode> modes;
{
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
+ }
+
modes = getHwComposer().getColorModes(*displayId);
}
outColorModes->clear();
@@ -1314,7 +1323,7 @@
}
nsecs_t SurfaceFlinger::getVsyncPeriod() const {
- const auto displayId = getInternalDisplayId();
+ const auto displayId = getInternalDisplayIdLocked();
if (!displayId || !getHwComposer().isConnected(*displayId)) {
return 0;
}
@@ -1431,9 +1440,10 @@
*compositorTiming = getBE().mCompositorTiming;
}
-void SurfaceFlinger::setRefreshRateTo(float newFps) {
- const auto displayId = getInternalDisplayId();
- if (!displayId || mBootStage != BootStage::FINISHED) {
+// TODO(b/123715322): Fix thread safety.
+void SurfaceFlinger::setRefreshRateTo(float newFps) NO_THREAD_SAFETY_ANALYSIS {
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display || mBootStage != BootStage::FINISHED) {
return;
}
// TODO(b/113612090): There should be a message queue flush here. Because this esentially
@@ -1442,8 +1452,7 @@
// refresh cycle.
// Don't do any updating if the current fps is the same as the new one.
- const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
- const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod();
+ const nsecs_t currentVsyncPeriod = getVsyncPeriod();
if (currentVsyncPeriod == 0) {
return;
}
@@ -1454,7 +1463,7 @@
return;
}
- auto configs = getHwComposer().getConfigs(*displayId);
+ auto configs = getHwComposer().getConfigs(*display->getId());
for (int i = 0; i < configs.size(); i++) {
const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
if (vsyncPeriod == 0) {
@@ -1464,11 +1473,12 @@
// TODO(b/113612090): There should be a better way at determining which config
// has the right refresh rate.
if (std::abs(fps - newFps) <= 1) {
- const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY);
- if (!display) return;
+ const sp<IBinder> token = display->getDisplayToken().promote();
+ LOG_ALWAYS_FATAL_IF(token == nullptr);
+
// This is posted in async function to avoid deadlock when getDisplayDevice
// requires mStateLock.
- setActiveConfigAsync(display, i);
+ setActiveConfigAsync(token, i);
ATRACE_INT("FPS", newFps);
}
}
@@ -1508,10 +1518,10 @@
repaintEverythingForHWC();
}
-void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
+void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
ATRACE_CALL();
Mutex::Autolock lock(mStateLock);
- if (const auto displayId = getInternalDisplayId()) {
+ if (const auto displayId = getInternalDisplayIdLocked()) {
getHwComposer().setVsyncEnabled(*displayId,
enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
}
@@ -1638,6 +1648,10 @@
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
+
+ updateCursorAsync();
+ updateInputFlinger();
+
refreshNeeded |= mRepaintEverything;
if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
// Signal a refresh if a transaction modified the window state,
@@ -1732,7 +1746,15 @@
bool SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
- return handlePageFlip();
+ bool refreshNeeded = handlePageFlip();
+
+ for (auto& layer : mLayersPendingRefresh) {
+ Region visibleReg;
+ visibleReg.set(layer->computeScreenBounds());
+ invalidateLayerStack(layer, visibleReg);
+ }
+ mLayersPendingRefresh.clear();
+ return refreshNeeded;
}
void SurfaceFlinger::calculateWorkingSet() {
@@ -1853,16 +1875,13 @@
if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
+ const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
if (!dirtyRegion.isEmpty()) {
+ base::unique_fd readyFence;
// redraw the whole screen
- doComposeSurfaces(displayDevice);
+ doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
- // and draw the dirty region
- auto& engine(getRenderEngine());
- engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
-
- display->getRenderSurface()->queueBuffer();
+ display->getRenderSurface()->queueBuffer(std::move(readyFence));
}
}
@@ -2399,7 +2418,7 @@
auto display = displayDevice->getCompositionDisplay();
const auto& displayState = display->getState();
- bool dirty = !display->getPhysicalSpaceDirtyRegion(false).isEmpty();
+ bool dirty = !display->getDirtyRegion(false).isEmpty();
bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
@@ -2450,7 +2469,7 @@
if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
+ const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
// repaint the framebuffer (if needed)
doDisplayComposition(displayDevice, dirtyRegion);
@@ -2598,14 +2617,13 @@
mPendingHotplugEvents.clear();
}
-void SurfaceFlinger::dispatchDisplayHotplugEvent(EventThread::DisplayType displayType,
- bool connected) {
+void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle, displayType, connected);
- mScheduler->hotplugReceived(mSfConnectionHandle, displayType, connected);
+ mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected);
+ mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected);
} else {
- mEventThread->onHotplugReceived(displayType, connected);
- mSFEventThread->onHotplugReceived(displayType, connected);
+ mEventThread->onHotplugReceived(displayId, connected);
+ mSFEventThread->onHotplugReceived(displayId, connected);
}
}
@@ -2621,7 +2639,7 @@
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
- const bool isInternalDisplay = displayId && displayId == getInternalDisplayId();
+ const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
creationArgs.isPrimary = isInternalDisplay;
if (useColorManagement && displayId) {
@@ -2704,19 +2722,18 @@
for (size_t i = 0; i < dc;) {
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
if (j < 0) {
- // Save display IDs before disconnecting.
- const auto internalDisplayId = getInternalDisplayId();
- const auto externalDisplayId = getExternalDisplayId();
-
// in drawing state but not in current state
if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
+ // Save display ID before disconnecting.
+ const auto displayId = display->getId();
display->disconnect();
+
+ if (!display->isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispatchDisplayHotplugEvent(displayId->value, false);
+ }
}
- if (internalDisplayId && internalDisplayId == draw[i].displayId) {
- dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, false);
- } else if (externalDisplayId && externalDisplayId == draw[i].displayId) {
- dispatchDisplayHotplugEvent(EventThread::DisplayType::External, false);
- }
+
mDisplays.erase(draw.keyAt(i));
} else {
// this display is in both lists. see if something changed.
@@ -2819,12 +2836,7 @@
dispSurface, producer));
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
-
- if (displayId == getInternalDisplayId()) {
- dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, true);
- } else if (displayId == getExternalDisplayId()) {
- dispatchDisplayHotplugEvent(EventThread::DisplayType::External, true);
- }
+ dispatchDisplayHotplugEvent(displayId->value, true);
}
}
}
@@ -2846,7 +2858,6 @@
* (perform the transaction for each of them if needed)
*/
- bool inputChanged = false;
if (transactionFlags & eTraversalNeeded) {
mCurrentState.traverseInZOrder([&](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
@@ -2857,7 +2868,7 @@
mVisibleRegionsDirty = true;
if (flags & Layer::eInputInfoChanged) {
- inputChanged = true;
+ mInputInfoChanged = true;
}
});
}
@@ -2969,22 +2980,23 @@
}
commitTransaction();
-
- if (inputChanged || mVisibleRegionsDirty) {
- updateInputWindows();
- }
- executeInputWindowCommands();
-
- updateCursorAsync();
}
-void SurfaceFlinger::updateInputWindows() {
+void SurfaceFlinger::updateInputFlinger() {
ATRACE_CALL();
-
- if (mInputFlinger == nullptr) {
+ if (!mInputFlinger) {
return;
}
+ if (mVisibleRegionsDirty || mInputInfoChanged) {
+ mInputInfoChanged = false;
+ updateInputWindowInfo();
+ }
+
+ executeInputWindowCommands();
+}
+
+void SurfaceFlinger::updateInputWindowInfo() {
Vector<InputWindowInfo> inputHandles;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -2998,10 +3010,6 @@
}
void SurfaceFlinger::executeInputWindowCommands() {
- if (!mInputFlinger) {
- return;
- }
-
for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) {
if (transferTouchFocusCommand.fromToken != nullptr &&
transferTouchFocusCommand.toToken != nullptr &&
@@ -3278,9 +3286,10 @@
Mutex::Autolock lock(mStateLock);
for (auto& layer : mLayersWithQueuedFrames) {
- const Region dirty(layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence));
+ if (layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence)) {
+ mLayersPendingRefresh.push_back(layer);
+ }
layer->useSurfaceDamage();
- invalidateLayerStack(layer, dirty);
if (layer->isBufferLatched()) {
newDataLatched = true;
}
@@ -3294,11 +3303,6 @@
mVisibleRegionsDirty |= visibleRegions;
- if (visibleRegions) {
- // Update input window info if the layer receives its first buffer.
- updateInputWindows();
- }
-
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
@@ -3335,13 +3339,15 @@
}
ALOGV("doDisplayComposition");
- if (!doComposeSurfaces(displayDevice)) return;
+ base::unique_fd readyFence;
+ if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
// swap buffers (presentation)
- display->getRenderSurface()->queueBuffer();
+ display->getRenderSurface()->queueBuffer(std::move(readyFence));
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) {
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
+ const Region& debugRegion, base::unique_fd* readyFence) {
ALOGV("doComposeSurfaces");
auto display = displayDevice->getCompositionDisplay();
@@ -3356,13 +3362,14 @@
mat4 colorMatrix;
bool applyColorMatrix = false;
- // Framebuffer will live in this scope for GPU composition.
- std::unique_ptr<renderengine::BindNativeBufferAsFramebuffer> fbo;
+ renderengine::DisplaySettings clientCompositionDisplay;
+ std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ sp<GraphicBuffer> buf;
if (hasClientComposition) {
ALOGV("hasClientComposition");
- sp<GraphicBuffer> buf = display->getRenderSurface()->dequeueBuffer();
+ buf = display->getRenderSurface()->dequeueBuffer();
if (buf == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
@@ -3371,24 +3378,30 @@
return false;
}
- // Bind the framebuffer in this scope.
- fbo = std::make_unique<renderengine::BindNativeBufferAsFramebuffer>(getRenderEngine(),
- buf->getNativeBuffer());
+ clientCompositionDisplay.physicalDisplay = displayState.scissor;
+ clientCompositionDisplay.clip = displayState.scissor;
+ const ui::Transform& displayTransform = displayState.transform;
+ mat4 m;
+ m[0][0] = displayTransform[0][0];
+ m[0][1] = displayTransform[0][1];
+ m[0][3] = displayTransform[0][2];
+ m[1][0] = displayTransform[1][0];
+ m[1][1] = displayTransform[1][1];
+ m[1][3] = displayTransform[1][2];
+ m[3][0] = displayTransform[2][0];
+ m[3][1] = displayTransform[2][1];
+ m[3][3] = displayTransform[2][2];
- if (fbo->getStatus() != NO_ERROR) {
- ALOGW("Binding buffer for display [%s] failed with status: %d",
- displayDevice->getDisplayName().c_str(), fbo->getStatus());
- return false;
- }
+ clientCompositionDisplay.globalTransform = m;
const auto* profile = display->getDisplayColorProfile();
Dataspace outputDataspace = Dataspace::UNKNOWN;
if (profile->hasWideColorGamut()) {
outputDataspace = displayState.dataspace;
}
- getRenderEngine().setOutputDataSpace(outputDataspace);
- getRenderEngine().setDisplayMaxLuminance(
- profile->getHdrCapabilities().getDesiredMaxLuminance());
+ clientCompositionDisplay.outputDataspace = outputDataspace;
+ clientCompositionDisplay.maxLuminance =
+ profile->getHdrCapabilities().getDesiredMaxLuminance();
const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
const bool skipClientColorTransform =
@@ -3399,44 +3412,7 @@
// Compute the global color transform matrix.
applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
if (applyColorMatrix) {
- colorMatrix = mDrawingState.colorMatrix;
- }
-
- display->getRenderSurface()->setViewportAndProjection();
-
- // Never touch the framebuffer if we don't have any framebuffer layers
- if (hasDeviceComposition) {
- // when using overlays, we assume a fully transparent framebuffer
- // NOTE: we could reduce how much we need to clear, for instance
- // remove where there are opaque FB layers. however, on some
- // GPUs doing a "clean slate" clear might be more efficient.
- // We'll revisit later if needed.
- getRenderEngine().clearWithColor(0, 0, 0, 0);
- } else {
- // we start with the whole screen area and remove the scissor part
- // we're left with the letterbox region
- // (common case is that letterbox ends-up being empty)
- const Region letterbox = bounds.subtract(displayState.scissor);
-
- // compute the area to clear
- const Region region = displayState.undefinedRegion.merge(letterbox);
-
- // screen is already cleared here
- if (!region.isEmpty()) {
- // can happen with SurfaceView
- drawWormhole(region);
- }
- }
-
- const Rect& bounds = displayState.bounds;
- const Rect& scissor = displayState.scissor;
- if (scissor != bounds) {
- // scissor doesn't match the screen's dimensions, so we
- // need to clear everything outside of it and enable
- // the GL scissor so we don't draw anything where we shouldn't
-
- // enable scissor for this frame
- getRenderEngine().setScissor(scissor);
+ clientCompositionDisplay.colorTransform = colorMatrix;
}
}
@@ -3445,10 +3421,11 @@
*/
ALOGV("Rendering client layers");
- const ui::Transform& displayTransform = displayState.transform;
bool firstLayer = true;
+ Region clearRegion = Region::INVALID_REGION;
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const Region clip(bounds.intersect(displayTransform.transform(layer->visibleRegion)));
+ const Region viewportRegion(displayState.viewport);
+ const Region clip(viewportRegion.intersect(layer->visibleRegion));
ALOGV("Layer: %s", layer->getName().string());
ALOGV(" Composition type: %s", to_string(layer->getCompositionType(displayId)).c_str());
if (!clip.isEmpty()) {
@@ -3464,22 +3441,28 @@
layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- layer->clearWithOpenGL(renderArea);
+ renderengine::LayerSettings layerSettings;
+ Region dummyRegion;
+ bool prepared = layer->prepareClientLayer(renderArea, clip, dummyRegion,
+ layerSettings);
+
+ if (prepared) {
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
+ layerSettings.alpha = half(0.0);
+ layerSettings.disableBlending = true;
+ clientCompositionLayers.push_back(layerSettings);
+ }
}
break;
}
case HWC2::Composition::Client: {
- if (layer->hasColorTransform()) {
- mat4 tmpMatrix;
- if (applyColorMatrix) {
- tmpMatrix = mDrawingState.colorMatrix;
- }
- tmpMatrix *= layer->getColorTransform();
- getRenderEngine().setColorTransform(tmpMatrix);
- } else {
- getRenderEngine().setColorTransform(colorMatrix);
+ renderengine::LayerSettings layerSettings;
+ bool prepared =
+ layer->prepareClientLayer(renderArea, clip, clearRegion, layerSettings);
+ if (prepared) {
+ clientCompositionLayers.push_back(layerSettings);
}
- layer->draw(renderArea, clip);
break;
}
default:
@@ -3491,14 +3474,23 @@
firstLayer = false;
}
- // Perform some cleanup steps if we used client composition.
if (hasClientComposition) {
- getRenderEngine().setColorTransform(mat4());
- getRenderEngine().disableScissor();
- display->getRenderSurface()->finishBuffer();
- // Clear out error flags here so that we don't wait until next
- // composition to log.
- getRenderEngine().checkErrors();
+ clientCompositionDisplay.clearRegion = clearRegion;
+ if (!debugRegion.isEmpty()) {
+ Region::const_iterator it = debugRegion.begin();
+ Region::const_iterator end = debugRegion.end();
+ while (it != end) {
+ const Rect& rect = *it++;
+ renderengine::LayerSettings layerSettings;
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
+ layerSettings.geometry.boundaries = rect.toFloatRect();
+ layerSettings.alpha = half(1.0);
+ clientCompositionLayers.push_back(layerSettings);
+ }
+ }
+ getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers,
+ buf->getNativeBuffer(), readyFence);
}
return true;
}
@@ -4849,7 +4841,7 @@
" gpu_to_cpu_unsupported : %d\n",
mTransactionFlags.load(), !mGpuToCpuSupported);
- if (const auto displayId = getInternalDisplayId();
+ if (const auto displayId = getInternalDisplayIdLocked();
displayId && getHwComposer().isConnected(*displayId)) {
const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
StringAppendF(&result,
@@ -5001,7 +4993,8 @@
// information, so it is OK to pass them.
case AUTHENTICATE_SURFACE:
case GET_ACTIVE_CONFIG:
- case GET_BUILT_IN_DISPLAY:
+ case GET_PHYSICAL_DISPLAY_IDS:
+ case GET_PHYSICAL_DISPLAY_TOKEN:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_NATIVE_PRIMARIES:
case GET_DISPLAY_CONFIGS:
@@ -5612,35 +5605,109 @@
void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
- bool useIdentityTransform) {
+ ANativeWindowBuffer* buffer, bool useIdentityTransform,
+ int* outSyncFd) {
ATRACE_CALL();
- auto& engine(getRenderEngine());
-
const auto reqWidth = renderArea.getReqWidth();
const auto reqHeight = renderArea.getReqHeight();
const auto sourceCrop = renderArea.getSourceCrop();
const auto rotation = renderArea.getRotationFlags();
- engine.setOutputDataSpace(renderArea.getReqDataSpace());
- engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance);
+ renderengine::DisplaySettings clientCompositionDisplay;
+ std::vector<renderengine::LayerSettings> clientCompositionLayers;
- // make sure to clear all GL error flags
- engine.checkErrors();
+ // assume that bounds are never offset, and that they are the same as the
+ // buffer bounds.
+ clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight);
+ ui::Transform transform = renderArea.getTransform();
+ mat4 m;
+ m[0][0] = transform[0][0];
+ m[0][1] = transform[0][1];
+ m[0][3] = transform[0][2];
+ m[1][0] = transform[1][0];
+ m[1][1] = transform[1][1];
+ m[1][3] = transform[1][2];
+ m[3][0] = transform[2][0];
+ m[3][1] = transform[2][1];
+ m[3][3] = transform[2][2];
- // set-up our viewport
- engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, rotation);
- engine.disableTexturing();
+ clientCompositionDisplay.globalTransform = m;
+ mat4 rotMatrix;
+ // Displacement for repositioning the clipping rectangle after rotating it
+ // with the rotation hint.
+ int displacementX = 0;
+ int displacementY = 0;
+ float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
+ switch (rotation) {
+ case ui::Transform::ROT_90:
+ rotMatrix = mat4::rotate(rot90InRadians, vec3(0, 0, 1));
+ displacementX = reqWidth;
+ break;
+ case ui::Transform::ROT_180:
+ rotMatrix = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1));
+ displacementX = reqWidth;
+ displacementY = reqHeight;
+ break;
+ case ui::Transform::ROT_270:
+ rotMatrix = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1));
+ displacementY = reqHeight;
+ break;
+ default:
+ break;
+ }
+ // We need to transform the clipping window into the right spot.
+ // First, rotate the clipping rectangle by the rotation hint to get the
+ // right orientation
+ const vec4 clipTL = vec4(sourceCrop.left, sourceCrop.top, 0, 1);
+ const vec4 clipBR = vec4(sourceCrop.right, sourceCrop.bottom, 0, 1);
+ const vec4 rotClipTL = rotMatrix * clipTL;
+ const vec4 rotClipBR = rotMatrix * clipBR;
+ const int newClipLeft = std::min(rotClipTL[0], rotClipBR[0]);
+ const int newClipTop = std::min(rotClipTL[1], rotClipBR[1]);
+ const int newClipRight = std::max(rotClipTL[0], rotClipBR[0]);
+ const int newClipBottom = std::max(rotClipTL[1], rotClipBR[1]);
+
+ // Now reposition the clipping rectangle with the displacement vector
+ // computed above.
+ const mat4 displacementMat = mat4::translate(vec4(displacementX, displacementY, 0, 1));
+
+ clientCompositionDisplay.clip =
+ Rect(newClipLeft + displacementX, newClipTop + displacementY,
+ newClipRight + displacementX, newClipBottom + displacementY);
+
+ // We need to perform the same transformation in layer space, so propagate
+ // it to the global transform.
+ mat4 clipTransform = displacementMat * rotMatrix;
+ clientCompositionDisplay.globalTransform *= clipTransform;
+ clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace();
+ clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
- // redraw the screen entirely...
- engine.clearWithColor(0, 0, 0, alpha);
+ renderengine::LayerSettings fillLayer;
+ fillLayer.source.buffer.buffer = nullptr;
+ fillLayer.source.solidColor = half3(0.0, 0.0, 0.0);
+ fillLayer.geometry.boundaries = FloatRect(0.0, 0.0, 1.0, 1.0);
+ fillLayer.alpha = half(alpha);
+ clientCompositionLayers.push_back(fillLayer);
+
+ Region clearRegion = Region::INVALID_REGION;
traverseLayers([&](Layer* layer) {
- engine.setColorTransform(layer->getColorTransform());
- layer->draw(renderArea, useIdentityTransform);
- engine.setColorTransform(mat4());
+ renderengine::LayerSettings layerSettings;
+ bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
+ layerSettings);
+ if (prepared) {
+ clientCompositionLayers.push_back(layerSettings);
+ }
});
+
+ clientCompositionDisplay.clearRegion = clearRegion;
+ base::unique_fd drawFence;
+ getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
+ &drawFence);
+
+ *outSyncFd = drawFence.release();
}
status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
@@ -5664,28 +5731,7 @@
ALOGW("FB is protected: PERMISSION_DENIED");
return PERMISSION_DENIED;
}
- auto& engine(getRenderEngine());
-
- // this binds the given EGLImage as a framebuffer for the
- // duration of this scope.
- renderengine::BindNativeBufferAsFramebuffer bufferBond(engine, buffer);
- if (bufferBond.getStatus() != NO_ERROR) {
- ALOGE("got ANWB binding error while taking screenshot");
- return INVALID_OPERATION;
- }
-
- // this will in fact render into our dequeued buffer
- // via an FBO, which means we didn't have to create
- // an EGLSurface and therefore we're not
- // dependent on the context's EGLConfig.
- renderScreenImplLocked(renderArea, traverseLayers, useIdentityTransform);
-
- base::unique_fd syncFd = engine.flush();
- if (syncFd < 0) {
- engine.finish();
- }
- *outSyncFd = syncFd.release();
-
+ renderScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, outSyncFd);
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a127550..c404ef2 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -313,7 +313,7 @@
compositionengine::CompositionEngine& getCompositionEngine() const;
// returns the default Display
- sp<const DisplayDevice> getDefaultDisplayDevice() const {
+ sp<const DisplayDevice> getDefaultDisplayDevice() {
Mutex::Autolock _l(mStateLock);
return getDefaultDisplayDeviceLocked();
}
@@ -327,7 +327,7 @@
// enable/disable h/w composer event
// TODO: this should be made accessible only to EventThread
- void setVsyncEnabled(EventThread::DisplayType displayType, bool enabled);
+ void setPrimaryVsyncEnabled(bool enabled);
// called on the main thread by MessageQueue when an internal message
// is received
@@ -414,7 +414,8 @@
sp<ISurfaceComposerClient> createConnection() override;
sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
void destroyDisplay(const sp<IBinder>& displayToken) override;
- sp<IBinder> getBuiltInDisplay(int32_t id) override;
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override;
+ sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
@@ -519,7 +520,8 @@
void handleTransaction(uint32_t transactionFlags);
void handleTransactionLocked(uint32_t transactionFlags);
- void updateInputWindows();
+ void updateInputFlinger();
+ void updateInputWindowInfo();
void executeInputWindowCommands();
void updateCursorAsync();
@@ -597,7 +599,8 @@
void startBootAnim();
void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
- bool useIdentityTransform);
+ ANativeWindowBuffer* buffer, bool useIdentityTransform,
+ int* outSyncFd);
status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
bool useIdentityTransform);
@@ -653,7 +656,7 @@
}
sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
- if (const auto token = getInternalDisplayToken()) {
+ if (const auto token = getInternalDisplayTokenLocked()) {
return getDisplayDeviceLocked(token);
}
return nullptr;
@@ -736,8 +739,11 @@
void logLayerStats();
void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
- // This fails if using GL and the surface has been destroyed.
- bool doComposeSurfaces(const sp<DisplayDevice>& display);
+ // This fails if using GL and the surface has been destroyed. readyFence
+ // will be populated if using GL and native fence sync is supported, to
+ // signal when drawing has completed.
+ bool doComposeSurfaces(const sp<DisplayDevice>& display, const Region& debugRegionm,
+ base::unique_fd* readyFence);
void postFramebuffer(const sp<DisplayDevice>& display);
void postFrame();
@@ -754,7 +760,7 @@
void processDisplayChangesLocked();
void processDisplayHotplugEventsLocked();
- void dispatchDisplayHotplugEvent(EventThread::DisplayType displayType, bool connected);
+ void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
/* ------------------------------------------------------------------------
* VSync
@@ -794,12 +800,12 @@
/*
* Display identification
*/
- sp<IBinder> getPhysicalDisplayToken(DisplayId displayId) const {
+ sp<IBinder> getPhysicalDisplayTokenLocked(DisplayId displayId) const {
const auto it = mPhysicalDisplayTokens.find(displayId);
return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
}
- std::optional<DisplayId> getPhysicalDisplayId(const sp<IBinder>& displayToken) const {
+ std::optional<DisplayId> getPhysicalDisplayIdLocked(const sp<IBinder>& displayToken) const {
for (const auto& [id, token] : mPhysicalDisplayTokens) {
if (token == displayToken) {
return id;
@@ -809,22 +815,16 @@
}
// TODO(b/74619554): Remove special cases for primary display.
- sp<IBinder> getInternalDisplayToken() const {
- const auto displayId = getInternalDisplayId();
- return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+ sp<IBinder> getInternalDisplayTokenLocked() const {
+ const auto displayId = getInternalDisplayIdLocked();
+ return displayId ? getPhysicalDisplayTokenLocked(*displayId) : nullptr;
}
- std::optional<DisplayId> getInternalDisplayId() const {
+ std::optional<DisplayId> getInternalDisplayIdLocked() const {
const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
}
- // TODO(b/74619554): Remove special cases for external display.
- std::optional<DisplayId> getExternalDisplayId() const {
- const auto hwcDisplayId = getHwComposer().getExternalHwcDisplayId();
- return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
- }
-
/*
* Debugging & dumpsys
*/
@@ -942,7 +942,6 @@
std::unique_ptr<VSyncSource> mSfEventThreadSource;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
std::unique_ptr<EventControlThread> mEventControlThread;
- std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
// Calculates correct offsets.
VSyncModulator mVsyncModulator;
@@ -953,9 +952,13 @@
// don't need synchronization
State mDrawingState{LayerVector::StateSet::Drawing};
bool mVisibleRegionsDirty;
+ // Set during transaction commit stage to track if the input info for a layer has changed.
+ bool mInputInfoChanged{false};
bool mGeometryInvalid;
bool mAnimCompositionPending;
std::vector<sp<Layer>> mLayersWithQueuedFrames;
+ // Tracks layers that need to update a display's dirty region.
+ std::vector<sp<Layer>> mLayersPendingRefresh;
sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
bool mHadClientComposition = false;
@@ -976,6 +979,7 @@
// this may only be written from the main thread with mStateLock held
// it may be read from other threads with mStateLock held
std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays;
+ std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
// don't use a lock for these, we don't care
int mDebugRegion;
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index f021d3d..61d09da 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -62,9 +62,11 @@
}
void setupBackgroundSurface() {
- mDisplay = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ mDisplay = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(mDisplay == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
const ssize_t displayWidth = info.w;
const ssize_t displayHeight = info.h;
@@ -170,10 +172,8 @@
}
TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) {
- std::function<bool()> condition = [=]() {
- sp<IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
- return (display != nullptr);
+ std::function<bool()> condition = [] {
+ return SurfaceComposerClient::getInternalDisplayToken() != nullptr;
};
// Anyone can access display information.
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true));
@@ -183,7 +183,7 @@
// The following methods are tested with a UID that is not root, graphics,
// or system, to show that anyone can access them.
setBinUID();
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_TRUE(display != nullptr);
DisplayInfo info;
@@ -199,7 +199,7 @@
}
TEST_F(CredentialsTest, GetDisplayColorModesTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
Vector<ui::ColorMode> outColorModes;
return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes);
@@ -208,7 +208,7 @@
}
TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
ui::DisplayPrimaries primaries;
return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries);
@@ -217,7 +217,7 @@
}
TEST_F(CredentialsTest, SetActiveConfigTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
return SurfaceComposerClient::setActiveConfig(display, 0);
};
@@ -225,7 +225,7 @@
}
TEST_F(CredentialsTest, SetActiveColorModeTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE);
};
@@ -258,7 +258,7 @@
}
TEST_F(CredentialsTest, CaptureTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
sp<GraphicBuffer> outBuffer;
return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
@@ -324,7 +324,8 @@
}
TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
bool result = false;
status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result);
ASSERT_EQ(NO_ERROR, error);
@@ -346,7 +347,8 @@
}
TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
std::function<status_t()> condition = [=]() {
bool result = false;
return SurfaceComposerClient::isWideColorDisplay(display, &result);
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index 89c26f4..ee857b0 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -34,7 +34,7 @@
auto surf = client->createSurface(String8("t"), 100, 100,
PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(surf != nullptr);
- surf->clear();
+ surf.clear();
}
};
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 8ec3e15..5cc946a 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -240,10 +240,12 @@
}
void SurfaceInterceptorTest::setupBackgroundSurface() {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+
ssize_t displayWidth = info.w;
ssize_t displayHeight = info.h;
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 1704424..7b21dbc 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -195,13 +195,12 @@
class ScreenCapture : public RefBase {
public:
static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto sf = ComposerService::getComposerService();
+ const auto token = sf->getInternalDisplayToken();
SurfaceComposerClient::Transaction().apply(true);
sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR,
- sf->captureScreen(display, &outBuffer, Rect(), 0, 0, false));
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(token, &outBuffer, Rect(), 0, 0, false));
*sc = std::make_unique<ScreenCapture>(outBuffer);
}
@@ -324,7 +323,6 @@
ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
}
@@ -502,12 +500,12 @@
private:
void SetUpDisplay() {
- mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
- ASSERT_NE(nullptr, mDisplay.get()) << "failed to get built-in display";
+ mDisplay = mClient->getInternalDisplayToken();
+ ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
// get display width/height
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
mDisplayWidth = info.w;
mDisplayHeight = info.h;
mDisplayRect =
@@ -558,8 +556,7 @@
return mDelegate->screenshot();
case RenderPath::VIRTUAL_DISPLAY:
- sp<IBinder> mainDisplay =
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken();
DisplayInfo mainDisplayInfo;
SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
@@ -1137,7 +1134,7 @@
.setRelativeLayer(layerG, layerR->getHandle(), 1)
.apply();
- layerG->clear();
+ layerG.clear();
// layerG should have been removed
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
@@ -3973,10 +3970,11 @@
LayerTransactionTest::SetUp();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
- sp<IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
ssize_t displayWidth = info.w;
ssize_t displayHeight = info.h;
@@ -4437,7 +4435,7 @@
mCapture->checkPixel(64, 64, 111, 111, 111);
}
- mChild->clear();
+ mChild.clear();
{
SCOPED_TRACE("After destroying child");
@@ -5309,7 +5307,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
auto redLayerHandle = redLayer->getHandle();
- redLayer->clear();
+ redLayer.clear();
SurfaceComposerClient::Transaction().apply(true);
sp<GraphicBuffer> outBuffer;
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 16e0891..f9e0b64 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -145,7 +145,7 @@
void TearDown() override;
void waitForDisplayTransaction();
- bool waitForHotplugEvent(uint32_t id, bool connected);
+ bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected);
sp<IComposer> mFakeService;
sp<SurfaceComposerClient> mComposerClient;
@@ -242,7 +242,7 @@
mMockComposer->runVSyncAndWait();
}
-bool DisplayTest::waitForHotplugEvent(uint32_t id, bool connected) {
+bool DisplayTest::waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
int waitCount = 20;
while (waitCount--) {
while (!mReceivedDisplayEvents.empty()) {
@@ -250,11 +250,12 @@
mReceivedDisplayEvents.pop_front();
ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
- "event hotplug: id %d, connected %d\t", event.header.id,
- event.hotplug.connected);
+ "event hotplug: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+ ", connected %d\t",
+ event.header.displayId, event.hotplug.connected);
if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
- event.header.id == id && event.hotplug.connected == connected) {
+ event.header.displayId == displayId && event.hotplug.connected == connected) {
return true;
}
}
@@ -294,13 +295,14 @@
waitForDisplayTransaction();
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
{
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
ASSERT_EQ(400u, info.w);
ASSERT_EQ(200u, info.h);
@@ -328,14 +330,15 @@
waitForDisplayTransaction();
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, false));
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
{
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
ASSERT_EQ(400u, info.w);
ASSERT_EQ(200u, info.h);
@@ -364,11 +367,12 @@
waitForDisplayTransaction();
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, false));
+ EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
{
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+ EXPECT_FALSE(display == nullptr);
+
DisplayInfo info;
auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
EXPECT_NE(NO_ERROR, result);
@@ -402,11 +406,12 @@
waitForDisplayTransaction();
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, true));
+ EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
{
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+ EXPECT_FALSE(display == nullptr);
+
DisplayInfo info;
auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
EXPECT_EQ(NO_ERROR, result);
@@ -473,10 +478,11 @@
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
ALOGI("TransactionTest::SetUp - display");
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
mDisplayWidth = info.w;
mDisplayHeight = info.h;
diff --git a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h b/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
index 2245ee1..8bed766 100644
--- a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
+++ b/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
@@ -75,14 +75,16 @@
template <typename... Args>
class AsyncCallRecorder<void (*)(Args...)> {
public:
- // For the tests, we expect the wait for an expected change to be signaled
- // to be much shorter than this.
- static constexpr std::chrono::milliseconds DEFAULT_CALL_EXPECTED_TIMEOUT{10};
+ // This wait value needs to be large enough to avoid flakes caused by delays
+ // scheduling threads, but small enough that tests don't take forever if
+ // something really is wrong. Based on some empirical evidence, 100ms should
+ // be enough to avoid the former.
+ static constexpr std::chrono::milliseconds DEFAULT_CALL_EXPECTED_TIMEOUT{100};
- // The wait here is tricky. We don't expect a change, but we don't want to
- // wait forever (or for longer than the typical test function runtime). As
- // even the simplest Google Test can take 1ms (1000us) to run, we wait for
- // half that time.
+ // The wait here is tricky. It's for when We don't expect to record a call,
+ // but we don't want to wait forever (or for longer than the typical test
+ // function runtime). As even the simplest Google Test can take 1ms (1000us)
+ // to run, we wait for half that time.
static constexpr std::chrono::microseconds UNEXPECTED_CALL_TIMEOUT{500};
using ArgTuple = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e092aed..ee79c18 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -45,8 +45,10 @@
using testing::_;
using testing::AtLeast;
+using testing::Between;
using testing::ByMove;
using testing::DoAll;
+using testing::Field;
using testing::Invoke;
using testing::IsNull;
using testing::Mock;
@@ -159,7 +161,6 @@
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
mock::DispSync* mPrimaryDispSync = new mock::DispSync();
- renderengine::mock::Image* mReImage = new renderengine::mock::Image();
renderengine::mock::Framebuffer* mReFrameBuffer = new renderengine::mock::Framebuffer();
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -279,11 +280,10 @@
EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
- EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
- EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
-
+ // TODO: remove once we verify that we can just grab the fence from the
+ // FramebufferSurface.
EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() {
- return base::unique_fd(0);
+ return base::unique_fd();
}));
EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
@@ -295,36 +295,18 @@
template <typename Case>
static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
- // Called once with a non-null value to set a framebuffer, and then
- // again with nullptr to clear it.
- EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull(), false))
- .WillOnce(Return(true));
- EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull(), false))
- .WillOnce(Return(true));
-
- EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
- EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
- .WillOnce(Return(
- ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
- EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, clearWithColor(0, 0, 0, 1)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd())));
- EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true));
-
- EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(_)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
- .Times(1);
- // This expectation retires on saturation as setViewportAndProjection is
- // called an extra time for the code path this setup is for.
- // TODO: Investigate this extra call
- EXPECT_CALL(*test->mRenderEngine,
- setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
- Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::Transform::ROT_0))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawLayers)
+ .WillRepeatedly(
+ [](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
+ ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.physicalDisplay);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.clip);
+ return NO_ERROR;
+ });
}
static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) {
@@ -348,31 +330,23 @@
EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
.WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
- EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
- .Times(1);
- EXPECT_CALL(*test->mRenderEngine, setColorTransform(_)).Times(2);
- // These expectations retire on saturation as the code path these
- // expectations are for appears to make an extra call to them.
- // TODO: Investigate this extra call
- EXPECT_CALL(*test->mRenderEngine,
- setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
- Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::Transform::ROT_0))
- .Times(1);
- EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull(), false))
- .WillOnce(Return(true));
- EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull(), false))
- .WillOnce(Return(true));
- EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
- .WillOnce(Return(
- ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
- EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
EXPECT_CALL(*test->mNativeWindow, queueBuffer(_, _)).WillOnce(Return(0));
EXPECT_CALL(*test->mNativeWindow, dequeueBuffer(_, _))
.WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1),
Return(0)));
+ EXPECT_CALL(*test->mRenderEngine, drawLayers)
+ .WillRepeatedly(
+ [](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
+ ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.physicalDisplay);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.clip);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace);
+ return NO_ERROR;
+ });
}
template <typename Case>
@@ -383,8 +357,6 @@
template <typename Case>
static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
Case::Layer::setupREScreenshotCompositionCallExpectations(test);
-
- EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
}
};
@@ -396,16 +368,11 @@
template <typename Case>
static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
Case::Layer::setupInsecureRECompositionCallExpectations(test);
-
- // TODO: Investigate this extra call
- EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
}
template <typename Case>
static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
Case::Layer::setupInsecureREScreenshotCompositionCallExpectations(test);
-
- EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
}
};
@@ -516,7 +483,6 @@
bool ignoredRecomputeVisibleRegions;
layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, Fence::NO_FENCE);
Mock::VerifyAndClear(test->mRenderEngine);
- Mock::VerifyAndClear(test->mReImage);
}
static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
@@ -598,33 +564,35 @@
}
static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mRenderEngine,
- setupLayerBlending(true, false, false,
- half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
- LayerProperties::COLOR[2], LayerProperties::COLOR[3]),
- 0.0f))
- .Times(1);
-
- EXPECT_CALL(*test->mRenderEngine, createImage())
- .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
- EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true));
- EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, setupLayerTexturing(_)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
- EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
- // This call retires on saturation as the code that renders a texture disables the state,
- // along with a top-level disable to ensure it is disabled for non-buffer layers.
- EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+ EXPECT_CALL(*test->mRenderEngine, drawLayers)
+ .WillOnce([](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<renderengine::LayerSettings>& layerSettings,
+ ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.physicalDisplay);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.clip);
+ // screen capture adds an additional color layer as an alpha
+ // prefill, so gtet the back layer.
+ renderengine::LayerSettings layer = layerSettings.back();
+ EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
+ EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
+ EXPECT_EQ(renderengine::Buffer::CachingHint::NO_CACHE,
+ layer.source.buffer.cacheHint);
+ EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
+ EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
+ EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
+ EXPECT_EQ(false, layer.source.buffer.isOpaque);
+ EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+ return NO_ERROR;
+ });
}
static void setupREBufferCompositionCallExpectations(CompositionTest* test) {
LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
-
- // TODO - Investigate and eliminate these differences between display
- // composition and screenshot composition.
- EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
}
static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
@@ -639,20 +607,28 @@
LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
}
- static void setupREColorCompositionCommonCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
- }
-
static void setupREColorCompositionCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
- EXPECT_CALL(*test->mRenderEngine,
- setupLayerBlending(true, false, true,
- half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
- LayerProperties::COLOR[2], LayerProperties::COLOR[3]),
- 0.0f))
- .Times(1);
- EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawLayers)
+ .WillOnce([](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<renderengine::LayerSettings>& layerSettings,
+ ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.physicalDisplay);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.clip);
+ // screen capture adds an additional color layer as an alpha
+ // prefill, so get the back layer.
+ renderengine::LayerSettings layer = layerSettings.back();
+ EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+ EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+ LayerProperties::COLOR[2]),
+ layer.source.solidColor);
+ EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+ return NO_ERROR;
+ });
}
static void setupREColorScreenshotCompositionCallExpectations(CompositionTest* test) {
@@ -692,10 +668,7 @@
EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
}
- static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mRenderEngine, setupFillWithColor(0, 0, 0, 1)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
- }
+ static void setupREBufferCompositionCommonCallExpectations(CompositionTest* /*test*/) {}
};
struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> {
@@ -704,25 +677,25 @@
static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure;
static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mRenderEngine, createImage())
- .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
- EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true));
- EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, setupLayerBlackedOut()).Times(1);
-
- EXPECT_CALL(*test->mRenderEngine,
- setupLayerBlending(true, false, false,
- half4(Base::COLOR[0], Base::COLOR[1], Base::COLOR[2],
- Base::COLOR[3]),
- 0.0f))
- .Times(1);
- EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
- EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
- EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
- // This call retires on saturation as the code that renders a texture disables the state,
- // along with a top-level disable to ensure it is disabled for non-buffer layers.
- EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+ EXPECT_CALL(*test->mRenderEngine, drawLayers)
+ .WillOnce([](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<renderengine::LayerSettings>& layerSettings,
+ ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.physicalDisplay);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.clip);
+ // screen capture adds an additional color layer as an alpha
+ // prefill, so get the back layer.
+ renderengine::LayerSettings layer = layerSettings.back();
+ EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
+ EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+ EXPECT_EQ(1.0f, layer.alpha);
+ return NO_ERROR;
+ });
}
static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
@@ -826,7 +799,6 @@
}
static void setupRECompositionCallExpectations(CompositionTest* test) {
- LayerProperties::setupREColorCompositionCommonCallExpectations(test);
LayerProperties::setupREColorCompositionCallExpectations(test);
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b7464d2..6659d4a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -45,9 +45,9 @@
namespace {
using testing::_;
-using testing::ByMove;
using testing::DoAll;
using testing::Mock;
+using testing::ResultOf;
using testing::Return;
using testing::SetArgPointee;
@@ -321,11 +321,6 @@
// Whether the display is primary
static constexpr Primary PRIMARY = primary;
- static constexpr auto displayType() {
- return static_cast<bool>(PRIMARY) ? EventThread::DisplayType::Primary
- : EventThread::DisplayType::External;
- }
-
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto injector =
FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
@@ -1497,6 +1492,9 @@
template <typename Case>
void setupCommonPreconditions();
+ template <typename Case, bool connected>
+ static void expectHotplugReceived(mock::EventThread*);
+
template <typename Case>
void setupCommonCallExpectationsForConnectProcessing();
@@ -1534,6 +1532,17 @@
injectFakeNativeWindowSurfaceFactory();
}
+template <typename Case, bool connected>
+void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
+ const auto convert = [](auto physicalDisplayId) {
+ return std::make_optional(DisplayId{physicalDisplayId});
+ };
+
+ EXPECT_CALL(*eventThread,
+ onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected))
+ .Times(1);
+}
+
template <typename Case>
void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
Case::Display::setupHwcHotplugCallExpectations(this);
@@ -1549,16 +1558,16 @@
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
- EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
- EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
+ expectHotplugReceived<Case, true>(mEventThread);
+ expectHotplugReceived<Case, true>(mSFEventThread);
}
template <typename Case>
void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
- EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
- EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
+ expectHotplugReceived<Case, false>(mEventThread);
+ expectHotplugReceived<Case, false>(mSFEventThread);
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index dd90063..fa5bb26 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -36,6 +36,9 @@
namespace android {
namespace {
+constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111;
+constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID = 222;
+
class MockVSyncSource : public VSyncSource {
public:
MOCK_METHOD1(setVSyncEnabled, void(bool));
@@ -72,7 +75,7 @@
ConnectionEventRecorder& connectionEventRecorder,
nsecs_t expectedTimestamp, unsigned expectedCount);
void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
- void expectHotplugEventReceivedByConnection(EventThread::DisplayType expectedDisplayType,
+ void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
@@ -106,8 +109,8 @@
mConnection = createConnection(mConnectionEventCallRecorder);
// A display must be connected for VSYNC events to be delivered.
- mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
+ mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
+ expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, true);
}
EventThreadTest::~EventThreadTest() {
@@ -116,7 +119,7 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
// EventThread should unregister itself as VSyncSource callback.
- EXPECT_FALSE(expectVSyncSetCallbackCallReceived());
+ EXPECT_TRUE(!mVSyncSetCallbackCallRecorder.waitForUnexpectedCall().has_value());
}
void EventThreadTest::createThread() {
@@ -183,16 +186,13 @@
expectedCount);
}
-void EventThreadTest::expectHotplugEventReceivedByConnection(
- EventThread::DisplayType expectedDisplayType, bool expectedConnected) {
- const uint32_t expectedDisplayId =
- expectedDisplayType == EventThread::DisplayType::Primary ? 0 : 1;
-
+void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
+ bool expectedConnected) {
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
- EXPECT_EQ(expectedDisplayId, event.header.id);
+ EXPECT_EQ(expectedDisplayId, event.header.displayId);
EXPECT_EQ(expectedConnected, event.hotplug.connected);
}
@@ -212,8 +212,8 @@
}
TEST_F(EventThreadTest, vsyncRequestIsIgnoredIfDisplayIsDisconnected) {
- mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
+ mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false);
+ expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false);
// Signal that we want the next vsync event to be posted to the connection.
mThread->requestNextVsync(mConnection, false);
@@ -400,24 +400,24 @@
expectVSyncSetPhaseOffsetCallReceived(321);
}
-TEST_F(EventThreadTest, postHotplugPrimaryDisconnect) {
- mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
+TEST_F(EventThreadTest, postHotplugInternalDisconnect) {
+ mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false);
+ expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false);
}
-TEST_F(EventThreadTest, postHotplugPrimaryConnect) {
- mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
+TEST_F(EventThreadTest, postHotplugInternalConnect) {
+ mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
+ expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, true);
}
TEST_F(EventThreadTest, postHotplugExternalDisconnect) {
- mThread->onHotplugReceived(EventThread::DisplayType::External, false);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, false);
+ mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, false);
+ expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, false);
}
TEST_F(EventThreadTest, postHotplugExternalConnect) {
- mThread->onHotplugReceived(EventThread::DisplayType::External, true);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, true);
+ mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, true);
+ expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, true);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
index 9fe9a18..dc63260 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
@@ -34,91 +34,117 @@
IdleTimerTest() = default;
~IdleTimerTest() override = default;
+ // This timeout should be used when a 3ms callback is expected.
+ // While the tests typically request a callback after 3ms, the scheduler
+ // does not always cooperate, at it can take significantly longer (observed
+ // 30ms).
+ static constexpr auto waitTimeForExpected3msCallback = 100ms;
+
+ // This timeout should be used when an 3ms callback is not expected.
+ // Note that there can be false-negatives if the callback happens later.
+ static constexpr auto waitTimeForUnexpected3msCallback = 6ms;
+
AsyncCallRecorder<void (*)()> mExpiredTimerCallback;
std::unique_ptr<IdleTimer> mIdleTimer;
+
+ void clearPendingCallbacks() {
+ while (mExpiredTimerCallback.waitForCall(0us).has_value()) {
+ }
+ }
};
namespace {
TEST_F(IdleTimerTest, createAndDestroyTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, [] {});
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {});
}
TEST_F(IdleTimerTest, startStopTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mExpiredTimerCallback.getInvocable());
+ auto startTime = std::chrono::steady_clock::now();
mIdleTimer->start();
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- // The timer expires after 30 ms, so the call to the callback should not happen.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall().has_value());
+ // The idle timer fires after 30ms, so there should be no callback within
+ // 25ms (waiting for a ballback for the full 30ms would be problematic).
+ bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value();
+ // Under ideal conditions there should be no event. But occasionally
+ // it is possible that the wait just prior takes more than 30ms, and
+ // a callback is observed. We check the elapsed time since before the IdleTimer
+ // thread was started as a sanity check to not have a flakey test.
+ EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms);
mIdleTimer->stop();
}
TEST_F(IdleTimerTest, resetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mExpiredTimerCallback.getInvocable());
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- // The timer expires after 30 ms, so the call to the callback should not happen.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ // Observe any event that happens in about 25ms. We don't care if one was
+ // observed or not.
+ mExpiredTimerCallback.waitForCall(25ms).has_value();
mIdleTimer->reset();
- // The timer was reset, so the call to the callback should not happen.
- std::this_thread::sleep_for(std::chrono::milliseconds(15));
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ // There may have been a race with the reset. Clear any callbacks we
+ // received right afterwards.
+ clearPendingCallbacks();
+ // A single callback should be generated after 30ms
+ EXPECT_TRUE(
+ mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback + 30ms).has_value());
+ // After one event, it should be idle, and not generate another.
+ EXPECT_FALSE(
+ mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback * 10).has_value());
mIdleTimer->stop();
+ // Final quick check that no more callback were observed.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
}
TEST_F(IdleTimerTest, startNotCalledTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
- std::this_thread::sleep_for(6ms);
// The start hasn't happened, so the callback does not happen.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
mIdleTimer->stop();
+ // Final quick check that no more callback were observed.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
}
TEST_F(IdleTimerTest, idleTimerIdlesTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(6ms);
- // The timer expires after 3 ms, so the call to the callback happens.
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
- std::this_thread::sleep_for(6ms);
- // Timer can be idle.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
- // Timer can be reset.
+ // A callback should be generated after 3ms
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
+ // After one event, it should be idle, and not generate another.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+ // Once reset, it should generate another
mIdleTimer->reset();
- std::this_thread::sleep_for(6ms);
- // Timer fires again.
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
+ // Final quick check that no more callback were observed.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
}
TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(6ms);
- // The timer expires after 3 ms, so the call to the callback should happen.
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
}
TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(6ms);
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
+ clearPendingCallbacks();
mIdleTimer->reset();
- std::this_thread::sleep_for(6ms);
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
}
TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(1ms);
mIdleTimer->stop();
- std::this_thread::sleep_for(3ms);
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ clearPendingCallbacks();
+ mIdleTimer->reset();
+ // No more idle events should be observed
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 4d9aec6..0db96d9 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -18,6 +18,8 @@
namespace android {
+constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = 999;
+
class SchedulerTest : public testing::Test {
protected:
class MockEventThreadConnection : public android::EventThreadConnection {
@@ -104,8 +106,7 @@
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
- ASSERT_NO_FATAL_FAILURE(
- mScheduler->hotplugReceived(nullptr, EventThread::DisplayType::Primary, false));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(nullptr, PHYSICAL_DISPLAY_ID, false));
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr));
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr));
std::string testString;
@@ -129,8 +130,8 @@
// The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads.
EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(connectionHandle,
- EventThread::DisplayType::Primary, false));
+ ASSERT_NO_FATAL_FAILURE(
+ mScheduler->hotplugReceived(connectionHandle, PHYSICAL_DISPLAY_ID, false));
EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle));
@@ -158,10 +159,9 @@
EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr);
- EXPECT_CALL(*mEventThread, onHotplugReceived(EventThread::DisplayType::Primary, false))
- .Times(1);
- ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(mConnectionHandle,
- EventThread::DisplayType::Primary, false));
+ EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1);
+ ASSERT_NO_FATAL_FAILURE(
+ mScheduler->hotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false));
EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle));
diff --git a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
index bc1f00d..ed628b8 100644
--- a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
+++ b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
@@ -16,6 +16,11 @@
#include <gtest/gtest.h>
+#include <sched.h>
+
+#include <processgroup/sched_policy.h>
+#include <system/graphics.h>
+
#include "libsurfaceflinger_unittest_main.h"
// ------------------------------------------------------------------------
@@ -39,6 +44,12 @@
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
+ // The SurfaceFlinger implementation assumes that threads resume
+ // execution as quickly as possible once they become unblocked.
+ // (These same calls are made in main_surfaceflinger.cpp)
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+ set_sched_policy(0, SP_FOREGROUND);
+
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--no-slow") == 0) {
g_noSlowTests = true;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 3242ef1..aaf67e9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -31,7 +31,7 @@
MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback));
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
- MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
+ MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
MOCK_METHOD1(registerDisplayEventConnection,
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 673a066..71048db 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -21,6 +21,8 @@
// There are a few of them requiring manual code for things such as layer
// discovery or chaining. They call into functions defined in this file.
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <stdlib.h>
#include <string.h>
@@ -32,6 +34,7 @@
#include <android-base/strings.h>
#include <cutils/properties.h>
#include <log/log.h>
+#include <utils/Trace.h>
#include <vulkan/vk_layer_interface.h>
#include <graphicsenv/GraphicsEnv.h>
@@ -1176,6 +1179,8 @@
VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance) {
+ ATRACE_CALL();
+
if (!EnsureInitialized())
return VK_ERROR_INITIALIZATION_FAILED;
@@ -1184,6 +1189,8 @@
void DestroyInstance(VkInstance instance,
const VkAllocationCallbacks* pAllocator) {
+ ATRACE_CALL();
+
if (instance != VK_NULL_HANDLE)
LayerChain::DestroyInstance(instance, pAllocator);
}
@@ -1192,17 +1199,23 @@
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice) {
+ ATRACE_CALL();
+
return LayerChain::CreateDevice(physicalDevice, pCreateInfo, pAllocator,
pDevice);
}
void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
+ ATRACE_CALL();
+
if (device != VK_NULL_HANDLE)
LayerChain::DestroyDevice(device, pAllocator);
}
VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount,
VkLayerProperties* pProperties) {
+ ATRACE_CALL();
+
if (!EnsureInitialized())
return VK_ERROR_INITIALIZATION_FAILED;
@@ -1225,6 +1238,8 @@
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
+ ATRACE_CALL();
+
if (!EnsureInitialized())
return VK_ERROR_INITIALIZATION_FAILED;
@@ -1253,6 +1268,8 @@
VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
uint32_t* pPropertyCount,
VkLayerProperties* pProperties) {
+ ATRACE_CALL();
+
uint32_t count;
const LayerChain::ActiveLayer* layers =
LayerChain::GetActiveLayers(physicalDevice, count);
@@ -1275,6 +1292,8 @@
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
+ ATRACE_CALL();
+
if (pLayerName) {
// EnumerateDeviceLayerProperties enumerates active layers for
// backward compatibility. The extension query here should work for
@@ -1302,6 +1321,8 @@
}
VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) {
+ ATRACE_CALL();
+
*pApiVersion = VK_API_VERSION_1_1;
return VK_SUCCESS;
}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a607a5d..421f727 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
@@ -31,6 +33,7 @@
#include <configstore/Utils.h>
#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
+#include <utils/Trace.h>
#include <utils/Vector.h>
#include "android-base/properties.h"
@@ -150,6 +153,8 @@
void* LoadLibrary(const android_dlextinfo& dlextinfo,
const char* subname,
int subname_len) {
+ ATRACE_CALL();
+
const char kLibFormat[] = "vulkan.%*s.so";
char* name = static_cast<char*>(
alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len)));
@@ -164,6 +169,8 @@
int LoadDriver(android_namespace_t* library_namespace,
const hwvulkan_module_t** module) {
+ ATRACE_CALL();
+
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = library_namespace,
@@ -198,6 +205,8 @@
}
int LoadBuiltinDriver(const hwvulkan_module_t** module) {
+ ATRACE_CALL();
+
auto ns = android_get_exported_namespace("sphal");
if (!ns)
return -ENOENT;
@@ -205,6 +214,8 @@
}
int LoadUpdatedDriver(const hwvulkan_module_t** module) {
+ ATRACE_CALL();
+
auto ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (!ns)
return -ENOENT;
@@ -212,6 +223,8 @@
}
bool Hal::Open() {
+ ATRACE_CALL();
+
ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once");
// Use a stub device unless we successfully open a real HAL device.
@@ -242,9 +255,11 @@
}
hwvulkan_device_t* device;
+ ATRACE_BEGIN("hwvulkan module open");
result =
module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
reinterpret_cast<hw_device_t**>(&device));
+ ATRACE_END();
if (result != 0) {
// Any device with a Vulkan HAL should be able to open the device.
ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result),
@@ -260,6 +275,8 @@
}
bool Hal::InitDebugReportIndex() {
+ ATRACE_CALL();
+
uint32_t count;
if (dev_->EnumerateInstanceExtensionProperties(nullptr, &count, nullptr) !=
VK_SUCCESS) {
@@ -821,8 +838,10 @@
}
}
+ ATRACE_BEGIN("driver.EnumerateInstanceExtensionProperties");
VkResult result = Hal::Device().EnumerateInstanceExtensionProperties(
pLayerName, pPropertyCount, pProperties);
+ ATRACE_END();
if (!pLayerName && (result == VK_SUCCESS || result == VK_INCOMPLETE)) {
int idx = Hal::Get().GetDebugReportIndex();
@@ -931,8 +950,10 @@
*pPropertyCount -= count;
}
+ ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
VkResult result = data.driver.EnumerateDeviceExtensionProperties(
physicalDevice, pLayerName, pPropertyCount, pProperties);
+ ATRACE_END();
if (pProperties) {
// map VK_ANDROID_native_buffer to VK_KHR_swapchain
@@ -968,12 +989,15 @@
if (result != VK_SUCCESS)
return result;
+ ATRACE_BEGIN("AllocateInstanceData");
InstanceData* data = AllocateInstanceData(data_allocator);
+ ATRACE_END();
if (!data)
return VK_ERROR_OUT_OF_HOST_MEMORY;
data->hook_extensions |= wrapper.GetHookExtensions();
+ ATRACE_BEGIN("autoDowngradeApiVersion");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
uint32_t api_version = ((pCreateInfo->pApplicationInfo)
@@ -989,7 +1013,9 @@
if (!pfn_enumerate_instance_version) {
icd_api_version = VK_API_VERSION_1_0;
} else {
+ ATRACE_BEGIN("pfn_enumerate_instance_version");
result = (*pfn_enumerate_instance_version)(&icd_api_version);
+ ATRACE_END();
}
uint32_t icd_api_major_version = VK_VERSION_MAJOR(icd_api_version);
uint32_t icd_api_minor_version = VK_VERSION_MINOR(icd_api_version);
@@ -1000,12 +1026,15 @@
wrapper.DowngradeApiVersion();
}
#pragma clang diagnostic pop
+ ATRACE_END();
// call into the driver
VkInstance instance;
+ ATRACE_BEGIN("driver.CreateInstance");
result = Hal::Device().CreateInstance(
static_cast<const VkInstanceCreateInfo*>(wrapper), pAllocator,
&instance);
+ ATRACE_END();
if (result != VK_SUCCESS) {
FreeInstanceData(data, data_allocator);
return result;
@@ -1066,8 +1095,10 @@
if (result != VK_SUCCESS)
return result;
+ ATRACE_BEGIN("AllocateDeviceData");
DeviceData* data = AllocateDeviceData(data_allocator,
instance_data.debug_report_callbacks);
+ ATRACE_END();
if (!data)
return VK_ERROR_OUT_OF_HOST_MEMORY;
@@ -1075,9 +1106,11 @@
// call into the driver
VkDevice dev;
+ ATRACE_BEGIN("driver.CreateDevice");
result = instance_data.driver.CreateDevice(
physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
pAllocator, &dev);
+ ATRACE_END();
if (result != VK_SUCCESS) {
FreeDeviceData(data, data_allocator);
return result;
@@ -1114,8 +1147,10 @@
}
VkPhysicalDeviceProperties properties;
+ ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
&properties);
+ ATRACE_END();
data->driver_device = dev;
data->driver_version = properties.driverVersion;
@@ -1141,6 +1176,8 @@
VkResult EnumeratePhysicalDevices(VkInstance instance,
uint32_t* pPhysicalDeviceCount,
VkPhysicalDevice* pPhysicalDevices) {
+ ATRACE_CALL();
+
const auto& data = GetData(instance);
VkResult result = data.driver.EnumeratePhysicalDevices(
@@ -1157,6 +1194,8 @@
VkInstance instance,
uint32_t* pPhysicalDeviceGroupCount,
VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ ATRACE_CALL();
+
VkResult result = VK_SUCCESS;
const auto& data = GetData(instance);
@@ -1217,6 +1256,8 @@
uint32_t queueFamilyIndex,
uint32_t queueIndex,
VkQueue* pQueue) {
+ ATRACE_CALL();
+
const auto& data = GetData(device);
data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
@@ -1226,6 +1267,8 @@
void GetDeviceQueue2(VkDevice device,
const VkDeviceQueueInfo2* pQueueInfo,
VkQueue* pQueue) {
+ ATRACE_CALL();
+
const auto& data = GetData(device);
data.driver.GetDeviceQueue2(device, pQueueInfo, pQueue);
@@ -1236,6 +1279,8 @@
AllocateCommandBuffers(VkDevice device,
const VkCommandBufferAllocateInfo* pAllocateInfo,
VkCommandBuffer* pCommandBuffers) {
+ ATRACE_CALL();
+
const auto& data = GetData(device);
VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo,
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index ba4cf00..af1adcf 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "layers_extensions.h"
#include <alloca.h>
@@ -33,6 +35,7 @@
#include <log/log.h>
#include <nativebridge/native_bridge.h>
#include <nativeloader/native_loader.h>
+#include <utils/Trace.h>
#include <ziparchive/zip_archive.h>
// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
@@ -428,6 +431,8 @@
}
void DiscoverLayersInPathList(const std::string& pathstr) {
+ ATRACE_CALL();
+
std::vector<std::string> paths = android::base::Split(pathstr, ":");
for (const auto& path : paths) {
ForEachFileInPath(path, [&](const std::string& filename) {
@@ -477,6 +482,8 @@
} // anonymous namespace
void DiscoverLayers() {
+ ATRACE_CALL();
+
if (property_get_bool("ro.debuggable", false) &&
prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
DiscoverLayersInPathList(kSystemLayerLibraryDir);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 47334f6..32e19f7 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <algorithm>
#include <grallocusage/GrallocUsageConversion.h>
@@ -21,6 +23,7 @@
#include <ui/BufferQueueDefs.h>
#include <sync/sync.h>
#include <utils/StrongPointer.h>
+#include <utils/Trace.h>
#include <utils/Vector.h>
#include <system/window.h>
#include <android/hardware/graphics/common/1.0/types.h>
@@ -486,6 +489,8 @@
const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* out_surface) {
+ ATRACE_CALL();
+
if (!allocator)
allocator = &GetData(instance).allocator;
void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
@@ -528,6 +533,8 @@
void DestroySurfaceKHR(VkInstance instance,
VkSurfaceKHR surface_handle,
const VkAllocationCallbacks* allocator) {
+ ATRACE_CALL();
+
Surface* surface = SurfaceFromHandle(surface_handle);
if (!surface)
return;
@@ -548,6 +555,8 @@
uint32_t /*queue_family*/,
VkSurfaceKHR surface_handle,
VkBool32* supported) {
+ ATRACE_CALL();
+
const Surface* surface = SurfaceFromHandle(surface_handle);
if (!surface) {
return VK_ERROR_SURFACE_LOST_KHR;
@@ -590,6 +599,8 @@
VkPhysicalDevice /*pdev*/,
VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR* capabilities) {
+ ATRACE_CALL();
+
int err;
ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
@@ -663,6 +674,8 @@
VkSurfaceKHR surface_handle,
uint32_t* count,
VkSurfaceFormatKHR* formats) {
+ ATRACE_CALL();
+
const InstanceData& instance_data = GetData(pdev);
// TODO(jessehall): Fill out the set of supported formats. Longer term, add
@@ -737,6 +750,8 @@
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
VkSurfaceCapabilities2KHR* pSurfaceCapabilities) {
+ ATRACE_CALL();
+
VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR(
physicalDevice, pSurfaceInfo->surface,
&pSurfaceCapabilities->surfaceCapabilities);
@@ -772,6 +787,8 @@
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
uint32_t* pSurfaceFormatCount,
VkSurfaceFormat2KHR* pSurfaceFormats) {
+ ATRACE_CALL();
+
if (!pSurfaceFormats) {
return GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,
pSurfaceInfo->surface,
@@ -803,6 +820,8 @@
VkSurfaceKHR surface,
uint32_t* count,
VkPresentModeKHR* modes) {
+ ATRACE_CALL();
+
int err;
int query_value;
ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
@@ -854,6 +873,8 @@
VkResult GetDeviceGroupPresentCapabilitiesKHR(
VkDevice,
VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+ ATRACE_CALL();
+
ALOGV_IF(pDeviceGroupPresentCapabilities->sType !=
VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR,
"vkGetDeviceGroupPresentCapabilitiesKHR: invalid "
@@ -876,6 +897,8 @@
VkDevice,
VkSurfaceKHR,
VkDeviceGroupPresentModeFlagsKHR* pModes) {
+ ATRACE_CALL();
+
*pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
return VK_SUCCESS;
}
@@ -885,6 +908,8 @@
VkSurfaceKHR surface,
uint32_t* pRectCount,
VkRect2D* pRects) {
+ ATRACE_CALL();
+
if (!pRects) {
*pRectCount = 1;
} else {
@@ -926,6 +951,8 @@
const VkSwapchainCreateInfoKHR* create_info,
const VkAllocationCallbacks* allocator,
VkSwapchainKHR* swapchain_handle) {
+ ATRACE_CALL();
+
int err;
VkResult result = VK_SUCCESS;
@@ -1150,9 +1177,11 @@
int32_t legacy_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;
+ ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsage2ANDROID");
result = dispatch.GetSwapchainGrallocUsage2ANDROID(
device, create_info->imageFormat, create_info->imageUsage,
swapchain_image_usage, &consumer_usage, &producer_usage);
+ ATRACE_END();
if (result != VK_SUCCESS) {
ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1160,9 +1189,11 @@
legacy_usage =
android_convertGralloc1To0Usage(producer_usage, consumer_usage);
} else if (dispatch.GetSwapchainGrallocUsageANDROID) {
+ ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsageANDROID");
result = dispatch.GetSwapchainGrallocUsageANDROID(
device, create_info->imageFormat, create_info->imageUsage,
&legacy_usage);
+ ATRACE_END();
if (result != VK_SUCCESS) {
ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1257,8 +1288,10 @@
&image_native_buffer.usage2.producer,
&image_native_buffer.usage2.consumer);
+ ATRACE_BEGIN("dispatch.CreateImage");
result =
dispatch.CreateImage(device, &image_create, nullptr, &img.image);
+ ATRACE_END();
if (result != VK_SUCCESS) {
ALOGD("vkCreateImage w/ native buffer failed: %u", result);
break;
@@ -1282,8 +1315,11 @@
}
}
if (result != VK_SUCCESS) {
- if (img.image)
+ if (img.image) {
+ ATRACE_BEGIN("dispatch.DestroyImage");
dispatch.DestroyImage(device, img.image, nullptr);
+ ATRACE_END();
+ }
}
}
@@ -1302,6 +1338,8 @@
void DestroySwapchainKHR(VkDevice device,
VkSwapchainKHR swapchain_handle,
const VkAllocationCallbacks* allocator) {
+ ATRACE_CALL();
+
const auto& dispatch = GetData(device).driver;
Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
if (!swapchain)
@@ -1327,6 +1365,8 @@
VkSwapchainKHR swapchain_handle,
uint32_t* count,
VkImage* images) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle,
"getting images for non-active swapchain 0x%" PRIx64
@@ -1355,6 +1395,8 @@
VkSemaphore semaphore,
VkFence vk_fence,
uint32_t* image_index) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
ANativeWindow* window = swapchain.surface.window.get();
VkResult result;
@@ -1435,6 +1477,8 @@
VkResult AcquireNextImage2KHR(VkDevice device,
const VkAcquireNextImageInfoKHR* pAcquireInfo,
uint32_t* pImageIndex) {
+ ATRACE_CALL();
+
// TODO: this should actually be the other way around and this function
// should handle any additional structures that get passed in
return AcquireNextImageKHR(device, pAcquireInfo->swapchain,
@@ -1464,6 +1508,8 @@
VKAPI_ATTR
VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
+ ATRACE_CALL();
+
ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
"vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
present_info->sType);
@@ -1675,6 +1721,8 @@
VkDevice,
VkSwapchainKHR swapchain_handle,
VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
VkResult result = VK_SUCCESS;
@@ -1690,6 +1738,8 @@
VkSwapchainKHR swapchain_handle,
uint32_t* count,
VkPastPresentationTimingGOOGLE* timings) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
ANativeWindow* window = swapchain.surface.window.get();
VkResult result = VK_SUCCESS;
@@ -1714,6 +1764,8 @@
VkResult GetSwapchainStatusKHR(
VkDevice,
VkSwapchainKHR swapchain_handle) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
VkResult result = VK_SUCCESS;
@@ -1731,6 +1783,7 @@
uint32_t swapchainCount,
const VkSwapchainKHR* pSwapchains,
const VkHdrMetadataEXT* pHdrMetadataEXTs) {
+ ATRACE_CALL();
for (uint32_t idx = 0; idx < swapchainCount; idx++) {
Swapchain* swapchain = SwapchainFromHandle(pSwapchains[idx]);