Add compatibility param to setFrameRate() api
Add a compatiblity param to the setFrameRate() api, so the system has
more info to decide the device frame rate when there are multiple
competing preferences.
I also changed the plumbing for setFrameRate() to go directly to surface
flinger, instead of through buffer queue. We're trying to avoid changes
to buffer queue code, to avoid disturbing the prebuilts.
Bug: 137287430
Test: Added new cts tests to verify behavior of the compatibility param.
cts-tradefed run commandAndExit cts-dev --module CtsGraphicsTestCases --test android.graphics.cts.SetFrameRateTest
Test: /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test --gtest_filter='SetFrameRateTest.*'
Change-Id: Ibe75a778fb459d4138a1446c1b38b44798b56a99
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 2f27fd2..ce41eab 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1112,6 +1112,42 @@
}
return NO_ERROR;
}
+
+ virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+ int8_t compatibility) {
+ Parcel data, reply;
+ status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed writing interface token: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = data.writeStrongBinder(IInterface::asBinder(surface));
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed writing strong binder: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = data.writeFloat(frameRate);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed writing float: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = data.writeByte(compatibility);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed writing byte: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err);
+ return err;
+ }
+ return NO_ERROR;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -1877,6 +1913,36 @@
return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ,
lightRadius);
}
+ case SET_FRAME_RATE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> binder;
+ status_t err = data.readStrongBinder(&binder);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed to read strong binder: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+ sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder);
+ if (!surface) {
+ ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+ float frameRate;
+ err = data.readFloat(&frameRate);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed to read float: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+ int8_t compatibility;
+ err = data.readByte(&compatibility);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+ status_t result = setFrameRate(surface, frameRate, compatibility);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 5547efc..a9c9b74 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -24,6 +24,8 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/LayerState.h>
+#include <cmath>
+
namespace android {
status_t layer_state_t::write(Parcel& output) const
@@ -113,6 +115,7 @@
output.writeFloat(shadowRadius);
output.writeInt32(frameRateSelectionPriority);
output.writeFloat(frameRate);
+ output.writeByte(frameRateCompatibility);
return NO_ERROR;
}
@@ -194,6 +197,7 @@
shadowRadius = input.readFloat();
frameRateSelectionPriority = input.readInt32();
frameRate = input.readFloat();
+ frameRateCompatibility = input.readByte();
return NO_ERROR;
}
@@ -427,6 +431,7 @@
if (other.what & eFrameRateChanged) {
what |= eFrameRateChanged;
frameRate = other.frameRate;
+ frameRateCompatibility = other.frameRateCompatibility;
}
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
@@ -474,4 +479,21 @@
syncInputWindows = input.readBool();
}
+bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) {
+ const char* functionName = inFunctionName != nullptr ? inFunctionName : "call";
+ int floatClassification = std::fpclassify(frameRate);
+ if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) {
+ ALOGE("%s failed - invalid frame rate %f", functionName, frameRate);
+ return false;
+ }
+
+ if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
+ compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) {
+ ALOGE("%s failed - invalid compatibility value %d", functionName, compatibility);
+ return false;
+ }
+
+ return true;
+}
+
}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 278cc59..f911e70 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -43,6 +43,7 @@
#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
#include <private/gui/ComposerService.h>
namespace android {
@@ -1413,7 +1414,8 @@
int Surface::dispatchSetFrameRate(va_list args) {
float frameRate = static_cast<float>(va_arg(args, double));
- return setFrameRate(frameRate);
+ int8_t compatibility = static_cast<int8_t>(va_arg(args, int));
+ return setFrameRate(frameRate, compatibility);
}
int Surface::dispatchAddCancelInterceptor(va_list args) {
@@ -2222,11 +2224,15 @@
mSurfaceListener->onBuffersDiscarded(discardedBufs);
}
-status_t Surface::setFrameRate(float frameRate) {
+status_t Surface::setFrameRate(float frameRate, int8_t compatibility) {
ATRACE_CALL();
- ALOGV("Surface::setTargetFrameRate");
- Mutex::Autolock lock(mMutex);
- return mGraphicBufferProducer->setFrameRate(frameRate);
+ ALOGV("Surface::setFrameRate");
+
+ if (!ValidateFrameRate(frameRate, compatibility, "Surface::setFrameRate")) {
+ return BAD_VALUE;
+ }
+
+ return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility);
}
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7017b7c..7f28c6c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1402,14 +1402,19 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate(
- const sp<SurfaceControl>& sc, float frameRate) {
+ const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
+ if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate")) {
+ mStatus = BAD_VALUE;
+ return *this;
+ }
s->what |= layer_state_t::eFrameRateChanged;
s->frameRate = frameRate;
+ s->frameRateCompatibility = compatibility;
return *this;
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e860f61..0659f0d 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -500,6 +500,12 @@
virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ,
float lightRadius) = 0;
+
+ /*
+ * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info.
+ */
+ virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+ int8_t compatibility) = 0;
};
// ----------------------------------------------------------------------------
@@ -557,6 +563,7 @@
SET_AUTO_LOW_LATENCY_MODE,
GET_GAME_CONTENT_TYPE_SUPPORT,
SET_GAME_CONTENT_TYPE,
+ SET_FRAME_RATE,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 2d53b48..7e3d5d5 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -20,8 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Errors.h>
-
+#include <android/native_window.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ITransactionCompletedListener.h>
#include <math/mat4.h>
@@ -36,6 +35,7 @@
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Rotation.h>
+#include <utils/Errors.h>
namespace android {
@@ -135,7 +135,8 @@
colorSpaceAgnostic(false),
shadowRadius(0.0f),
frameRateSelectionPriority(-1),
- frameRate(0.0f) {
+ frameRate(0.0f),
+ frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -221,7 +222,9 @@
// Priority of the layer assigned by Window Manager.
int32_t frameRateSelectionPriority;
+ // Layer frame rate and compatibility. See ANativeWindow_setFrameRate().
float frameRate;
+ int8_t frameRateCompatibility;
};
struct ComposerState {
@@ -292,6 +295,12 @@
return compare_type(lhs.token, rhs.token);
}
+// Returns true if the frameRate and compatibility are valid values, false
+// othwerise. If either of the params are invalid, an error log is printed, and
+// functionName is added to the log to indicate which function call failed.
+// functionName can be null.
+bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName);
+
}; // namespace android
#endif // ANDROID_SF_LAYER_STATE_H
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 4a353fc..ad7cbfe 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -179,7 +179,7 @@
status_t getConsumerUsage(uint64_t* outUsage) const;
// See IGraphicBufferProducer::setFrameRate
- status_t setFrameRate(float frameRate);
+ status_t setFrameRate(float frameRate, int8_t compatibility);
protected:
virtual ~Surface();
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d0bb6a3..fe3dec5 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -525,7 +525,8 @@
const Rect& source, const Rect& dst, int transform);
Transaction& setShadowRadius(const sp<SurfaceControl>& sc, float cornerRadius);
- Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate);
+ Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate,
+ int8_t compatibility);
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 70fd888..8c0f8f8 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -854,6 +854,11 @@
return NO_ERROR;
}
+ status_t setFrameRate(const sp<IGraphicBufferProducer>& /*surface*/, float /*frameRate*/,
+ int8_t /*compatibility*/) override {
+ return NO_ERROR;
+ }
+
protected:
IBinder* onAsBinder() override { return nullptr; }