Merge "Include Rect.h explictly" into rvc-dev
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2307fbf..605c2e8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -430,6 +430,19 @@
}
status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const {
+ // If we write the Transaction to a parcel, we want to ensure the Buffers are cached
+ // before crossing the IPC boundary. Otherwise the receiving party will cache the buffers
+ // but is unlikely to use them again as they are owned by the other process.
+ // You may be asking yourself, is this const cast safe? Const cast is safe up
+ // until the point where you try and write to an object that was originally const at which
+ // point we enter undefined behavior. In this case we are safe though, because there are
+ // two possibilities:
+ // 1. The SurfaceComposerClient::Transaction was originally non-const. Safe.
+ // 2. It was originall const! In this case not only was it useless, but it by definition
+ // contains no composer states and so cacheBuffers will not perform any writes.
+
+ const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers();
+
parcel->writeUint32(mForceSynchronous);
parcel->writeUint32(mTransactionNestCount);
parcel->writeBool(mAnimation);
@@ -507,7 +520,7 @@
mInputWindowCommands.merge(other.mInputWindowCommands);
- mContainsBuffer = other.mContainsBuffer;
+ mContainsBuffer |= other.mContainsBuffer;
mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
other.clear();
return *this;
@@ -547,6 +560,11 @@
layer_state_t* s = getLayerState(handle);
if (!(s->what & layer_state_t::eBufferChanged)) {
continue;
+ } else if (s->what & layer_state_t::eCachedBufferChanged) {
+ // If eBufferChanged and eCachedBufferChanged are both trued then that means
+ // we already cached the buffer in a previous call to cacheBuffers, perhaps
+ // from writeToParcel on a Transaction that was merged in to this one.
+ continue;
}
// Don't try to cache a null buffer. Sending null buffers is cheap so we shouldn't waste
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index d56a82f..36a54a7 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -793,35 +793,66 @@
// top rectangle and the bottom rectangle, and turn off blending for the middle rectangle.
FloatRect bounds = layer.geometry.roundedCornersCrop;
- // Firstly, we need to convert the coordination from layer native coordination space to
- // device coordination space.
- // TODO(143929254): Verify that this transformation is correct
- const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform;
- const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
- const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
- const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate;
- const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
- bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1],
- rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]);
-
- // Secondly, if the display is rotated, we need to undo the rotation on coordination and
- // align the (left, top) and (right, bottom) coordination with the device coordination
- // space.
+ // Explicitly compute the transform from the clip rectangle to the physical
+ // display. Normally, this is done in glViewport but we explicitly compute
+ // it here so that we can get the scissor bounds correct.
+ const Rect& source = display.clip;
+ const Rect& destination = display.physicalDisplay;
+ // Here we compute the following transform:
+ // 1. Translate the top left corner of the source clip to (0, 0)
+ // 2. Rotate the clip rectangle about the origin in accordance with the
+ // orientation flag
+ // 3. Translate the top left corner back to the origin.
+ // 4. Scale the clip rectangle to the destination rectangle dimensions
+ // 5. Translate the top left corner to the destination rectangle's top left
+ // corner.
+ const mat4 translateSource = mat4::translate(vec4(-source.left, -source.top, 0, 1));
+ mat4 rotation;
+ int displacementX = 0;
+ int displacementY = 0;
+ float destinationWidth = static_cast<float>(destination.getWidth());
+ float destinationHeight = static_cast<float>(destination.getHeight());
+ float sourceWidth = static_cast<float>(source.getWidth());
+ float sourceHeight = static_cast<float>(source.getHeight());
+ const float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
switch (display.orientation) {
case ui::Transform::ROT_90:
- std::swap(bounds.left, bounds.right);
+ rotation = mat4::rotate(rot90InRadians, vec3(0, 0, 1));
+ displacementX = source.getHeight();
+ std::swap(sourceHeight, sourceWidth);
break;
case ui::Transform::ROT_180:
- std::swap(bounds.left, bounds.right);
- std::swap(bounds.top, bounds.bottom);
+ rotation = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1));
+ displacementY = source.getHeight();
+ displacementX = source.getWidth();
break;
case ui::Transform::ROT_270:
- std::swap(bounds.top, bounds.bottom);
+ rotation = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1));
+ displacementY = source.getWidth();
+ std::swap(sourceHeight, sourceWidth);
break;
default:
break;
}
+ const mat4 intermediateTranslation = mat4::translate(vec4(displacementX, displacementY, 0, 1));
+ const mat4 scale = mat4::scale(
+ vec4(destinationWidth / sourceWidth, destinationHeight / sourceHeight, 1, 1));
+ const mat4 translateDestination =
+ mat4::translate(vec4(destination.left, destination.top, 0, 1));
+ const mat4 globalTransform =
+ translateDestination * scale * intermediateTranslation * rotation * translateSource;
+
+ const mat4 transformMatrix = globalTransform * layer.geometry.positionTransform;
+ const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
+ const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
+ const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate;
+ const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
+ bounds = FloatRect(std::min(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]),
+ std::min(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1]),
+ std::max(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]),
+ std::max(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1]));
+
// Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners
// and the middle part without rounded corners.
const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index c0766ab..ca16d2c 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -40,16 +40,6 @@
// z=1.
Rect clip = Rect::INVALID_RECT;
- // Global transform to apply to all layers.
- // The global transform is assumed to automatically apply when projecting
- // the clip rectangle onto the physical display; however, this should be
- // explicitly provided to perform CPU-side optimizations such as computing
- // scissor rectangles for rounded corners which require transformation to
- // the phsical display space.
- //
- // This transform is also assumed to include the orientation flag below.
- mat4 globalTransform = mat4();
-
// Maximum luminance pulled from the display's HDR capabilities.
float maxLuminance = 1.0f;
@@ -62,9 +52,7 @@
mat4 colorTransform = mat4();
// Region that will be cleared to (0, 0, 0, 1) prior to rendering.
- // RenderEngine will transform the clearRegion passed in here, by
- // globalTransform, so that it will be in the same coordinate space as the
- // rendered layers.
+ // This is specified in layer-stack space.
Region clearRegion = Region::INVALID_REGION;
// An additional orientation flag to be applied after clipping the output.
@@ -76,8 +64,7 @@
static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
return lhs.physicalDisplay == rhs.physicalDisplay && lhs.clip == rhs.clip &&
- lhs.globalTransform == rhs.globalTransform && lhs.maxLuminance == rhs.maxLuminance &&
- lhs.outputDataspace == rhs.outputDataspace &&
+ lhs.maxLuminance == rhs.maxLuminance && lhs.outputDataspace == rhs.outputDataspace &&
lhs.colorTransform == rhs.colorTransform &&
lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.orientation == rhs.orientation;
}
@@ -89,7 +76,6 @@
PrintTo(settings.physicalDisplay, os);
*os << "\n .clip = ";
PrintTo(settings.clip, os);
- *os << "\n .globalTransform = " << settings.globalTransform;
*os << "\n .maxLuminance = " << settings.maxLuminance;
*os << "\n .outputDataspace = ";
PrintTo(settings.outputDataspace, os);
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index ce9131d..f5bf014 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -924,7 +924,6 @@
settings.physicalDisplay = fullscreenRect();
// Here logical space is 4x4
settings.clip = Rect(4, 4);
- settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1));
settings.clearRegion = Region(Rect(2, 4));
std::vector<const renderengine::LayerSettings*> layers;
// dummy layer, without bounds should not render anything
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index d8e4059..f799ce4 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -203,7 +203,7 @@
std::vector<ui::PlaneLayout> planeLayouts;
status_t err = getPlaneLayouts(bufferHandle, &planeLayouts);
- if (err != NO_ERROR && !planeLayouts.empty()) {
+ if (err == NO_ERROR && !planeLayouts.empty()) {
if (outBytesPerPixel) {
int32_t bitsPerPixel = planeLayouts.front().sampleIncrementInBits;
for (const auto& planeLayout : planeLayouts) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index c345405..308ec5a 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -268,12 +268,9 @@
}
bool Display::getSkipColorTransform() const {
- if (!mId) {
- return false;
- }
-
- auto& hwc = getCompositionEngine().getHwComposer();
- return hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform);
+ const auto& hwc = getCompositionEngine().getHwComposer();
+ return mId ? hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform)
+ : hwc.hasCapability(HWC2::Capability::SkipClientColorTransform);
}
bool Display::anyLayersRequireClientComposition() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 248933e..34d0cb2 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -829,7 +829,6 @@
renderengine::DisplaySettings clientCompositionDisplay;
clientCompositionDisplay.physicalDisplay = outputState.destinationClip;
clientCompositionDisplay.clip = outputState.sourceClip;
- clientCompositionDisplay.globalTransform = outputState.transform.asMatrix4();
clientCompositionDisplay.orientation = outputState.orientation;
clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
? outputState.dataspace
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 88f2686..f73a6f7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -681,15 +681,17 @@
using DisplayGetSkipColorTransformTest = DisplayWithLayersTestCommon;
-TEST_F(DisplayGetSkipColorTransformTest, doesNothingIfNonHwcDisplay) {
+TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfNonHwcDisplay) {
+ EXPECT_CALL(mHwComposer, hasCapability(HWC2::Capability::SkipClientColorTransform))
+ .WillOnce(Return(true));
auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)};
- EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform());
+ EXPECT_TRUE(nonHwcDisplay->getSkipColorTransform());
}
-TEST_F(DisplayGetSkipColorTransformTest, checksHwcCapability) {
+TEST_F(DisplayGetSkipColorTransformTest, checksDisplayCapability) {
EXPECT_CALL(mHwComposer,
- hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID),
+ hasDisplayCapability(DEFAULT_DISPLAY_ID,
HWC2::DisplayCapability::SkipClientColorTransform))
.WillOnce(Return(true));
EXPECT_TRUE(mDisplay->getSkipColorTransform());
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 88f6649..52bd6a1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -40,8 +40,7 @@
MOCK_CONST_METHOD3(getDisplayIdentificationData,
bool(hwc2_display_t, uint8_t*, DisplayIdentificationData*));
MOCK_CONST_METHOD1(hasCapability, bool(HWC2::Capability));
- MOCK_CONST_METHOD2(hasDisplayCapability,
- bool(const std::optional<DisplayId>&, HWC2::DisplayCapability));
+ MOCK_CONST_METHOD2(hasDisplayCapability, bool(DisplayId, HWC2::DisplayCapability));
MOCK_METHOD3(allocateVirtualDisplay,
std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 63bb459..1c9cd9c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3100,9 +3100,8 @@
.andIfUsesHdr(true)
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
- mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
- mat4(), Region::INVALID_REGION,
- kDefaultOutputOrientation})
+ kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
+ Region::INVALID_REGION, kDefaultOutputOrientation})
.execute()
.expectAFenceWasReturned();
}
@@ -3112,9 +3111,8 @@
.andIfUsesHdr(false)
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
- mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
- mat4(), Region::INVALID_REGION,
- kDefaultOutputOrientation})
+ kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
+ Region::INVALID_REGION, kDefaultOutputOrientation})
.execute()
.expectAFenceWasReturned();
}
@@ -3124,7 +3122,7 @@
.andIfUsesHdr(true)
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
- mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
+ kDefaultMaxLuminance, kDefaultOutputDataspace,
kDefaultColorTransformMat, Region::INVALID_REGION,
kDefaultOutputOrientation})
.execute()
@@ -3136,7 +3134,7 @@
.andIfUsesHdr(false)
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
- mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
+ kDefaultMaxLuminance, kDefaultOutputDataspace,
kDefaultColorTransformMat, Region::INVALID_REGION,
kDefaultOutputOrientation})
.execute()
@@ -3149,9 +3147,8 @@
.andIfUsesHdr(true)
.andIfSkipColorTransform(true)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
- mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
- mat4(), Region::INVALID_REGION,
- kDefaultOutputOrientation})
+ kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
+ Region::INVALID_REGION, kDefaultOutputOrientation})
.execute()
.expectAFenceWasReturned();
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 560299a..f30d662 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -190,17 +190,10 @@
return mCapabilities.count(capability) > 0;
}
-bool HWComposer::hasDisplayCapability(const std::optional<DisplayId>& displayId,
+bool HWComposer::hasDisplayCapability(DisplayId displayId,
HWC2::DisplayCapability capability) const {
- if (!displayId) {
- // Checkout global capabilities for displays without a corresponding HWC display.
- if (capability == HWC2::DisplayCapability::SkipClientColorTransform) {
- return hasCapability(HWC2::Capability::SkipClientColorTransform);
- }
- return false;
- }
- RETURN_IF_INVALID_DISPLAY(*displayId, false);
- return mDisplayData.at(*displayId).hwcDisplay->getCapabilities().count(capability) > 0;
+ RETURN_IF_INVALID_DISPLAY(displayId, false);
+ return mDisplayData.at(displayId).hwcDisplay->getCapabilities().count(capability) > 0;
}
std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 3cb40b1..e18419a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -70,7 +70,7 @@
DisplayIdentificationData* outData) const = 0;
virtual bool hasCapability(HWC2::Capability capability) const = 0;
- virtual bool hasDisplayCapability(const std::optional<DisplayId>& displayId,
+ virtual bool hasDisplayCapability(DisplayId displayId,
HWC2::DisplayCapability capability) const = 0;
// Attempts to allocate a virtual display and returns its ID if created on the HWC device.
@@ -234,7 +234,7 @@
DisplayIdentificationData* outData) const override;
bool hasCapability(HWC2::Capability capability) const override;
- bool hasDisplayCapability(const std::optional<DisplayId>& displayId,
+ bool hasDisplayCapability(DisplayId displayId,
HWC2::DisplayCapability capability) const override;
// Attempts to allocate a virtual display and returns its ID if created on the HWC device.
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 0d6a92e..8347650 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -429,7 +429,13 @@
ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName);
std::string debugInfo = "VsyncSource debug info:\n";
mVSyncSource->dump(debugInfo);
- ALOGW("%s", debugInfo.c_str());
+ // Log the debug info line-by-line to avoid logcat overflow
+ auto pos = debugInfo.find('\n');
+ while (pos != std::string::npos) {
+ ALOGW("%s", debugInfo.substr(0, pos).c_str());
+ debugInfo = debugInfo.substr(pos + 1);
+ pos = debugInfo.find('\n');
+ }
}
LOG_FATAL_IF(!mVSyncState);
diff --git a/services/surfaceflinger/Scheduler/TimeKeeper.h b/services/surfaceflinger/Scheduler/TimeKeeper.h
index 38f0708..da2195c 100644
--- a/services/surfaceflinger/Scheduler/TimeKeeper.h
+++ b/services/surfaceflinger/Scheduler/TimeKeeper.h
@@ -53,6 +53,8 @@
*/
virtual void alarmCancel() = 0;
+ virtual void dump(std::string& result) const = 0;
+
protected:
TimeKeeper(TimeKeeper const&) = delete;
TimeKeeper& operator=(TimeKeeper const&) = delete;
diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp
index 8f81c2c..7c5058e 100644
--- a/services/surfaceflinger/Scheduler/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/Timer.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "SchedulerTimer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <android-base/stringprintf.h>
#include <log/log.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
@@ -29,28 +30,53 @@
#include "Timer.h"
namespace android::scheduler {
+using base::StringAppendF;
static constexpr size_t kReadPipe = 0;
static constexpr size_t kWritePipe = 1;
-Timer::Timer()
- : mTimerFd(timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK)),
- mEpollFd(epoll_create1(EPOLL_CLOEXEC)) {
- if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
- ALOGE("could not create TimerDispatch mPipes");
- };
-
- mDispatchThread = std::thread(std::bind(&Timer::dispatch, this));
+Timer::Timer() {
+ reset();
+ mDispatchThread = std::thread([this]() { threadMain(); });
}
Timer::~Timer() {
endDispatch();
mDispatchThread.join();
+ cleanup();
+}
- close(mPipes[kWritePipe]);
- close(mPipes[kReadPipe]);
- close(mEpollFd);
- close(mTimerFd);
+void Timer::reset() {
+ cleanup();
+ mTimerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+ mEpollFd = epoll_create1(EPOLL_CLOEXEC);
+ if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
+ ALOGE("could not create TimerDispatch mPipes");
+ return;
+ };
+ setDebugState(DebugState::Reset);
+}
+
+void Timer::cleanup() {
+ if (mTimerFd != -1) {
+ close(mTimerFd);
+ mTimerFd = -1;
+ }
+
+ if (mEpollFd != -1) {
+ close(mEpollFd);
+ mEpollFd = -1;
+ }
+
+ if (mPipes[kReadPipe] != -1) {
+ close(mPipes[kReadPipe]);
+ mPipes[kReadPipe] = -1;
+ }
+
+ if (mPipes[kWritePipe] != -1) {
+ close(mPipes[kWritePipe]);
+ mPipes[kWritePipe] = -1;
+ }
}
void Timer::endDispatch() {
@@ -99,7 +125,14 @@
}
}
-void Timer::dispatch() {
+void Timer::threadMain() {
+ while (dispatch()) {
+ reset();
+ }
+}
+
+bool Timer::dispatch() {
+ setDebugState(DebugState::Running);
struct sched_param param = {0};
param.sched_priority = 2;
if (pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m) != 0) {
@@ -116,7 +149,7 @@
timerEvent.data.u32 = DispatchType::TIMER;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mTimerFd, &timerEvent) == -1) {
ALOGE("Error adding timer fd to epoll dispatch loop");
- return;
+ return true;
}
epoll_event terminateEvent;
@@ -124,18 +157,20 @@
terminateEvent.data.u32 = DispatchType::TERMINATE;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mPipes[kReadPipe], &terminateEvent) == -1) {
ALOGE("Error adding control fd to dispatch loop");
- return;
+ return true;
}
uint64_t iteration = 0;
char const traceNamePrefix[] = "TimerIteration #";
static constexpr size_t maxlen = arrayLen(traceNamePrefix) + max64print;
std::array<char, maxlen> str_buffer;
- auto timing = true;
- while (timing) {
+
+ while (true) {
+ setDebugState(DebugState::Waiting);
epoll_event events[DispatchType::MAX_DISPATCH_TYPE];
int nfds = epoll_wait(mEpollFd, events, DispatchType::MAX_DISPATCH_TYPE, -1);
+ setDebugState(DebugState::Running);
if (ATRACE_ENABLED()) {
snprintf(str_buffer.data(), str_buffer.size(), "%s%" PRIu64, traceNamePrefix,
iteration++);
@@ -144,29 +179,62 @@
if (nfds == -1) {
if (errno != EINTR) {
- timing = false;
- continue;
+ ALOGE("Error waiting on epoll: %s", strerror(errno));
+ return true;
}
}
for (auto i = 0; i < nfds; i++) {
if (events[i].data.u32 == DispatchType::TIMER) {
static uint64_t mIgnored = 0;
+ setDebugState(DebugState::Reading);
read(mTimerFd, &mIgnored, sizeof(mIgnored));
+ setDebugState(DebugState::Running);
std::function<void()> cb;
{
std::lock_guard<decltype(mMutex)> lk(mMutex);
cb = mCallback;
}
if (cb) {
+ setDebugState(DebugState::InCallback);
cb();
+ setDebugState(DebugState::Running);
}
}
if (events[i].data.u32 == DispatchType::TERMINATE) {
- timing = false;
+ ALOGE("Terminated");
+ setDebugState(DebugState::Running);
+ return false;
}
}
}
}
+void Timer::setDebugState(DebugState state) {
+ std::lock_guard lk(mMutex);
+ mDebugState = state;
+}
+
+const char* Timer::strDebugState(DebugState state) const {
+ switch (state) {
+ case DebugState::Reset:
+ return "Reset";
+ case DebugState::Running:
+ return "Running";
+ case DebugState::Waiting:
+ return "Waiting";
+ case DebugState::Reading:
+ return "Reading";
+ case DebugState::InCallback:
+ return "InCallback";
+ case DebugState::Terminated:
+ return "Terminated";
+ }
+}
+
+void Timer::dump(std::string& result) const {
+ std::lock_guard lk(mMutex);
+ StringAppendF(&result, "\t\tDebugState: %s\n", strDebugState(mDebugState));
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Timer.h b/services/surfaceflinger/Scheduler/Timer.h
index 0ae82c8..a8e2d5a 100644
--- a/services/surfaceflinger/Scheduler/Timer.h
+++ b/services/surfaceflinger/Scheduler/Timer.h
@@ -34,18 +34,27 @@
// Most users will want to serialize thes calls so as to be aware of the timer state.
void alarmIn(std::function<void()> const& cb, nsecs_t fireIn) final;
void alarmCancel() final;
+ void dump(std::string& result) const final;
private:
- int const mTimerFd;
- int const mEpollFd;
- std::array<int, 2> mPipes;
+ enum class DebugState { Reset, Running, Waiting, Reading, InCallback, Terminated };
+ void reset();
+ void cleanup();
+ void setDebugState(DebugState state) EXCLUDES(mMutex);
+ const char* strDebugState(DebugState state) const;
+
+ int mTimerFd = -1;
+ int mEpollFd = -1;
+ std::array<int, 2> mPipes = {-1, -1};
std::thread mDispatchThread;
- void dispatch();
+ void threadMain();
+ bool dispatch();
void endDispatch();
- std::mutex mMutex;
+ mutable std::mutex mMutex;
std::function<void()> mCallback GUARDED_BY(mMutex);
+ DebugState mDebugState GUARDED_BY(mMutex);
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 460d4a5..cd15617 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -168,6 +168,7 @@
mIntendedWakeupTime = targetTime;
mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
targetTime - now);
+ mLastTimerSchedule = mTimeKeeper->now();
}
void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
@@ -226,6 +227,7 @@
std::vector<Invocation> invocations;
{
std::lock_guard<decltype(mMutex)> lk(mMutex);
+ mLastTimerCallback = mTimeKeeper->now();
for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
auto& callback = it->second;
auto const wakeupTime = callback->wakeupTime();
@@ -322,10 +324,15 @@
void VSyncDispatchTimerQueue::dump(std::string& result) const {
std::lock_guard<decltype(mMutex)> lk(mMutex);
+ StringAppendF(&result, "\tTimer:\n");
+ mTimeKeeper->dump(result);
StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
mMinVsyncDistance / 1e6f);
StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
- (mIntendedWakeupTime - systemTime()) / 1e6f);
+ (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
+ StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
+ (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
+ (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
StringAppendF(&result, "\tCallbacks:\n");
for (const auto& [token, entry] : mCallbacks) {
entry->dump(result);
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 390e0c4..26a8ec0 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -152,6 +152,10 @@
std::array<char, maxlen> str_buffer;
void note(std::string_view name, nsecs_t in, nsecs_t vs);
} mTraceBuffer GUARDED_BY(mMutex);
+
+ // For debugging purposes
+ nsecs_t mLastTimerCallback GUARDED_BY(mMutex) = kInvalidTime;
+ nsecs_t mLastTimerSchedule GUARDED_BY(mMutex) = kInvalidTime;
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index aa0005d..2979322 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1217,7 +1217,7 @@
displayToken.get());
return NAME_NOT_FOUND;
}
- *outSupport = getHwComposer().hasDisplayCapability(displayId,
+ *outSupport = getHwComposer().hasDisplayCapability(*displayId,
HWC2::DisplayCapability::AutoLowLatencyMode);
return NO_ERROR;
}
@@ -1488,7 +1488,7 @@
return NAME_NOT_FOUND;
}
*outSupport =
- getHwComposer().hasDisplayCapability(displayId, HWC2::DisplayCapability::Brightness);
+ getHwComposer().hasDisplayCapability(*displayId, HWC2::DisplayCapability::Brightness);
return NO_ERROR;
}
@@ -4404,6 +4404,7 @@
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
mScheduler->dump(mAppConnectionHandle, result);
+ mScheduler->getPrimaryDispSync().dump(result);
}
void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
@@ -5755,7 +5756,6 @@
// buffer bounds.
clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight);
clientCompositionDisplay.clip = sourceCrop;
- clientCompositionDisplay.globalTransform = mat4();
clientCompositionDisplay.orientation = rotation;
clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace();
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 0b1251e..f0b895d 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -36,22 +36,21 @@
: mFlinger(flinger), mSfLock(flinger.mDrawingStateLock) {}
void SurfaceTracing::mainLoop() {
- addFirstEntry();
- bool enabled = true;
+ bool enabled = addFirstEntry();
while (enabled) {
LayersTraceProto entry = traceWhenNotified();
enabled = addTraceToBuffer(entry);
}
}
-void SurfaceTracing::addFirstEntry() {
+bool SurfaceTracing::addFirstEntry() {
const auto displayDevice = mFlinger.getDefaultDisplayDevice();
LayersTraceProto entry;
{
std::scoped_lock lock(mSfLock);
entry = traceLayersLocked("tracing.enable", displayDevice);
}
- addTraceToBuffer(entry);
+ return addTraceToBuffer(entry);
}
LayersTraceProto SurfaceTracing::traceWhenNotified() {
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index a00e5d6..e90fc4d 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -90,7 +90,7 @@
};
void mainLoop();
- void addFirstEntry();
+ bool addFirstEntry();
LayersTraceProto traceWhenNotified();
LayersTraceProto traceLayersLocked(const char* where,
const sp<const DisplayDevice>& displayDevice)
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 3543361..1899bed 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -71,6 +71,7 @@
MOCK_CONST_METHOD0(now, nsecs_t());
MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
MOCK_METHOD0(alarmCancel, void());
+ MOCK_CONST_METHOD1(dump, void(std::string&));
void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
mCallback = callback;
@@ -188,6 +189,7 @@
}
void alarmCancel() final { mControllableClock.alarmCancel(); }
nsecs_t now() const final { return mControllableClock.now(); }
+ void dump(std::string&) const final {}
private:
TimeKeeper& mControllableClock;